]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/PrincipalTypes.java
Multiple reader thread support for db client
[simantics/platform.git] / bundles / org.simantics.db.impl / src / org / simantics / db / impl / query / PrincipalTypes.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.db.impl.query;
13
14 import java.util.ArrayList;
15 import java.util.Arrays;
16
17 import org.simantics.db.common.utils.Logger;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.impl.graph.ReadGraphImpl;
20 import org.simantics.db.impl.procedure.InternalProcedure;
21
22 import gnu.trove.procedure.TIntProcedure;
23 import gnu.trove.set.hash.TIntHashSet;
24
25 public final class PrincipalTypes extends CollectionUnaryQuery {
26
27         PrincipalTypes(final int resource) {
28                 super(resource);
29         }
30
31         @Override
32         final public void removeEntry(QueryProcessor provider) {
33                 provider.cache.remove(this);
34         }
35
36         static class Ints {
37
38                 private TIntHashSet set = null;
39                 public int single = 0;
40
41                 public boolean add(int val) {
42                         if(single == val) return false;
43                         if(single == 0) {
44                                 single = val;
45                                 return true;
46                         }
47                         if(set == null) set = new TIntHashSet(4);
48                         set.add(val);
49                         return true;
50                 }
51
52                 public int size() {
53
54                         if(single == 0) return 0;
55                         if(set == null) return 1;
56                         return set.size() + 1;
57
58                 }
59
60                 public int[] toArray() {
61
62                         int[] result = Arrays.copyOf(set.toArray(), set.size() + 1);
63                         result[set.size()] = single;
64                         return result;
65
66                 }
67
68                 public void forEach(TIntProcedure proc) {
69                         proc.execute(single);
70                         if(set != null) set.forEach(proc);
71                 }
72
73         }
74
75         @Override
76         public void compute(final ReadGraphImpl graph, final IntProcedure proc) throws DatabaseException {
77                 computeForEach(graph, id, this, proc);
78         }
79         
80         public static Object computeForEach(final ReadGraphImpl graph, final int id, final PrincipalTypes entry, final IntProcedure procedure_) throws DatabaseException {
81
82             IntProcedure procedure = entry != null ? entry : procedure_;
83             
84             Object result = computeForEach2(graph, id, entry, procedure);
85             
86             if(entry != null) entry.performFromCache(graph, procedure_);
87             
88             return result;
89             
90         }
91             
92         public static Object computeForEach2(final ReadGraphImpl graph, final int id, final PrincipalTypes parent, final IntProcedure procedure) throws DatabaseException {
93
94             QueryProcessor provider = graph.processor;
95                 
96                 provider.querySupport.ensureLoaded(graph, id);
97                 assert(id != 0);
98
99                 int ret = provider.querySupport.getSingleInstance(id);
100                 if(ret > 0) {
101                         procedure.execute(graph, ret);
102                         procedure.finished(graph);
103                         return ret;
104                 }
105
106                 final int instanceOf = provider.getInstanceOf();
107                 final int inherits = provider.getInherits();
108                 final int subrelationOf = provider.getSubrelationOf();
109
110                 final Ints indirect = new Ints();
111                 final Ints material = new Ints();
112
113                 IntProcedure directProc = new IntProcedure() {
114
115                         @Override
116                         public void execute(ReadGraphImpl graph, int i) {
117                                 material.add(i);
118                         }
119
120                         @Override
121                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
122                                 procedure.exception(graph, t);
123                         }
124
125                         @Override
126                         public void finished(ReadGraphImpl graph) {
127                         }
128
129                 };
130
131                 IntProcedure indirectProc = new IntProcedure() {
132
133                         @Override
134                         public void execute(ReadGraphImpl graph, int i) {
135                                 indirect.add(i);
136                         }
137
138                         @Override
139                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
140                                 procedure.exception(graph, t);
141                         }
142
143                         @Override
144                         public void finished(ReadGraphImpl graph) {
145                         }
146
147                 };
148
149                 provider.querySupport.getObjects(graph, id, instanceOf, directProc);
150                 provider.querySupport.getObjects(graph, id, inherits, indirectProc);
151                 provider.querySupport.getObjects(graph, id, subrelationOf, indirectProc);
152
153                 if(indirect.size() == 0) {
154                         int size = material.size(); 
155                         if(size == 0) {
156                                 procedure.finished(graph);
157                                 return null;
158                         } else if(size == 1) {
159                                 int single = material.single; 
160                                 procedure.execute(graph, single);
161                                 procedure.finished(graph);
162                                 return single;
163                         } else {
164                                 addPrincipalType(graph, new TIntHashSet(4), material.toArray(), 0, provider, parent, procedure);
165                                 return null;
166                         }
167                 }
168
169                 indirect.forEach(new TIntProcedure() {
170
171                         int finishes = 0;
172                         
173                         @Override
174                         public boolean execute(final int arg0) {
175                                 try {
176                                         return execute0(arg0);
177                                 } catch (DatabaseException e) {
178                                         Logger.defaultLogError(e);
179                                 }
180                                 return false;
181                         }
182                         
183                         public boolean execute0(final int arg0) throws DatabaseException {
184
185                                 // No self-loops!
186                                 if(arg0 == id) {
187                                         int current = (++finishes);
188                                         if(current == indirect.size()) {
189                                                 int size = material.size(); 
190                                                 if(size == 0) {
191                                                         procedure.finished(graph);
192                                                         return true;
193                                                 } else if(size == 1) {
194                                                         int single = material.single; 
195                                                         procedure.execute(graph, single);
196                                                         procedure.finished(graph);
197                                                         return true;
198                                                 } else {
199                                                         addPrincipalType(graph, new TIntHashSet(4), material.toArray(), 0, provider, parent, procedure);
200                                                         return true;
201                                                 }
202                                         }
203                                         return true;
204                                 }
205
206                                 QueryCache.runnerPrincipalTypes(graph, arg0, parent, null, new IntProcedure() {
207
208                                         @Override
209                                         public void execute(ReadGraphImpl graph, int i) {
210                                                 synchronized(material) {
211                                                         material.add(i);
212                                                 }
213                                         }
214
215                                         @Override
216                                         public void finished(ReadGraphImpl graph) throws DatabaseException {
217
218                                                 int current = (++finishes);
219                                                 if(current == indirect.size()) {
220                                                         int size = material.size(); 
221                                                         if(size == 0) {
222                                                                 procedure.finished(graph);
223                                                                 return;
224                                                         } else if(size == 1) {
225                                                                 int single = material.single; 
226                                                                 procedure.execute(graph, single);
227                                                                 procedure.finished(graph);
228                                                                 return;
229                                                         } else {
230                                                                 addPrincipalType(graph, new TIntHashSet(4), material.toArray(), 0, provider, parent, procedure);
231                                                                 return;
232                                                         }
233                                                 }
234
235                                         }
236
237                                         @Override
238                                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
239                                                 procedure.exception(graph, t);
240                                         }
241
242                                 });
243
244                                 return true;
245
246                         }
247
248                 });
249                 
250                 return null;
251
252         }
253
254         private static void finish(ReadGraphImpl graph, final TIntHashSet rejects, final int[] material, final IntProcedure proc) throws DatabaseException {
255
256                 for(int i : material) {
257                         if(!rejects.contains(i)) {
258                                 proc.execute(graph, i);
259                         }
260                 }
261
262                 proc.finished(graph);
263
264                 return;
265
266         }
267
268         private static void addPrincipalType(final ReadGraphImpl graph, final TIntHashSet rejects, final int[] material, int index, final QueryProcessor provider, final PrincipalTypes parent, final IntProcedure proc) throws DatabaseException {
269
270                 if(index == material.length) { 
271                         finish(graph, rejects, material, proc);
272                         return;
273                 }
274
275                 int type = material[index++];
276                 while(rejects.contains(type)) {
277                         if(index == material.length) { 
278                                 finish(graph, rejects, material, proc);
279                                 return;
280                         }
281                         type = material[index++];
282                 }
283                 
284                 final int nextIndex = index;
285
286                 QueryCache.runnerSuperTypes(graph, type, parent, null, new InternalProcedure<IntSet>() {
287
288                         @Override
289                         public void execute(ReadGraphImpl graph, IntSet supers) throws DatabaseException {
290
291                                 synchronized(rejects) {
292
293                                         supers.forEach(new TIntProcedure() {
294
295                                                 @Override
296                                                 public boolean execute(int arg0) {
297                                                         rejects.add(arg0);
298                                                         return true;
299                                                 }
300
301                                         });
302
303                                 }
304
305                                 addPrincipalType(graph, rejects, material, nextIndex, provider, parent, proc);
306
307                         }
308
309                         @Override
310                         public void exception(ReadGraphImpl graph, Throwable t) throws DatabaseException {
311                                 proc.exception(graph, t);
312                         }
313
314                 });
315
316         }
317
318         @Override
319         public String toString() {
320                 return "PrincipalTypes[" + id + "]";
321         }
322     
323     @Override
324     protected void fillImpliedParents(QueryProcessor processor, ArrayList<CacheEntry<?>> result) {
325     }
326
327 }