]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Simupedia tuning
authorAntti Villberg <antti.villberg@semantum.fi>
Wed, 8 Jan 2020 15:12:00 +0000 (17:12 +0200)
committerAntti Villberg <antti.villberg@semantum.fi>
Wed, 8 Jan 2020 15:12:00 +0000 (17:12 +0200)
Change-Id: Ic18f95c59eb4c3d02e211f181bed57b68b152045

19 files changed:
bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java
bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
bundles/org.simantics.db.layer0/adapters.xml
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/SessionGarbageCollection.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java

index ec4d56c211ad54640d6d6f429d8847e8d6bf7760..1e4b5cbac508623fff9fd9d5017043818ce1ee42 100644 (file)
@@ -102,17 +102,15 @@ public class MainProgram implements Runnable, Closeable {
 
                                if(updates.isEmpty()) {
 
-                                       long start = System.nanoTime();
-
-                                       operationQueue.waitFor();
+                                       long duration = operationQueue.waitFor();
 
                                        if (!alive)
                                                break main;
 
-                                       long duration = System.nanoTime()-start;
                                        if(duration > 4000000000L) {
                                                checkIdle();
                                        }
+                                       
                                }
 
 //                             long sss = System.nanoTime();
index 7a9d8aba23f1b714d190a92552f879066775a94e..48b891f0ef4215926adb8f06b099b78e07874630 100644 (file)
@@ -157,18 +157,23 @@ class OperationQueue {
         * Wake up when new operations are scheduled or the last operation is committed
         * Called by MainProgram thread
         */
-       synchronized void waitFor() {
+       synchronized long waitFor() {
 
-               mainProgram.assertMainProgramThread();
+           mainProgram.assertMainProgramThread();
 
-               // One last check within the monitor 
-               if(!operations.isEmpty() || !tasks.isEmpty()) return;
+           // One last check within the monitor 
+           if(!operations.isEmpty() || !tasks.isEmpty()) return 0;
 
-               try {
-                       wait(5000);
-               } catch (InterruptedException e) {
-                       LOGGER.error("Unexpected interruption", e);
-               }
+           long start = System.nanoTime();
+           System.err.println("start =" + start);
+
+           try {
+               wait(5000);
+           } catch (InterruptedException e) {
+               LOGGER.error("Unexpected interruption", e);
+           }
+           
+           return System.nanoTime() - start;
 
        }
 
index 2e5411d39f8ea5c90242d22fc0fe400c4bda058a..ba39c57dfe65f5db752d9a1977a4bdd5cefa36db 100644 (file)
@@ -1926,9 +1926,9 @@ public class ReadGraphImpl implements AsyncReadGraph {
        public <T> T syncRequest(final Read<T> request) throws DatabaseException {
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                T result = (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true);
-               task.finish();
+               //task.finish();
                return result;
                
        }
@@ -1950,10 +1950,10 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                ListenerBase listener = procedure != null ? getListenerBase(procedure) : null;
                T result = QueryCache.resultReadEntry(this, request, parent, listener, procedure);
-               task.finish();
+               //task.finish();
                return result;
 
        }
@@ -2038,10 +2038,10 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                ListenerBase listener = getListenerBase(procedure);
                T result = (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); 
-               task.finish();
+               //task.finish();
                return result;
 
        }
@@ -5248,7 +5248,7 @@ public class ReadGraphImpl implements AsyncReadGraph {
                assert (request != null);
                assert (procedure != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                
         AsyncBarrierImpl barrier = asyncBarrier;
         if(barrier != null)
@@ -5268,7 +5268,7 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                                                @Override
                                                public void execute(AsyncReadGraph graph, T result) {
-                                                       task.finish();
+                                                       //task.finish();
                                                        procedure.execute(graph, result);
                                                if(barrier != null)
                                                    barrier.dec();
@@ -5276,7 +5276,7 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                                                @Override
                                                public void exception(AsyncReadGraph graph, Throwable throwable) {
-                                                       task.finish();
+                                                       //task.finish();
                                                        procedure.exception(graph, throwable);
                             if(barrier != null)
                                 barrier.dec();
index 9daab950e3964a8681a12fabc5ef0b2cfaf74ceb..b873bfd73ef8f9b97773977b2459d7cdb502e9c6 100644 (file)
@@ -14,9 +14,10 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.db.DevelopmentKeys;
@@ -37,372 +38,462 @@ public class QueryListening {
 
     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(QueryListening.class);
 
-       final private QueryProcessor                            processor;
-       private THashSet<ListenerEntry>                         scheduledListeners    = new THashSet<ListenerEntry>();
-       private boolean                                         firingListeners       = false;
-       final THashMap<CacheEntry, ArrayList<ListenerEntry>>    listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
-       private BlockingQueue<Runnable>                         tasks = new ArrayBlockingQueue<Runnable>(2048);
-       private Map<ListenerBase,ListenerEntry>                 addedEntries = new HashMap<>();
-       
-       QueryListening(QueryProcessor processor) {
-               this.processor = processor;
-               new DependencyManagementThread(processor, tasks).start();
-       }
-       
-       public void sync() {
-               Semaphore s = new Semaphore(0);
-               try {
-                       tasks.put(() -> {
-                               s.release();
-                       });
-                       s.acquire();
-               } catch (Throwable t) {
-                       LOGGER.error("Error while waiting for query dependency management", t);
-               }
-       }
-       
-       static class DependencyManagementThread extends Thread {
-               
-               final private QueryProcessor processor;
-               final BlockingQueue<Runnable> tasks;
-               
-               DependencyManagementThread(QueryProcessor processor, BlockingQueue<Runnable> tasks) {
-                       setName("Query Dependency Manager");
-                       this.processor = processor;
-                       this.tasks = tasks;
-               }
-               
-               @Override
-               public void run() {
-                       while(processor.isAlive()) {
-                               try {
-                                       Runnable r = tasks.take();
-                                       r.run();
-                               } catch (Throwable t) {
-                                       // Spurious problems?
-                                       LOGGER.error("Error while waiting for query dependency management tasks", t);
-                               }
-                       }
-               }
-               
-       }
-       
-       public boolean hasScheduledUpdates() {
-               return !scheduledListeners.isEmpty();
-       }
-
-       void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
-               
-               try {
-                       tasks.put(() -> {
-
-                               if (parent != null && !inferred) {
-                                       try {
-                                               if(!child.isImmutable(graph))
-                                                       child.addParent(parent);
-                                       } catch (DatabaseException e) {
-                                               LOGGER.error("Error while registering query dependencies", e);
-                                       }
-                                       if (Development.DEVELOPMENT) {
-                                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) {
-                                                       System.out.println(child + " -> " + parent);
-                                               }
-                                       }
-                               }
-
-                               if (listener != null)
-                                       registerListener(child, listener, procedure);
-
-                       });
-               } catch (InterruptedException e) {
-                       LOGGER.error("Error while registering dependencies", e);
-               }
-               
-       }
-
-       void registerFirstKnown(ListenerBase base, Object result) {
-               
-               tasks.offer(() -> {
-
-                       ListenerEntry entry = addedEntries.get(base);
-                       if(entry != null) entry.setLastKnown(result);
-                       
-               });
-               
-       }
-
-       public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
-
-               assert (entry != null);
-
-               if (base.isDisposed())
-                       return null;
-
-               return addListener(entry, base, procedure);
-
-       }
-
-       /*
-        * Registers a listener and returns an entry iff the entry was added
-        */
-       private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
-
-               assert (entry != null);
-               assert (procedure != null);
-
-               ArrayList<ListenerEntry> list = listeners.get(entry);
-               if (list == null) {
-                       list = new ArrayList<>(1);
-                       listeners.put(entry, list);
-               }
-
-               ListenerEntry result = new ListenerEntry(entry, base, procedure);
-               // Equals is here based on base
-               int currentIndex = list.indexOf(result);
-               // There was already a listener
-               if(currentIndex > -1) {
-                       ListenerEntry current = list.get(currentIndex);
-                       if(!current.base.isDisposed()) return null;
-                       list.set(currentIndex, result);
-               } else {
-                       list.add(result);
-               }
-
-               if (Development.DEVELOPMENT) {
-                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                               new Exception().printStackTrace();
-                               System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
-                       }
-               }
-               
-               addedEntries.put(base, result);
-               
-               return result;
-
-       }
-
-       void scheduleListener(ListenerEntry entry) {
-               assert (entry != null);
-               if (Development.DEVELOPMENT) {
-                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                               System.err.println("Scheduled " + entry.procedure);
-                       }
-               }
-               scheduledListeners.add(entry);
-       }
-
-       private void removeListener(ListenerEntry entry) {
-               assert (entry != null);
-               ArrayList<ListenerEntry> list = listeners.get(entry.entry);
-               if(list == null) return;
-               boolean success = list.remove(entry);
-               assert (success);
-               if (list.isEmpty())
-                       listeners.remove(entry.entry);
-       }
-
-       boolean hasListener(CacheEntry entry) {
-               if(listeners.get(entry) != null) return true;
-               return false;
-       }
-
-       boolean hasListenerAfterDisposing(CacheEntry entry) {
-               if(listeners.get(entry) != null) {
-                       ArrayList<ListenerEntry> entries = listeners.get(entry);
-                       ArrayList<ListenerEntry> list = null;
-                       for (ListenerEntry e : entries) {
-                               if (e.base.isDisposed()) {
-                                       if(list == null) list = new ArrayList<ListenerEntry>();
-                                       list.add(e);
-                               }
-                       }
-                       if(list != null) {
-                               for (ListenerEntry e : list) {
-                                       entries.remove(e);
-                               }
-                       }
-                       if (entries.isEmpty()) {
-                               listeners.remove(entry);
-                               return false;
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-       List<ListenerEntry> getListenerEntries(CacheEntry entry) {
-               hasListenerAfterDisposing(entry);
-               if(listeners.get(entry) != null)
-                       return listeners.get(entry);
-               else 
-                       return Collections.emptyList();
-       }
-
-       void processListenerReport(CacheEntry<?> entry, Map<CacheEntry, Set<ListenerBase>> workarea) {
-
-               if(!workarea.containsKey(entry)) {
-
-                       HashSet<ListenerBase> ls = new HashSet<ListenerBase>();
-                       for(ListenerEntry e : getListenerEntries(entry))
-                               ls.add(e.base);
-
-                       workarea.put(entry, ls);
-
-                       for(CacheEntry parent : entry.getParents(processor)) {
-                               processListenerReport(parent, workarea);
-                               ls.addAll(workarea.get(parent));
-                       }
-
-               }
-
-       }
-
-       public synchronized ListenerReport getListenerReport() throws IOException {
-
-               class ListenerReportImpl implements ListenerReport {
-
-                       Map<CacheEntry, Set<ListenerBase>> workarea = new HashMap<CacheEntry, Set<ListenerBase>>();
-
-                       @Override
-                       public void print(PrintStream b) {
-                               Map<ListenerBase, Integer> hist = new HashMap<ListenerBase, Integer>();
-                               for(Map.Entry<CacheEntry, Set<ListenerBase>> e : workarea.entrySet()) {
-                                       for(ListenerBase l : e.getValue()) {
-                                               Integer i = hist.get(l);
-                                               hist.put(l, i != null ? i-1 : -1);
-                                       }
-                               }
-
-                               for(Pair<ListenerBase, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
-                                       b.print("" + -p.second + " " + p.first + "\n");
-                               }
-
-                               b.flush();
-                       }
-
-               }
-
-               ListenerReportImpl result = new ListenerReportImpl();
-
-               Collection<CacheEntryBase> all = processor.allCaches(new CacheCollectionResult()).toCollection();
-               for(CacheEntryBase entry : all) {
-                       hasListenerAfterDisposing(entry);
-               }
-               for(CacheEntryBase entry : all) {
-                       processListenerReport(entry, result.workarea);
-               }
-
-               return result;
-
-       }
-
-       public synchronized String reportListeners(File file) throws IOException {
-
-               if (!processor.isAlive())
-                       return "Disposed!";
-
-               PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
-               ListenerReport report = getListenerReport();
-               report.print(b);
-
-               return "Done reporting listeners.";
-
-       }
-
-       public void fireListeners(WriteGraphImpl graph) {
-
-               assert (!processor.updating);
-               assert (!processor.cache.collecting);
-               assert (!firingListeners);
-
-               firingListeners = true;
-
-               try {
-
-                       // Performing may cause further events to be scheduled.
-                       while (!scheduledListeners.isEmpty()) {
-
-                               // Clone current events to make new entries possible during
-                               // firing.
-                               THashSet<ListenerEntry> entries = scheduledListeners;
-                               scheduledListeners = new THashSet<ListenerEntry>();
+    final private QueryProcessor                            processor;
+    private THashSet<ListenerEntry>                         scheduledListeners    = new THashSet<ListenerEntry>();
+    private boolean                                         firingListeners       = false;
+    final THashMap<CacheEntry, ArrayList<ListenerEntry>>    listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
+    private EventBusImpl                                    eventBus;
+    private Consumer<Runnable>                              consumer;
+    private Map<ListenerBase,ListenerEntry>                 addedEntries = new HashMap<>();
+
+    int execCount=0;
+    int queueCount = 0;
+
+    static class TL extends ThreadLocal<ArrayList<Runnable>> {
+
+        Map<Thread,ArrayList<Runnable>> allQueues = new HashMap<>();
+        ArrayList<ArrayList<Runnable>> dispatchedQueues = new ArrayList<>();
+
+        @Override
+        protected synchronized ArrayList<Runnable> initialValue() {
+            ArrayList<Runnable> result = new ArrayList<>();
+            allQueues.put(Thread.currentThread(), result);
+            return result;
+        }
+
+        synchronized void sendToExecution() {
+            ArrayList<Runnable> rs = allQueues.remove(Thread.currentThread());
+            dispatchedQueues.add(rs);
+            notify();
+        }
+
+        synchronized ArrayList<ArrayList<Runnable>> getDispatchedQueues() {
+            ArrayList<ArrayList<Runnable>> result = dispatchedQueues;
+            dispatchedQueues = new ArrayList<>();
+            return result;
+        }
+
+    }
+
+    static class EventBusImpl {
+
+        private static final int BUFFER_SIZE = 100;
+
+        TL queues = new TL();
+        Semaphore flush = null;
+
+        public boolean isTerminated() {
+            return false;
+        }
+
+        public Consumer<Runnable> newConsumer() {
+            return new Consumer<Runnable>() {
+
+                @Override
+                public void accept(Runnable arg0) {
+                    ArrayList<Runnable> l = queues.get();
+                    l.add(arg0);
+                    if(l.size() == BUFFER_SIZE) {
+                        queues.remove();
+                        queues.sendToExecution();
+                    }
+                }
+            };
+        }
+
+        public void shutdown() {
+        }
+
+        public void start(ThreadFactory arg1) {
+            arg1.newThread(new Runnable() {
+
+                @Override
+                public void run() {
+                    synchronized(queues) {
+                        while(!isTerminated()) {
+                            try {
+                                ArrayList<ArrayList<Runnable>> qs = queues.getDispatchedQueues();
+                                for(ArrayList<Runnable> queue : qs) {
+                                    for(Runnable r : queue)
+                                        r.run();
+                                }
+                                if(flush != null) {
+                                    for(ArrayList<Runnable> queue : queues.allQueues.values()) {
+                                        for(Runnable r : queue) {
+                                            r.run();   
+                                        }
+                                        queue.clear();
+                                    }
+                                    Semaphore s = flush;
+                                    flush = null;
+                                    s.release();
+                                }
+                                queues.wait(1000);
+                            } catch (InterruptedException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+
+            }).start();
+        }
+
+        void flush() {
+            synchronized(queues) {
+                flush = new Semaphore(0);
+                queues.notify();
+            }
+            try {
+                flush.acquire();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    QueryListening(QueryProcessor processor) {
+        this.processor = processor;
+        eventBus = new EventBusImpl();
+        consumer = eventBus.newConsumer();
+        eventBus.start(new ThreadFactory()
+        {
+            @Override
+            public Thread newThread(Runnable r) {
+                System.err.println("new Thread " + r);
+                return new Thread(r, "QueryDependencyManager");
+            }
+        });
+    }
+
+    public void sync() {
+        try {
+            eventBus.flush();
+        } catch (Throwable t) {
+            LOGGER.error("Error while waiting for query dependency management", t);
+        }
+    }
+
+    public boolean hasScheduledUpdates() {
+        return !scheduledListeners.isEmpty();
+    }
+
+    public synchronized void dispatch(Runnable r) {
+        queueCount++;
+        consumer.accept(r);
+    }
+
+    void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
+
+        dispatch(() -> {
+
+            if (parent != null && !inferred) {
+                try {
+                    if(!child.isImmutable(graph))
+                        child.addParent(parent);
+                } catch (DatabaseException e) {
+                    LOGGER.error("Error while registering query dependencies", e);
+                }
+                if (Development.DEVELOPMENT) {
+                    if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) {
+                        System.out.println(child + " -> " + parent);
+                    }
+                }
+            }
+
+            if (listener != null)
+                registerListener(child, listener, procedure);
+
+        });
+
+    }
+
+    void registerFirstKnown(ListenerBase base, Object result) {
+        
+        if(base == null) return;
+
+        dispatch(() -> {
+
+            ListenerEntry entry = addedEntries.get(base);
+            if(entry != null) entry.setLastKnown(result);
+
+        });
+
+    }
+
+    public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
+
+        assert (entry != null);
+
+        if (base.isDisposed())
+            return null;
+
+        return addListener(entry, base, procedure);
+
+    }
+
+    /*
+     * Registers a listener and returns an entry iff the entry was added
+     */
+    private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
+
+        assert (entry != null);
+        assert (procedure != null);
+
+        ArrayList<ListenerEntry> list = listeners.get(entry);
+        if (list == null) {
+            list = new ArrayList<>(1);
+            listeners.put(entry, list);
+        }
+
+        ListenerEntry result = new ListenerEntry(entry, base, procedure);
+        // Equals is here based on base
+        int currentIndex = list.indexOf(result);
+        // There was already a listener
+        if(currentIndex > -1) {
+            ListenerEntry current = list.get(currentIndex);
+            if(!current.base.isDisposed()) return null;
+            list.set(currentIndex, result);
+        } else {
+            list.add(result);
+        }
+
+        if (Development.DEVELOPMENT) {
+            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                new Exception().printStackTrace();
+                System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
+            }
+        }
+
+        addedEntries.put(base, result);
+
+        return result;
+
+    }
+
+    void scheduleListener(ListenerEntry entry) {
+        assert (entry != null);
+        if (Development.DEVELOPMENT) {
+            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                System.err.println("Scheduled " + entry.procedure);
+            }
+        }
+        scheduledListeners.add(entry);
+    }
+
+    private void removeListener(ListenerEntry entry) {
+        assert (entry != null);
+        ArrayList<ListenerEntry> list = listeners.get(entry.entry);
+        if(list == null) return;
+        boolean success = list.remove(entry);
+        assert (success);
+        if (list.isEmpty())
+            listeners.remove(entry.entry);
+    }
+
+    boolean hasListener(CacheEntry entry) {
+        if(listeners.get(entry) != null) return true;
+        return false;
+    }
+
+    boolean hasListenerAfterDisposing(CacheEntry entry) {
+        if(listeners.get(entry) != null) {
+            ArrayList<ListenerEntry> entries = listeners.get(entry);
+            ArrayList<ListenerEntry> list = null;
+            for (ListenerEntry e : entries) {
+                if (e.base.isDisposed()) {
+                    if(list == null) list = new ArrayList<ListenerEntry>();
+                    list.add(e);
+                }
+            }
+            if(list != null) {
+                for (ListenerEntry e : list) {
+                    entries.remove(e);
+                }
+            }
+            if (entries.isEmpty()) {
+                listeners.remove(entry);
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    List<ListenerEntry> getListenerEntries(CacheEntry entry) {
+        hasListenerAfterDisposing(entry);
+        if(listeners.get(entry) != null)
+            return listeners.get(entry);
+        else 
+            return Collections.emptyList();
+    }
+
+    void processListenerReport(CacheEntry<?> entry, Map<CacheEntry, Set<ListenerBase>> workarea) {
+
+        if(!workarea.containsKey(entry)) {
+
+            HashSet<ListenerBase> ls = new HashSet<ListenerBase>();
+            for(ListenerEntry e : getListenerEntries(entry))
+                ls.add(e.base);
+
+            workarea.put(entry, ls);
+
+            for(CacheEntry parent : entry.getParents(processor)) {
+                processListenerReport(parent, workarea);
+                ls.addAll(workarea.get(parent));
+            }
+
+        }
+
+    }
+
+    public synchronized ListenerReport getListenerReport() throws IOException {
+
+        class ListenerReportImpl implements ListenerReport {
+
+            Map<CacheEntry, Set<ListenerBase>> workarea = new HashMap<CacheEntry, Set<ListenerBase>>();
+
+            @Override
+            public void print(PrintStream b) {
+                Map<ListenerBase, Integer> hist = new HashMap<ListenerBase, Integer>();
+                for(Map.Entry<CacheEntry, Set<ListenerBase>> e : workarea.entrySet()) {
+                    for(ListenerBase l : e.getValue()) {
+                        Integer i = hist.get(l);
+                        hist.put(l, i != null ? i-1 : -1);
+                    }
+                }
+
+                for(Pair<ListenerBase, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
+                    b.print("" + -p.second + " " + p.first + "\n");
+                }
+
+                b.flush();
+            }
+
+        }
+
+        ListenerReportImpl result = new ListenerReportImpl();
+
+        Collection<CacheEntryBase> all = processor.allCaches(new CacheCollectionResult()).toCollection();
+        for(CacheEntryBase entry : all) {
+            hasListenerAfterDisposing(entry);
+        }
+        for(CacheEntryBase entry : all) {
+            processListenerReport(entry, result.workarea);
+        }
+
+        return result;
+
+    }
+
+    public synchronized String reportListeners(File file) throws IOException {
+
+        if (!processor.isAlive())
+            return "Disposed!";
+
+        PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
+        ListenerReport report = getListenerReport();
+        report.print(b);
+
+        return "Done reporting listeners.";
+
+    }
+
+    public void fireListeners(WriteGraphImpl graph) {
+
+        assert (!processor.updating);
+        assert (!processor.cache.collecting);
+        assert (!firingListeners);
+
+        firingListeners = true;
+
+        try {
 
-                               ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
+            // Performing may cause further events to be scheduled.
+            while (!scheduledListeners.isEmpty()) {
 
-                               for (ListenerEntry listenerEntry : entries) {
+                // Clone current events to make new entries possible during
+                // firing.
+                THashSet<ListenerEntry> entries = scheduledListeners;
+                scheduledListeners = new THashSet<ListenerEntry>();
 
-                                       if (pruneListener(listenerEntry)) {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               new Exception().printStackTrace();
-                                                               System.err.println("Pruned " + listenerEntry.procedure);
-                                                       }
-                                               }
-                                               continue;
-                                       }
+                ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
 
-                                       final CacheEntry entry = listenerEntry.entry;
-                                       assert (entry != null);
+                for (ListenerEntry listenerEntry : entries) {
 
-                                       Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown());
+                    if (pruneListener(listenerEntry)) {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                new Exception().printStackTrace();
+                                System.err.println("Pruned " + listenerEntry.procedure);
+                            }
+                        }
+                        continue;
+                    }
+
+                    final CacheEntry entry = listenerEntry.entry;
+                    assert (entry != null);
+
+                    Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown());
+
+                    if (newValue != ListenerEntry.NOT_CHANGED) {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                new Exception().printStackTrace();
+                                System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
+                            }
+                        }
+                        schedule.add(listenerEntry);
+                        listenerEntry.setLastKnown(entry.getResult());
+                    }
+
+                }
+
+                for(ListenerEntry listenerEntry : schedule) {
+                    final CacheEntry entry = listenerEntry.entry;
+                    if (Development.DEVELOPMENT) {
+                        if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                            System.err.println("Firing " + listenerEntry.procedure);
+                        }
+                    }
+                    try {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
+                            }
+                        }
+                        entry.performFromCache(graph, listenerEntry.procedure);
+                    } catch (Throwable t) {
+                        t.printStackTrace();
+                    }
+                }
+
+            }
+
+        } finally {
+            firingListeners = false;
+        }
+
+    }
+
+    void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
+
+        Iterable<CacheEntry> oldParents = entry.getParents(processor);
+        for (CacheEntry parent : oldParents) {
+            if(!parent.isDiscarded())
+                todo.push(new UpdateEntry(entry, parent, indent + 2));
+        }
+
+    }
+
+    private boolean pruneListener(ListenerEntry entry) {
+        if (entry.base.isDisposed()) {
+            removeListener(entry);
+            return true;
+        } else {
+            return false;
+        }
+    }
 
