]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/org/simantics/db/procore/cluster/ResourceTableSmall.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore / src / org / simantics / db / procore / cluster / ResourceTableSmall.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.db.procore.cluster;\r
13 \r
14 import java.util.ArrayList;\r
15 \r
16 import org.simantics.db.Resource;\r
17 import org.simantics.db.common.utils.Logger;\r
18 import org.simantics.db.exception.DatabaseException;\r
19 import org.simantics.db.impl.ClusterBase;\r
20 import org.simantics.db.impl.ClusterI;\r
21 import org.simantics.db.impl.ClusterI.ObjectProcedure;\r
22 import org.simantics.db.impl.ClusterI.PredicateProcedure;\r
23 import org.simantics.db.impl.ClusterI.Procedure;\r
24 import org.simantics.db.impl.ClusterSupport;\r
25 import org.simantics.db.impl.ClusterTraitsBase;\r
26 import org.simantics.db.impl.Modifier;\r
27 import org.simantics.db.impl.Table;\r
28 import org.simantics.db.impl.TableFactory;\r
29 import org.simantics.db.impl.TableSizeListener;\r
30 import org.simantics.db.impl.graph.ReadGraphImpl;\r
31 import org.simantics.db.procedure.AsyncContextMultiProcedure;\r
32 import org.simantics.db.procedure.AsyncMultiProcedure;\r
33 import org.simantics.db.procore.cluster.PredicateTable.Status;\r
34 \r
35 \r
36 \r
37 public final class ResourceTableSmall extends Table<long[]> {\r
38     public ResourceTableSmall(TableSizeListener sizeListener, int[] header, int headerBase) {\r
39         super(TableFactory.getLongFactory(), sizeListener, header, headerBase);\r
40     }\r
41 \r
42     public ResourceTableSmall(TableSizeListener sizeListener, int[] header, int headerBase, long[] longs) {\r
43         super(TableFactory.getLongFactory(), sizeListener, header, headerBase, longs);\r
44     }\r
45 \r
46     public int getUsedSize() {\r
47         return getTableCount();\r
48     }\r
49 \r
50     public short createResource() {\r
51         final int INDEX = getTableCount();\r
52         final int SIZE = ResourceElementSmall.getSizeOf();\r
53         int resourceIndex = createNewElement(SIZE);\r
54         assert (0 != resourceIndex);\r
55         final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE);\r
56         ResourceElementSmall.construct(getTable(), REAL_INDEX);\r
57         incResourceCount();\r
58         return (short)(INDEX + ZERO_SHIFT);\r
59     }\r
60 \r
61     void createResource(int resourceIndex) {\r
62         final int tableCount = getTableCount();\r
63         if (resourceIndex <= tableCount) { // old index\r
64             int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
65             if (ResourceElementSmall.isEmpty(getTable(), realIndex))\r
66                 return;\r
67         } if (resourceIndex == tableCount+1) {\r
68             createResource();\r
69             return;\r
70         }\r
71         throw new InternalError("Trying to create resource with illegal index=" + resourceIndex);\r
72     }\r
73 \r
74     public short getCompleteObjectRef(int resourceIndex) {\r
75         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
76         return ResourceElementSmall.getCompleteObjectRef(getTable(), realIndex);\r
77     }\r
78     \r
79     public ClusterI.CompleteTypeEnum getCompleteType(int resourceIndex) {\r
80         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
81         return ResourceElementSmall.getCompleteType(getTable(), realIndex);\r
82     }\r
83     \r
84     public int getPredicateIndex(int resourceIndex) {\r
85         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
86         return ResourceElementSmall.getPredicateIndex(table, realIndex);\r
87     }\r
88 \r
89     public void setPredicateIndex(int resourceIndex, int predicateIndex) {\r
90         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
91         ResourceElementSmall.setPredicateIndex(getTable(), realIndex, predicateIndex);\r
92     }\r
93 \r
94     public byte[] getValue(ValueTableSmall valueTable, int resourceIndex)\r
95     throws DatabaseException {\r
96         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
97         return ResourceElementSmall.getValue(valueTable, getTable(), realIndex);\r
98     }\r
99 //KRAA:\r
100 //    char[] getString(ValueTableSmall valueTable, int resourceIndex) {\r
101 //        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
102 //        return ResourceElementSmall.getString(valueTable, getTable(), realIndex);\r
103 //    }\r
104 \r
105     public boolean hasValue(int resourceIndex) {\r
106         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
107         return ResourceElementSmall.hasValue(getTable(), realIndex);\r
108     }\r
109 \r
110 //    boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) {\r
111 //        int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
112 //        return ResourceElementSmall.hasValue(valueTable, getTable(), realIndex, value);\r
113 //    }\r
114 \r
115     public boolean removeValue(ValueTableSmall valueTable, int resourceIndex) {\r
116         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
117         boolean ret = ResourceElementSmall.removeValue(valueTable, getTable(), realIndex);\r
118 //        if (ret && !ResourceElementSmall.isUsed(getTable(), realIndex))\r
119 //            decResourceCount();\r
120         return ret;\r
121     }\r
122 \r
123     public void setValue(ValueTableSmall valueTable, int resourceIndex, byte[] value, int length)\r
124     throws OutOfSpaceException {\r
125         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
126         ResourceElementSmall.setValue(valueTable, getTable(), realIndex, value, length);\r
127     }\r
128 \r
129     public boolean isValueEx(ValueTableSmall valueTable, int resourceIndex) {\r
130         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
131         return ResourceElementSmall.isValueEx(valueTable, getTable(), realIndex);\r
132     }\r
133 \r
134     public void setValueEx(ValueTableSmall valueTable, int resourceIndex) {\r
135         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
136         ResourceElementSmall.setValueEx(valueTable, getTable(), realIndex);\r
137     }\r
138 \r
139     static final int RESOURCE_COUNT_INDEX = 0;\r
140     static final int FOREIGN_COUNT_INDEX = 1; // Reserved by server.\r
141     static final int CLUSTER_STATUS_INDEX = 2;\r
142 \r
143     int incResourceCount() {\r
144         int count = getExtra(RESOURCE_COUNT_INDEX) + 1;\r
145         setExtra(RESOURCE_COUNT_INDEX, count);\r
146         return count;\r
147     }\r
148 \r
149 //    int decResourceCount() {\r
150 //        int count = getExtra(RESOURCE_COUNT_INDEX) - 1;\r
151 //        setExtra(RESOURCE_COUNT_INDEX, count);\r
152 //        return count;\r
153 //    }\r
154 \r
155     public int getResourceCount() {\r
156         return getExtra(RESOURCE_COUNT_INDEX);\r
157     }\r
158     public int getClusterStatus() {\r
159         return getExtra(CLUSTER_STATUS_INDEX);\r
160     }\r
161     public void setClusterStatus(int value) {\r
162         setExtra(CLUSTER_STATUS_INDEX, value);\r
163     }\r
164 \r
165     <Context> boolean foreachResource(ClusterI.ObjectProcedure<Context> procedure, Context context,\r
166             ClusterSupport support, Modifier modifier) throws DatabaseException {\r
167         final int tsize = getTableSize();\r
168 //        final int rsize = getResourceCount();\r
169         final int esize = ResourceElementSmall.getSizeOf();\r
170         //int count = 0;\r
171         int key = ZERO_SHIFT;\r
172         for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) {\r
173             if (ResourceElementSmall.isUsed(getTable(), i)) {\r
174                 int ref;\r
175                 if (null == modifier)\r
176                     ref = key;\r
177                 else\r
178                     ref = modifier.execute(key);\r
179                 if (procedure.execute(context, ref))\r
180                     return true; // loop was broken by procedure\r
181 //                if (rsize == ++count)\r
182 //                    return false; // loop finished\r
183             }\r
184         }\r
185         //assert(rsize == count);\r
186         return false; // loop finished\r
187     }\r
188 \r
189     public <Context> boolean foreachPredicate(int resourceIndex\r
190             , ClusterI.PredicateProcedure<Context> procedure, Context context\r
191             , ClusterSupport support, Modifier modifier, CompleteTable ct)\r
192     throws DatabaseException {\r
193         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
194         return ResourceElementSmall.foreachPredicate(getTable(), realIndex\r
195                 , procedure, context, support, modifier, ct);\r
196     }\r
197 \r
198     public int getSingleObject(int resourceIndex, ClusterSupport support, short pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
199         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
200         return ResourceElementSmall.getSingleObject(table, realIndex, support, pRef, completeType, ct, modifier);\r
201     }\r
202 \r
203     public void foreachObject(int resourceIndex, ReadGraphImpl graph,\r
204             AsyncMultiProcedure<Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
205         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
206         ResourceElementSmall.foreachObject(table, realIndex, graph, procedure, support,\r
207                 pRef, completeType, ct, modifier);\r
208     }\r
209 \r
210     public <C> void foreachObject(int resourceIndex, ReadGraphImpl graph, C context,\r
211             AsyncContextMultiProcedure<C, Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct, Modifier modifier) throws DatabaseException {\r
212         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
213         ResourceElementSmall.foreachObject(table, realIndex, graph, context, procedure, support,\r
214                 pRef, completeType, ct, modifier);\r
215     }\r
216 \r
217     public <Context> boolean foreachObject(int resourceIndex\r
218             , ClusterI.ObjectProcedure<Context> procedure, Context context\r
219             , ClusterSupport support, Modifier modifier,\r
220             short pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
221     throws DatabaseException {\r
222         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
223         return ResourceElementSmall.foreachObject(table, realIndex\r
224                 , procedure, context, support, modifier\r
225                 , pRef, completeType, ct);\r
226     }\r
227     public int addStatement(int resourceIndex, short pRef, short oRef, PredicateTable pt, ObjectTable ot\r
228             , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
229             throws DatabaseException {\r
230         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
231         return ResourceElementSmall.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, completeType, ct);\r
232     }\r
233 \r
234     public boolean removeStatementFromCache(int resourceIndex, short pRef, short oRef,\r
235             ClusterI.CompleteTypeEnum completeType, CompleteTable ct)\r
236     throws DatabaseException {\r
237         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
238         boolean ret = ResourceElementSmall.removeStatement(getTable(), realIndex, pRef, oRef, completeType, ct);\r
239 //        if (ret && !ResourceElementSmall.isUsed(getTable(), realIndex))\r
240 //            decResourceCount();\r
241         return ret;\r
242     }\r
243     \r
244     public void removeStatement(int resourceIndex, short pRef, short oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct,\r
245             PredicateTable pt, ObjectTable ot, ClusterSupport support)\r
246             throws DatabaseException {\r
247         int realIndex = checkIndexAndGetRealIndex(resourceIndex);\r
248         boolean removed = ResourceElementSmall.removeStatement(getTable(), realIndex,\r
249                 pRef, oRef, pCompleteType, ct);\r
250         if (!removed)\r
251             return;\r
252         int predicateIndex = ResourceElementSmall.getPredicateIndex(getTable(), realIndex);\r
253         if (0 == predicateIndex) {\r
254 //            if (!ResourceElementSmall.isUsed(getTable(), realIndex))\r
255 //                decResourceCount();\r
256             return;\r
257         } else if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType)\r
258             return; // Complete type statements are not kept in statement cache.\r
259         // We have one more statements in predicate table.\r
260         // Here we check if statement cache needs fixing.\r
261         GetStatementsSmall gs = new GetStatementsSmall(ot);\r
262         pt.foreachPredicate(predicateIndex, gs, null, null, null);\r
263         ArrayList<Statement> stms = gs.getStatements();\r
264 \r
265         final int SIZE = stms.size();\r
266         if (SIZE < 3) {\r
267             for (int i = 0; i < SIZE; ++i) {\r
268                 Statement stm = stms.get(i);\r
269                 PredicateTable.Status ret = pt.removePredicate(predicateIndex,\r
270                         stm.pRef, stm.oIndex, ot);\r
271                 if (ret == Status.NothingRemoved)\r
272                     throw new DatabaseException("Internal error during statement cache fix (2).");\r
273                 assert(stm.pRef < (1<<16));\r
274                 assert(stm.oIndex < 1<<16);\r
275                 int pi = ResourceElementSmall.addStatement(getTable(), realIndex, (short)stm.pRef, (short)stm.oIndex,\r
276                         pt, ot, ClusterI.CompleteTypeEnum.NotComplete, ct);\r
277                 assert(0 >= pi);\r
278             }\r
279             assert(0 == pt.getPredicateSetSize(predicateIndex));\r
280             ResourceElementSmall.setPredicateIndex(getTable(), realIndex, 0);\r
281         } else {\r
282             for (int i = 0; i < SIZE; ++i) {\r
283                 Statement stm = stms.get(i);\r
284                 assert(stm.pRef < (1<<16));\r
285                 assert(stm.oIndex < 1<<16);\r
286                 int pIndex = ResourceElementSmall.addStatement(getTable(), realIndex,\r
287                         (short)stm.pRef, (short)stm.oIndex, pt, ot, ClusterI.CompleteTypeEnum.NotComplete, ct);\r
288                 if (pIndex > 0)\r
289                     return; // cache fixed and full, p and o sets in use\r
290             }\r
291             throw new DatabaseException("Internal error during statement cache fix (3).");\r
292         }\r
293 //        if (!ResourceElementSmall.isUsed(getTable(), realIndex))\r
294 //            decResourceCount();\r
295     }\r
296 \r
297     private int checkIndexAndGetRealIndex(final int resourceIndex) {\r
298         if (ClusterTraitsBase.isIllegalResourceIndex(resourceIndex))\r
299             throw new RuntimeException("Illegal resource index. index=" + resourceIndex + ".");\r
300         if(resourceIndex > getTableCount())\r
301             throw new RuntimeException("Illegal resource index. index=" + resourceIndex + " table count=" + getTableCount());\r
302         final int SIZE = ResourceElementSmall.getSizeOf();\r
303         final int REAL_INDEX = resourceIndex * SIZE - (SIZE - ZERO_SHIFT) + offset;\r
304         return REAL_INDEX;\r
305     }\r
306     void check(ClusterImpl cluster)\r
307     throws DatabaseException {\r
308 //        throw new Error("Not implemented.//KRAA:");\r
309     }\r
310 \r
311     public void toBig(ClusterBase big, final ClusterSupport support, final ClusterBase small)\r
312     throws DatabaseException {\r
313         int resourceIndex = 1;\r
314         long[] table = getTable();\r
315         int ps = getHeader().getOffset() + ZERO_SHIFT;\r
316         final int TABLE_SIZE = getTableSize();\r
317         int pe = ps + TABLE_SIZE;\r
318         for (int p=ps; p<pe; p+=ResourceElementSmall.getSizeOf(), ++resourceIndex) {\r
319             big.createResource(support);\r
320             int subjectKey = ClusterTraits.createResourceKey(small.clusterKey, resourceIndex);  \r
321             if (!ResourceElementSmall.isUsed(table, p))\r
322                 continue;\r
323             int cr = ResourceElementSmall.getCompleteObjectRef(table, p);\r
324             if (0 != cr) {\r
325                 ClusterI.CompleteTypeEnum ct = ResourceElementSmall.getCompleteType(table, p);\r
326                 if (ClusterI.CompleteTypeEnum.NotComplete != ct) {\r
327                     int pKey = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(ct);\r
328                     int oKey = small.getCompleteObjectKey(subjectKey, support);\r
329                     big.addRelation(subjectKey, pKey, oKey, support);\r
330                 } else {\r
331                     final class ForeachObject<Context>\r
332                     implements ClusterI.ObjectProcedure<Context> {\r
333                         int sKey;\r
334                         ClusterBase big;\r
335                         public ForeachObject(int sKey, ClusterBase big) {\r
336                             this.sKey = sKey;\r
337                             this.big = big;\r
338                         }\r
339                         @Override\r
340                         public boolean execute(Context context, int completeRef)\r
341                         throws DatabaseException {\r
342                             ClusterI.CompleteTypeEnum ct = ClusterTraitsSmall.completeRefAndTypeGetType(completeRef);\r
343                             int p = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(ct);\r
344                             int o = small.execute(completeRef & 0xFFFF);\r
345                             big.addRelation(sKey, p, o, support);\r
346                             return false; // Continue looping.\r
347                         }\r
348                     }\r
349                     ForeachObject<Object> op = new ForeachObject<Object>(subjectKey, big);\r
350                     small.getCompleteTable().foreach(cr & 0xFFFF, op, null, support, null);\r
351                 }\r
352             }\r
353             int pi = ResourceElementSmall.getPredicateIndex(table, p);\r
354             if (0 != pi) {\r
355                 ToBigStatements tbs = new ToBigStatements(small, big, support, subjectKey);\r
356                 small.getPredicateTable().foreach(pi, tbs, null, null, null);\r
357             } else {\r
358                 int p1 = ResourceElementSmall.getStm1Predicate(table, p);\r
359                 int o1 = ResourceElementSmall.getStm1Object(table, p);\r
360                 if (p1 != 0) {\r
361                     int pk1 = small.execute(p1);\r
362                     int ok1 = small.execute(o1);\r
363                     big.addRelation(subjectKey, pk1, ok1, support);\r
364                     int p2 = ResourceElementSmall.getStm2Predicate(table, p);\r
365                     int o2 = ResourceElementSmall.getStm2Object(table, p);\r
366                     if (p2 != 0) {\r
367                         int pk2 = small.execute(p2);\r
368                         int ok2 = small.execute(o2);\r
369                         big.addRelation(subjectKey, pk2, ok2, support);\r
370                     }\r
371                 }\r
372             }\r
373             int valueIndex = ResourceElementSmall.getValueIndex(table, p);\r
374             if (ClusterTraitsSmall.VALUE_INDEX_EX == valueIndex)\r
375               big.setValueEx(subjectKey);\r
376             else {\r
377                 byte[] value = ResourceElementSmall.getValue((ValueTableSmall)small.getValueTable(), table, p);\r
378                 if (null != value)\r
379                     big.setValue(subjectKey, value, value.length, support);\r
380             }\r
381         }\r
382     }\r
383 \r
384     @Override\r
385     public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,\r
386             ClusterSupport support, Modifier modifier) throws DatabaseException {\r
387         throw new UnsupportedOperationException();\r
388     }\r
389 }\r
390 \r
391 class CalculateStatementsSmall\r
392 implements ClusterI.PredicateProcedure<CalculateStatements> {\r
393     private ObjectTable         ot;\r
394     private final int           sRef;\r
395 \r
396     CalculateStatementsSmall(int sRef, ObjectTable ot) {\r
397         this.sRef = sRef;\r
398         this.ot = ot;\r
399     }\r
400 \r
401     @Override\r
402     public boolean execute(CalculateStatements context\r
403             , final int pKey, int oIndex) {\r
404         if (ClusterTraits.statementIndexIsDirect(oIndex))\r
405             return false; // osize = 1\r
406         try {\r
407             oIndex = ClusterTraits.statementIndexGet(oIndex);\r
408         } catch (DatabaseException e) {\r
409             Logger.getDefault().logError("Missing object set for s="\r
410                     + sRef + " p=" + pKey, null);\r
411             return false; // continue looping\r
412         }\r
413         int osize = ot.getObjectSetSize(oIndex);\r
414         if (osize == 3 || osize > 9)\r
415             System.out.println("Resource " + sRef + " predicate " + pKey + " has "\r
416                     + osize + " objects.");\r
417         return true; // break loop\r
418     }\r
419 }\r
420 \r
421 class GetStatementsSmall implements ClusterI.PredicateProcedure<Object>, ClusterI.ObjectProcedure<Integer> {\r
422     private ObjectTable         ot;\r
423     private final ArrayList<Statement> stms = new ArrayList<Statement>(); \r
424     GetStatementsSmall(ObjectTable ot) {\r
425         this.ot = ot;\r
426     }\r
427     ArrayList<Statement> getStatements() {\r
428         return stms;\r
429     }\r
430     @Override\r
431     public boolean execute(Object context, int pRef, int oIndex) {\r
432         try {\r
433             ot.foreachObject(oIndex, this, pRef, null, null);\r
434         } catch (DatabaseException e) {\r
435             e.printStackTrace();\r
436             return false; // continue looping\r
437         }\r
438         if (stms.size() > 2)\r
439             return true; // break loop\r
440         return false; // continue looping\r
441     }\r
442     \r
443     @Override\r
444     public boolean execute(Integer pRef, int oRef) {\r
445         stms.add(new Statement(pRef, oRef));\r
446         if (stms.size() > 2)\r
447             return true; // break loop\r
448         return false; // continue looping\r
449     }\r
450 }\r
451 \r
452 class ToBigStatements implements PredicateProcedure<Object>, ObjectProcedure<Integer> {\r
453     private ClusterBase small;\r
454     private ClusterBase big;\r
455     private ClusterSupport support;\r
456     private int subjectKey;\r
457     ToBigStatements(ClusterBase small, ClusterBase big, ClusterSupport support, int subjectKey) {\r
458         this.small = small;\r
459         this.big = big;\r
460         this.support = support;\r
461         this.subjectKey = subjectKey;\r
462     }\r
463     @Override\r
464     public boolean execute(Object context, int pRef, int oIndex) {\r
465         try {\r
466             small.getObjectTable().foreach(oIndex, this, pRef, null, null);\r
467         } catch (DatabaseException e) {\r
468             e.printStackTrace();\r
469             return false; // continue looping\r
470         }\r
471         return false; // continue looping\r
472     }\r
473 \r
474     @Override\r
475     public boolean execute(Integer pRef, int oRef)\r
476     throws DatabaseException {\r
477         int pKey = small.execute(pRef);\r
478         int oKey = small.execute(oRef);\r
479         big.addRelation(subjectKey, pKey, oKey, support);\r
480         return false; // continue looping\r
481     }\r
482     \r
483 }\r