KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > objectserver > tx > TransactionSequencerTest


1 /*
2  * Copyright (c) 2003-2006 Terracotta, Inc. All rights reserved.
3  */

4 package com.tc.objectserver.tx;
5
6 import com.tc.net.protocol.tcm.ChannelID;
7 import com.tc.object.ObjectID;
8 import com.tc.object.dmi.DmiDescriptor;
9 import com.tc.object.dna.impl.ObjectStringSerializer;
10 import com.tc.object.lockmanager.api.LockID;
11 import com.tc.object.tx.TransactionID;
12 import com.tc.object.tx.TxnBatchID;
13 import com.tc.object.tx.TxnType;
14 import com.tc.objectserver.core.api.TestDNA;
15 import com.tc.test.TCTestCase;
16 import com.tc.util.Assert;
17 import com.tc.util.SequenceID;
18
19 import java.security.SecureRandom JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Random JavaDoc;
30 import java.util.Set JavaDoc;
31
32 public class TransactionSequencerTest extends TCTestCase {
33
34   private int sqID;
35   private int txnID;
36   private int batchID;
37   private ChannelID channelID;
38   private TransactionSequencer sequencer;
39   private int start;
40
41   public void setUp() throws Exception JavaDoc {
42     txnID = 100;
43     sqID = 100;
44     batchID = 100;
45     start = 1;
46     channelID = new ChannelID(0);
47     sequencer = new TransactionSequencer();
48   }
49
50   // Test 1
51
// Nothing is pending - disjoint anyway
52
public void testNoPendingDisjointTxn() throws Exception JavaDoc {
53     List JavaDoc txns = createDisjointTxns(5);
54     sequencer.addTransactions(txns);
55     assertEquals(txns, getAllTxnsPossible());
56     assertFalse(sequencer.isPending(txns));
57   }
58
59   // Test 2
60
// Nothing is pending - not disjoint though
61
public void testNoPendingJointTxn() throws Exception JavaDoc {
62     List JavaDoc txns = createIntersectingLocksTxns(5);
63     sequencer.addTransactions(txns);
64     assertEquals(txns, getAllTxnsPossible());
65     assertFalse(sequencer.isPending(txns));
66   }
67
68   // Test 3
69
// txn goes pending - disjoint anyway
70
public void testPendingDisJointTxn() throws Exception JavaDoc {
71     List JavaDoc txns = createDisjointTxns(5);
72     sequencer.addTransactions(txns);
73     ServerTransaction t1 = sequencer.getNextTxnToProcess();
74     assertNotNull(t1);
75     // Make it pending
76
sequencer.makePending(t1);
77     assertTrue(sequencer.isPending(txns));
78     txns.remove(t1);
79     assertEquals(txns, getAllTxnsPossible());
80     assertTrue(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
81     // Nomore txns
82
assertNull(sequencer.getNextTxnToProcess());
83     sequencer.makeUnpending(t1);
84     assertFalse(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
85     // Nomore txns
86
assertNull(sequencer.getNextTxnToProcess());
87   }
88
89   // Test 4
90
// txn goes pending - intersecting set
91
public void testPendingJointAtLocksTxn() throws Exception JavaDoc {
92     List JavaDoc txns = createIntersectingLocksTxns(5);
93     sequencer.addTransactions(txns);
94     ServerTransaction t1 = sequencer.getNextTxnToProcess();
95     assertNotNull(t1);
96     // Make it pending
97
sequencer.makePending(t1);
98     assertTrue(sequencer.isPending(txns));
99     txns.remove(t1);
100
101     // Since locks are common no txn should be available
102
assertNull(sequencer.getNextTxnToProcess());
103     assertTrue(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
104     sequencer.makeUnpending(t1);
105     assertFalse(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
106     // Rest of the txns
107
assertEquals(txns, getAllTxnsPossible());
108   }
109
110   // Test 5
111
// txn goes pending - intersecting set
112
public void testPendingJointAtObjectsTxn() throws Exception JavaDoc {
113     List JavaDoc txns = createIntersectingObjectsTxns(5);
114     sequencer.addTransactions(txns);
115     ServerTransaction t1 = sequencer.getNextTxnToProcess();
116     assertNotNull(t1);
117     // Make it pending
118
sequencer.makePending(t1);
119     assertTrue(sequencer.isPending(txns));
120     txns.remove(t1);
121
122     // Since locks are common no txn should be available
123
assertNull(sequencer.getNextTxnToProcess());
124     assertTrue(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
125     sequencer.makeUnpending(t1);
126     assertFalse(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
127     // Rest of the txns
128
assertEquals(txns, getAllTxnsPossible());
129   }
130
131   // Test 6
132
// txn goes pending - intersecting set
133
public void testPendingJointAtBothLocksAndObjectsTxn() throws Exception JavaDoc {
134     List JavaDoc txns = createIntersectingLocksObjectsTxns(5);
135     sequencer.addTransactions(txns);
136     ServerTransaction t1 = sequencer.getNextTxnToProcess();
137     assertNotNull(t1);
138     // Make it pending
139
sequencer.makePending(t1);
140     assertTrue(sequencer.isPending(txns));
141     txns.remove(t1);
142
143     // Since locks are common no txn should be available
144
assertNull(sequencer.getNextTxnToProcess());
145     assertTrue(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
146     sequencer.makeUnpending(t1);
147     assertFalse(sequencer.isPending(Arrays.asList(new Object JavaDoc[] { t1 })));
148     // Rest of the txns
149
assertEquals(txns, getAllTxnsPossible());
150   }
151
152   // Test 7
153
// Test error conditions
154
public void testErrorConditions() throws Exception JavaDoc {
155     // Call makepending twice
156
List JavaDoc txns = createDisjointTxns(5);
157     sequencer.addTransactions(txns);
158     ServerTransaction t1 = sequencer.getNextTxnToProcess();
159     assertNotNull(t1);
160     sequencer.makePending(t1);
161     assertTrue(sequencer.isPending(txns));
162     try {
163       sequencer.makePending(t1);
164       fail();
165     } catch (Throwable JavaDoc t) {
166       // expected
167
}
168
169     // Call make unpending for something that is not pendin
170
ServerTransaction t2 = sequencer.getNextTxnToProcess();
171     assertNotNull(t2);
172     try {
173       sequencer.makeUnpending(t2);
174       fail();
175     } catch (Throwable JavaDoc t) {
176       // expected
177
}
178     sequencer.makeUnpending(t1);
179   }
180
181   public void testOrderingByOID() {
182     List JavaDoc txns = new ArrayList JavaDoc();
183
184     int lock = 0;
185
186     ServerTransaction txn1 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(1),
187                                                        new SequenceID(sqID++), createLocks(lock, lock++), channelID,
188                                                        createDNAs(1, 1), new ObjectStringSerializer(),
189                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
190                                                        DmiDescriptor.EMPTY_ARRAY);
191
192     ServerTransaction txn2 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(2),
193                                                        new SequenceID(sqID++), createLocks(lock, lock++), channelID,
194                                                        createDNAs(2, 2), new ObjectStringSerializer(),
195                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
196                                                        DmiDescriptor.EMPTY_ARRAY);
197
198     ServerTransaction txn3 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(3),
199                                                        new SequenceID(sqID++), createLocks(lock, lock++), channelID,
200                                                        createDNAs(2, 3), new ObjectStringSerializer(),
201                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
202                                                        DmiDescriptor.EMPTY_ARRAY);
203
204     ServerTransaction txn4 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(4),
205                                                        new SequenceID(sqID++), createLocks(lock, lock++), channelID,
206                                                        createDNAs(1, 2), new ObjectStringSerializer(),
207                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
208                                                        DmiDescriptor.EMPTY_ARRAY);
209
210     txns.add(txn1);
211     txns.add(txn2);
212     txns.add(txn3);
213     txns.add(txn4);
214     sequencer.addTransactions(txns);
215
216     sequencer.makePending(sequencer.getNextTxnToProcess());
217     sequencer.makePending(sequencer.getNextTxnToProcess());
218
219     Object JavaDoc o;
220     o = sequencer.getNextTxnToProcess();
221     Assert.assertNull(o);
222     o = sequencer.getNextTxnToProcess();
223     Assert.assertNull(o);
224
225     sequencer.makeUnpending(txn2);
226     sequencer.makeUnpending(txn1);
227
228     ServerTransaction shouldBe3 = sequencer.getNextTxnToProcess();
229     ServerTransaction shouldBe4 = sequencer.getNextTxnToProcess();
230
231     Assert.assertEquals(txn3, shouldBe3);
232     Assert.assertEquals(txn4, shouldBe4);
233   }
234
235   public void testOrderingByLock() {
236     List JavaDoc txns = new ArrayList JavaDoc();
237
238     int oid = 0;
239
240     ServerTransaction txn1 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(1),
241                                                        new SequenceID(sqID++), createLocks(1, 1), channelID,
242                                                        createDNAs(oid, oid++), new ObjectStringSerializer(),
243                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
244                                                        DmiDescriptor.EMPTY_ARRAY);
245
246     ServerTransaction txn2 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(2),
247                                                        new SequenceID(sqID++), createLocks(2, 2), channelID,
248                                                        createDNAs(oid, oid++), new ObjectStringSerializer(),
249                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
250                                                        DmiDescriptor.EMPTY_ARRAY);
251
252     ServerTransaction txn3 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(3),
253                                                        new SequenceID(sqID++), createLocks(2, 3), channelID,
254                                                        createDNAs(oid, oid++), new ObjectStringSerializer(),
255                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
256                                                        DmiDescriptor.EMPTY_ARRAY);
257
258     ServerTransaction txn4 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(4),
259                                                        new SequenceID(sqID++), createLocks(1, 2), channelID,
260                                                        createDNAs(oid, oid++), new ObjectStringSerializer(),
261                                                        Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList JavaDoc(),
262                                                        DmiDescriptor.EMPTY_ARRAY);
263
264     txns.add(txn1);
265     txns.add(txn2);
266     txns.add(txn3);
267     txns.add(txn4);
268     sequencer.addTransactions(txns);
269
270     sequencer.makePending(sequencer.getNextTxnToProcess());
271     sequencer.makePending(sequencer.getNextTxnToProcess());
272
273     Object JavaDoc o;
274     o = sequencer.getNextTxnToProcess();
275     Assert.assertNull(o);
276     o = sequencer.getNextTxnToProcess();
277     Assert.assertNull(o);
278
279     sequencer.makeUnpending(txn2);
280     sequencer.makeUnpending(txn1);
281
282     ServerTransaction shouldBe3 = sequencer.getNextTxnToProcess();
283     ServerTransaction shouldBe4 = sequencer.getNextTxnToProcess();
284
285     Assert.assertEquals(txn3, shouldBe3);
286     Assert.assertEquals(txn4, shouldBe4);
287   }
288
289   public void testRandom() {
290     for (int i = 0; i < 100; i++) {
291       System.err.println("Running testRandom : " + i);
292       doRandom();
293       sequencer = new TransactionSequencer();
294     }
295   }
296
297   public void testRandomFailedSeed1() {
298     long seed = -7748167846395034562L;
299     System.err.println("Testing failed seed : " + seed);
300     doRandom(seed);
301   }
302
303   public void testRandomFailedSeed2() {
304     long seed = -149113776740941224L;
305     System.err.println("Testing failed seed : " + seed);
306     doRandom(seed);
307   }
308
309   // XXX: multi-threaded version of this?
310
// XXX: add cases with locks in common between TXNs
311
private void doRandom() {
312     final long seed = new SecureRandom JavaDoc().nextLong();
313     System.err.println("seed is " + seed);
314     doRandom(seed);
315   }
316
317   private void doRandom(long seed) {
318     Random JavaDoc rnd = new Random JavaDoc(seed);
319
320     int lock = 0;
321     final int numObjects = 25;
322     long versionsIn[] = new long[numObjects];
323     long versionsRecv[] = new long[numObjects];
324
325     Set JavaDoc pending = new HashSet JavaDoc();
326
327     for (int loop = 0; loop < 10000; loop++) {
328       List JavaDoc txns = new ArrayList JavaDoc();
329       for (int i = 0, n = rnd.nextInt(3) + 1; i < n; i++) {
330         txns.add(createRandomTxn(rnd.nextInt(3) + 1, versionsIn, rnd, lock++));
331       }
332
333       sequencer.addTransactions(txns);
334
335       ServerTransaction next = null;
336       while ((next = sequencer.getNextTxnToProcess()) != null) {
337         if (rnd.nextInt(3) == 0) {
338           sequencer.makePending(next);
339           pending.add(next);
340           continue;
341         }
342
343         processTransaction(next, versionsRecv);
344
345         if (pending.size() > 0 && rnd.nextInt(4) == 0) {
346           for (int i = 0, n = rnd.nextInt(pending.size()); i < n; i++) {
347             Iterator JavaDoc iter = pending.iterator();
348             ServerTransaction pendingTxn = (ServerTransaction) iter.next();
349             iter.remove();
350             processTransaction(pendingTxn, versionsRecv);
351             sequencer.makeUnpending(pendingTxn);
352           }
353         }
354       }
355
356     }
357   }
358
359   private void processTransaction(ServerTransaction next, long[] versionsRecv) {
360     for (Iterator JavaDoc iter = next.getChanges().iterator(); iter.hasNext();) {
361       TestDNA dna = (TestDNA) iter.next();
362       int oid = (int) dna.getObjectID().toLong();
363       long ver = dna.version;
364       long expect = versionsRecv[oid] + 1;
365       if (expect != ver) {
366         //
367
throw new AssertionError JavaDoc(oid + " : Expected change to increment to version " + expect
368                                  + ", but change was to version " + ver);
369       }
370       versionsRecv[oid] = ver;
371     }
372   }
373
374   private ServerTransaction createRandomTxn(int numObjects, long[] versions, Random JavaDoc rnd, int lockID) {
375     Map JavaDoc dnas = new HashMap JavaDoc();
376     while (numObjects > 0) {
377       int i = rnd.nextInt(versions.length);
378       if (!dnas.containsKey(new Integer JavaDoc(i))) {
379         TestDNA dna = new TestDNA(new ObjectID(i));
380         dna.version = ++versions[i];
381         dnas.put(new Integer JavaDoc(i), dna);
382         numObjects--;
383       }
384     }
385
386     return new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++),
387                                      createLocks(lockID, lockID), channelID, new ArrayList JavaDoc(dnas.values()),
388                                      new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL,
389                                      new LinkedList JavaDoc(), DmiDescriptor.EMPTY_ARRAY);
390   }
391
392   private List JavaDoc getAllTxnsPossible() {
393     List JavaDoc txns = new ArrayList JavaDoc();
394     ServerTransaction txn;
395     while ((txn = sequencer.getNextTxnToProcess()) != null) {
396       txns.add(txn);
397     }
398     return txns;
399   }
400
401   private List JavaDoc createDisjointTxns(int count) {
402     List JavaDoc txns = new ArrayList JavaDoc();
403     batchID++;
404     int j = 3;
405     while (count-- > 0) {
406       int e = start + j;
407       txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++),
408                                          createLocks(start, e), channelID, createDNAs(start, e),
409                                          new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL,
410                                          new LinkedList JavaDoc(), DmiDescriptor.EMPTY_ARRAY));
411       start = e + 1;
412     }
413     return txns;
414   }
415
416   private List JavaDoc createIntersectingLocksTxns(int count) {
417     List JavaDoc txns = new ArrayList JavaDoc();
418     batchID++;
419     int j = 3;
420     while (count-- > 0) {
421       int e = start + j;
422       txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++),
423                                          createLocks(start, e + j), channelID, createDNAs(start, e),
424                                          new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL,
425                                          new LinkedList JavaDoc(), DmiDescriptor.EMPTY_ARRAY));
426       start = e + 1;
427     }
428     return txns;
429   }
430
431   private List JavaDoc createIntersectingObjectsTxns(int count) {
432     List JavaDoc txns = new ArrayList JavaDoc();
433     batchID++;
434     int j = 3;
435     while (count-- > 0) {
436       int e = start + j;
437       txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++),
438                                          createLocks(start, e), channelID, createDNAs(start, e + j),
439                                          new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL,
440                                          new LinkedList JavaDoc(), DmiDescriptor.EMPTY_ARRAY));
441       start = e + 1;
442     }
443     return txns;
444   }
445
446   private List JavaDoc createIntersectingLocksObjectsTxns(int count) {
447     List JavaDoc txns = new ArrayList JavaDoc();
448     batchID++;
449     int j = 3;
450     while (count-- > 0) {
451       int e = start + j;
452       txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++),
453                                          createLocks(start, e + j), channelID, createDNAs(start, e + j),
454                                          new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL,
455                                          new LinkedList JavaDoc(), DmiDescriptor.EMPTY_ARRAY));
456       start = e + 1;
457     }
458     return txns;
459   }
460
461   private List JavaDoc createDNAs(int s, int e) {
462     List JavaDoc dnas = new ArrayList JavaDoc();
463     for (int i = s; i <= e; i++) {
464       dnas.add(new TestDNA(new ObjectID(i)));
465     }
466     return dnas;
467   }
468
469   private LockID[] createLocks(int s, int e) {
470     LockID[] locks = new LockID[e - s + 1];
471     for (int j = s; j <= e; j++) {
472       locks[j - s] = new LockID("@" + j);
473     }
474     return locks;
475   }
476 }
477
Popular Tags