-                                       if (newValue != ListenerEntry.NOT_CHANGED) {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               new Exception().printStackTrace();
-                                                               System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
-                                                       }
-                                               }
-                                               schedule.add(listenerEntry);
-                                               listenerEntry.setLastKnown(entry.getResult());
-                                       }
-
-                               }
-
-                               for(ListenerEntry listenerEntry : schedule) {
-                                       final CacheEntry entry = listenerEntry.entry;
-                                       if (Development.DEVELOPMENT) {
-                                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                       System.err.println("Firing " + listenerEntry.procedure);
-                                               }
-                                       }
-                                       try {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
-                                                       }
-                                               }
-                                               entry.performFromCache(graph, listenerEntry.procedure);
-                                       } catch (Throwable t) {
-                                               t.printStackTrace();
-                                       }
-                               }
-
-                       }
-
-               } finally {
-                       firingListeners = false;
-               }
-
-       }
-       
-       void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
-
-               Iterable<CacheEntry> oldParents = entry.getParents(processor);
-               for (CacheEntry parent : oldParents) {
-                       if(!parent.isDiscarded())
-                               todo.push(new UpdateEntry(entry, parent, indent + 2));
-               }
-
-       }
-
-       private boolean pruneListener(ListenerEntry entry) {
-               if (entry.base.isDisposed()) {
-                       removeListener(entry);
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
 }
index 46c857794303636849112477f417b46c65d694cd..50a9a827a6b6d3ef707d87707e778b091ef62633 100644 (file)
@@ -268,10 +268,10 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
 
                @Override
                public String toString() {
-//                     if(graph == null)
+                       if(rootGraph == null)
                                return "SessionTask[no graph]";
-//                     else
-//                             return "SessionTask[" + graph.parent + "]";
+                       else
+                               return "SessionTask[" + rootGraph.parent + "]";
                }
                
 //             public int getLevel() {
index 11a3ff235c889257472f54e7d60e3af240b13f9f..bdf1f143574e9cf62caeec571ec9a12607f461ce 100644 (file)
@@ -35,7 +35,8 @@
 
        <target interface="org.simantics.db.layer0.variable.VariableBuilder">
                <type uri="http://www.simantics.org/Layer0-0.0/Entity"
-                       class="org.simantics.db.layer0.variable.StandardVariableBuilder" >
+                       class="org.simantics.db.layer0.variable.StandardVariableBuilder"
+                       constructor="get" >
                </type>
        </target>
 
index 4d208b4571d14faaac8772dc30e3e0df241d1ef9..150c760aa0cd2d26069b03c84d75b7d8f03a9218 100644 (file)
@@ -103,4 +103,96 @@ public class PropertyInfo {
                .append("]");
                return sb.toString();
        }
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((builder == null) ? 0 : builder.hashCode());
+        result = prime * result + ((classifications == null) ? 0 : classifications.hashCode());
+        result = prime * result + ((defaultBinding == null) ? 0 : defaultBinding.hashCode());
+        result = prime * result + ((definedUnit == null) ? 0 : definedUnit.hashCode());
+        result = prime * result + (hasEnumerationRange ? 1231 : 1237);
+        result = prime * result + (isFunctional ? 1231 : 1237);
+        result = prime * result + (isHasProperty ? 1231 : 1237);
+        result = prime * result + ((literalRange == null) ? 0 : literalRange.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((predicate == null) ? 0 : predicate.hashCode());
+        result = prime * result + ((requiredDatatype == null) ? 0 : requiredDatatype.hashCode());
+        result = prime * result + ((requiredValueType == null) ? 0 : requiredValueType.hashCode());
+        result = prime * result + ((subliteralPredicates == null) ? 0 : subliteralPredicates.hashCode());
+        result = prime * result + ((valueAccessor == null) ? 0 : valueAccessor.hashCode());
+        return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PropertyInfo other = (PropertyInfo) obj;
+        if (builder == null) {
+            if (other.builder != null)
+                return false;
+        } else if (!builder.equals(other.builder))
+            return false;
+        if (classifications == null) {
+            if (other.classifications != null)
+                return false;
+        } else if (!classifications.equals(other.classifications))
+            return false;
+        if (defaultBinding == null) {
+            if (other.defaultBinding != null)
+                return false;
+        } else if (!defaultBinding.equals(other.defaultBinding))
+            return false;
+        if (definedUnit == null) {
+            if (other.definedUnit != null)
+                return false;
+        } else if (!definedUnit.equals(other.definedUnit))
+            return false;
+        if (hasEnumerationRange != other.hasEnumerationRange)
+            return false;
+        if (isFunctional != other.isFunctional)
+            return false;
+        if (isHasProperty != other.isHasProperty)
+            return false;
+        if (literalRange == null) {
+            if (other.literalRange != null)
+                return false;
+        } else if (!literalRange.equals(other.literalRange))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (predicate == null) {
+            if (other.predicate != null)
+                return false;
+        } else if (!predicate.equals(other.predicate))
+            return false;
+        if (requiredDatatype == null) {
+            if (other.requiredDatatype != null)
+                return false;
+        } else if (!requiredDatatype.equals(other.requiredDatatype))
+            return false;
+        if (requiredValueType == null) {
+            if (other.requiredValueType != null)
+                return false;
+        } else if (!requiredValueType.equals(other.requiredValueType))
+            return false;
+        if (subliteralPredicates == null) {
+            if (other.subliteralPredicates != null)
+                return false;
+        } else if (!subliteralPredicates.equals(other.subliteralPredicates))
+            return false;
+        if (valueAccessor == null) {
+            if (other.valueAccessor != null)
+                return false;
+        } else if (!valueAccessor.equals(other.valueAccessor))
+            return false;
+        return true;
+    }
 }
