]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/DebugSupportImpl.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / DebugSupportImpl.java
1 package fi.vtt.simantics.procore.internal;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.lang.management.ManagementFactory;
6 import java.lang.reflect.Method;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.TreeSet;
10 import java.util.UUID;
11
12 import org.eclipse.core.runtime.Platform;
13 import org.osgi.framework.Bundle;
14 import org.simantics.databoard.binding.mutable.Variant;
15 import org.simantics.databoard.parser.repository.DataValueRepository;
16 import org.simantics.db.DirectStatements;
17 import org.simantics.db.Resource;
18 import org.simantics.db.Session;
19 import org.simantics.db.Statement;
20 import org.simantics.db.WriteGraph;
21 import org.simantics.db.common.request.WriteRequest;
22 import org.simantics.db.common.request.WriteResultRequest;
23 import org.simantics.db.common.utils.Logger;
24 import org.simantics.db.common.utils.NameUtils;
25 import org.simantics.db.exception.DatabaseException;
26 import org.simantics.db.exception.ServiceException;
27 import org.simantics.db.exception.ValidationException;
28 import org.simantics.db.impl.Activator;
29 import org.simantics.db.impl.ClusterI;
30 import org.simantics.db.impl.ResourceImpl;
31 import org.simantics.db.impl.graph.ReadGraphImpl;
32 import org.simantics.db.impl.graph.WriteLogger;
33 import org.simantics.db.impl.query.QueryProcessor;
34 import org.simantics.db.impl.query.QuerySupport;
35 import org.simantics.db.procore.cluster.ClusterBig;
36 import org.simantics.db.procore.cluster.ClusterImpl;
37 import org.simantics.db.procore.cluster.ClusterSmall;
38 import org.simantics.db.service.DebugSupport;
39 import org.simantics.db.service.QueryControl;
40 import org.simantics.db.service.XSupport;
41 import org.simantics.layer0.Layer0;
42 import org.simantics.scl.runtime.function.Function2;
43 import org.simantics.scl.runtime.function.Function3;
44 import org.simantics.scl.runtime.function.FunctionImpl2;
45 import org.simantics.scl.runtime.function.FunctionImpl3;
46 import org.simantics.utils.Development;
47 import org.simantics.utils.FileUtils;
48 import org.slf4j.LoggerFactory;
49
50 import gnu.trove.map.hash.TIntIntHashMap;
51 import gnu.trove.procedure.TIntIntProcedure;
52 import gnu.trove.procedure.TIntShortProcedure;
53 import gnu.trove.set.hash.TIntHashSet;
54
55 public class DebugSupportImpl implements DebugSupport {
56
57     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(DebugSupportImpl.class);
58
59         final private Map<String, Function2<WriteGraph, String, Object>> getCommands = new HashMap<String, Function2<WriteGraph, String, Object>>();
60         final private Map<String, Function3<WriteGraph, File, String, String>> listCommands = new HashMap<String, Function3<WriteGraph, File, String, String>>();
61         final private Map<String, Function2<WriteGraph, String, String>> execCommands = new HashMap<String, Function2<WriteGraph, String, String>>();
62         final private Map<String, Function2<WriteGraph, String, String>> printCommands = new HashMap<String, Function2<WriteGraph, String, String>>();
63
64         private static SessionImplSocket getSession(WriteGraph graph) {
65                 return (SessionImplSocket)graph.getSession();
66         }
67
68         DebugSupportImpl() {
69
70                 getCommands.put("listeners", new FunctionImpl2<WriteGraph, String, Object>() {
71
72                         @Override
73                         public Object apply(WriteGraph graph, String args) {
74                                 try {
75                                         return getSession(graph).queryProvider2.listening.getListenerReport();
76                                 } catch (IOException e) {
77                                         Logger.defaultLogError(e);
78                                         return e.getMessage();
79                                 }
80                         }
81
82                 });
83
84                 listCommands.put("counters", new FunctionImpl3<WriteGraph, File, String, String>() {
85
86                         @Override
87                         public String apply(WriteGraph graph, File file, String args) {
88                                 try {
89                                         return ReadGraphImpl.listCounters(file);
90                                 } catch (IOException e) {
91                                         Logger.defaultLogError(e);
92                                         return e.getMessage();
93                                 }
94                         }
95
96                 });
97
98                 listCommands.put("queries", new FunctionImpl3<WriteGraph, File, String, String>() {
99
100                         @Override
101                         public String apply(WriteGraph graph, File file, String args) {
102                                 try {
103                                         return getSession(graph).queryProvider2.reportQueries(file);
104                                 } catch (IOException e) {
105                                         Logger.defaultLogError(e);
106                                         return e.getMessage();
107                                 }
108                         }
109
110                 });
111
112         listCommands.put("queryData", new FunctionImpl3<WriteGraph, File, String, String>() {
113
114             @Override
115             public String apply(WriteGraph graph, File file, String args) {
116                 try {
117                     getSession(graph).queryProvider2.save();
118                     return "Saved queries";
119                 } catch (IOException e) {
120                     LOGGER.error("Error while saving queries", e);
121                     return e.getMessage();
122                 }
123             }
124
125         });
126
127                 listCommands.put("queryActivity", new FunctionImpl3<WriteGraph, File, String, String>() {
128
129                         @Override
130                         public String apply(WriteGraph graph, File file, String args) {
131                                 try {
132                                         return getSession(graph).queryProvider2.reportQueryActivity(file);
133                                 } catch (IOException e) {
134                                         Logger.defaultLogError(e);
135                                         return e.getMessage();
136                                 }
137                         }
138
139                 });
140
141                 listCommands.put("listeners", new FunctionImpl3<WriteGraph, File, String, String>() {
142
143                         @Override
144                         public String apply(WriteGraph graph, File file, String args) {
145                                 try {
146                                         return getSession(graph).queryProvider2.listening.reportListeners(file);
147                                 } catch (IOException e) {
148                                         Logger.defaultLogError(e);
149                                         return e.getMessage();
150                                 }
151                         }
152
153                 });
154
155                 listCommands.put("clusters", new FunctionImpl3<WriteGraph, File, String, String>() {
156
157                         @Override
158                         public String apply(WriteGraph graph, File file, String args) {
159                                 return reportClusters(getSession(graph), file);
160                         }
161
162                 });
163
164         listCommands.put("cluster", new FunctionImpl3<WriteGraph, File, String, String>() {
165
166             @Override
167             public String apply(WriteGraph graph, File file, String args) {
168                 return reportCluster(graph, file, args);
169             }
170
171         });
172
173                 listCommands.put("virtuals", new FunctionImpl3<WriteGraph, File, String, String>() {
174
175                         @Override
176                         public String apply(WriteGraph graph, File file, String args) {
177                                 return reportVirtuals(getSession(graph), file);
178                         }
179
180                 });
181
182                 listCommands.put("heap", new FunctionImpl3<WriteGraph, File, String, String>() {
183
184                         @Override
185                         public String apply(WriteGraph graph, File file, String args) {
186
187                                 try {
188
189                                         file.delete();
190
191                                         Object bean = getBean();
192                                         if (bean == null)
193                                                 return "Could not retrieve bean.";
194
195                                         Method m = bean.getClass().getMethod("dumpHeap", String.class, boolean.class);
196                                         if (args.length() > 0) {
197                                                 m.invoke(bean, file.getParent() + "/" + args, true);
198                                         } else {
199                                                 m.invoke(bean, file.getAbsolutePath(), true);
200                                         }
201
202                                 } catch (Throwable t) {
203                                         Logger.defaultLogError(t);
204                                         return "Unexpected exception " + t;
205                                 }
206
207                                 return "Wrote " + file.getAbsolutePath();
208
209                     }
210
211                     private Object getBean() {
212                         Class<?> beanClass = getBeanClass();
213                         if (beanClass == null)
214                             return null;
215                         try {
216                             Object bean = ManagementFactory.newPlatformMXBeanProxy(
217                                     ManagementFactory.getPlatformMBeanServer(),
218                                     "com.sun.management:type=HotSpotDiagnostic",
219                                     beanClass);
220                             return bean;
221                         } catch (IOException e) {
222                             return null;
223                         }
224                     }
225
226                     private Class<?> getBeanClass() {
227                         try {
228                             Class<?> clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
229                             return clazz;
230                         } catch (ClassNotFoundException e) {
231                             return null;
232                         }
233                     }
234
235                 });
236
237                 execCommands.put("WriteLogger.read", new FunctionImpl2<WriteGraph, String, String>() {
238
239                         @Override
240                         public String apply(WriteGraph graph, String args) {
241                                 graph.getSession().async(new WriteRequest() {
242
243                                         @Override
244                                         public void perform(WriteGraph graph) throws DatabaseException {
245                                                 try {
246                                                         WriteLogger.read(graph);
247                                                 } catch (Exception e) {
248                                                         e.printStackTrace();
249                                                 }
250                                         }
251
252                                 });
253                                 return "Started to read the write log.";
254                         }
255
256                 });
257
258                 execCommands.put("ReadGraph.resetCounters", new FunctionImpl2<WriteGraph, String, String>() {
259
260                         @Override
261                         public String apply(WriteGraph graph, String args) {
262                                 graph.getSession().async(new WriteRequest() {
263
264                                         @Override
265                                         public void perform(WriteGraph graph) throws DatabaseException {
266                                                 try {
267                                                         ReadGraphImpl.resetCounters();
268                                                 } catch (Exception e) {
269                                                         e.printStackTrace();
270                                                 }
271                                         }
272
273                                 });
274                                 return "Started to read the write log.";
275                         }
276
277                 });
278
279                 execCommands.put("QueryControl.flush", new FunctionImpl2<WriteGraph, String, String>() {
280
281                         @Override
282                         public String apply(WriteGraph graph, String args) {
283                                 QueryControl qc = graph.getService(QueryControl.class);
284                                 qc.flush(graph);
285                                 return "Flushed queries.";
286                         }
287
288                 });
289
290         execCommands.put("DebugSupport.validateClusters", new FunctionImpl2<WriteGraph, String, String>() {
291
292             @Override
293             public String apply(WriteGraph graph, String args) {
294                 return validateClusters(graph);
295             }
296
297         });
298
299         execCommands.put("DebugSupport.writeForMs", new FunctionImpl2<WriteGraph, String, String>() {
300
301             @Override
302             public String apply(WriteGraph graph, String args) {
303                 Integer amount = Integer.parseInt(args);
304                 return writeForMs(graph, amount);
305             }
306
307         });
308
309                 printCommands.put("nextId", new FunctionImpl2<WriteGraph, String, String>() {
310
311                         @Override
312                         public String apply(WriteGraph graph, String args) {
313                                 try {
314                                         SessionImplSocket session = getSession(graph);
315                                         ClusterImpl cluster = session.clusterTable.getNewResourceCluster(session.clusterTranslator, session.graphSession, false);
316                                         long cid = cluster.getClusterId();
317                                         int rid = cluster.getNumberOfResources(session.clusterTranslator);
318                                         return cid + "#" + rid;
319                                 } catch (Throwable t) {
320                                         return UUID.randomUUID().toString();
321                                 }
322                         }
323
324                 });
325
326                 printCommands.put("usedMemory", new FunctionImpl2<WriteGraph, String, String>() {
327
328                         @Override
329                         public String apply(WriteGraph graph, String args) {
330                                 try {
331                                         Runtime runtime = Runtime.getRuntime();
332                                         return "" + (runtime.totalMemory() - runtime.freeMemory());
333                                 } catch (Throwable t) {
334                                         return UUID.randomUUID().toString();
335                                 }
336                         }
337
338                 });
339
340         }
341
342         private String reportClusters(SessionImplSocket session, File file) {
343
344                 try {
345                         StringBuilder b = new StringBuilder();
346                         long totalApproxSize = 0;
347                         int loaded = 0;
348                         for(ClusterI cluster : session.clusterTable.getClusters()) {
349                                 b.append("[" + cluster.getClusterKey() + "]: ");
350                                 if(cluster instanceof ClusterSmall) b.append("ClusterSmall[" + cluster.getClusterId() + "]");
351                                 if(cluster instanceof ClusterBig) b.append("ClusterBig[" + cluster.getClusterId() + "]");
352                                 if(cluster instanceof ClusterWriteOnly) b.append("ClusterWriteOnly[" + cluster.getClusterId() + "]");
353                                 if(cluster.isLoaded()) {
354                                         long approx = cluster.getUsedSpace();
355                                         b.append(" approx size = " + approx + " bytes.\n");
356                                         totalApproxSize += approx;
357                                         loaded++;
358                                 } else {
359                                         b.append(" is not loaded.\n");
360                                 }
361                         }
362                         b.append("#Total approx size is " + totalApproxSize + " bytes.\n");
363                         b.append("#Amount of loaded clusters is " + loaded + ".\n");
364                         FileUtils.writeFile(file, b.toString().getBytes());
365                 } catch (IOException e) {
366                         e.printStackTrace();
367                 } catch (DatabaseException e) {
368                         e.printStackTrace();
369                 }
370
371                 return "OK";
372
373         }
374
375     private String reportCluster(final WriteGraph graph, File file, String args) {
376
377         try {
378
379             final StringBuilder b = new StringBuilder();
380             final SessionImplSocket session = (SessionImplSocket)graph.getSession();
381             long clusterId = Long.parseLong(args);
382             b.append("cluster id: " + clusterId);
383             b.append("\n");
384             b.append("internal resources: ");
385             b.append("\n");
386             ClusterI cluster = session.clusterTable.getClusterByClusterId(clusterId);
387             for(int i=1;i<=cluster.getNumberOfResources(session.clusterTranslator);i++) {
388                 Resource r = session.getResource(i, clusterId);
389                 String def = NameUtils.getSafeName(graph, r);
390                 b.append( i+": " + def);
391                 b.append("\n");
392             }
393             if(cluster instanceof ClusterSmall) {
394                 ClusterSmall clusterSmall = (ClusterSmall)cluster;
395                 b.append("foreign resources: ");
396                 b.append("\n");
397                 final TIntIntHashMap clusterHistogram = new TIntIntHashMap();
398                 clusterSmall.foreignTable.getResourceHashMap().forEachEntry(new TIntShortProcedure() {
399
400                     @Override
401                     public boolean execute(int index, short pos) {
402                         try {
403                             Resource r = session.getResource(index);
404                             String def = NameUtils.getSafeName(graph, r, true);
405                             int cluster = index >>> 12;
406                             int key = index & 0xfff;
407                             int exist = clusterHistogram.get(cluster);
408                             clusterHistogram.put(cluster, exist+1);
409                             b.append( cluster + "$" + key +": " + def);
410                             b.append("\n");
411                         } catch (ValidationException e) {
412                             e.printStackTrace();
413                         } catch (ServiceException e) {
414                             e.printStackTrace();
415                         }
416                         return true;
417                     }
418                 });
419                 b.append("foreign histogram: ");
420                 b.append("\n");
421                 clusterHistogram.forEachEntry(new TIntIntProcedure() {
422
423                     @Override
424                     public boolean execute(int cluster, int count) {
425                         b.append( cluster +": " + count);
426                         b.append("\n");
427                         return true;
428                     }
429                 });
430             }
431
432             FileUtils.writeFile(file, b.toString().getBytes());
433         } catch (IOException e) {
434             e.printStackTrace();
435         } catch (DatabaseException e) {
436             e.printStackTrace();
437         }
438
439         return "OK";
440
441     }
442
443         private String reportVirtuals(SessionImplSocket session, File file) {
444
445                 session.virtualGraphServerSupport.report(file);
446
447                 return "OK";
448
449         }
450
451         public Object query(Session session, final String command) {
452                 try {
453                         return session.sync(new WriteResultRequest<Object>() {
454
455                                 @Override
456                                 public Object perform(WriteGraph graph) throws DatabaseException {
457                                         return query(graph, command);
458                                 }
459
460                         });
461                 } catch (DatabaseException e) {
462                         Logger.defaultLogError(e);
463                         return null;
464                 }
465         }
466
467         @Override
468         public Object query(WriteGraph graph, String command) {
469
470                 Bundle bundle = Platform.getBundle(Activator.BUNDLE_ID);
471                 File base = Utils.getBaseFile(bundle);
472
473                 command = command.trim();
474
475                 try {
476
477                         if("help".equals(command)) {
478
479                                 return
480                                                 "Welcome to the Simantics session debugger.<br><br>" +
481                                                 "This shell allows you to make following queries into the running Simantics database session:<br>" +
482                                                 "<ul><li>Get commands, which return debug objects. Type 'help get' to obtain more information.</li>" +
483                                                 "<li>List commands, which create debug listings into files. Type 'help list' to obtain more information.</li>" +
484                                                 "<li>Print commands, which output information about session state. Type 'help print' to obtain more information.</li>" +
485                                                 "<li>Set commands, which modify session state variables. Type 'help set' to obtain more information.</li>" +
486                                                 "<li>Exec commands, which perform certain actions. Type 'help exec' to obtain more information.</li></ul>"
487                                                 ;
488
489                         } else if ("help get".equals(command)) {
490
491                                 StringBuilder b = new StringBuilder();
492                                 b.append("The following get commands are available.<br><ul>");
493                                 for(String key : getCommands.keySet())
494                                         b.append("<li>" + key + "</li>");
495
496                                 b.append("</ul>");
497
498                                 return b.toString();
499
500                         } else if ("help list".equals(command)) {
501
502                                 StringBuilder b = new StringBuilder();
503                                 b.append("The following list commands are available.<br><ul>");
504                                 for(String key : listCommands.keySet())
505                                         b.append("<li>" + key + "</li>");
506
507                                 b.append("</ul>");
508
509                                 return b.toString();
510
511                         } else if ("help exec".equals(command)) {
512
513                                 StringBuilder b = new StringBuilder();
514                                 b.append("The following exec commands are available.<br><ul>");
515                                 for(String key : execCommands.keySet())
516                                         b.append("<li>" + key + "</li>");
517
518                                 b.append("</ul>");
519
520                                 return b.toString();
521
522                         } else if ("help print".equals(command)) {
523
524                                 StringBuilder b = new StringBuilder();
525                                 b.append("The following print commands are available.<br><ul>");
526                                 for(String key : printCommands.keySet())
527                                         b.append("<li>" + key + "</li>");
528
529                                 b.append("</ul>");
530
531                                 return b.toString();
532
533                         } else if ("help set".equals(command)) {
534
535                                 StringBuilder b = new StringBuilder();
536                                 b.append("The following set commands are available.<br><ul>");
537
538                                 for(Map.Entry<String, Variant> e : Development.getProperties().entrySet()) {
539                                         b.append("<li>" + e.getKey() + " - " + e.getValue().getBinding().type() + "</li>");
540                                 }
541
542                                 b.append("</ul>");
543
544                                 return b.toString();
545
546                         } else if(command.startsWith("get")) {
547
548                                 String remainder = command.substring(3).trim();
549
550                                 for(Map.Entry<String, Function2<WriteGraph, String, Object>> e : getCommands.entrySet()) {
551                                         String key = e.getKey();
552                                         if(remainder.startsWith(key)) {
553                                                 String args = remainder.substring(key.length()).trim();
554                                                 return e.getValue().apply(graph, args);
555                                         }
556                                 }
557
558                         } else if(command.startsWith("list")) {
559
560                                 String remainder = command.substring(4).trim();
561
562                                 for(Map.Entry<String, Function3<WriteGraph, File, String, String>> e : listCommands.entrySet()) {
563                                         String key = e.getKey();
564                                         if(remainder.startsWith(key)) {
565                                                 String args = remainder.substring(key.length()).trim();
566                                                 File file = new File(base, key + ".list");
567                                                 base.mkdirs();
568                                                 e.getValue().apply(graph, file, args);
569                                                 return "Wrote " + file.getAbsolutePath();
570                                         }
571                                 }
572
573                         } else if(command.startsWith("set")) {
574
575                                 String remainder = command.substring(3).trim();
576                                 String[] keyAndValue = remainder.split("=");
577                                 if(keyAndValue.length == 2) {
578
579                                         Variant exist = Development.getProperties().get(keyAndValue[0]);
580                                         if(exist != null) {
581                                                 Development.setProperty(keyAndValue[0], exist.getBinding().parseValue(keyAndValue[1], new DataValueRepository()), exist.getBinding());
582                                                 return "Property " + keyAndValue[0] + " was set to '" + keyAndValue[1] + "'";
583                                         } else {
584                                                 return query(graph, "help set");
585                                         }
586                                 } else {
587                                         return query(graph, "help set");
588                                 }
589
590                         } else if(command.startsWith("print")) {
591
592                                 String remainder = command.substring(5).trim();
593
594                                 for(Map.Entry<String, Function2<WriteGraph, String, String>> e : printCommands.entrySet()) {
595                                         String key = e.getKey();
596                                         if(remainder.startsWith(key)) {
597                                                 String args = remainder.substring(key.length()).trim();
598                                                 return e.getValue().apply(graph, args);
599                                         }
600                                 }
601
602                         } else if(command.startsWith("exec")) {
603
604                                 String remainder = command.substring(4).trim();
605
606                                 for(Map.Entry<String, Function2<WriteGraph, String, String>> e : execCommands.entrySet()) {
607                                         String key = e.getKey();
608                                         if(remainder.startsWith(key)) {
609                                                 String args = remainder.substring(key.length()).trim();
610                                                 return e.getValue().apply(graph, args);
611                                         }
612                                 }
613
614                         }
615
616                         return "Unknown command '" + command + "'";
617
618                 } catch (Throwable t) {
619
620                         t.printStackTrace();
621
622                         return t.getMessage();
623
624                 }
625
626         }
627         private void writeResouce(WriteGraph graph) throws DatabaseException {
628         Layer0 l0 = Layer0.getInstance(graph);
629         Resource r = graph.newResource();
630         graph.claim(r, l0.InstanceOf, l0.Entity);
631         XSupport xs = (XSupport)graph.getService(XSupport.class);
632         xs.flushCluster(r);
633         }
634         private void wait(int amount) {
635         long start = System.nanoTime();
636         long limit = amount * 1000000L;
637         while ((System.nanoTime() - start) < limit) {
638             try {
639                 Thread.sleep(100);
640             } catch (InterruptedException e) {
641                 e.printStackTrace();
642             }
643         }
644         }
645         String writeForMs(WriteGraph graph, int amount) {
646         try {
647             writeResouce(graph);
648             wait(amount);
649             writeResouce(graph);
650         } catch (DatabaseException e) {
651             e.printStackTrace();
652         }
653
654                 return "Slept for " + amount + " ms in write transaction.";
655         }
656
657         String validateClusters(WriteGraph graph) {
658
659             ReadGraphImpl impl = (ReadGraphImpl)graph;
660             QueryProcessor processor = impl.processor;
661
662             QuerySupport qs = graph.getService(QuerySupport.class);
663
664             TIntHashSet done = new TIntHashSet();
665             TreeSet<Integer> fringe = new TreeSet<Integer>();
666
667             ResourceImpl root = (ResourceImpl)graph.getRootLibrary();
668
669             done.add(root.id);
670             fringe.add(root.id);
671
672             while(!fringe.isEmpty()) {
673                 int r = fringe.first();
674                 fringe.remove(r);
675                 DirectStatements ds = qs.getStatements(impl, r, processor, true);
676             for(Statement stm : ds) {
677                 ResourceImpl p = (ResourceImpl)stm.getPredicate();
678                 ResourceImpl o = (ResourceImpl)stm.getObject();
679                 if(done.add(p.id)) fringe.add(p.id);
680                 if(done.add(o.id)) fringe.add(o.id);
681             }
682                 qs.getValue(impl, r);
683             }
684
685             return "Validated " + done.size() + " resources.";
686
687         }
688
689 }