1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.procore.cluster;
14 import java.util.ArrayList;
16 import org.simantics.db.Resource;
17 import org.simantics.db.common.utils.Logger;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.db.exception.ExternalValueException;
20 import org.simantics.db.exception.ValidationException;
21 import org.simantics.db.impl.ClusterBase;
22 import org.simantics.db.impl.ClusterI;
23 import org.simantics.db.impl.ClusterI.CompleteTypeEnum;
24 import org.simantics.db.impl.ClusterI.ObjectProcedure;
25 import org.simantics.db.impl.ClusterI.PredicateProcedure;
26 import org.simantics.db.impl.ClusterI.Procedure;
27 import org.simantics.db.impl.ClusterSupport;
28 import org.simantics.db.impl.ClusterTraitsBase;
29 import org.simantics.db.impl.Modifier;
30 import org.simantics.db.impl.ResourceImpl;
31 import org.simantics.db.impl.Table;
32 import org.simantics.db.impl.TableFactory;
33 import org.simantics.db.impl.TableSizeListener;
34 import org.simantics.db.impl.graph.ReadGraphImpl;
35 import org.simantics.db.procedure.AsyncContextMultiProcedure;
36 import org.simantics.db.procedure.AsyncMultiProcedure;
37 import org.simantics.db.procore.cluster.PredicateTable.Status;
40 final class ResourceElement {
41 private static final boolean DEBUG = ClusterImpl.DEBUG;
42 private static final int DESCRIPTOR_OFFSET = 0; // predicate descriptor
43 private static final int VALUE_OFFSET = 1; // value descriptor
44 private static final int STM_OFFSET = 2; // first statement
45 private static final int SIZE_OF = 4;
47 static void construct(long[] table, int index) {
48 int i = DESCRIPTOR_OFFSET + index;
49 table[i++] = 0; // predicate capacity & index
50 table[i++] = 0; // value capacity & index
51 table[i++] = 0; // stm1
52 table[i++] = 0; // stm2
55 static void destruct(long[] table, int index) {
56 int i = DESCRIPTOR_OFFSET + index;
57 table[i++] = 0; // predicate capacity & index
58 table[i++] = 0; // value capacity & index
59 table[i++] = 0; // stm1
60 table[i++] = 0; // stm2
63 static boolean isUsed(long[] table, int index) {
64 int i = DESCRIPTOR_OFFSET + index;
76 static int getSizeOf() {
80 static int getCompleteObjectRef(long[] table, int index) {
81 int i = DESCRIPTOR_OFFSET + index;
82 return BitUtility.getHighInt(table[i]);
85 static void setCompleteObjectRef(long[] table, int index, int ref) {
86 int i = DESCRIPTOR_OFFSET + index;
87 table[i] = BitUtility.setHighInt(table[i], ref);
90 static int getPredicateIndex(long[] table, int index) {
91 int i = DESCRIPTOR_OFFSET + index;
92 int predicateIndex = BitUtility.getLowInt(table[i]);
93 assert (predicateIndex >= 0);
94 return predicateIndex;
97 static void setPredicateIndex(long[] table, int index, int predicateIndex) {
98 assert (predicateIndex >= 0);
99 int i = DESCRIPTOR_OFFSET + index;
100 table[i] = BitUtility.setLowInt(table[i], predicateIndex);
103 static int copyValue(ValueTable valueTable, long[] table, int index, byte[] byteTable, int byteSize, int byteBase,
105 int i = VALUE_OFFSET + index;
106 if (0 == table[i] || -1 == table[i])
107 return byteCurrent; // no value or external value
108 // getValueCapacity call optimized away
109 int capacity = BitUtility.getLowInt(table[i]);
110 int valueIndex = getValueIndex(table, index);
113 valueTable.getValue(valueIndex, byteTable, byteCurrent, capacity);
114 valueIndex = byteCurrent - byteBase;
115 setValueIndex(table, index, valueIndex);
116 byteCurrent += capacity;
120 static byte[] getValue(ValueTable valueTable, long[] table, int index)
121 throws DatabaseException {
122 int i = VALUE_OFFSET + index;
124 return null; // no value
126 throw new ExternalValueException("Value stored externally.");
127 // getValueCapacity call optimized away
128 int capacity = BitUtility.getLowInt(table[i]);
129 byte[] t = new byte[capacity];
130 int valueIndex = getValueIndex(table, index);
131 valueTable.getValue(valueIndex, t, 0, capacity);
135 // static int getString(ValueTable valueTable, long[] table, int index, char[] t)
136 // throws DatabaseException {
137 // long l = table[index + VALUE_OFFSET];
139 // throw new ExternalValueException("String stored externally.");
140 // int capacity = (int)l;
141 // int valueIndex = (int) (l >>> 32);
142 //// char[] t = new char[capacity-1];
143 // valueTable.getString(valueIndex, t, 0, capacity-1);
144 // return capacity-1;
148 static boolean hasValue(long[] table, int index) {
149 int i = VALUE_OFFSET + index;
150 return 0 != table[i];
153 // static boolean hasValue(ValueTable valueTable, long[] table, int index, byte[] value) {
154 // int i = VALUE_OFFSET + index;
155 // if (0 == table[i])
157 // // getValueCapacity call optimized away
158 // int capacity = BitUtility.getLowInt(table[i]);
159 // if (capacity != value.length)
161 // int valueIndex = getValueIndex(table, index);
162 // return valueTable.isEqual(valueIndex, value);
165 static boolean removeValue(ValueTable valueTable, long[] table, int index) {
166 int i = VALUE_OFFSET + index;
169 else if (-1 != table[i]) {
170 // getValueCapacity call optimized away
171 int capacity = BitUtility.getLowInt(table[i]);
172 int valueIndex = getValueIndex(table, index);
173 valueTable.removeValue(valueIndex, capacity);
175 //setValueCapacityAndIndex(table, index, 0, 0); optimized away
180 public static void setValue(ValueTable valueTable, long[] table, int index, byte[] value, int length) {
181 int i = VALUE_OFFSET + index;
182 // getValueCapacity call optimized away
183 int capacity = BitUtility.getLowInt(table[i]);
184 int valueIndex = getValueIndex(table, index);
185 if (length <= capacity) {
186 valueTable.setValue(valueIndex, value, length);
187 // we "leak" memory TODO: add value size member to
188 // resource entry or value entry
189 setValueCapacity(table, index, length);
191 if (valueIndex != 0 && capacity > 0)
192 valueTable.removeValue(valueIndex, capacity);
193 valueIndex = valueTable.createValue(value, 0, length);
195 setValueCapacityAndIndex(table, index, capacity, valueIndex);
199 public static boolean isValueEx(ValueTable valueTable, long[] table, int index) {
200 int i = VALUE_OFFSET + index;
206 public static void setValueEx(ValueTable valueTable, long[] table, int index) {
207 int i = VALUE_OFFSET + index;
210 else if (0 != table[i]) {
211 int capacity = BitUtility.getLowInt(table[i]);
212 int valueIndex = getValueIndex(table, index);
213 valueTable.removeValue(valueIndex, capacity);
215 //setValueCapacityAndIndex(table, index, 0, 0); optimized away
218 static class ValueData {
221 // ValueData(int capacity, int index) {
222 // this.capacity = capacity;
223 // this.index = index;
226 static void getValueCapacityAndIndex(ValueData vd, long[] table, int index) {
227 int i = VALUE_OFFSET + index;
228 // getValueCapacity call optimized away
229 vd.capacity = BitUtility.getLowInt(table[i]);
230 vd.index = getValueIndex(table, index);
233 private static int getValueIndex(long[] table, int index) {
234 int i = VALUE_OFFSET + index;
235 return BitUtility.getHighInt(table[i]);
238 private static void setValueIndex(long[] table, int index, int valueIndex) {
239 int i = VALUE_OFFSET + index;
240 table[i] = BitUtility.setHighInt(table[i], valueIndex);
243 private static void setValueCapacity(long[] table, int index, int capacity) {
244 int i = VALUE_OFFSET + index;
245 table[i] = BitUtility.setLowInt(table[i], capacity);
248 private static void setValueCapacityAndIndex(long[] table, int index, int capacity, int valueIndex) {
249 int i = VALUE_OFFSET + index;
250 table[i] = BitUtility.setLowAndHighInt(table[i], capacity, valueIndex);
253 public static <Context> boolean foreachPredicate(long[] table, int index,
254 ClusterI.PredicateProcedure<Context> procedure,
255 Context context, ClusterSupport support, Modifier modifier,
257 throws DatabaseException {
259 System.out.println("ResourceElement.foreachPredicate: 1");
260 int completeRef = ResourceElement.getCompleteObjectRef(table, index);
261 if (0 != completeRef) {
262 if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
263 boolean broken = ct.foreachPredicate(completeRef, procedure, context, support, modifier);
265 System.out.println("ResourceElement.foreachPredicate: multi-complete ci=" + completeRef + " break=" + broken);
267 return true; // loop broken by procedure
269 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
270 if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
271 int key = ClusterTraitsBase.getCompleteTypeResourceKeyFromEnum(completeType);
272 boolean broken = procedure.execute(context, key, 0);
274 System.out.println("ResourceElement.foreachPredicate: complete rk=" + key + " break=" + broken);
276 return true; // loop broken by procedure
280 // If predicate set is in use it will contain also these statements.
281 if (0 != ResourceElement.getPredicateIndex(table, index)) {
283 System.out.println("ResourceElement.foreachPredicate: more than 2 objects");
286 int i = STM_OFFSET + index;
287 int p1 = BitUtility.getHighInt(table[i]);
290 System.out.println("ResourceElement.foreachPredicate: empty cache");
291 return false; // loop finished, no statements
294 if (null == modifier)
297 externalRef = modifier.execute(p1);
299 System.out.println("ResourceElement.foreachPredicate: cache1 pk=" + externalRef);
300 if (procedure.execute(context, externalRef, 0))
301 return true; // loop broken by procedure
302 int p2 = BitUtility.getHighInt(table[++i]);
303 if (0 == p2 || p1 == p2) {
305 System.out.println("ResourceElement.foreachPredicate: cache2 empty");
306 return false; // loop finished, one statement
307 } if (null == modifier)
310 externalRef = modifier.execute(p2);
312 System.out.println("ResourceElement.foreachPredicate: cache2 pk=" + externalRef);
313 if (procedure.execute(context, externalRef, 0))
314 return true; // loop broken by procedure
316 System.out.println("ResourceElement.foreachPredicate: not in cache");
317 return false; // loop finished, two statements
320 public static int getSingleObject(long[] table, int index, ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
321 throws DatabaseException {
323 System.out.println("ResourceElement.getSingleObject: index=" + index);
324 if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
325 int completeRef = getCompleteObjectRef(table, index);
326 if (0 == completeRef)
327 return 0; // no objects for given complete type
328 if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
329 // Multiple complete type elements.
331 System.out.println("ResourceElement.getSingleObject was complete 2");
333 implements ClusterI.ObjectProcedure<Integer> {
335 public boolean execute(Integer context, int completeRef)
336 throws DatabaseException {
337 ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
338 if (pCompleteType == oCompleteType) { // we have a match
339 if (context != 0) { // we have an old match
340 context = 0; // multiple objects for given type
341 return true; // break loop
343 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
344 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
345 if (0 == clusterIndex) {
346 context = modifier.execute(resourceIndex);
348 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
349 context = modifier.execute(externalRef);
352 return true; // continue looping
356 ForeachObject t = new ForeachObject();
357 // CompleteRef is complete object set index.
359 ct.foreachComplete(completeRef, t, c, support, modifier);
362 // one complete type element
363 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
364 if (pCompleteType != completeType)
366 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
367 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
368 if (0 == clusterIndex) {
369 return modifier.execute(resourceIndex);
371 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
372 return modifier.execute(externalRef);
375 int i = STM_OFFSET + index;
376 int p1 = BitUtility.getHighInt(table[i]);
378 return 0; // loop finished, no statements
381 int o1 = BitUtility.getLowInt(table[i]);
382 result = modifier.execute(o1);
383 // procedure.execute(graph, new ResourceImpl(null, modifier.execute(o1)));
385 // if (null == modifier)
388 // externalRef = modifier.execute(callerThread, o1);
389 // if (procedure.execute(callerThread, context, externalRef))
390 // return true; // loop broken by procedure
392 int p2 = BitUtility.getHighInt(table[++i]);
393 if (0 == p2 || pRef != p2)
394 return result; // loop finished, one statements
397 if (result != 0) return -1;
399 int o2 = BitUtility.getLowInt(table[i]);
400 return modifier.execute(o2);
403 // int o2 = BitUtility.getLowInt(table[i]);
405 // if (null == modifier)
408 // externalRef = modifier.execute(callerThread, o2);
409 // if (procedure.execute(callerThread, context, externalRef))
410 // return true; // loop broken by procedure
411 // return false; // loop finished
412 // procedure.execute(graph, new ResourceImpl(null, modifier.execute(o2)));
415 public static void foreachObject(long[] table, int index,
416 final ReadGraphImpl graph, final AsyncMultiProcedure<Resource> procedure,
417 final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
418 throws DatabaseException {
420 System.out.println("ResourceElement.foreachObject1: index=" + index);
421 if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
422 int completeRef = getCompleteObjectRef(table, index);
423 if (0 == completeRef) {
424 procedure.finished(graph);
425 // graph.state.dec(0);
426 return; // no objects for given complete type
428 if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
429 // Multiple complete type statements.
431 System.out.println("ResourceElement.was complete 2");
432 class ForeachObject implements ClusterI.ObjectProcedure<Object> {
434 public boolean execute(Object context, int completeRef) throws DatabaseException {
435 ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
436 if (pCompleteType == oCompleteType) {
437 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
438 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
439 if (0 == clusterIndex) {
440 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
442 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
443 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
446 return false; // continue looping
450 ForeachObject t = new ForeachObject();
451 // CompleteRef is complete object set index.
452 ct.foreachComplete(completeRef, t, null, support, modifier);
453 procedure.finished(graph);
454 // graph.state.dec(0);
455 return; // loop finished
457 // one complete type element
458 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
459 if (pCompleteType != completeType) {
460 procedure.finished(graph);
461 // graph.state.dec(0);
464 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
465 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
466 if (0 == clusterIndex) {
467 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
469 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
470 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
472 procedure.finished(graph);
473 // graph.state.dec(0);
474 return; // loop finished
476 int i = STM_OFFSET + index;
478 int p1 = (int) (l >>> 32);
480 procedure.finished(graph);
481 // graph.state.dec(0);
482 return; // loop finished, no statements
486 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
488 // if (null == modifier)
491 // externalRef = modifier.execute(callerThread, o1);
492 // if (procedure.execute(callerThread, context, externalRef))
493 // return true; // loop broken by procedure
495 long l2 = table[++i];
496 int p2 = (int) (l2 >>> 32);
498 procedure.finished(graph);
499 // graph.state.dec(0);
500 return; // loop finished, one statements
503 procedure.execute(graph, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
504 procedure.finished(graph);
505 // graph.state.dec(0);
508 public static <C> void foreachObject(long[] table, int index,
509 final ReadGraphImpl graph, final C context, final AsyncContextMultiProcedure<C, Resource> procedure,
510 final ClusterSupport support, final int pRef, final ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, final Modifier modifier)
511 throws DatabaseException {
513 System.out.println("ResourceElement.foreachObject1: index=" + index);
514 if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
515 int completeRef = getCompleteObjectRef(table, index);
516 if (0 == completeRef) {
517 procedure.finished(graph);
518 // graph.state.dec(0);
519 return; // no objects for given complete type
521 if (ClusterTraits.completeReferenceIsMultiple(completeRef)) {
522 // Multiple complete type statements.
524 System.out.println("ResourceElement.was complete 2");
525 class ForeachObject implements ClusterI.ObjectProcedure<Object> {
527 public boolean execute(Object _context, int completeRef) throws DatabaseException {
528 ClusterI.CompleteTypeEnum oCompleteType = ClusterTraits.completeReferenceGetType(completeRef);
529 if (pCompleteType == oCompleteType) {
530 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
531 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
532 if (0 == clusterIndex) {
533 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
535 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
536 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
539 return false; // continue looping
543 ForeachObject t = new ForeachObject();
544 // CompleteRef is complete object set index.
545 ct.foreachComplete(completeRef, t, null, support, modifier);
546 procedure.finished(graph);
547 // graph.state.dec(0);
548 return; // loop finished
550 // one complete type element
551 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
552 if (pCompleteType != completeType) {
553 procedure.finished(graph);
554 // graph.state.dec(0);
557 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
558 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
559 if (0 == clusterIndex) {
560 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(resourceIndex)));
562 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
563 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(externalRef)));
565 procedure.finished(graph);
566 // graph.state.dec(0);
567 return; // loop finished
569 int i = STM_OFFSET + index;
571 int p1 = (int) (l >>> 32);
573 procedure.finished(graph);
574 // graph.state.dec(0);
575 return; // loop finished, no statements
579 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o1)));
581 // if (null == modifier)
584 // externalRef = modifier.execute(callerThread, o1);
585 // if (procedure.execute(callerThread, context, externalRef))
586 // return true; // loop broken by procedure
588 long l2 = table[++i];
589 int p2 = (int) (l2 >>> 32);
591 procedure.finished(graph);
592 // graph.state.dec(0);
593 return; // loop finished, one statements
596 procedure.execute(graph, context, new ResourceImpl(graph.getResourceSupport(), modifier.execute(o2)));
597 procedure.finished(graph);
598 // graph.state.dec(0);
601 public static <Context> boolean foreachObject(long[] table, int index
602 , ClusterI.ObjectProcedure<Context> procedure
603 , Context context, ClusterSupport support, Modifier modifier
604 , final int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
605 throws DatabaseException {
607 System.out.println("ResourceElement.foreachObject2: 1 ");
608 if (ClusterI.CompleteTypeEnum.NotComplete != pCompleteType) {
609 int completeRef = getCompleteObjectRef(table, index);
610 if (0 == completeRef) {
612 System.out.println("ResourceElement.foreachObject2: no complete");
613 return false; // no objects for given complete type
615 if (ClusterTraits.completeReferenceIsMultiple(completeRef)) { // multiple complete type elements
617 System.out.println("ResourceElement.foreachObject2: multi-complete ci=" + completeRef);
618 return ct.foreachObject(completeRef, procedure, context, support, modifier, pCompleteType);
620 // one complete type element
621 ClusterI.CompleteTypeEnum completeType = ClusterTraits.completeReferenceGetType(completeRef);
622 if (pCompleteType != completeType) {
624 System.out.println("ResourceElement.foreachObject2: complete different predicate");
627 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
628 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
629 if (0 == clusterIndex) {
631 if (null == modifier)
632 externalRef = resourceIndex;
634 externalRef = modifier.execute(resourceIndex);
636 System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
637 if (procedure.execute(context, externalRef))
638 return true; // loop broken by procedure
640 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
641 if (null != modifier)
642 externalRef = modifier.execute(externalRef);
644 System.out.println("ResourceElement.foreachObject2: complete ok=" + externalRef);
645 if (procedure.execute(context, externalRef))
646 return true; // loop broken by procedure
648 return false; // loop finished
650 int i = STM_OFFSET + index;
651 int p1 = BitUtility.getHighInt(table[i]);
654 System.out.println("ResourceElement.foreachObject2: empty cache=");
655 return false; // loop finished, no statements
658 int o1 = BitUtility.getLowInt(table[i]);
660 if (null == modifier)
663 externalRef = modifier.execute(o1);
665 System.out.println("ResourceElement.foreachObject2: cache1 ok=" + externalRef);
666 if (procedure.execute(context, externalRef))
667 return true; // loop broken by procedure
669 int p2 = BitUtility.getHighInt(table[++i]);
670 if (0 == p2 || pRef != p2) {
672 System.out.println("ResourceElement.foreachObject2: not in cache1");
673 return false; // loop finished, one statements
675 int o2 = BitUtility.getLowInt(table[i]);
677 if (null == modifier)
680 externalRef = modifier.execute(o2);
682 System.out.println("ResourceElement.foreachObject2: cache2 ok=" + externalRef);
683 return procedure.execute(context, externalRef);
685 static boolean isEmpty(long[] table, int index) {
686 return getStatementCount(table, index) == 0 && !hasValue(table, index);
688 static int getStatementCount(long[] table, int index) {
689 int i = STM_OFFSET + index;
690 int p1 = BitUtility.getHighInt(table[i]);
691 int p2 = BitUtility.getLowInt(table[++i]);
696 int predicateIndex = getPredicateIndex(table, index);
697 if (0 == predicateIndex)
701 private static int makeCompleteObjectRef(int oRef, ClusterI.CompleteTypeEnum completeType) {
704 int resourceIndex = oRef;
705 int clusterIndex = 0;
706 ref = ClusterTraits.completeReferenceMake(completeType.getValue(), resourceIndex, clusterIndex);
709 assert(!ClusterTraits.isFlat(oRef));
710 ref = (completeType.getValue() <<30) | (oRef & 0x3FFFFFFF);
714 static int addStatement(long[] table, int index, int pRef, int oRef
715 , PredicateTable pt, ObjectTable ot
716 , ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
717 throws DatabaseException {
720 if (ClusterI.CompleteTypeEnum.NotComplete != completeType) {
721 int cRef = makeCompleteObjectRef(oRef, completeType);
722 int ctr = getCompleteObjectRef(table, index);
724 setCompleteObjectRef(table, index, cRef);
728 return -1; // old complete
729 else if (ClusterTraits.completeReferenceIsMultiple(ctr)) {
730 nRef = ct.addComplete(ctr, cRef);
732 return -1; // old complete
734 nRef = ct.createCompleteArraySet(ctr, cRef);
736 setCompleteObjectRef(table, index, nRef);
738 return 0; // added to complete
740 int i = STM_OFFSET + index;
741 int p1 = BitUtility.getHighInt(table[i]);
742 int o1 = BitUtility.getLowInt(table[i]);
744 table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
745 return 0; // added to stm cache
746 } else if (p1 == pRef && o1 == oRef)
747 return -1; // same statement
748 int p2 = BitUtility.getHighInt(table[++i]);
749 int o2 = BitUtility.getLowInt(table[i]);
751 table[i] = BitUtility.setLowAndHighInt(table[i], oRef, pRef);
752 return 0; // added to stm cache
753 } else if (p2 == pRef && o2 == oRef)
754 return -1; // same statement
755 int predicateIndex = getPredicateIndex(table, index);
756 if (0 == predicateIndex) {
758 int objectIndex = ot.createObjectSet(o1, o2);
759 assert (0 != objectIndex);
760 int[] os = new int[1];
761 os[0] = ClusterTraits.statementIndexMake(objectIndex);
762 int[] ps = new int[1];
764 predicateIndex = pt.createPredicateSet(ps, os);
766 int[] os = new int[2];
769 int[] ps = new int[2];
772 predicateIndex = pt.createPredicateSet(ps, os);
774 assert (0 != predicateIndex);
775 setPredicateIndex(table, index, predicateIndex);
777 assert (0 != predicateIndex);
778 return predicateIndex;
781 static boolean removeStatement(long[] table, int index, int pRef, int oRef,
782 ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
783 throws DatabaseException {
786 if (completeType != ClusterI.CompleteTypeEnum.NotComplete) {
787 int completeRef = ResourceElement.getCompleteObjectRef(table, index);
788 if (0 != completeRef) {
789 ClusterI.CompleteTypeEnum completeType2 = ClusterTraits.completeReferenceGetType(completeRef);
790 if (completeType == completeType2) {
791 int clusterIndex = ClusterTraits.completeReferenceGetForeignIndex(completeRef);
792 int resourceIndex = ClusterTraits.completeReferenceGetResourceIndex(completeRef);
793 if (0 == clusterIndex) {
794 if (oRef == resourceIndex) {
795 ResourceElement.setCompleteObjectRef(table, index, 0);
796 return true; // statement removed
799 int externalRef = ClusterTraits.createForeignReference(clusterIndex, resourceIndex);
800 if (oRef == externalRef) {
801 ResourceElement.setCompleteObjectRef(table, index, 0);
802 return true; // statement removed
805 } else if (completeType2 == ClusterI.CompleteTypeEnum.NotComplete) { // multiple complete type references
806 int cRef = makeCompleteObjectRef(oRef, completeType);
807 int oldSize = ct.getCompleteSetSize(completeRef);
808 int newSize = ct.removeComplete(completeRef, cRef);
809 if (oldSize == newSize)
810 return false; // not removed
811 else if (newSize == 1) {
812 cRef = ct.removeLast(completeRef);
813 ResourceElement.setCompleteObjectRef(table, index, cRef);
819 int i = STM_OFFSET + index;
820 int p1 = BitUtility.getHighInt(table[i]);
821 int o1 = BitUtility.getLowInt(table[i]);
823 return false; // no statements cached
824 else if (p1 == pRef && o1 == oRef) {
825 table[i] = table[i + 1];
826 // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
828 return true; // statement removed
830 int p2 = BitUtility.getHighInt(table[++i]);
831 int o2 = BitUtility.getLowInt(table[i]);
833 return false; // no match
834 else if (p2 == pRef && o2 == oRef) {
835 // BitUtility.setLowAndHighInt(table[i], 0, 0); optimized away
837 return true; // statement removed
843 public final class ResourceTable extends Table<long[]> {
844 public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase) {
845 super(TableFactory.getLongFactory(), sizeListener, header, headerBase);
848 public ResourceTable(TableSizeListener sizeListener, int[] header, int headerBase, long[] longs) {
849 super(TableFactory.getLongFactory(), sizeListener, header, headerBase, longs);
852 public int getUsedSize() {
853 return getTableCount();
856 public short createResource() {
857 final int INDEX = getTableCount();
858 final int SIZE = ResourceElement.getSizeOf();
859 int resourceIndex = createNewElement(SIZE);
860 assert (0 != resourceIndex);
861 final int REAL_INDEX = checkIndexAndGetRealIndex(resourceIndex, SIZE);
862 ResourceElement.construct(getTable(), REAL_INDEX);
864 return (short)(INDEX + ZERO_SHIFT);
867 void createResource(int resourceIndex) {
868 final int tableCount = getTableCount();
869 if (resourceIndex <= tableCount) { // old index
870 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
871 if (ResourceElement.isEmpty(getTable(), realIndex))
873 } if (resourceIndex == tableCount+1) {
877 throw new InternalError("Trying to create resource with illegal index=" + resourceIndex);
880 // void deleteResource(int resourceIndex) {
881 // int realIndex = checkIndexAndGetRealIndex(resourceIndex);
882 // ResourceElement.destruct(getTable(), realIndex);
883 // decResourceCount();
886 public int getCompleteObjectRef(int resourceIndex) {
887 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
888 return ResourceElement.getCompleteObjectRef(getTable(), realIndex);
891 public int getPredicateIndex(int resourceIndex) {
892 int i = (resourceIndex<<2) - 3 + offset;
893 return (int)table[i];
896 public void setPredicateIndex(int resourceIndex, int predicateIndex) {
897 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
898 ResourceElement.setPredicateIndex(getTable(), realIndex, predicateIndex);
901 public byte[] getValue(ValueTable valueTable, int resourceIndex)
902 throws DatabaseException {
903 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
904 return ResourceElement.getValue(valueTable, getTable(), realIndex);
908 // int getString(ValueTable valueTable, int resourceIndex, char[] chars)
909 // throws DatabaseException {
910 // //int realIndex = checkIndexAndGetRealIndex(resourceIndex);
911 // return ResourceElement.getString(valueTable, getTable(), 4 * resourceIndex - 3 + offset, chars);
914 public boolean hasValue(int resourceIndex) {
915 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
916 return ResourceElement.hasValue(getTable(), realIndex);
919 // boolean hasValue(ValueTable valueTable, int resourceIndex, byte[] value) {
920 // int realIndex = checkIndexAndGetRealIndex(resourceIndex);
921 // return ResourceElement.hasValue(valueTable, getTable(), realIndex, value);
924 public boolean removeValue(ValueTable valueTable, int resourceIndex) {
925 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
926 boolean ret = ResourceElement.removeValue(valueTable, getTable(), realIndex);
927 // if (ret && !ResourceElement.isUsed(getTable(), realIndex))
928 // decResourceCount();
932 public void setValue(ValueTable valueTable, int resourceIndex, byte[] value, int length) {
933 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
934 ResourceElement.setValue(valueTable, getTable(), realIndex, value, length);
937 public boolean isValueEx(ValueTable valueTable, int resourceIndex) {
938 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
939 return ResourceElement.isValueEx(valueTable, getTable(), realIndex);
942 public void setValueEx(ValueTable valueTable, int resourceIndex) {
943 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
944 ResourceElement.setValueEx(valueTable, getTable(), realIndex);
947 static final int RESOURCE_COUNT_INDEX = 0;
948 static final int FOREIGN_COUNT_INDEX = 1; // Reserved by server.
949 static final int CLUSTER_STATUS_INDEX = 2;
951 int incResourceCount() {
952 int count = getExtra(RESOURCE_COUNT_INDEX) + 1;
953 setExtra(RESOURCE_COUNT_INDEX, count);
957 // int decResourceCount() {
958 // int count = getExtra(RESOURCE_COUNT_INDEX) - 1;
959 // setExtra(RESOURCE_COUNT_INDEX, count);
963 public int getResourceCount() {
964 return getExtra(RESOURCE_COUNT_INDEX);
966 public int getClusterStatus() {
967 return getExtra(CLUSTER_STATUS_INDEX);
969 public void setClusterStatus(int value) {
970 setExtra(CLUSTER_STATUS_INDEX, value);
974 final int tsize = getTableSize();
975 final int esize = ResourceElement.getSizeOf();
976 long[] table = getTable();
977 for (int i = getTableBase(); i < getTableBase() + tsize; i += esize) {
978 if (ResourceElement.isUsed(getTable(), i)) {
979 System.out.println(" -" + Long.toHexString(table[i]) + " " + Long.toHexString(table[i+1]) + " " + Long.toHexString(table[i+2]) + " " + Long.toHexString(table[i+3]));
985 public <Context> boolean foreachResource(ClusterI.ObjectProcedure<Context> procedure, Context context,
986 ClusterSupport support, Modifier modifier) throws DatabaseException {
987 final int tsize = getTableSize();
988 // final int rsize = getResourceCount();
989 final int esize = ResourceElement.getSizeOf();
991 int key = ZERO_SHIFT;
992 for (int i = getTableBase(); i < getTableBase() + tsize; i += esize, ++key) {
993 if (ResourceElement.isUsed(getTable(), i)) {
995 if (null == modifier)
998 ref = modifier.execute(key);
999 if (procedure.execute(context, ref))
1000 return true; // loop was broken by procedure
1001 // if (rsize == ++count)
1002 // return false; // loop finished
1005 //assert(rsize == count);
1006 return false; // loop finished
1009 public <Context> boolean foreachPredicate(int resourceIndex
1010 , ClusterI.PredicateProcedure<Context> procedure, Context context
1011 , ClusterSupport support, Modifier modifier, CompleteTable ct)
1012 throws DatabaseException {
1013 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1014 return ResourceElement.foreachPredicate(getTable(), realIndex
1015 , procedure, context, support, modifier, ct);
1018 public int getSingleObject(int resourceIndex, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1019 // return ResourceElement.getSingleObject(table, realIndex, support, pRef, pCompleteType, ct, modifier);
1020 return ResourceElement.getSingleObject(table, 4 * resourceIndex - 3 + offset, support, pRef, pCompleteType, ct, modifier);
1023 public void foreachObject(int resourceIndex, ReadGraphImpl graph,
1024 AsyncMultiProcedure<Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1025 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1026 ResourceElement.foreachObject(table, realIndex, graph, procedure, support,
1027 pRef, pCompleteType, ct, modifier);
1030 public <C> void foreachObject(int resourceIndex, ReadGraphImpl graph, C context,
1031 AsyncContextMultiProcedure<C, Resource> procedure, ClusterSupport support, int pRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct, Modifier modifier) throws DatabaseException {
1032 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1033 ResourceElement.foreachObject(table, realIndex, graph, context, procedure, support,
1034 pRef, pCompleteType, ct, modifier);
1037 public <Context> boolean foreachObject(int resourceIndex
1038 , ClusterI.ObjectProcedure<Context> procedure, Context context
1039 , ClusterSupport support, Modifier modifier,
1040 int pRef, ClusterI.CompleteTypeEnum completeType, CompleteTable ct)
1041 throws DatabaseException {
1042 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1043 return ResourceElement.foreachObject(table, realIndex
1044 , procedure, context, support, modifier
1045 , pRef, completeType, ct);
1047 public int addStatement(int resourceIndex, int pRef, int oRef, PredicateTable pt, ObjectTable ot
1048 , ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
1049 throws DatabaseException {
1050 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1051 return ResourceElement.addStatement(getTable(), realIndex, pRef, oRef, pt, ot, pCompleteType, ct);
1054 public boolean removeStatementFromCache(int resourceIndex, int pRef, int oRef,
1055 ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct)
1056 throws DatabaseException {
1057 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1058 boolean ret = ResourceElement.removeStatement(getTable(), realIndex, pRef, oRef, pCompleteType, ct);
1059 // if (ret && !ResourceElement.isUsed(getTable(), realIndex))
1060 // decResourceCount();
1064 public void removeStatement(int resourceIndex, int pRef, int oRef, ClusterI.CompleteTypeEnum pCompleteType, CompleteTable ct,
1065 PredicateTable pt, ObjectTable ot, ClusterBase cluster, ClusterSupport support)
1066 throws DatabaseException {
1067 int realIndex = checkIndexAndGetRealIndex(resourceIndex);
1068 boolean removed = ResourceElement.removeStatement(getTable(), realIndex,
1069 pRef, oRef, pCompleteType, ct);
1072 int predicateIndex = ResourceElement.getPredicateIndex(getTable(), realIndex);
1073 if (0 == predicateIndex) {
1074 // if (!ResourceElement.isUsed(getTable(), realIndex))
1075 // decResourceCount();
1078 GetStatements gs = new GetStatements(ot);
1079 pt.foreachPredicate(predicateIndex, gs, null, null, null);
1080 ArrayList<Statement> stms = gs.getStatements();
1082 final int SIZE = stms.size();
1084 for (int i = 0; i < SIZE; ++i) {
1085 Statement stm = stms.get(i);
1086 PredicateTable.Status ret = pt.removePredicate(predicateIndex,
1087 stm.pRef, stm.oIndex, ot);
1088 if (ret == Status.NothingRemoved)
1089 throw new DatabaseException("Internal error during statement cache fix (2).");
1090 int predicateKey = cluster.makeResourceKey(stm.pRef);
1091 int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
1092 ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
1093 int pi = ResourceElement.addStatement(getTable(), realIndex, stm.pRef, stm.oIndex,
1094 pt, ot, completeType, ct);
1097 assert(0 == pt.getPredicateSetSize(predicateIndex));
1098 ResourceElement.setPredicateIndex(getTable(), realIndex, 0);
1100 for (int i = 0; i < SIZE; ++i) {
1101 Statement stm = stms.get(i);
1102 int predicateKey = cluster.makeResourceKey(stm.pRef);
1103 int completeTypeInt = ClusterTraitsBase.getCompleteTypeIntFromResourceKey(predicateKey);
1104 ClusterI.CompleteTypeEnum completeType = CompleteTypeEnum.make(completeTypeInt);
1105 int pIndex = ResourceElement.addStatement(getTable(), realIndex,
1106 stm.pRef, stm.oIndex, pt, ot, completeType, ct);
1108 return; // cache fixed and full, p and o sets in use
1110 throw new DatabaseException("Internal error during statement cache fix (3).");
1112 // if (!ResourceElement.isUsed(getTable(), realIndex))
1113 // decResourceCount();
1117 private int checkIndexAndGetRealIndex(final int INDEX) {
1119 assert(INDEX <= getTableCount());
1120 // final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
1121 // final int TABLE_INDEX = (INDEX - ZERO_SHIFT) * ResourceElement.getSizeOf() + ZERO_SHIFT;
1122 // return checkIndexAndGetRealIndex(TABLE_INDEX, ResourceElement.getSizeOf());
1123 return 4 * INDEX - 3 + offset;
1125 public void check(ClusterBase cluster)
1126 throws DatabaseException {
1128 cluster.checkValueInit();
1129 long[] table = getTable();
1130 int ps = getHeader().getOffset() + ZERO_SHIFT;
1131 final int TABLE_SIZE = getTableSize();
1132 int pe = ps + TABLE_SIZE;
1133 for (int p=ps; p<pe; p+=ResourceElement.getSizeOf()) {
1134 if (!ResourceElement.isUsed(table, p))
1136 int cr = ResourceElement.getCompleteObjectRef(table, p);
1138 if (ClusterTraits.completeReferenceIsMultiple(cr))
1139 cluster.checkCompleteSetReference(cr);
1141 int fi = ClusterTraits.completeReferenceGetForeignIndex(cr);
1142 int ri = ClusterTraits.completeReferenceGetResourceIndex(cr);
1144 cluster.checkForeingIndex(fi);
1145 else if (ri < 1 || ri > TABLE_SIZE)
1146 throw new ValidationException("Illegal resource index=" + ri);
1149 int pi = ResourceElement.getPredicateIndex(table, p);
1151 cluster.checkPredicateIndex(pi);
1153 ResourceElement.ValueData vd = new ResourceElement.ValueData();
1154 ResourceElement.getValueCapacityAndIndex(vd, table, p);
1155 cluster.checkValue(vd.capacity, vd.index);
1157 cluster.checkValueFini();
1161 public <Context> boolean foreach(int setIndex, Procedure procedure, Context context,
1162 ClusterSupport support, Modifier modifier) throws DatabaseException {
1163 throw new UnsupportedOperationException();
1168 Statement(int pRef, int oIndex) {
1170 this.oIndex = oIndex;
1176 class CalculateStatements
1177 implements ClusterI.PredicateProcedure<CalculateStatements> {
1178 private ObjectTable ot;
1179 private final int sRef;
1181 CalculateStatements(int sRef, ObjectTable ot) {
1187 public boolean execute(final CalculateStatements context
1188 , final int pKey, int oIndex) {
1189 if (ClusterTraits.statementIndexIsDirect(oIndex))
1190 return false; // osize = 1
1192 oIndex = ClusterTraits.statementIndexGet(oIndex);
1193 } catch (DatabaseException e) {
1194 Logger.getDefault().logError("Missing object set for s="
1195 + sRef + " p=" + pKey, null);
1196 return false; // continue looping
1198 int osize = ot.getObjectSetSize(oIndex);
1199 if (osize == 3 || osize > 9)
1200 System.out.println("Resource " + sRef + " predicate " + pKey + " has "
1201 + osize + " objects.");
1202 return true; // break loop
1206 class GetStatements implements PredicateProcedure<Object>, ObjectProcedure<Integer> {
1207 private ObjectTable ot;
1208 private final ArrayList<Statement> stms = new ArrayList<Statement>();
1209 GetStatements(ObjectTable ot) {
1212 ArrayList<Statement> getStatements() {
1216 public boolean execute(Object context, int pRef, int oIndex) {
1218 ot.foreachObject(oIndex, this, pRef, null, null);
1219 } catch (DatabaseException e) {
1220 e.printStackTrace();
1221 return false; // continue looping
1223 if (stms.size() > 2)
1224 return true; // break loop
1225 return false; // continue looping
1229 public boolean execute(Integer pRef, int oRef) {
1230 stms.add(new Statement(pRef, oRef));
1231 if (stms.size() > 2)
1232 return true; // break loop
1233 return false; // continue looping