index c168e22860b25dba84ff1b715376c4a878effcfb..c58ced3d860eb6ae6359809cbbaec0a1da251256 100644 (file)
@@ -75,10 +75,10 @@ public class SessionGarbageCollection {
         if(_monitor == null) _monitor = new NullProgressMonitor();
         QueryControl qc = graph.getService(QueryControl.class);
         ClusterControl cc = graph.getService(ClusterControl.class);
-        _monitor.beginTask("Collect clusters", IProgressMonitor.UNKNOWN);
-        cc.gc(graph, clusterTarget);
-        _monitor.beginTask("Collect queries", IProgressMonitor.UNKNOWN);
-        qc.gc(graph, allowedTimeInMs);
+//        _monitor.beginTask("Collect clusters", IProgressMonitor.UNKNOWN);
+//        cc.gc(graph, clusterTarget);
+//        _monitor.beginTask("Collect queries", IProgressMonitor.UNKNOWN);
+//        qc.gc(graph, allowedTimeInMs);
     }
 
     /**
index b1af87f98490016490d0891087da8e5679946d47..6e83fe139fe77f5dadc3dd069f4bc6e6de56038c 100644 (file)
@@ -6,6 +6,17 @@ import org.simantics.db.exception.DatabaseException;
 
 public class StandardVariableBuilder<Node> implements VariableBuilder<Node> {
 
+    private static StandardVariableBuilder INSTANCE = null;
+    
+    private StandardVariableBuilder() {}
+    
+    public static synchronized StandardVariableBuilder get() {
+        if(INSTANCE == null) {
+            INSTANCE = new StandardVariableBuilder<>();
+        }
+        return INSTANCE;
+    }
+
        @Override
        public Variable buildChild(ReadGraph graph, Variable parent, VariableNode<Node> node, Resource child) {
                return new StandardGraphChildVariable(parent, node, child);
index 9a53060bef2c0b246a21e465da1f0e53756d2f17..f057b98b67732aeb22c36b636cb9e99ede1d48c5 100644 (file)
@@ -7,16 +7,19 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.document.server.JSONObject;
 
 public class DocumentRequest extends VariableRead<List<JSONObject>> {
        
-       public static boolean PROFILE = false;
+       public static boolean PROFILE = true;
        // Thresholds in microseconds
        public static int PROFILE_THRESHOLD_NODEREQUEST = 2000;
        public static int PROFILE_THRESHOLD_VALUEREQUEST = 500;
@@ -35,20 +38,43 @@ public class DocumentRequest extends VariableRead<List<JSONObject>> {
         if(nodes.isEmpty()) {
             return Collections.emptyList();
         }
-        
-        
-        /*TreeMap<String, Variable> nodeMap = new TreeMap<String, Variable>();
-        
-        for (Variable node : nodes) {
-               nodeMap.put(node.getURI(graph), node);
+
+        if(PROFILE) {
+            long dura = System.nanoTime()-s;
+            System.err.println("DocumentRequest1 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
-        System.out.println("*************************************************************************");
-        for (Variable node : nodeMap.values()) {
-               System.out.println("               " + node.getURI(graph));
-        }*/
-        
-        for(Variable node : nodes) {
-            rs.add(graph.syncRequest(new NodeRequest(node), TransientCacheAsyncListener.<JSONObject>instance()));
+
+        graph.syncRequest(new AsyncReadRequest() {
+
+            @Override
+            public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                for(Variable node : nodes) {
+                    graph.asyncRequest(new NodeRequest(node), new AsyncProcedure<JSONObject> () {
+
+                        @Override
+                        public void execute(AsyncReadGraph graph, JSONObject result) {
+                            synchronized (rs) {
+                                rs.add(result);
+                            }
+                        }
+
+                        @Override
+                        public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        }
+
+                    });
+                    
+                }
+                
+            }
+            
+        });
+
+
+        if(PROFILE) {
+            long dura = System.nanoTime()-s;
+            System.err.println("DocumentRequest2 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
 
                ArrayList<JSONObject> result = new ArrayList<JSONObject>(rs);
@@ -63,7 +89,7 @@ public class DocumentRequest extends VariableRead<List<JSONObject>> {
         
         if(PROFILE) {
                long dura = System.nanoTime()-s;
-               System.err.println("DocumentRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
+               System.err.println("DocumentRequest3 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
 
                return result;
index 8d96c4798cb59e0947bda57879f9019915afae39..82b190544ef43e7da9bd8ebb12dd0f79f6128d38 100644 (file)
@@ -5,6 +5,8 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
 import org.simantics.document.server.DocumentServerUtils.AttributesRequest;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
 import org.simantics.document.server.JSONObject;
 
 public class NodeRequest extends VariableRead<JSONObject> {
@@ -18,17 +20,13 @@ public class NodeRequest extends VariableRead<JSONObject> {
 
     @Override
     public JSONObject perform(ReadGraph graph) throws DatabaseException {
-        long s = DocumentRequest.PROFILE ? System.nanoTime() : 0L;
 
-        JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable));
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
 
-        if (DocumentRequest.PROFILE) {
-            long dura = System.nanoTime()-s;
-            if (dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) {
-                System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
-            }
-        }
+        JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable));
 
+        if(DocumentRequest.PROFILE) task.finish();
+        
         return staticContent;
     }
 
index f3f1177fc4d1f613950bc7b4f7d56e2ec010105f..99526368e8cc3e21e1b92451f4dd915db45d40ba 100644 (file)
@@ -1,47 +1,72 @@
 package org.simantics.document.server.request;
 
-import gnu.trove.set.hash.THashSet;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableChildren;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
+
+import gnu.trove.set.hash.THashSet;
 
 public class NodesRequest extends VariableRead<Set<Variable>> {
 
     public NodesRequest(Variable var) {
         super(var);
-       }
-
-       @Override
-       public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
-
-               long s = System.nanoTime();
-               
-               StructuralResource2.getInstance(graph);
-               if(variable == null)
-                       return Collections.emptySet();
-               
-               Set<Variable> nodes = new THashSet<Variable>();
-               Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
-               for(Variable child : children) {
-                       Set<Variable> childNodes = graph.syncRequest(new NodesRequest2(child));
-                       nodes.addAll(childNodes);
-               }
-               
-        if(DocumentRequest.PROFILE) {
-               long dura = System.nanoTime()-s;
-               System.err.println("NodesRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
-        }
-               
-               return nodes;
-
-       }
+    }
+
+    @Override
+    public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
+
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
+
+        StructuralResource2.getInstance(graph);
+        if(variable == null)
+            return Collections.emptySet();
+
+        Set<Variable> nodes = new THashSet<Variable>();
+
+        Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
+
+        graph.syncRequest(new AsyncReadRequest() {
+
+            @Override
+            public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                for(Variable child : children) {
+                    graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure<Set<Variable>>() {
+
+                        @Override
+                        public void execute(AsyncReadGraph graph, Set<Variable> result) {
+                            synchronized(nodes) {
+                                nodes.addAll(result);
+                            }
+                        }
+
+                        @Override
+                        public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        }
+                        
+                    });
+                }
+
+            }
+
+        });
+
+        if(DocumentRequest.PROFILE) task.finish();
+
+        return nodes;
+
+    }
 
 }
