]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/ClusterStream.java
DB client state gets corrupted
[simantics/platform.git] / bundles / org.simantics.db.procore / src / fi / vtt / simantics / procore / internal / ClusterStream.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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 fi.vtt.simantics.procore.internal;
13
14 import java.util.ArrayList;
15
16 import org.simantics.db.common.utils.Logger;
17 import org.simantics.db.exception.DatabaseException;
18 import org.simantics.db.service.ClusterUID;
19
20 final public class ClusterStream {
21
22     // public static long duration2 = 0;
23
24     public static final boolean DEBUG = false;
25     public static final byte NULL_OPERATION = 0;
26     public static final byte CREATE_OPERATION = 1;
27     public static final byte SET_OPERATION = 4;
28     public static final byte MODI_OPERATION = 6;
29     public static final byte KILL_OPERATION = 7;
30     boolean off = false;
31     public GraphSession graphSession;
32     final SessionImplSocket session;
33 //    private int flushCount = 0;
34     final private boolean alwaysOff;
35     private int stamp;
36     private int acceptedStamp;
37     private boolean dirty = false;
38 //    final private ArrayList<ClusterChange> clusterChanges = new ArrayList<ClusterChange>();
39
40     final ClusterChangeManager changes = new ClusterChangeManager();
41
42 //    final TLongObjectHashMap<ClusterChange> clusterChanges = new TLongObjectHashMap<ClusterChange>();
43
44     // private final Change lastChange = new Change();
45     ClusterStream(SessionImplSocket session, GraphSession graphSession,
46             boolean alwaysOff) {
47         this.session = session;
48         this.graphSession = graphSession;
49         this.alwaysOff = alwaysOff;
50     }
51
52
53     boolean isDirty() {
54         return dirty;
55     }
56
57     void markDirty() {
58         dirty = true;
59     }
60
61     void setOff(boolean value) {
62         if (alwaysOff) {
63             off = true;
64         } else {
65             off = value;
66         }
67     }
68
69     boolean getOff() {
70         return off;
71     }
72
73     void createResource(ClusterChange cc, short operationIndex, ClusterUID clusterUID) {
74         if (off)
75             return;
76         assert (null != cc);
77         assert (0 != operationIndex);
78         assert (!ClusterUID.Null.equals(clusterUID));
79         if (DEBUG)
80             System.out.println("DEBUG: Created resource index=" + operationIndex + " cluster=" + clusterUID);
81         cc.createResource(operationIndex);
82     }
83
84     final void addStatementIndex(Change change, int key, ClusterUID clusterUID, byte op) {
85         if (off)
86             return;
87         assert (key > 0);
88         assert (null != change);
89         assert (!ClusterUID.Null.equals(clusterUID));
90         change.addStatementIndex(key, clusterUID, op);
91     }
92
93     void addStatement(ClusterChange cc, Change change) {
94         if (off)
95             return;
96         assert (null != cc);
97         assert (null != change);
98         cc.addChange(change);
99     }
100
101     void cancelStatement(Change change) {
102         if (off)
103             return;
104         assert (null != change);
105         change.init();
106     }
107
108     void removeStatement(ClusterChange cc, Change change) {
109         if (off)
110             return;
111         assert (null != cc);
112         assert (null != change);
113         cc.addChange(change);
114     }
115
116     void cancelValue(Change change) {
117         if (off)
118             return;
119         assert (null != change);
120         change.init();
121     }
122
123     void removeValue(ClusterChange cc, Change change) {
124         if (off)
125             return;
126         assert (null != cc);
127         assert (null != change);
128         cc.addChange(change);
129     }
130
131     void setValue(ClusterChange cc, Change change, long clusterId, byte[] bytes, int length) {
132         if (off)
133             return;
134         assert (null != cc);
135         assert (null != change);
136         // ClusterChange cc = getClusterChange(clusterId);
137         cc.setValue(change, bytes, length);
138     }
139
140     void modiValue(ClusterChange cc, Change change, long clusterId,
141             long voffset, int length, byte[] bytes, int offset) {
142         assert (null != cc);
143         assert (null != change);
144         cc.modiValue(change, voffset, length, bytes, offset);
145     }
146
147     void undoValueEx(ClusterChange cc, Change change, int resourceIndex) {
148         cc.undoValueEx(resourceIndex);
149     }
150     void setImmutable(ClusterChange cc, Change change, boolean immutable) {
151         if (off)
152             return;
153         cc.setImmutable(immutable);
154     }
155     void setDeleted(ClusterChange cc, Change change, boolean deleted) {
156         if (off)
157             return;
158         cc.setDeleted(deleted);
159     }
160     public void corruptCluster(ClusterChange cc, long clusterId)
161             throws DatabaseException {
162         if (off)
163             return;
164         if (DEBUG)
165             System.out.println("ClusterStream.corrupt cid=" + clusterId + ".");
166         assert (null != cc);
167         cc.corrupt();
168     }
169
170     int getStamp() {
171         return stamp;
172     }
173
174     void flush() {
175         if (off)
176             return;
177 //        flushCount++;
178         return;
179     }
180
181     void flush(ClusterUID clusterUID) {
182         if (off)
183             return;
184         ArrayList<ClusterChange> ccs = new ArrayList<ClusterChange>();
185         for(ClusterChange cc : changes.get()) {
186             if(cc.clusterUID.equals(clusterUID)) {
187                 if (cc.flush(graphSession, cc.clusterUID)) {
188                     ccs.add(cc);
189                     if (stamp == acceptedStamp)
190                         ++stamp;
191                 } else {
192                     Logger.defaultLogError("Failed to flush ClusterStream. cluster=" + clusterUID);
193                 }
194             }
195         }
196         changes.remove(ccs);
197     }
198
199     /**
200      * @return true if the stream has accepted all changes
201      */
202     public boolean reallyFlush() {
203         // Last possibility to mark clusters immutable before write only clusters are gone
204         session.handleCreatedClusters();
205         // These shall be requested from server
206         session.clusterTable.removeWriteOnlyClusters();
207         if (!off && changes.size() > 0) {
208             for(ClusterChange cc : changes.get()) {
209                 if (cc.flush(graphSession, cc.clusterUID))
210                     if (stamp == acceptedStamp)
211                         ++stamp;
212             }
213             changes.clear();
214         }
215         dirty = false;
216         return hasAcceptedAllChanges();
217     }
218
219     /**
220      * Clear all changes and set stream status to empty.
221      */
222     public void clear() {
223         changes.clear();
224         acceptedStamp = stamp;
225         dirty = false;
226     }
227
228     private boolean hasAcceptedAllChanges() {
229         return stamp == acceptedStamp;
230     }
231
232     void accept() {
233         acceptedStamp = stamp;
234     }
235
236
237
238     static class DebugInfo {
239         long nStms;
240         long nLocal;
241         long nPartly;
242         long nForeign;
243         long nValues;
244         long sValues;
245         long sForeign;
246         long tot;
247
248         void clear() {
249             nStms = 0;
250             nLocal = 0;
251             nPartly = 0;
252             nForeign = 0;
253             sForeign = 0;
254             nValues = 0;
255             sValues = 0;
256             tot = 0;
257         }
258
259         void add(DebugInfo di) {
260             nStms += di.nStms;
261             nLocal += di.nLocal;
262             nPartly += di.nPartly;
263             nForeign += di.nForeign;
264             sForeign += di.sForeign;
265             nValues += di.nValues;
266             sValues += di.sValues;
267             tot += di.tot;
268         }
269
270         @Override
271         public String toString() {
272             return "val=" + nValues + " stm=" + nStms + " loc=" + nLocal
273                     + " par=" + nPartly + " ful=" + nForeign + " for="
274                     + sForeign + " vat=" + sValues + " tot=" + tot;
275         }
276     }
277
278     enum StmEnum {
279         Add(0, (byte) 0), Remove(1, (byte) 0x20);
280         StmEnum(int ordinal, byte mask) {
281             this.ordinal = ordinal;
282             this.mask = mask;
283         }
284
285         public int ordinal;
286         private byte mask;
287
288         byte getOrMask() {
289             return mask;
290         }
291     }
292
293     final static class Data {
294
295         final byte mask; // or mask for operation code (don't care bits are zero)
296         final short bits; // how many bits are reserved for resource index (0,2,4,6)
297         final int bytes;
298
299         Data(int mask, int bits, ClusterEnum a, ClusterEnum b) {
300             this.mask = (byte) (mask << bits);
301             this.bits = (short) bits;
302             this.bytes = bytes(bits, a, b);
303         }
304
305         private static int bytes(int bits, ClusterEnum a, ClusterEnum b) {
306             int left = 6 - bits;
307             if (a != ClusterEnum.ForeignShort) {
308                 left += 6;
309             }
310             if (b != ClusterEnum.ForeignShort) {
311                 left += 6;
312             }
313             int bytes = left >>> 3;
314             if ((left & 7) != 0)
315                 bytes++;
316             return bytes;
317         }
318
319
320     }
321
322     enum ClusterEnum {
323         Local(0), ForeignShort(1), ForeignLong(2);
324         public int ordinal;
325
326         ClusterEnum(int ordinal) {
327             this.ordinal = ordinal;
328         }
329
330         static Data[][][] maps = new Data[2][3][3];
331         static {
332             maps[StmEnum.Add.ordinal][Local.ordinal][Local.ordinal] = new Data(
333                     0, 2, Local, Local);
334             maps[StmEnum.Add.ordinal][Local.ordinal][ForeignShort.ordinal] = new Data(
335                     12, 4, Local, ForeignShort);
336             maps[StmEnum.Add.ordinal][Local.ordinal][ForeignLong.ordinal] = new Data(
337                     2, 2, Local, ForeignLong);
338             maps[StmEnum.Add.ordinal][ForeignShort.ordinal][Local.ordinal] = new Data(
339                     13, 4, ForeignShort, Local);
340             maps[StmEnum.Add.ordinal][ForeignShort.ordinal][ForeignShort.ordinal] = new Data(
341                     1, 6, ForeignShort, ForeignShort);
342             maps[StmEnum.Add.ordinal][ForeignShort.ordinal][ForeignLong.ordinal] = new Data(
343                     14, 4, ForeignShort, ForeignLong);
344             maps[StmEnum.Add.ordinal][ForeignLong.ordinal][Local.ordinal] = new Data(
345                     4, 2, ForeignLong, Local);
346             maps[StmEnum.Add.ordinal][ForeignLong.ordinal][ForeignShort.ordinal] = new Data(
347                     15, 4, ForeignLong, ForeignShort);
348             maps[StmEnum.Add.ordinal][ForeignLong.ordinal][ForeignLong.ordinal] = new Data(
349                     6, 2, ForeignLong, ForeignLong);
350
351             maps[StmEnum.Remove.ordinal][Local.ordinal][Local.ordinal] = new Data(
352                     1, 2, Local, Local);
353             maps[StmEnum.Remove.ordinal][Local.ordinal][ForeignShort.ordinal] = new Data(
354                     49, 0, Local, ForeignShort);
355             maps[StmEnum.Remove.ordinal][Local.ordinal][ForeignLong.ordinal] = new Data(
356                     3, 2, Local, ForeignLong);
357             maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][Local.ordinal] = new Data(
358                     2, 4, ForeignShort, Local);
359             maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][ForeignShort.ordinal] = new Data(
360                     2, 6, ForeignShort, ForeignShort);
361             maps[StmEnum.Remove.ordinal][ForeignShort.ordinal][ForeignLong.ordinal] = new Data(
362                     50, 0, ForeignShort, ForeignLong);
363             maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][Local.ordinal] = new Data(
364                     5, 2, ForeignLong, Local);
365             maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][ForeignShort.ordinal] = new Data(
366                     51, 0, ForeignLong, ForeignShort);
367             maps[StmEnum.Remove.ordinal][ForeignLong.ordinal][ForeignLong.ordinal] = new Data(
368                     7, 2, ForeignLong, ForeignLong);
369         }
370
371         static Data getData(StmEnum s, ClusterEnum a, ClusterEnum b) {
372             return maps[s.ordinal][a.ordinal][b.ordinal];
373             // return maps.get(s).get(a).get(b);
374         }
375     }
376
377     enum OpEnum {
378         Create((byte) 52), Set((byte) 53), SetShort((byte) 56), Delete(
379                 (byte) 54), Modify((byte) 55);
380         OpEnum(byte mask) {
381             this.mask = mask;
382         }
383
384         public byte getOrMask() {
385             return mask;
386         }
387
388         private byte mask;
389     }
390 }