]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AsyncReadEntry.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / AsyncReadEntry.java
index f409b40c8c330069023ede4686c6363ba76ae948..2fdb43d113332e4f33b6b131685fd8c80c112b22 100644 (file)
  *******************************************************************************/
 package org.simantics.db.impl.query;
 
+import java.util.Collection;
+
+import org.simantics.databoard.Bindings;
 import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.DevelopmentKeys;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.BlockingAsyncProcedure;
-import org.simantics.db.impl.DebugPolicy;
-import org.simantics.db.impl.graph.AsyncBarrierImpl;
 import org.simantics.db.impl.graph.ReadGraphImpl;
 import org.simantics.db.impl.query.QueryProcessor.SessionTask;
 import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.db.request.AsyncRead;
+import org.simantics.utils.Development;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements AsyncProcedure<T> {
+final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements AsyncProcedure<T>, IPending {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AsyncReadEntry.class);
 
-    protected AsyncRead<T> request;
+    protected AsyncRead<T> id;
+    protected PendingTaskSupport pendingTaskSupport;
 
     AsyncReadEntry(AsyncRead<T> request) {
-        this.request = request;
-        if (DebugPolicy.QUERY_STATE)
-            System.out.println("[QUERY STATE]: created " + this);
+        this.id = request;
+               if (Development.DEVELOPMENT) {
+                       if(Development.<Boolean>getProperty(DevelopmentKeys.CACHE_ENTRY_STATE, Bindings.BOOLEAN)) {
+                       System.err.println("[QUERY STATE]: created " + this);
+                       }
+               }
     }
 
     @Override
     int makeHash() {
-        return request.hashCode();
+        return id.hashCode();
     }
 
     @Override
     public Object getOriginalRequest() {
-        return request;
+        return id;
     }
 
     @Override
@@ -71,7 +78,7 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
                 try {
 
-                    BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure<>(graph.asyncBarrier, graph, new AsyncProcedure<T>() {
+                    BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure(graph, AsyncReadEntry.this, new AsyncProcedure<T>() {
 
                         @Override
                         public void execute(AsyncReadGraph graph, T result) {
@@ -84,11 +91,9 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
                             except(t);
                         }
 
-                    }, request);
-
-                    request.perform(graph, proc);
-
-                    proc.get();
+                    }, id, true);
+                    
+                    proc.performSync(id);
 
                 } catch (Throwable t) {
                     except(t);
@@ -103,17 +108,17 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
             @Override
             public int type() {
-                return request.getFlags();
+                return id.getFlags();
             }
 
             @Override
             public String toString() {
-                if (request == null)
+                if (id == null)
                     return "DISCARDED";
                 else if (isExcepted())
-                    return request.toString() + " " + getResult();
+                    return id.toString() + " " + getResult();
                 else
-                    return request.toString() + " " + statusOrException;
+                    return id.toString() + " " + statusOrException;
             }
 
         };
@@ -146,97 +151,71 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
     }
 
-    public static <T> T computeForEach(ReadGraphImpl graph, AsyncRead<T> request, AsyncReadEntry<T> entry,
+    public static <T> T computeForEach(ReadGraphImpl callerGraph, AsyncRead<T> request, AsyncReadEntry<T> entry,
             AsyncProcedure<T> procedure_, boolean needsToBlock) throws DatabaseException {
 
-        AsyncProcedure<T> procedure = entry != null ? entry : procedure_;
-
-        ReadGraphImpl queryGraph = graph.withParent(entry);
-        
-        BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure<>(queryGraph.asyncBarrier, graph, null, request);
-        
-        class AsyncTask extends SessionTask {
-
-               int counter = 0;
-            T result;
-            DatabaseException exception;
-            
-            public AsyncTask(ReadGraphImpl graph) {
-                super(graph);
-            }
-
-            @Override
-            public void run(int thread) {
-                if(needsToBlock) proc.waitBarrier();
-                if(proc.isDone()) {
-                    try {
-                        result = (T)proc.get();
-                        if(procedure != null) procedure.execute(graph, result);
-                    } catch (DatabaseException e) {
-                        if(procedure != null) procedure.exception(graph, e);
-                        exception = e;
-                    } catch (Throwable t) {
-                        DatabaseException dbe = new DatabaseException(t);
-                        if(procedure != null) procedure.exception(graph, dbe);
-                        exception = dbe;
-                    } finally {
-                        if (entry != null)
-                            entry.performFromCache(graph, procedure_);
-                    }
-                } else {
-                       if(counter++ > 10000) {
-                               AsyncBarrierImpl.printReverse(queryGraph.asyncBarrier, 2);
-                               AsyncBarrierImpl caller = queryGraph.asyncBarrier.caller;
-                               while(caller != null) {
-                                       System.err.println("called by " + AsyncBarrierImpl.report(caller));
-                                       caller = caller.caller;
-                               }
-                               for(AsyncBarrierImpl ab : AsyncBarrierImpl.debuggerMap.keySet()) {
-                               AsyncBarrierImpl.printReverse(ab, 2);
-                               }
-                               throw new IllegalStateException("Eternal loop in queries.");
-                       }
-                    graph.processor.schedule(this);            
-                }
-            }
-            
-        }
-        
-        request.perform(queryGraph, proc);
-        
-        AsyncTask task = new AsyncTask(graph);
-
-        if(needsToBlock) task.run(0);
-        else if (proc.isDone()) task.run(0);
-        else  {
-            graph.processor.schedule(task);
+        BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure(callerGraph, entry, procedure_, request, needsToBlock);
+        if(needsToBlock) {
+            return proc.performSync(request);
+        } else {
+            proc.performAsync(request);
             return null;
         }
-        
-        if(task.exception != null) throw task.exception;
-        else return task.result;
 
     }
 
     @Override
     public String toString() {
         if (isDiscarded())
-            return "DISCARDED " + request.toString();
+            return "DISCARDED " + id.toString();
         else if (isExcepted())
-            return request.toString() + " " + getResult();
+            return id.toString() + " " + getResult();
         else
-            return request.toString() + " " + statusOrException;
+            return id.toString() + " " + statusOrException;
     }
 
     @Override
     public void execute(AsyncReadGraph graph, T result) {
-        setResult(result);
-        setReady();
+        Collection<SessionTask> tasks = null;
+        synchronized(this) {
+            setResult(result);
+            setReady();
+            if(pendingTaskSupport != null)
+                tasks = pendingTaskSupport.executePending();
+        }
+        if(tasks != null)
+            for(SessionTask task : tasks)
+                ((ReadGraphImpl)graph).processor.scheduleNow(task);
+    }
+
+    @Override
+    public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
+        Collection<SessionTask> tasks = null;
+        synchronized(this) {
+            except(throwable);
+            if(pendingTaskSupport != null)
+                tasks = pendingTaskSupport.executePending();
+        }
+        if(tasks != null)
+            for(SessionTask task : tasks)
+                ((ReadGraphImpl)graph).processor.scheduleNow(task);
+    }
+
+    public void executeWhenResultIsAvailable(QueryProcessor processor, SessionTask task) {
+        boolean ready = false;
+        synchronized(this) {
+            if(pendingTaskSupport == null)
+                pendingTaskSupport = new PendingTaskSupport(this);
+            ready = pendingTaskSupport.executeWhenResultIsAvailable(task);
+        }
+        if(ready) {
+            processor.scheduleNow(task);
+        }
     }
 
     @Override
-    public void exception(AsyncReadGraph graph, Throwable throwable) {
-        except(throwable);
+    public String classId() {
+        return null;
     }
 
 }