\ No newline at end of file
index 0f57a01c03f2cfc87ff34c9f3a1339fa9dbe9d52..6251fb6ec8d283ace11c7cd5592e40907efded21 100644 (file)
@@ -2,48 +2,91 @@ package org.simantics.document.server.request;
 
 import gnu.trove.set.hash.THashSet;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
 import org.simantics.databoard.Bindings;
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.VariableChildren;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.document.base.ontology.DocumentationResource;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
 
 public class NodesRequest2 extends VariableRead<Set<Variable>> {
 
     public NodesRequest2(Variable var) {
         super(var);
-       }
-
-       @Override
-       public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
-           
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);
-
-               Resource type = variable.getPossibleType(graph);
-               if(type == null) return Collections.emptySet();
-               
-               if(!graph.isInheritedFrom(type, DOC.Components_Component)) return Collections.emptySet();
-
-               Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN);
-               if(pathExists != null && !pathExists) return Collections.emptySet();
-
-               if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
-                       return Collections.singleton(variable);
-               } else {
-                       Set<Variable> result = new THashSet<Variable>();
-                       for(Variable child : variable.getChildren(graph)) {
-                               Set<Variable> nodes = graph.syncRequest(new NodesRequest2(child));
-                               result.addAll(nodes);
-                       }
-               
-                       return result;
-               }
-
-       }
+    }
+
+    @Override
+    public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
+
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
+
+        DocumentationResource DOC = DocumentationResource.getInstance(graph);
+
+        Resource type = variable.getPossibleType(graph);
+        if(type == null) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        if(!graph.isInheritedFrom(type, DOC.Components_Component)) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN);
+        if(pathExists != null && !pathExists) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.singleton(variable);
+        } else {
+            Set<Variable> result = new THashSet<Variable>();
+            Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
+            graph.syncRequest(new AsyncReadRequest() {
+
+                @Override
+                public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                    for(Variable child : children) {
+                        graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure<Set<Variable>>() {
+
+                            @Override
+                            public void execute(AsyncReadGraph graph, Set<Variable> vars) {
+                                synchronized(result) {
+                                    result.addAll(vars);
+                                }
+                            }
+
+                            @Override
+                            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                            }
+                            
+                        });
+                    }
+
+                }
+
+            });
+            
+            if(DocumentRequest.PROFILE) task.finish();
+            return result;
+            
+        }
+
+    }
 
 }
