]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.indexing/src/org/simantics/db/indexing/IndexedRelationsImpl.java
Improve startup time for fresh or rollback'd session in index writing
[simantics/platform.git] / bundles / org.simantics.db.indexing / src / org / simantics / db / indexing / IndexedRelationsImpl.java
index bc9247e37818302ce53b3bdbfd5b35f9c406d21d..390c0d17fce817225bde69d07e4515408fee4229 100644 (file)
  *******************************************************************************/
 package org.simantics.db.indexing;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.WeakHashMap;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -27,16 +32,22 @@ import org.eclipse.core.runtime.SubMonitor;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.RequestProcessor;
 import org.simantics.db.Resource;
+import org.simantics.db.common.request.ReadRequest;
 import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.utils.NameUtils;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.exception.InvalidResourceReferenceException;
 import org.simantics.db.indexing.IndexedRelationsSearcherBase.State;
 import org.simantics.db.layer0.adapter.GenericRelation;
 import org.simantics.db.layer0.genericrelation.IndexException;
 import org.simantics.db.layer0.genericrelation.IndexedRelations;
+import org.simantics.db.layer0.util.Layer0Utils;
 import org.simantics.db.service.QueryControl;
 import org.simantics.db.service.SerialisationSupport;
+import org.simantics.operation.Layer0X;
 import org.simantics.utils.datastructures.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * @author Tuukka Lehtonen
