001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.tx;
006:
007: import com.tc.net.groups.ClientID;
008: import com.tc.net.protocol.tcm.ChannelID;
009: import com.tc.object.ObjectID;
010: import com.tc.object.dmi.DmiDescriptor;
011: import com.tc.object.dna.impl.ObjectStringSerializer;
012: import com.tc.object.lockmanager.api.LockID;
013: import com.tc.object.tx.TransactionID;
014: import com.tc.object.tx.TxnBatchID;
015: import com.tc.object.tx.TxnType;
016: import com.tc.objectserver.context.ApplyCompleteEventContext;
017: import com.tc.objectserver.context.ApplyTransactionContext;
018: import com.tc.objectserver.context.CommitTransactionContext;
019: import com.tc.objectserver.context.LookupEventContext;
020: import com.tc.objectserver.context.RecallObjectsContext;
021: import com.tc.objectserver.core.api.TestDNA;
022: import com.tc.objectserver.core.impl.TestManagedObject;
023: import com.tc.objectserver.gtx.TestGlobalTransactionManager;
024: import com.tc.objectserver.impl.TestObjectManager;
025: import com.tc.test.TCTestCase;
026: import com.tc.util.SequenceID;
027:
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.Collections;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.LinkedList;
035: import java.util.List;
036: import java.util.Map;
037: import java.util.Set;
038:
039: public class TransactionalObjectManagerTest extends TCTestCase {
040:
041: TestObjectManager objectManager;
042: TransactionSequencer sequencer;
043: TestTransactionalStageCoordinator coordinator;
044: private TransactionalObjectManagerImpl txObjectManager;
045: private TestGlobalTransactionManager gtxMgr;
046:
047: public void setUp() {
048: objectManager = new TestObjectManager();
049: sequencer = new TransactionSequencer();
050: coordinator = new TestTransactionalStageCoordinator();
051: gtxMgr = new TestGlobalTransactionManager();
052: txObjectManager = new TransactionalObjectManagerImpl(
053: objectManager, sequencer, gtxMgr, coordinator);
054: }
055:
056: // This test is added to reproduce a failure. More test are needed for TransactionalObjectManager
057: public void testTxnObjectManagerRecallAllOnGC() throws Exception {
058:
059: Map changes = new HashMap();
060:
061: changes.put(new ObjectID(1), new TestDNA(new ObjectID(1)));
062: changes.put(new ObjectID(2), new TestDNA(new ObjectID(2)));
063:
064: ServerTransaction stxn1 = new ServerTransactionImpl(gtxMgr,
065: new TxnBatchID(1), new TransactionID(1),
066: new SequenceID(1), new LockID[0], new ClientID(
067: new ChannelID(2)), new ArrayList(changes
068: .values()), new ObjectStringSerializer(),
069: Collections.EMPTY_MAP, TxnType.NORMAL,
070: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
071: List txns = new ArrayList();
072: txns.add(stxn1);
073:
074: txObjectManager.addTransactions(txns);
075:
076: // Lookup context should have been fired
077: LookupEventContext loc = (LookupEventContext) coordinator.lookupSink.queue
078: .remove(0);
079: assertNotNull(loc);
080: assertTrue(coordinator.lookupSink.queue.isEmpty());
081:
082: txObjectManager.lookupObjectsForTransactions();
083:
084: // for txn1 - ObjectID 1, 2
085: Object args[] = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
086: .take();
087: assertNotNull(args);
088:
089: // Apply should have been called as we have Object 1, 2
090: ApplyTransactionContext aoc = (ApplyTransactionContext) coordinator.applySink.queue
091: .remove(0);
092: assertTrue(stxn1 == aoc.getTxn());
093: assertNotNull(aoc);
094: assertTrue(coordinator.applySink.queue.isEmpty());
095:
096: // Next txn
097: changes.put(new ObjectID(3), new TestDNA(new ObjectID(3)));
098: changes.put(new ObjectID(4), new TestDNA(new ObjectID(4)));
099:
100: ServerTransaction stxn2 = new ServerTransactionImpl(gtxMgr,
101: new TxnBatchID(2), new TransactionID(2),
102: new SequenceID(1), new LockID[0], new ClientID(
103: new ChannelID(2)), new ArrayList(changes
104: .values()), new ObjectStringSerializer(),
105: Collections.EMPTY_MAP, TxnType.NORMAL,
106: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
107:
108: txns.clear();
109: txns.add(stxn2);
110:
111: txObjectManager.addTransactions(txns);
112:
113: // Lookup context should have been fired
114: loc = (LookupEventContext) coordinator.lookupSink.queue
115: .remove(0);
116: assertNotNull(loc);
117: assertTrue(coordinator.lookupSink.queue.isEmpty());
118:
119: objectManager.makePending = true;
120: txObjectManager.lookupObjectsForTransactions();
121:
122: // for txn2, ObjectID 3, 4
123: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
124: .take();
125: assertNotNull(args);
126:
127: // Apply and commit complete for the first transaction
128: txObjectManager.applyTransactionComplete(stxn1
129: .getServerTransactionID());
130: ApplyCompleteEventContext acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
131: .remove(0);
132: assertNotNull(acec);
133: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
134:
135: txObjectManager.processApplyComplete();
136: CommitTransactionContext ctc = (CommitTransactionContext) coordinator.commitSink.queue
137: .remove(0);
138: assertNotNull(ctc);
139: assertTrue(coordinator.commitSink.queue.isEmpty());
140:
141: txObjectManager.commitTransactionsComplete(ctc);
142: Collection applied = ctc.getAppliedServerTransactionIDs();
143: assertTrue(applied.size() == 1);
144: assertEquals(stxn1.getServerTransactionID(), applied.iterator()
145: .next());
146: Collection objects = ctc.getObjects();
147: assertTrue(objects.size() == 2);
148:
149: Set recd = new HashSet();
150: TestManagedObject tmo;
151: for (Iterator i = objects.iterator(); i.hasNext();) {
152: tmo = (TestManagedObject) i.next();
153: recd.add(tmo.getID());
154: }
155:
156: Set expected = new HashSet();
157: expected.add(new ObjectID(1));
158: expected.add(new ObjectID(2));
159:
160: assertEquals(expected, recd);
161:
162: // Process the request for 3, 4
163: objectManager.makePending = false;
164: objectManager.processPending(args);
165:
166: // Lookup context should have been fired
167: loc = (LookupEventContext) coordinator.lookupSink.queue
168: .remove(0);
169: assertNotNull(loc);
170: assertTrue(coordinator.lookupSink.queue.isEmpty());
171:
172: // Dont give out 1,2
173: objectManager.makePending = true;
174: txObjectManager.lookupObjectsForTransactions();
175:
176: // for txn2, ObjectID 1, 2
177: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
178: .take();
179: assertNotNull(args);
180:
181: // Apply should not have been called as we dont have Obejct 1, 2
182: assertTrue(coordinator.applySink.queue.isEmpty());
183:
184: // now do a recall.
185: txObjectManager.recallAllCheckedoutObject();
186: RecallObjectsContext roc = (RecallObjectsContext) coordinator.recallSink.queue
187: .remove(0);
188: assertNotNull(roc);
189: assertTrue(coordinator.recallSink.queue.isEmpty());
190:
191: // process recall
192: txObjectManager.recallCheckedoutObject(roc);
193:
194: // check 2 and only 2 object are released
195: Collection released = (Collection) objectManager.releaseAllQueue
196: .take();
197: assertNotNull(released);
198:
199: System.err.println("Released = " + released);
200:
201: assertEquals(2, released.size());
202:
203: HashSet ids_expected = new HashSet();
204: ids_expected.add(new ObjectID(3));
205: ids_expected.add(new ObjectID(4));
206:
207: HashSet ids_recd = new HashSet();
208:
209: for (Iterator i = released.iterator(); i.hasNext();) {
210: tmo = (TestManagedObject) i.next();
211: ids_recd.add(tmo.getID());
212: }
213:
214: assertEquals(ids_expected, ids_recd);
215: }
216:
217: // This test is added to reproduce a failure. More test are needed for TransactionalObjectManager
218: // This test is only slightly different from the above on in that the final recall should happen for 3 objects
219: public void testTxnObjectManagerRecallAllOnGCCase2()
220: throws Exception {
221:
222: Map changes = new HashMap();
223:
224: changes.put(new ObjectID(1), new TestDNA(new ObjectID(1)));
225: changes.put(new ObjectID(2), new TestDNA(new ObjectID(2)));
226:
227: ServerTransaction stxn1 = new ServerTransactionImpl(gtxMgr,
228: new TxnBatchID(1), new TransactionID(1),
229: new SequenceID(1), new LockID[0], new ClientID(
230: new ChannelID(2)), new ArrayList(changes
231: .values()), new ObjectStringSerializer(),
232: Collections.EMPTY_MAP, TxnType.NORMAL,
233: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
234: List txns = new ArrayList();
235: txns.add(stxn1);
236:
237: txObjectManager.addTransactions(txns);
238:
239: // Lookup context should have been fired
240: LookupEventContext loc = (LookupEventContext) coordinator.lookupSink.queue
241: .remove(0);
242: assertNotNull(loc);
243: assertTrue(coordinator.lookupSink.queue.isEmpty());
244:
245: txObjectManager.lookupObjectsForTransactions();
246:
247: // for txn1 - ObjectID 1, 2
248: Object args[] = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
249: .take();
250: assertNotNull(args);
251:
252: // Apply should have been called as we have Obejct 1, 2
253: ApplyTransactionContext aoc = (ApplyTransactionContext) coordinator.applySink.queue
254: .remove(0);
255: assertTrue(stxn1 == aoc.getTxn());
256: assertNotNull(aoc);
257: assertTrue(coordinator.applySink.queue.isEmpty());
258:
259: // Next txn
260: changes.put(new ObjectID(3), new TestDNA(new ObjectID(3)));
261: changes.put(new ObjectID(4), new TestDNA(new ObjectID(4)));
262:
263: ServerTransaction stxn2 = new ServerTransactionImpl(gtxMgr,
264: new TxnBatchID(2), new TransactionID(2),
265: new SequenceID(1), new LockID[0], new ClientID(
266: new ChannelID(2)), new ArrayList(changes
267: .values()), new ObjectStringSerializer(),
268: Collections.EMPTY_MAP, TxnType.NORMAL,
269: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
270:
271: txns.clear();
272: txns.add(stxn2);
273:
274: txObjectManager.addTransactions(txns);
275:
276: // Lookup context should have been fired
277: loc = (LookupEventContext) coordinator.lookupSink.queue
278: .remove(0);
279: assertNotNull(loc);
280: assertTrue(coordinator.lookupSink.queue.isEmpty());
281:
282: objectManager.makePending = true;
283: txObjectManager.lookupObjectsForTransactions();
284:
285: // for txn2, ObjectID 3, 4
286: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
287: .take();
288: assertNotNull(args);
289:
290: // Apply and commit complete for the first transaction
291: txObjectManager.applyTransactionComplete(stxn1
292: .getServerTransactionID());
293: ApplyCompleteEventContext acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
294: .remove(0);
295: assertNotNull(acec);
296: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
297:
298: txObjectManager.processApplyComplete();
299: CommitTransactionContext ctc = (CommitTransactionContext) coordinator.commitSink.queue
300: .remove(0);
301: assertNotNull(ctc);
302: assertTrue(coordinator.commitSink.queue.isEmpty());
303:
304: txObjectManager.commitTransactionsComplete(ctc);
305: Collection applied = ctc.getAppliedServerTransactionIDs();
306: assertTrue(applied.size() == 1);
307: assertEquals(stxn1.getServerTransactionID(), applied.iterator()
308: .next());
309: Collection objects = ctc.getObjects();
310: assertTrue(objects.size() == 2);
311:
312: Set recd = new HashSet();
313: TestManagedObject tmo;
314: for (Iterator i = objects.iterator(); i.hasNext();) {
315: tmo = (TestManagedObject) i.next();
316: recd.add(tmo.getID());
317: }
318:
319: Set expected = new HashSet();
320: expected.add(new ObjectID(1));
321: expected.add(new ObjectID(2));
322:
323: assertEquals(expected, recd);
324:
325: // Process the request for 3, 4
326: objectManager.makePending = false;
327: objectManager.processPending(args);
328:
329: // Lookup context should have been fired
330: loc = (LookupEventContext) coordinator.lookupSink.queue
331: .remove(0);
332: assertNotNull(loc);
333: assertTrue(coordinator.lookupSink.queue.isEmpty());
334:
335: // Dont give out 1,2
336: objectManager.makePending = true;
337: txObjectManager.lookupObjectsForTransactions();
338:
339: // for txn2, ObjectID 1, 2
340: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
341: .take();
342: assertNotNull(args);
343:
344: // Apply should not have been called as we dont have Obejct 1, 2
345: assertTrue(coordinator.applySink.queue.isEmpty());
346:
347: // --------------------------------This is where its differernt from case 1-------------------------
348: // Process the request for 5 and 6
349: changes.clear();
350: changes.put(new ObjectID(5), new TestDNA(new ObjectID(5)));
351: ServerTransaction stxn3 = new ServerTransactionImpl(gtxMgr,
352: new TxnBatchID(3), new TransactionID(3),
353: new SequenceID(2), new LockID[0], new ClientID(
354: new ChannelID(2)), new ArrayList(changes
355: .values()), new ObjectStringSerializer(),
356: Collections.EMPTY_MAP, TxnType.NORMAL,
357: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
358:
359: txns.clear();
360: txns.add(stxn3);
361: txObjectManager.addTransactions(txns);
362:
363: // Lookup context should have been fired
364: loc = (LookupEventContext) coordinator.lookupSink.queue
365: .remove(0);
366: assertNotNull(loc);
367: assertTrue(coordinator.lookupSink.queue.isEmpty());
368:
369: objectManager.makePending = false;
370: txObjectManager.lookupObjectsForTransactions();
371:
372: // for txn3 - ObjectID 5
373: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
374: .take();
375: assertNotNull(args);
376:
377: // Apply should have been called as we have Object 5
378: aoc = (ApplyTransactionContext) coordinator.applySink.queue
379: .remove(0);
380: assertTrue(stxn3 == aoc.getTxn());
381: assertNotNull(aoc);
382: assertTrue(coordinator.applySink.queue.isEmpty());
383:
384: // Next Txn , Object 5, 6
385: changes.put(new ObjectID(6), new TestDNA(new ObjectID(6)));
386: ServerTransaction stxn4 = new ServerTransactionImpl(gtxMgr,
387: new TxnBatchID(4), new TransactionID(4),
388: new SequenceID(3), new LockID[0], new ClientID(
389: new ChannelID(2)), new ArrayList(changes
390: .values()), new ObjectStringSerializer(),
391: Collections.EMPTY_MAP, TxnType.NORMAL,
392: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
393:
394: txns.clear();
395: txns.add(stxn4);
396: txObjectManager.addTransactions(txns);
397:
398: // Lookup context should have been fired
399: loc = (LookupEventContext) coordinator.lookupSink.queue
400: .remove(0);
401: assertNotNull(loc);
402: assertTrue(coordinator.lookupSink.queue.isEmpty());
403:
404: objectManager.makePending = true;
405: txObjectManager.lookupObjectsForTransactions();
406:
407: // for txn4, ObjectID 6
408: args = (Object[]) objectManager.lookupObjectForCreateIfNecessaryContexts
409: .take();
410: assertNotNull(args);
411:
412: // Apply and commit complete for the 3'rd transaction
413: txObjectManager.applyTransactionComplete(stxn3
414: .getServerTransactionID());
415: acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
416: .remove(0);
417: assertNotNull(acec);
418: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
419:
420: txObjectManager.processApplyComplete();
421: ctc = (CommitTransactionContext) coordinator.commitSink.queue
422: .remove(0);
423: assertNotNull(ctc);
424: assertTrue(coordinator.commitSink.queue.isEmpty());
425:
426: txObjectManager.commitTransactionsComplete(ctc);
427: applied = ctc.getAppliedServerTransactionIDs();
428: assertTrue(applied.size() == 1);
429: assertEquals(stxn3.getServerTransactionID(), applied.iterator()
430: .next());
431: objects = ctc.getObjects();
432: assertTrue(objects.size() == 1);
433:
434: recd = new HashSet();
435: for (Iterator i = objects.iterator(); i.hasNext();) {
436: tmo = (TestManagedObject) i.next();
437: recd.add(tmo.getID());
438: }
439:
440: expected = new HashSet();
441: expected.add(new ObjectID(5));
442:
443: assertEquals(expected, recd);
444:
445: // Process the request for 6, still 1 and 2 is not given out
446: objectManager.makePending = false;
447: objectManager.processPending(args);
448:
449: // Lookup context should have been fired
450: loc = (LookupEventContext) coordinator.lookupSink.queue
451: .remove(0);
452: assertNotNull(loc);
453: assertTrue(coordinator.lookupSink.queue.isEmpty());
454:
455: // Now before look up thread got a chance to execute, recall gets executed.
456: objectManager.makePending = true; // Since we dont want to give out 5 when we do a recall commit
457: // -------------------------------------------------------------------------------------------------
458:
459: // now do a recall.
460: txObjectManager.recallAllCheckedoutObject();
461: RecallObjectsContext roc = (RecallObjectsContext) coordinator.recallSink.queue
462: .remove(0);
463: assertNotNull(roc);
464: assertTrue(coordinator.recallSink.queue.isEmpty());
465:
466: // process recall
467: txObjectManager.recallCheckedoutObject(roc);
468:
469: // check that all 3 objects (3,4,6) are released -- different from case 1
470: Collection released = (Collection) objectManager.releaseAllQueue
471: .take();
472: assertNotNull(released);
473:
474: System.err.println("Released = " + released);
475:
476: assertEquals(3, released.size());
477:
478: HashSet ids_expected = new HashSet();
479: ids_expected.add(new ObjectID(3));
480: ids_expected.add(new ObjectID(4));
481: ids_expected.add(new ObjectID(6));
482:
483: HashSet ids_recd = new HashSet();
484:
485: for (Iterator i = released.iterator(); i.hasNext();) {
486: tmo = (TestManagedObject) i.next();
487: ids_recd.add(tmo.getID());
488: }
489:
490: assertEquals(ids_expected, ids_recd);
491: }
492:
493: }
|