001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.tx;
005:
006: import EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
007:
008: import java.util.Collections;
009: import java.util.HashSet;
010: import java.util.LinkedList;
011: import java.util.List;
012: import java.util.Set;
013:
014: import junit.framework.TestCase;
015:
016: public class TransactionBatchAccountingTest extends TestCase {
017: private TransactionBatchAccounting acct;
018: private Sequence sequence;
019:
020: public void setUp() throws Exception {
021: acct = new TransactionBatchAccounting();
022: sequence = new Sequence();
023: }
024:
025: public void testBasics() throws Exception {
026: final List incompleteBatchIDs = new LinkedList();
027: // try adding an empty batch
028: Batch batch1 = new Batch(new TxnBatchID(sequence.next()));
029: acct.addBatch(batch1.batchID, batch1.transactionIDs);
030: // there should be no incomplete batches
031: assertEquals(Collections.EMPTY_LIST, acct
032: .addIncompleteBatchIDsTo(new LinkedList()));
033: // the min incomplete batch id should be the null id.
034: assertEquals(TxnBatchID.NULL_BATCH_ID, acct
035: .getMinIncompleteBatchID());
036:
037: // try adding a batch with a two transactions
038: TransactionID txID1 = new TransactionID(sequence.next());
039: TransactionID txID2 = new TransactionID(sequence.next());
040:
041: Batch batch2 = new Batch(new TxnBatchID(sequence.next()));
042: batch2.addTransactionID(txID1);
043: batch2.addTransactionID(txID2);
044: incompleteBatchIDs.add(batch2.batchID);
045: acct.addBatch(batch2.batchID, batch2.transactionIDs);
046:
047: TransactionID txID3 = new TransactionID(sequence.next());
048: Batch batch3 = new Batch(new TxnBatchID(sequence.next()));
049: batch3.addTransactionID(txID3);
050: incompleteBatchIDs.add(batch3.batchID);
051: acct.addBatch(batch3.batchID, batch3.transactionIDs);
052:
053: TransactionID txID4 = new TransactionID(sequence.next());
054: Batch batch4 = new Batch(new TxnBatchID(sequence.next()));
055: batch4.addTransactionID(txID4);
056: incompleteBatchIDs.add(batch4.batchID);
057: acct.addBatch(batch4.batchID, batch4.transactionIDs);
058:
059: // LWM is the lowest txn id, since there were no acknowledgements
060: assertEquals(txID1, acct.getLowWaterMark());
061:
062: // check the incomplete batches
063: assertEquals(incompleteBatchIDs, acct
064: .addIncompleteBatchIDsTo(new LinkedList()));
065: assertEquals(incompleteBatchIDs.get(0), acct
066: .getMinIncompleteBatchID());
067:
068: // ACK the first transaction in the multi-transaction batch
069: assertEquals(TxnBatchID.NULL_BATCH_ID, acct.acknowledge(txID1));
070: // there should still be no completed batches
071: assertEquals(incompleteBatchIDs, acct
072: .addIncompleteBatchIDsTo(new LinkedList()));
073:
074: //LWM moved up
075: assertEquals(txID2, acct.getLowWaterMark());
076:
077: // ACK the last transaction in the multi-transaction batch. This should cause that batch to become complete AND
078: // cause all of its constituent transactions to become completed.
079: assertEquals(batch2.batchID, acct.acknowledge(txID2));
080: incompleteBatchIDs.remove(batch2.batchID);
081: assertEquals(incompleteBatchIDs, acct
082: .addIncompleteBatchIDsTo(new LinkedList()));
083: assertEquals(incompleteBatchIDs.get(0), acct
084: .getMinIncompleteBatchID());
085:
086: //LWM moved up
087: assertEquals(txID3, acct.getLowWaterMark());
088:
089: // LWM remains the same
090: assertEquals(txID3, acct.getLowWaterMark());
091:
092: // ACK another transaction
093: assertEquals(batch3.batchID, acct.acknowledge(txID3));
094: incompleteBatchIDs.remove(batch3.batchID);
095: assertEquals(incompleteBatchIDs, acct
096: .addIncompleteBatchIDsTo(new LinkedList()));
097: assertEquals(incompleteBatchIDs.get(0), acct
098: .getMinIncompleteBatchID());
099:
100: //LWM moved up
101: assertEquals(txID4, acct.getLowWaterMark());
102:
103: // ACK the last transaction
104: assertEquals(batch4.batchID, acct.acknowledge(txID4));
105: incompleteBatchIDs.remove(batch4.batchID);
106: assertEquals(Collections.EMPTY_LIST, incompleteBatchIDs);
107: assertEquals(incompleteBatchIDs, acct
108: .addIncompleteBatchIDsTo(new LinkedList()));
109: assertEquals(TxnBatchID.NULL_BATCH_ID, acct
110: .getMinIncompleteBatchID());
111:
112: //LWM moved up
113: assertEquals(txID4.next(), acct.getLowWaterMark());
114:
115: }
116:
117: /**
118: * Tests that the set of incomplete batch ids comes out in the same order it come in.
119: */
120: public void testBatchOrdering() throws Exception {
121: List batchIDs = new LinkedList();
122: for (int i = 0; i < 1000; i++) {
123: TxnBatchID batchID = new TxnBatchID(sequence.next());
124: Set transactionIDs = new HashSet();
125: for (int j = 0; j < 10; j++) {
126: transactionIDs.add(new TransactionID(sequence.next()));
127: }
128: acct.addBatch(batchID, transactionIDs);
129: batchIDs.add(batchID);
130:
131: assertEquals(batchIDs, acct
132: .addIncompleteBatchIDsTo(new LinkedList()));
133: }
134: }
135:
136: private static final class Sequence {
137: private SynchronizedLong sequence = new SynchronizedLong(0);
138:
139: public long next() {
140: return sequence.increment();
141: }
142: }
143:
144: private static final class Batch {
145:
146: private final TxnBatchID batchID;
147: private final Set transactionIDs = new HashSet();
148:
149: public Batch(TxnBatchID batchID) {
150: this .batchID = batchID;
151: }
152:
153: public void addTransactionID(TransactionID txID) {
154: transactionIDs.add(txID);
155: }
156: }
157:
158: }
|