\ No newline at end of file
index 31ef0dc5a0cb9863874d042858aec59d451adadd..23704156cbbaa73bec8b83c99bbabfaf0f382e16 100644 (file)
@@ -357,4 +357,9 @@ public class ConcreteModule implements Module {
     public ModuleDebugInfo getModuleDebugInfo() {
         return moduleDebugInfo;
     }
+    
+    public Map<String, byte[]> getClasses() {
+        return classes;
+    }
+    
 }
index 5ae73c41240700f44662e1b70f6851487752b290..2e35427cdcda7014e7bacd12cb10c6c7de9312fa 100644 (file)
@@ -3,9 +3,15 @@ package org.simantics.scl.compiler.runtime;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.Remapper;
 import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
@@ -16,6 +22,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
 import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder;
 import org.simantics.scl.compiler.internal.decompilation.DecompilerFactory;
 import org.simantics.scl.compiler.internal.decompilation.IDecompiler;
+import org.simantics.scl.compiler.module.ConcreteModule;
 import org.simantics.scl.compiler.module.Module;
 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
 import org.simantics.scl.compiler.top.ValueNotFound;
@@ -28,7 +35,7 @@ public class RuntimeModule {
     private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeModule.class);
     
     public static final boolean VALIDATE_CLASS_NAMES = true;
