]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/CodeGen.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / CodeGen.java
1 package org.simantics.db.impl.query;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.UnsupportedEncodingException;
6 import java.net.MalformedURLException;
7 import java.net.URL;
8 import java.net.URLDecoder;
9
10 import org.simantics.utils.FileUtils;
11
12 public class CodeGen {
13
14     int indent = 4;
15
16     class GenerationInfo {
17         String p1;
18         String keyName;
19         String keyToId;
20         String procedure;
21         boolean useNeedsToBlock;
22         String entryCreationArguments;
23         GenerationInfo(String p1, String keyName, String keyToId, String p4, String procedure, String entryCreationArguments, boolean useNeedsToBlock) {
24             this.p1 = p1;
25             this.keyName = keyName;
26             this.keyToId = keyToId;
27             this.procedure = procedure;
28             this.useNeedsToBlock = useNeedsToBlock;
29             this.entryCreationArguments = entryCreationArguments;
30         }
31     }
32
33     GenerationInfo signatureR1RelationInfo = new GenerationInfo  ( "int r", "r", "keyR", "long", "InternalProcedure<RelationInfo>", "", false );
34     GenerationInfo signatureR1Bytes = new GenerationInfo  ( "int r", "r", "keyR", "long", "InternalProcedure<byte[]>", "", false );
35     GenerationInfo signatureR1IntSet = new GenerationInfo  ( "int r", "r", "keyR", "long", "InternalProcedure<IntSet>", "", false );
36     GenerationInfo signatureR1IP = new GenerationInfo  ( "int r", "r", "keyR", "long", "IntProcedure", "", false );
37     GenerationInfo signatureR2IP = new GenerationInfo  ( "int r1, int r2", "r1,r2", "keyR2", "long", "IntProcedure", "", false );
38     GenerationInfo signatureR2TIP = new GenerationInfo  ( "int r1, int r2", "r1,r2", "keyR2", "long", "TripleIntProcedure", "", false );
39     GenerationInfo signatureID1 = new GenerationInfo  ( "String id", "id", "keyID", "String", "InternalProcedure<Integer>", "", false );
40     GenerationInfo signatureID2 = new GenerationInfo  ( "String id", "id", "keyID", "String", "InternalProcedure<TObjectIntHashMap<String>>", "", false );
41     GenerationInfo signatureChildMap = new GenerationInfo  ( "int r", "r", "keyR", "long", "InternalProcedure<ObjectResourceIdMap<String>>", "", false );
42     GenerationInfo signatureRead = new GenerationInfo  ( "Read<?> r", "r", "id", "long", "AsyncProcedure", "", true );
43     GenerationInfo signatureAsyncRead = new GenerationInfo  ( "AsyncRead<?> r", "r", "id", "long", "AsyncProcedure", "", true );
44     GenerationInfo signatureMultiRead = new GenerationInfo  ( "MultiRead<?> r", "r", "id", "long", "SyncMultiProcedure", "", false );
45     GenerationInfo signatureAsyncMultiRead = new GenerationInfo  ( "AsyncMultiRead<?> r", "r", "id", "long", "AsyncMultiProcedure", "", false );
46     GenerationInfo signatureExternalRead = new GenerationInfo  ( "ExternalRead<?> r", "r", "id", "long", "AsyncProcedure", ", graph", false );
47
48     private void line(StringBuilder content, String line) {
49         for(int i=0;i<indent;i++)
50             content.append(" ");
51         content.append(line);
52         content.append("\n");
53     }
54
55     public void generateQuery(StringBuilder content, String clazz, GenerationInfo signature, boolean runnerShortcut, boolean genReturn) {
56         generateGetOrCreate(content, clazz, signature);
57         generateRemove(content, clazz, signature);
58         generateRunner(content, clazz, signature, runnerShortcut, genReturn);
59     }
60
61     public void generateRunner(StringBuilder content, String clazz, GenerationInfo signature, boolean shortcut, boolean genReturn) {
62
63         line(content, "public static " + (genReturn ? "Object" : "void") + " runner" + clazz + "(ReadGraphImpl graph, " + signature.p1 + ", CacheEntry parent, ListenerBase listener, final " + signature.procedure + " procedure" + (signature.useNeedsToBlock ? ", boolean needsToBlock" : "") + ") throws DatabaseException {");
64         line(content, "    QueryCache cache  = graph.processor.cache;");
65         if(shortcut) {
66             line(content, "    if(parent == null && listener == null && !cache.shouldCache(graph.processor, " + signature.keyName + ")) {");
67             line(content, "        if (SINGLE) {");
68             line(content, "            " + clazz + " e = cache.peek" + clazz + "(" + signature.keyName + ");");
69             line(content, "            if (e != null && e.isReady()) {");
70             line(content, "                " + (genReturn ? "return " : "") + "e.performFromCache(graph, procedure);");
71             if(!genReturn) line(content, "                return;");
72             line(content, "            }");
73             line(content, "        }");
74             line(content, "        " + (genReturn ? "return " : "") + clazz + ".computeForEach(graph, " + signature.keyName + ", null, procedure" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
75             if(!genReturn) line(content, "        return;");
76             line(content, "    }");
77         }
78         if(signature.useNeedsToBlock) {
79             line(content, "    " + clazz + " entry = (" + clazz + ")cache.getOrCreate" + clazz + "(graph, " + signature.keyName + ", needsToBlock);");
80             line(content, "    if(entry == null) {");
81             line(content, "      graph.processor.schedule(new SessionTask(graph) {");
82             line(content, "        @Override");
83             line(content, "        public void run0(int thread) {");
84             line(content, "          try {");
85             line(content, "            runner" + clazz + "(graph, r, parent, listener, procedure, needsToBlock);");
86             line(content, "          } catch (DatabaseException e) {");
87             line(content, "            Logger.defaultLogError(e);");
88             line(content, "          }");
89             line(content, "        }");
90             line(content, "      });");
91             line(content, "      return null;");
92             line(content, "    }");
93         } else {
94             line(content, "    " + clazz + " entry = (" + clazz + ")cache.getOrCreate" + clazz + "(graph, " + signature.keyName + ");");
95         }
96         line(content, "    " + signature.procedure + " procedure_ = procedure != null ? procedure : emptyProcedure" + clazz + ";");
97         line(content, "    if(entry.isReady()) {");
98         line(content, "      graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
99         if(genReturn) {
100             line(content, "      Object result = entry.performFromCache(graph, procedure_);");
101             line(content, "      graph.processor.listening.registerFirstKnown(listener, result);");
102             line(content, "      return result;");
103         } else {
104             line(content, "      entry.performFromCache(graph, procedure_);");
105         }
106         line(content, "    }");
107         line(content, "    else {");
108         line(content, "      assert(entry.isPending());");
109         if(genReturn) {
110             line(content, "      graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
111             if(shortcut) line(content, "      Object result = " + clazz + ".computeForEach(graph, " + signature.keyName + ", entry, procedure_" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
112             else line(content, "      entry.compute(graph, procedure_);"); 
113             line(content, "      graph.processor.listening.registerFirstKnown(listener, result);");
114             line(content, "      return result;");
115         } else {
116             line(content, "      graph.processor.listening.registerDependencies(graph, entry, parent, listener, procedure_, false);");
117             if(shortcut) line(content, "      " + clazz + ".computeForEach(graph, " + signature.keyName + ", entry, procedure_" + (signature.useNeedsToBlock ? ", needsToBlock" : "") + ");");
118             else line(content, "      entry.compute(graph, procedure_);"); 
119         }
120         line(content, "    }");
121         line(content, "}");
122         line(content, "");
123
124         String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
125
126         line(content, "private " + clazz + " peek" + clazz + "(" + signature.p1 + ") {");
127         line(content, "    synchronized(" + lower +"Map) {");
128         line(content, "        return (" + clazz + ") " + lower + "Map.get(" + signature.keyName + ");");
129         line(content, "    }");
130         line(content, "}");
131         line(content, "");
132     }
133
134     public void generateRemove(StringBuilder content, String clazz, GenerationInfo signature) {
135
136         String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
137
138         line(content, "void remove(" + clazz + " entry) {");
139         line(content, "    synchronized(" + lower + "Map) {");
140         line(content, "        " + lower + "Map.remove(entry.id);");
141         line(content, "    }");
142         line(content, "}");
143         line(content, "");
144
145     }
146
147     public void generateGetOrCreate(StringBuilder content, String clazz, GenerationInfo signature) {
148
149         String lower = Character.toLowerCase(clazz.charAt(0)) + clazz.substring(1);
150
151         line(content, "" + clazz + " getOrCreate" + clazz + "(ReadGraphImpl graph, " + signature.p1 + (signature.useNeedsToBlock ? ", boolean needsToBlock" : "") +  ") throws DatabaseException {");
152         line(content, "    " + clazz + " existing = null;");
153         line(content, "    synchronized(" + lower + "Map) {");
154         line(content, "        existing = (" + clazz + ")" + lower + "Map.get(" + signature.keyName + ");");
155         line(content, "        if(existing == null) {");
156         line(content, "            existing = new " + clazz + "(" + signature.keyName + signature.entryCreationArguments + ");");
157         line(content, "            existing.setPending(querySupport);");
158         line(content, "            " + lower + "Map.put(" + signature.keyToId + "(" + signature.keyName + "), existing);");
159         line(content, "            size++;");
160         line(content, "            return existing;");
161         line(content, "        }");
162         line(content, "        if(existing.requiresComputation()) {");
163         line(content, "            existing.setPending(querySupport);");
164         line(content, "            return existing;");
165         line(content, "        }");
166         line(content, "    }");
167         line(content, "    if(existing.isPending()) {");
168         if(signature.useNeedsToBlock) {
169             line(content, "      if(needsToBlock)");
170             line(content, "        waitPending(graph, existing);");
171             line(content, "      else {");
172             line(content, "        return null;");
173             line(content, "      }");
174         } else {
175             line(content, "      waitPending(graph, existing);");
176         }
177         line(content, "    }");
178         line(content, "    return existing;");
179         line(content, "}");
180         line(content, "");
181
182     }
183
184     public void generate() {
185
186         URL classLocation = CodeGen.class.getResource(".");
187         if (classLocation != null) {
188             if (classLocation.getProtocol().equals("file")) {
189                 try {
190                     URL resource = new URL(classLocation, ".");
191                     File path = new File(URLDecoder.decode(resource.getPath(), "UTF-8"));
192                     String target = path.getAbsolutePath().replace("\\", "/");
193                     target = target.replace("/bin/", "/src/") + "/QueryCache.java";
194                     System.err.println("target=" + target);
195                     File source = new File(target);
196                     StringBuilder content = new StringBuilder();
197                     content.append("package org.simantics.db.impl.query;\n");
198                     content.append("\n");
199
200                     content.append("import org.simantics.db.ObjectResourceIdMap;\n");
201                     content.append("import org.simantics.db.RelationInfo;\n");
202                     content.append("import org.simantics.db.common.utils.Logger;\n");
203                     content.append("import org.simantics.db.exception.DatabaseException;\n");
204                     content.append("import org.simantics.db.impl.graph.ReadGraphImpl;\n");
205                     content.append("import org.simantics.db.impl.procedure.InternalProcedure;\n");
206                     content.append("import org.simantics.db.impl.query.QueryProcessor.SessionTask;\n");
207                     content.append("import org.simantics.db.procedure.AsyncMultiProcedure;\n");
208                     content.append("import org.simantics.db.procedure.AsyncProcedure;\n");
209                     content.append("import org.simantics.db.procedure.ListenerBase;\n");
210                     content.append("import org.simantics.db.procedure.SyncMultiProcedure;\n");
211                     content.append("import org.simantics.db.request.AsyncMultiRead;\n");
212                     content.append("import org.simantics.db.request.AsyncRead;\n");
213                     content.append("import org.simantics.db.request.ExternalRead;\n");
214                     content.append("import org.simantics.db.request.MultiRead;\n");
215                     content.append("import org.simantics.db.request.Read;\n");
216                     content.append("\n");
217
218                     content.append("public class QueryCache extends QueryCacheBase {\n");
219                     content.append("\n");
220
221                     line(content, "private static final boolean SINGLE = true;");
222                     content.append("\n");
223
224                     line(content,"public QueryCache(QuerySupport querySupport, int threads) {");
225                     line(content,"    super(querySupport, threads);");
226                     line(content,"}");
227                     content.append("\n");
228
229                     generateQuery(content, "Objects", signatureR2IP, true, false);
230                     generateQuery(content, "Statements", signatureR2TIP, true, false);
231                     generateQuery(content, "DirectObjects", signatureR2IP, true, false);
232                     generateQuery(content, "RelationInfoQuery", signatureR1RelationInfo, true, false);
233                     generateQuery(content, "URIToResource", signatureID1, true, false);
234                     generateQuery(content, "ValueQuery", signatureR1Bytes, true, false);
235                     generateQuery(content, "OrderedSet", signatureR1IP, true, false);
236                     generateQuery(content, "PrincipalTypes", signatureR1IP, true, false);
237                     generateQuery(content, "DirectPredicates", signatureR1IntSet, true, false);
238                     generateQuery(content, "Predicates", signatureR1IntSet, true, false);
239                     generateQuery(content, "ReadEntry", signatureRead, true, true);
240                     generateQuery(content, "AsyncReadEntry", signatureAsyncRead, true, true);
241                     generateQuery(content, "Types", signatureR1IntSet, true, false);
242                     generateQuery(content, "ChildMap", signatureChildMap, true, false);
243                     generateQuery(content, "TypeHierarchy", signatureR1IntSet, true, false);
244                     generateQuery(content, "SuperTypes", signatureR1IntSet, true, false);
245                     generateQuery(content, "SuperRelations", signatureR1IntSet, true, false);
246
247                     generateQuery(content, "AssertedPredicates", signatureR1IP, false, false);
248                     generateQuery(content, "AssertedStatements", signatureR2TIP, false, false);
249                     generateQuery(content, "DirectSuperRelations", signatureR1IP, false, false);
250                     generateQuery(content, "MultiReadEntry", signatureMultiRead, false, false);
251                     generateQuery(content, "AsyncMultiReadEntry", signatureAsyncMultiRead, false, false);
252                     generateQuery(content, "ExternalReadEntry", signatureExternalRead, false, false);
253                     content.append("}\n");
254                     FileUtils.writeFile(source, content.toString().getBytes());
255                 } catch (MalformedURLException e) {
256                     e.printStackTrace();
257                 } catch (UnsupportedEncodingException e) {
258                     e.printStackTrace();
259                 } catch (IOException e) {
260                     e.printStackTrace();
261                 }
262             }
263         }
264
265     }
266
267     public static void main(String[] args) {
268         new CodeGen().generate();
269     }
270
271 }