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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package fi.vtt.simantics.procore.internal;
\r
14 import java.util.ArrayList;
\r
16 import org.simantics.db.common.utils.Logger;
\r
17 import org.simantics.db.exception.DatabaseException;
\r
18 import org.simantics.db.service.ClusterUID;
\r
20 final public class ClusterStream {
\r
22 // public static long duration2 = 0;
\r
24 public static final boolean DEBUG = false;
\r
25 public static final byte NULL_OPERATION = 0;
\r
26 public static final byte CREATE_OPERATION = 1;
\r
27 public static final byte SET_OPERATION = 4;
\r
28 public static final byte MODI_OPERATION = 6;
\r
29 public static final byte KILL_OPERATION = 7;
\r
30 boolean off = false;
\r
31 public GraphSession graphSession;
\r
32 final SessionImplSocket session;
\r
33 // private int flushCount = 0;
\r
34 final private boolean alwaysOff;
\r
36 private int acceptedStamp;
\r
37 private boolean dirty = false;
\r
38 // final private ArrayList<ClusterChange> clusterChanges = new ArrayList<ClusterChange>();
\r
40 final ClusterChangeManager changes = new ClusterChangeManager();
\r
42 // final TLongObjectHashMap<ClusterChange> clusterChanges = new TLongObjectHashMap<ClusterChange>();
\r
44 // private final Change lastChange = new Change();
\r
45 ClusterStream(SessionImplSocket session, GraphSession graphSession,
\r
46 boolean alwaysOff) {
\r
47 this.session = session;
\r
48 this.graphSession = graphSession;
\r
49 this.alwaysOff = alwaysOff;
\r
61 void setOff(boolean value) {
\r
73 void createResource(ClusterChange cc, short operationIndex, ClusterUID clusterUID) {
\r
76 assert (null != cc);
\r
77 assert (0 != operationIndex);
\r
78 assert (!ClusterUID.Null.equals(clusterUID));
\r
80 System.out.println("DEBUG: Created resource index=" + operationIndex + " cluster=" + clusterUID);
\r
81 cc.createResource(operationIndex);
\r
84 final void addStatementIndex(Change change, int key, ClusterUID clusterUID, byte op) {
\r
88 assert (null != change);
\r
89 assert (!ClusterUID.Null.equals(clusterUID));
\r
90 change.addStatementIndex(key, clusterUID, op);
\r
93 void addStatement(ClusterChange cc, Change change) {
\r
96 assert (null != cc);
\r
97 assert (null != change);
\r
98 cc.addChange(change);
\r
101 void cancelStatement(Change change) {
\r
104 assert (null != change);
\r
108 void removeStatement(ClusterChange cc, Change change) {
\r
111 assert (null != cc);
\r
112 assert (null != change);
\r
113 cc.addChange(change);
\r
116 void cancelValue(Change change) {
\r
119 assert (null != change);
\r
123 void removeValue(ClusterChange cc, Change change) {
\r
126 assert (null != cc);
\r
127 assert (null != change);
\r
128 cc.addChange(change);
\r
131 void setValue(ClusterChange cc, Change change, long clusterId, byte[] bytes, int length) {
\r
134 assert (null != cc);
\r
135 assert (null != change);
\r
136 // ClusterChange cc = getClusterChange(clusterId);
\r
137 cc.setValue(change, bytes, length);
\r
140 void modiValue(ClusterChange cc, Change change, long clusterId,
\r
141 long voffset, int length, byte[] bytes, int offset) {
\r
142 assert (null != cc);
\r
143 assert (null != change);
\r
144 cc.modiValue(change, voffset, length, bytes, offset);
\r
147 void undoValueEx(ClusterChange cc, Change change, int resourceIndex) {
\r
148 cc.undoValueEx(resourceIndex);
\r
150 void setImmutable(ClusterChange cc, Change change, boolean immutable) {
\r
153 cc.setImmutable(immutable);
\r
155 void setDeleted(ClusterChange cc, Change change, boolean deleted) {
\r
158 cc.setDeleted(deleted);
\r
160 public void corruptCluster(ClusterChange cc, long clusterId)
\r
161 throws DatabaseException {
\r
165 System.out.println("ClusterStream.corrupt cid=" + clusterId + ".");
\r
166 assert (null != cc);
\r
181 void flush(ClusterUID clusterUID) {
\r
184 ArrayList<ClusterChange> ccs = new ArrayList<ClusterChange>();
\r
185 for(ClusterChange cc : changes.get()) {
\r
186 if(cc.clusterUID.equals(clusterUID)) {
\r
187 if (cc.flush(graphSession, cc.clusterUID)) {
\r
189 if (stamp == acceptedStamp)
\r
192 Logger.defaultLogError("Failed to flush ClusterStream. cluster=" + clusterUID);
\r
196 changes.remove(ccs);
\r
200 * @return true if the stream has accepted all changes
\r
202 public boolean reallyFlush() {
\r
203 // Last possibility to mark clusters immutable before write only clusters are gone
\r
204 session.handleCreatedClusters();
\r
205 // These shall be requested from server
\r
206 session.clusterTable.removeWriteOnlyClusters();
\r
207 if (!off && changes.size() > 0) {
\r
208 for(ClusterChange cc : changes.get()) {
\r
209 if (cc.flush(graphSession, cc.clusterUID))
\r
210 if (stamp == acceptedStamp)
\r
216 return hasAcceptedAllChanges();
\r
220 * Clear all changes and set stream status to empty.
\r
222 public void clear() {
\r
224 acceptedStamp = stamp;
\r
228 private boolean hasAcceptedAllChanges() {
\r
229 return stamp == acceptedStamp;
\r
233 acceptedStamp = stamp;
\r
238 static class DebugInfo {
\r
259 void add(DebugInfo di) {
\r
261 nLocal += di.nLocal;
\r
262 nPartly += di.nPartly;
\r
263 nForeign += di.nForeign;
\r
264 sForeign += di.sForeign;
\r
265 nValues += di.nValues;
\r
266 sValues += di.sValues;
\r
271 public String toString() {
\r
272 return "val=" + nValues + " stm=" + nStms + " loc=" + nLocal
\r
273 + " par=" + nPartly + " ful=" + nForeign + " for="
\r
274 + sForeign + " vat=" + sValues + " tot=" + tot;
\r
279 Add(0, (byte) 0), Remove(1, (byte) 0x20);
\r
280 StmEnum(int ordinal, byte mask) {
\r
281 this.ordinal = ordinal;
\r
285 public int ordinal;
\r
293 final static class Data {
\r
295 final byte mask; // or mask for operation code (don't care bits are zero)
\r
296 final short bits; // how many bits are reserved for resource index (0,2,4,6)
\r
299 Data(int mask, int bits, ClusterEnum a, ClusterEnum b) {
\r
300 this.mask = (byte) (mask << bits);
\r
301 this.bits = (short) bits;
\r
302 this.bytes = bytes(bits, a, b);
\r
305 private static int bytes(int bits, ClusterEnum a, ClusterEnum b) {
\r
306 int left = 6 - bits;
\r
307 if (a != ClusterEnum.ForeignShort) {
\r
310 if (b != ClusterEnum.ForeignShort) {
\r
313 int bytes = left >>> 3;
\r
314 if ((left & 7) != 0)
\r
323 Local(0), ForeignShort(1), ForeignLong(2);
\r
324 public int ordinal;
\r
326 ClusterEnum(int ordinal) {
\r
327 this.ordinal = ordinal;
\r
330 static Data[][][] maps = new Data[2][3][3];
\r
332 maps[StmEnum.Add.ordinal][Local.ordinal][Local.ordinal] = new Data(
\r
333 0, 2, Local, Local);
\r
334 maps[StmEnum.Add.ordinal][Local.ordinal][ForeignShort.ordinal] = new Data(
\r
335 12, 4, Local, ForeignShort);
\r
336 maps[StmEnum.Add.ordinal][Local.ordinal][ForeignLong.ordinal] = new Data(
\r
337 2, 2, Local, ForeignLong);
\r
338 maps[StmEnum.Add.ordinal][ForeignShort.ordinal][Local.ordinal] = new Data(
\r
339 13, 4, ForeignShort, Local);
\r
340 maps[StmEnum.Add.ordinal][ForeignShort.ordinal][ForeignShort.ordinal] = new Data(
\r
341 1, 6, ForeignShort, ForeignShort);
\r
342 maps[StmEnum.Add.ordinal][ForeignShort.ordinal][ForeignLong.ordinal] = new Data(
\r
343 14, 4, ForeignShort, ForeignLong);
\r
344 maps[StmEnum.Add.ordinal][ForeignLong.ordinal][Local.ordinal] = new Data(
\r
345 4, 2, ForeignLong, Local);
\r
346 maps[StmEnum.Add.ordinal][ForeignLong.ordinal][ForeignShort.ordinal] = new Data(
\r
347 15, 4, ForeignLong, ForeignShort);
\r
348 maps[StmEnum.Add.ordinal][ForeignLong.ordinal][ForeignLong.ordinal] = new Data(
\r
349 6, 2, ForeignLong, ForeignLong);
\r
351 maps[StmEnum.Remove.ordinal][Local.ordinal][Local.ordinal] = new Data(
\r
352 1, 2, Local, Local);
\r
353 maps[StmEnum.Remove.ordinal][Local.ordinal][ForeignShort.ordinal] = new Data(
\r
354 49, 0, Local, ForeignShort);
\r
355 maps[StmEnum.Remove.ordinal][Local.ordinal][ForeignLong.ordinal] = new Data(
\r
356 3, 2, Local, ForeignLong);
\r
357 maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][Local.ordinal] = new Data(
\r
358 2, 4, ForeignShort, Local);
\r
359 maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][ForeignShort.ordinal] = new Data(
\r
360 2, 6, ForeignShort, ForeignShort);
\r
361 maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][ForeignLong.ordinal] = new Data(
\r
362 50, 0, ForeignShort, ForeignLong);
\r
363 maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][Local.ordinal] = new Data(
\r
364 5, 2, ForeignLong, Local);
\r
365 maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][ForeignShort.ordinal] = new Data(
\r
366 51, 0, ForeignLong, ForeignShort);
\r
367 maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][ForeignLong.ordinal] = new Data(
\r
368 7, 2, ForeignLong, ForeignLong);
\r
371 static Data getData(StmEnum s, ClusterEnum a, ClusterEnum b) {
\r
372 return maps[s.ordinal][a.ordinal][b.ordinal];
\r
373 // return maps.get(s).get(a).get(b);
\r
378 Create((byte) 52), Set((byte) 53), SetShort((byte) 56), Delete(
\r
379 (byte) 54), Modify((byte) 55);
\r
380 OpEnum(byte mask) {
\r
384 public byte getOrMask() {
\r