@@ -44,6 +55,8 @@ import org.simantics.utils.datastructures.Pair;
  */
 public class IndexedRelationsImpl implements IndexedRelations {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(IndexedRelationsImpl.class);
+    
     Map<Object, RWLock> indexLocks = new WeakHashMap<Object, RWLock>();
 
     static class LockHandle {
@@ -125,7 +138,7 @@ public class IndexedRelationsImpl implements IndexedRelations {
         return rwlock.tryLock(processor, write);
     }
 
-    private IndexedRelationsSearcherBase makeSearcher(final RequestProcessor processor, final Resource relation, final Resource input) {
+    private static IndexedRelationsSearcherBase makeSearcher(final RequestProcessor processor, final Resource relation, final Resource input) {
        try {
                        return processor.syncRequest(new UniqueRead<IndexedRelationsSearcherBase>() {
 
@@ -370,7 +383,7 @@ public class IndexedRelationsImpl implements IndexedRelations {
 
     @Override
     public void insert(IProgressMonitor monitor, RequestProcessor processor, GenericRelation relation,  
-            Resource relationResource, Resource input, Collection<Object[]> documents) {
+            Resource relationResource, Resource input, Collection<Object[]> documents) throws IndexException {
 
 //        System.out.println("Inserting to index: " + input + " " + documents);
 
@@ -413,7 +426,7 @@ public class IndexedRelationsImpl implements IndexedRelations {
 
     @Override
     public void remove(IProgressMonitor monitor, RequestProcessor processor, GenericRelation relation,
-            Resource relationResource, Resource input, String key, Collection<Object> keyValues) {
+            Resource relationResource, Resource input, String key, Collection<Object> keyValues) throws IndexException {
 
         if (relation == null)
             throw new IllegalArgumentException("null relation");
@@ -473,7 +486,7 @@ public class IndexedRelationsImpl implements IndexedRelations {
     
     @Override
     public boolean replace(IProgressMonitor monitor, RequestProcessor processor, GenericRelation relation,
-            Resource relationResource, Resource input, String key, Collection<Object> keyValues, Collection<Object[]> documents) {
+            Resource relationResource, Resource input, String key, Collection<Object> keyValues, Collection<Object[]> documents) throws IndexException {
 
         if (relation == null)
             throw new IllegalArgumentException("null relation");
@@ -521,16 +534,15 @@ public class IndexedRelationsImpl implements IndexedRelations {
         IndexedRelationsSearcherBase searcher = makeSearcher(processor, relationResource, input);
 
         LockHandle handle = lock(processor, Pair.make(relationResource, input), true);
-
+        Path path = DatabaseIndexing.getIndexLocation(processor.getSession(), relationResource, input);
         try {
             searcher.changeState(monitor, processor.getSession(), State.NONE);
             if (!searcher.checkState(State.NONE))
                 throw new IndexException("Could not close index for input " + input + " before removing it");
 
-            File path = DatabaseIndexing.getIndexLocation(processor.getSession(), relationResource, input);
             DatabaseIndexing.deleteIndex(path);
-
         } catch (IOException e) {
+            LOGGER.error("Could not delete {}", path.toAbsolutePath(), e);
             throw new IndexException(e);
         } finally {
             handle.unlock();
@@ -538,4 +550,79 @@ public class IndexedRelationsImpl implements IndexedRelations {
 
     }
 
+    @Override
+    public void fullRebuild(IProgressMonitor monitor, RequestProcessor processor) throws IndexException {
+        try {
+            processor.syncRequest(new ReadRequest() {
+                @Override
+                public void run(ReadGraph graph) throws DatabaseException {
+                    try {
+                        fullRebuild(monitor, graph);
+                    } catch (IOException e) {
+                        throw new DatabaseException(e);
+                    }
+                }
+            });
+        } catch (DatabaseException e) {
+            throw new IndexException(e);
+        }
+    }
+
+    private void fullRebuild(IProgressMonitor monitor, ReadGraph graph) throws DatabaseException, IOException {
+        long startTime = System.currentTimeMillis();
+        Resource relation = Layer0X.getInstance(graph).DependenciesRelation;
+        SerialisationSupport ss = graph.getService(SerialisationSupport.class);
+        Set<Resource> indexRoots = Layer0Utils.listIndexRoots(graph);
+        List<CompletableFuture<?>> waitFor = new ArrayList<>(indexRoots.size());
+        SubMonitor mon = SubMonitor.convert(monitor, indexRoots.size()*2);
+
+        for (Resource indexRoot : indexRoots) {
+            monitor.subTask(NameUtils.getSafeName(graph, indexRoot));
+
+            IndexedRelationsSearcherBase searcher = makeSearcher(graph, relation, indexRoot);
+
+            GenericRelation r = graph.adapt(relation, GenericRelation.class);
+            if (r == null)
+                throw new DatabaseException("Given resource " + relation + "could not be adapted to GenericRelation.");
+
+            Object[] bound = new Object[] { ss.getRandomAccessId(indexRoot) };
+            GenericRelation selection = r.select(IndexedRelationsSearcherBase.getPattern(r, bound.length), bound);
+
+            long relStart = System.currentTimeMillis();
+            List<Object[]> results = selection.realize(graph);
+            if (LOGGER.isDebugEnabled()) {
+                long relEnd = System.currentTimeMillis() - relStart;
+                LOGGER.debug(indexRoot + " realized " + relEnd);
+            }
+            mon.worked(1);
+
+            CompletableFuture<?> result = new CompletableFuture<>();
+            waitFor.add(result);
+            ForkJoinPool.commonPool().submit(() -> {
+                long startTime1 = System.currentTimeMillis();
+                try {
+                    searcher.initializeIndexImpl(result, mon.newChild(1, SubMonitor.SUPPRESS_ALL_LABELS), r, results, bound, true);
+                    searcher.setReady();
+                } catch (IOException e) {
+                    result.completeExceptionally(e);
+                    LOGGER.error("Could not initialize index", e);
+                } finally {
+                    if (LOGGER.isDebugEnabled())
+                        LOGGER.debug(indexRoot + " initialized " + (System.currentTimeMillis() - startTime1));
+                }
+            });
+        }
+        for (CompletableFuture<?> fut : waitFor) {
+            try {
+                fut.get();
+            } catch (InterruptedException | ExecutionException e) {
+                throw (IOException) e.getCause();
+            }
+        }
+        if (LOGGER.isInfoEnabled()) {
+            long endTime = System.currentTimeMillis() - startTime;
+            LOGGER.info("All indexes rebuilt in {}", endTime);
+        }
+    }
+
 }