-    public static final boolean TRACE_CLASS_CREATION = false;
+    public static final boolean TRACE_CLASS_CREATION = true;
     
     Module module;
     ModuleClassLoader classLoader;
@@ -123,7 +130,8 @@ public class RuntimeModule {
         }
         
         private Class<?> getClass(String name) throws ClassNotFoundException {
-            //System.out.println("getClass " + name);
+            
+            System.out.println(moduleName + ":getClass " + name);
             
             // If the class is not generated from SCL, use parent class loader
             if(!name.startsWith(SCL_PACKAGE_PREFIX)) {
@@ -160,6 +168,22 @@ public class RuntimeModule {
             }
         }
         
+//        protected Class<?> loadClass(String name, boolean resolve)
+//                throws ClassNotFoundException
+//            {
+//                synchronized (getClassLoadingLock(name)) {
+//                    // First, check if the class has already been loaded
+//                    Class<?> c = findLoadedClass(name);
+//                    if (c == null) {
+//                        c = getClass(name);
+//                    }
+//                    if (resolve) {
+//                        resolveClass(c);
+//                    }
+//                    return c;
+//                }
+//            }
+        
         @Override
         public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
             Class<?> clazz = getClass(name);
@@ -168,6 +192,11 @@ public class RuntimeModule {
             return clazz;
         }
         
+        @Override
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            return super.loadClass(name);
+        }
+        
         public Module getModule(String moduleName) {
             //System.out.println("ModuleClassLoader.getModule(" + moduleName + ")");
             if(moduleName.equals(this.moduleName))
@@ -285,4 +314,105 @@ public class RuntimeModule {
         classLoader = null;
         classBuilder = null;
     }
+    
+    public class ClassNameRecordingRemapper extends Remapper {
+
+        private final Set<? super String> classNames;
+
+        public ClassNameRecordingRemapper(Set<? super String> classNames) {
+            this.classNames = classNames;
+        }
+        
+        @Override
+        public String map(String typeName) {
+            classNames.add(typeName);
+            return super.map(typeName);
+        }
+        
+        @Override
+        public String mapDesc(String desc) {
+            //classNames.add(desc);
+            return super.mapDesc(desc);
+        }
+        @Override
+        public String mapFieldName(String owner, String name, String desc) {
+            return super.mapFieldName(owner, name, desc);
+        }
+        @Override
+        public String mapInvokeDynamicMethodName(String name, String desc) {
+            // TODO Auto-generated method stub
+            return super.mapInvokeDynamicMethodName(name, desc);
+        }
+        @Override
+        public String mapMethodDesc(String desc) {
+            //classNames.add(desc);
+            return super.mapMethodDesc(desc);
+        }
+        @Override
+        public String mapMethodName(String owner, String name, String desc) {
+            // TODO Auto-generated method stub
+            return super.mapMethodName(owner, name, desc);
+        }
+        @Override
+        public String mapSignature(String signature, boolean typeSignature) {
+            //classNames.add(signature);
+            return super.mapSignature(signature, typeSignature);
+        }
+        @Override
+        public String mapType(String type) {
+            classNames.add(type);
+            return super.mapType(type);
+        }
+        @Override
+        public String[] mapTypes(String[] types) {
+            for(String type : types)
+                classNames.add(type);
+            // TODO Auto-generated method stub
+            return super.mapTypes(types);
+        }
+        @Override
+        public Object mapValue(Object value) {
+            //classNames.add(value.toString());
+            // TODO Auto-generated method stub
+            return super.mapValue(value);
+        }
+    }
+    
+    public Set<String> classReferences(String className) {
+        try {
+            HashSet<String> referencedClasses = new HashSet<>();
+            ClassNameRecordingRemapper m = new ClassNameRecordingRemapper(referencedClasses);
+            ClassReader cr = new ClassReader(module.getClass(className));
+            int ASM5 = 5 << 16 | 0 << 8 | 0;
+            //TraceClassVisitor tcv = new TraceClassVisitor(null, new PrintWriter(System.err));
+            ClassVisitor cv1 = new ClassVisitor(ASM5) {};
+            ClassVisitor cv = new ClassRemapper(cv1, m);
+            cr.accept(cv, ClassReader.SKIP_DEBUG);
+            System.err.println(className + " refs: " + referencedClasses);
+            return referencedClasses;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+    
+    public void loadReferences() {
+        ConcreteModule cm = (ConcreteModule)module;
+        try {
+            for(String className : cm.getClasses().keySet()) {
+                Set<String> refs = classReferences(className);
+                for(String s : refs) {
+                    String internalName = s.replace('/', '.');
+                    try {
+                        classLoader.loadClass(internalName);
+                    } catch (Throwable e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+    }
+
 }
\ No newline at end of file
index b51b188cda117823c4d8b0308f13eb607615aa91..f69395c3d74ca110ca043fcfc010d4730825fbf6 100644 (file)
@@ -76,7 +76,7 @@ public class ExpressionEvaluator {
     private Type expectedType;
     private LocalEnvironment localEnvironment;
     private LocalStorage localStorage;
-    private boolean interpretIfPossible = true;
+    private boolean interpretIfPossible = false;
     private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION;
     private boolean validateOnly;
     
index 2e717f945780574f71c3382c33cb3bf157fa55e2..1e0360051ff318849582e947f30f729033ed15b9 100644 (file)
@@ -4,10 +4,12 @@ import java.util.ArrayList;
 
 import org.simantics.scl.compiler.errors.DoesNotExist;
 import org.simantics.scl.compiler.errors.Failable;
+import org.simantics.scl.compiler.module.ConcreteModule;
 import org.simantics.scl.compiler.module.Module;
 import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
 import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.runtime.RuntimeModule;
 import org.simantics.scl.compiler.source.repository.ModuleSourceRepository;
 import org.simantics.scl.compiler.testing.repository.TestRepository;
 import org.simantics.scl.osgi.internal.Activator;
@@ -47,9 +49,9 @@ public class SCLOsgi {
                 System.out.print(moduleName);
                 System.out.print(" - ");
                 Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
-                if(module.didSucceed())
+                if(module.didSucceed()) {
                     System.out.println("succeeded");
-                else if(module == DoesNotExist.INSTANCE)
+                else if(module == DoesNotExist.INSTANCE)
                     System.out.println("does not exist"); // should not happen
                 else {
                     System.out.println("error");
@@ -67,4 +69,54 @@ public class SCLOsgi {
         }
         return null;
     }
+    
+    public static String compileAllModules2() {
+        ArrayList<String> modulesWithErrors = new ArrayList<String>(); 
+        SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure<String>() {
+            @Override
+            public boolean execute(String moduleName) {
+                System.out.print(moduleName);
+                System.out.print(" - ");
+                Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
+                if(module.didSucceed()) {
+                    System.out.println("succeeded");
+                } else if(module == DoesNotExist.INSTANCE)
+                    System.out.println("does not exist"); // should not happen
+                else {
+                    System.out.println("error");
+                    modulesWithErrors.add(moduleName);
+                }
+                return true;
+            }
+        });
+        SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure<String>() {
+            @Override
+            public boolean execute(String moduleName) {
+                System.out.print(moduleName);
+                System.out.print(" - ");
+                Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
+                if(module.didSucceed()) {
+                    Failable<RuntimeModule> frm = SCLOsgi.MODULE_REPOSITORY.getRuntimeModule(moduleName);
+                    RuntimeModule rm = frm.getResult();
+                    rm.loadReferences();
+                    System.out.println("succeeded");
+                } else if(module == DoesNotExist.INSTANCE)
+                    System.out.println("does not exist"); // should not happen
+                else {
+                    System.out.println("error");
+                    modulesWithErrors.add(moduleName);
+                }
+                return true;
+            }
+        });
+        if(!modulesWithErrors.isEmpty()) {
+            StringBuilder b = new StringBuilder();
+            b.append("Some SCL modules failed to compile:");
+            for(String module : modulesWithErrors)
+                b.append(' ').append(module);
+            return b.toString();
+        }
+        return null;
+    }
+    
 }
index 5a1bb23fbdb13b3ba9c517cd7cea3b9bbf662ba3..07d32a8e961dea7264687711b56588950ef93627 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Map;
 public class ThreadLogVisualizer {
        
     // Do not show tasks shorter than 5ms
-    final public static long DISCARD_LIMIT = 2 * 1000 * 1000;
+    final public static long DISCARD_LIMIT = 50 * 1000 * 1000;
     // 1s columns
     final public static long COLUMN_WIDTH = 1000000000;
     
index 2f3425c58b5be1975c3014fb7a1aee03c41154fa..67cc929039057bab260ccb4f2826c207a66156c1 100644 (file)
@@ -23,7 +23,7 @@ public class ThreadLogger implements IThreadLogger {
 
     public static String LOG_FILE = "threads.log";
     
-    public static boolean LOG = false;
+    public static boolean LOG = true;
 
     static Object loggerCreationLock = new Object();
     static ThreadLogger logger = null;