0001: /*
0002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
0003: * notice. All rights reserved.
0004: */
0005: package com.tc.objectserver.api;
0006:
0007: import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
0008:
0009: import com.tc.exception.ImplementMe;
0010: import com.tc.lang.TCThreadGroup;
0011: import com.tc.lang.ThrowableHandler;
0012: import com.tc.logging.TCLogger;
0013: import com.tc.logging.TCLogging;
0014: import com.tc.net.groups.ClientID;
0015: import com.tc.net.protocol.tcm.ChannelID;
0016: import com.tc.object.BaseDSOTestCase;
0017: import com.tc.object.ObjectID;
0018: import com.tc.object.SerializationUtil;
0019: import com.tc.object.cache.EvictionPolicy;
0020: import com.tc.object.cache.LRUEvictionPolicy;
0021: import com.tc.object.cache.NullCache;
0022: import com.tc.object.cache.TestCacheStats;
0023: import com.tc.object.dmi.DmiDescriptor;
0024: import com.tc.object.dna.api.DNA;
0025: import com.tc.object.dna.api.DNACursor;
0026: import com.tc.object.dna.api.DNAEncoding;
0027: import com.tc.object.dna.api.DNAException;
0028: import com.tc.object.dna.api.LiteralAction;
0029: import com.tc.object.dna.api.LogicalAction;
0030: import com.tc.object.dna.api.PhysicalAction;
0031: import com.tc.object.dna.impl.ObjectStringSerializer;
0032: import com.tc.object.dna.impl.UTF8ByteDataHolder;
0033: import com.tc.object.lockmanager.api.LockID;
0034: import com.tc.object.tx.TransactionID;
0035: import com.tc.object.tx.TxnBatchID;
0036: import com.tc.object.tx.TxnType;
0037: import com.tc.objectserver.context.ApplyCompleteEventContext;
0038: import com.tc.objectserver.context.ApplyTransactionContext;
0039: import com.tc.objectserver.context.CommitTransactionContext;
0040: import com.tc.objectserver.context.LookupEventContext;
0041: import com.tc.objectserver.context.ManagedObjectFaultingContext;
0042: import com.tc.objectserver.context.ManagedObjectFlushingContext;
0043: import com.tc.objectserver.context.ObjectManagerResultsContext;
0044: import com.tc.objectserver.context.RecallObjectsContext;
0045: import com.tc.objectserver.core.api.Filter;
0046: import com.tc.objectserver.core.api.GarbageCollector;
0047: import com.tc.objectserver.core.api.ManagedObject;
0048: import com.tc.objectserver.core.api.TestDNA;
0049: import com.tc.objectserver.core.impl.MarkAndSweepGarbageCollector;
0050: import com.tc.objectserver.core.impl.TestManagedObject;
0051: import com.tc.objectserver.gtx.TestGlobalTransactionManager;
0052: import com.tc.objectserver.impl.InMemoryManagedObjectStore;
0053: import com.tc.objectserver.impl.ObjectInstanceMonitorImpl;
0054: import com.tc.objectserver.impl.ObjectManagerConfig;
0055: import com.tc.objectserver.impl.ObjectManagerImpl;
0056: import com.tc.objectserver.impl.ObjectManagerStatsImpl;
0057: import com.tc.objectserver.impl.PersistentManagedObjectStore;
0058: import com.tc.objectserver.l1.api.ClientStateManager;
0059: import com.tc.objectserver.l1.impl.ClientStateManagerImpl;
0060: import com.tc.objectserver.managedobject.BackReferences;
0061: import com.tc.objectserver.managedobject.ManagedObjectStateFactory;
0062: import com.tc.objectserver.managedobject.NullManagedObjectChangeListenerProvider;
0063: import com.tc.objectserver.mgmt.ManagedObjectFacade;
0064: import com.tc.objectserver.mgmt.MapEntryFacade;
0065: import com.tc.objectserver.persistence.api.ManagedObjectPersistor;
0066: import com.tc.objectserver.persistence.api.ManagedObjectStore;
0067: import com.tc.objectserver.persistence.api.PersistenceTransaction;
0068: import com.tc.objectserver.persistence.api.PersistenceTransactionProvider;
0069: import com.tc.objectserver.persistence.api.Persistor;
0070: import com.tc.objectserver.persistence.impl.InMemoryPersistor;
0071: import com.tc.objectserver.persistence.impl.TestPersistenceTransaction;
0072: import com.tc.objectserver.persistence.impl.TestPersistenceTransactionProvider;
0073: import com.tc.objectserver.persistence.sleepycat.CustomSerializationAdapterFactory;
0074: import com.tc.objectserver.persistence.sleepycat.DBEnvironment;
0075: import com.tc.objectserver.persistence.sleepycat.SerializationAdapterFactory;
0076: import com.tc.objectserver.persistence.sleepycat.SleepycatPersistor;
0077: import com.tc.objectserver.persistence.sleepycat.SleepycatSerializationAdapterFactory;
0078: import com.tc.objectserver.tx.ServerTransaction;
0079: import com.tc.objectserver.tx.ServerTransactionImpl;
0080: import com.tc.objectserver.tx.TestTransactionalStageCoordinator;
0081: import com.tc.objectserver.tx.TransactionSequencer;
0082: import com.tc.objectserver.tx.TransactionalObjectManagerImpl;
0083: import com.tc.stats.counter.sampled.SampledCounter;
0084: import com.tc.stats.counter.sampled.SampledCounterConfig;
0085: import com.tc.stats.counter.sampled.SampledCounterImpl;
0086: import com.tc.text.PrettyPrinter;
0087: import com.tc.util.SequenceID;
0088: import com.tc.util.concurrent.LifeCycleState;
0089: import com.tc.util.concurrent.StoppableThread;
0090: import com.tc.util.concurrent.ThreadUtil;
0091:
0092: import java.io.File;
0093: import java.util.ArrayList;
0094: import java.util.Arrays;
0095: import java.util.Collection;
0096: import java.util.Collections;
0097: import java.util.Date;
0098: import java.util.HashMap;
0099: import java.util.HashSet;
0100: import java.util.Iterator;
0101: import java.util.LinkedList;
0102: import java.util.List;
0103: import java.util.Map;
0104: import java.util.Set;
0105: import java.util.concurrent.CyclicBarrier;
0106:
0107: /**
0108: * @author steve
0109: */
0110: public class ObjectManagerTest extends BaseDSOTestCase {
0111:
0112: private Map managed;
0113: private ObjectManagerImpl objectManager;
0114: private TestObjectManagerConfig config;
0115: private ClientStateManager clientStateManager;
0116: private ManagedObjectStore objectStore;
0117: private TCLogger logger;
0118: private ObjectManagerStatsImpl stats;
0119: private SampledCounter newObjectCounter;
0120: private SampledCounterImpl objectfaultCounter;
0121: private TestPersistenceTransactionProvider persistenceTransactionProvider;
0122: private TestPersistenceTransaction NULL_TRANSACTION;
0123: private TestTransactionalStageCoordinator coordinator;
0124: private TestGlobalTransactionManager gtxMgr;
0125: private TransactionalObjectManagerImpl txObjectManager;
0126:
0127: /**
0128: * Constructor for ObjectManagerTest.
0129: *
0130: * @param arg0
0131: */
0132: public ObjectManagerTest(String arg0) {
0133: super (arg0);
0134: }
0135:
0136: protected void setUp() throws Exception {
0137: super .setUp();
0138: this .logger = TCLogging.getLogger(getClass());
0139: this .managed = new HashMap();
0140: config = new TestObjectManagerConfig();
0141: clientStateManager = new ClientStateManagerImpl(TCLogging
0142: .getLogger(ClientStateManager.class));
0143: ManagedObjectStateFactory.disableSingleton(true);
0144: ManagedObjectStateFactory.createInstance(
0145: new NullManagedObjectChangeListenerProvider(),
0146: new InMemoryPersistor());
0147: this .newObjectCounter = new SampledCounterImpl(
0148: new SampledCounterConfig(1, 1, true, 0L));
0149: this .objectfaultCounter = new SampledCounterImpl(
0150: new SampledCounterConfig(1, 1, true, 0L));
0151: stats = new ObjectManagerStatsImpl(newObjectCounter,
0152: objectfaultCounter);
0153: persistenceTransactionProvider = new TestPersistenceTransactionProvider();
0154: NULL_TRANSACTION = TestPersistenceTransaction.NULL_TRANSACTION;
0155: }
0156:
0157: private void initObjectManager() {
0158: initObjectManager(createThreadGroup());
0159: }
0160:
0161: private TCThreadGroup createThreadGroup() {
0162: return new TCThreadGroup(new ThrowableHandler(TCLogging
0163: .getLogger(ObjectManagerImpl.class)));
0164: }
0165:
0166: private void initObjectManager(ThreadGroup threadGroup) {
0167: initObjectManager(threadGroup, new NullCache());
0168: }
0169:
0170: private void initObjectManager(ThreadGroup threadGroup,
0171: EvictionPolicy cache) {
0172: this .objectStore = new InMemoryManagedObjectStore(this .managed);
0173: initObjectManager(threadGroup, cache, this .objectStore);
0174: }
0175:
0176: private void initObjectManager(ThreadGroup threadGroup,
0177: EvictionPolicy cache, ManagedObjectStore store) {
0178: TestSink faultSink = new TestSink();
0179: TestSink flushSink = new TestSink();
0180: this .objectManager = new ObjectManagerImpl(config, threadGroup,
0181: clientStateManager, store, cache,
0182: persistenceTransactionProvider, faultSink, flushSink);
0183: new TestMOFaulter(this .objectManager, store, faultSink).start();
0184: new TestMOFlusher(this .objectManager, flushSink).start();
0185: }
0186:
0187: private void initTransactionObjectManager() {
0188: TransactionSequencer sequencer = new TransactionSequencer();
0189: coordinator = new TestTransactionalStageCoordinator();
0190: gtxMgr = new TestGlobalTransactionManager();
0191: txObjectManager = new TransactionalObjectManagerImpl(
0192: objectManager, sequencer, gtxMgr, coordinator);
0193: objectManager.setTransactionalObjectManager(txObjectManager);
0194: }
0195:
0196: public void testShutdownAndSetGarbageCollector() throws Exception {
0197: initObjectManager();
0198: objectManager.stop();
0199: try {
0200: objectManager.setGarbageCollector(null);
0201: fail("Should have thrown a ShutdownError.");
0202: } catch (ShutdownError e) {
0203: // ok.
0204: }
0205: }
0206:
0207: public void testShutdownAndLookup() throws Exception {
0208: initObjectManager();
0209: objectManager.stop();
0210: try {
0211: objectManager.getObjectByID(null);
0212: fail("Should have thrown a ShutdownError.");
0213: } catch (ShutdownError e) {
0214: // ok;
0215: }
0216: }
0217:
0218: public void testShutdownAndLookupRootID() throws Exception {
0219: initObjectManager();
0220: objectManager.stop();
0221: try {
0222: objectManager.lookupRootID(null);
0223: fail("Should have thrown a ShutdownError.");
0224: } catch (ShutdownError e) {
0225: // ok.
0226: }
0227: }
0228:
0229: public void testShutdownAndCreateRoot() throws Exception {
0230: initObjectManager();
0231: objectManager.stop();
0232: try {
0233: objectManager.createRoot(null, null);
0234: fail("Should have thrown a ShutdownError.");
0235: } catch (ShutdownError e) {
0236: // ok.
0237: }
0238: }
0239:
0240: public void testShutdownAndCreateObject() throws Exception {
0241: initObjectManager();
0242: objectManager.stop();
0243: try {
0244: objectManager.createObject(null);
0245: fail("Should have thrown a ShutdownError.");
0246: } catch (ShutdownError e) {
0247: // ok.
0248: }
0249: }
0250:
0251: public void testShutdownAndGetRoots() throws Exception {
0252: initObjectManager();
0253: objectManager.stop();
0254: try {
0255: objectManager.getRoots();
0256: fail("Should have thrown a ShutdownError");
0257: } catch (ShutdownError e) {
0258: // ok.
0259: }
0260:
0261: }
0262:
0263: public void testShutdownAndLookupObjectsForCreateIfNecessary()
0264: throws Exception {
0265: initObjectManager();
0266:
0267: objectManager.stop();
0268:
0269: try {
0270: objectManager.lookupObjectsFor(null, null);
0271: fail("Should have thrown a ShutdownError.");
0272: } catch (ShutdownError e) {
0273: // ok.
0274: }
0275: }
0276:
0277: public void testShutdownAndLookupObjectsFor() throws Exception {
0278: initObjectManager();
0279:
0280: objectManager.stop();
0281:
0282: try {
0283: objectManager.lookupObjectsAndSubObjectsFor(null, null, -1);
0284: fail("Should have thrown a ShutdownError.");
0285: } catch (ShutdownError e) {
0286: // ok.
0287: }
0288: }
0289:
0290: public void testNewObjectIDs() {
0291: // this test is to make sure that the list of newly created objects IDs is
0292: // accurate in the lookup results
0293: initObjectManager();
0294:
0295: Set ids = new HashSet(); // important to use a Set here
0296:
0297: ObjectID id1;
0298: ids.add((id1 = new ObjectID(1)));
0299: ObjectID id2;
0300: ids.add((id2 = new ObjectID(2)));
0301: ClientID key = new ClientID(new ChannelID(0));
0302:
0303: TestResultsContext results = new TestResultsContext(ids, ids);
0304: this .objectManager.lookupObjectsFor(key, results);
0305: assertEquals(2, results.objects.size());
0306:
0307: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0308:
0309: ManagedObject mo = (ManagedObject) results.objects.get(id1);
0310: TestArrayDNA ta;
0311: mo.apply((ta = new TestArrayDNA(id1)), new TransactionID(1),
0312: new BackReferences(), imo, false);
0313: mo = (ManagedObject) results.objects.get(id2);
0314: mo.apply(new TestArrayDNA(id2), new TransactionID(2),
0315: new BackReferences(), imo, false);
0316:
0317: Map ic = imo.getInstanceCounts();
0318: assertEquals(1, ic.size());
0319: assertEquals(new Integer(2), ic.get(ta.getTypeName()));
0320:
0321: this .objectManager.releaseAll(NULL_TRANSACTION, results.objects
0322: .values());
0323:
0324: ids.add(new ObjectID(3));
0325: ids.add(new ObjectID(4));
0326: Set newIDs = new HashSet();
0327: newIDs.add(new ObjectID(3));
0328: newIDs.add(new ObjectID(4));
0329:
0330: results = new TestResultsContext(ids, newIDs);
0331:
0332: this .objectManager.lookupObjectsFor(key, results);
0333: assertEquals(4, results.objects.size());
0334:
0335: int count = 100;
0336: for (Iterator i = ids.iterator(); i.hasNext();) {
0337: ObjectID id = (ObjectID) i.next();
0338: mo = (ManagedObject) results.objects.get(id);
0339: if (newIDs.contains(id)) {
0340: mo.apply(new TestArrayDNA(id), new TransactionID(
0341: count++), new BackReferences(), imo, false);
0342: } else {
0343: mo.apply(new TestArrayDNA(id, true), new TransactionID(
0344: count++), new BackReferences(), imo, false);
0345:
0346: }
0347: }
0348: ic = imo.getInstanceCounts();
0349: assertEquals(1, ic.size());
0350: assertEquals(new Integer(4), ic.get(ta.getTypeName()));
0351:
0352: this .objectManager.releaseAll(NULL_TRANSACTION, results.objects
0353: .values());
0354: }
0355:
0356: public void testArrayFacade() throws Exception {
0357: initObjectManager();
0358:
0359: ObjectID id = new ObjectID(1);
0360: HashSet ids = new HashSet();
0361: ids.add(id);
0362:
0363: TestResultsContext responseContext = new TestResultsContext(
0364: ids, ids);
0365: final Map lookedUpObjects = responseContext.objects;
0366:
0367: this .objectManager.lookupObjectsFor(null, responseContext);
0368: assertEquals(ids.size(), lookedUpObjects.size());
0369:
0370: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0371: ManagedObject mo = (ManagedObject) lookedUpObjects.get(id);
0372: mo.apply(new TestArrayDNA(id), new TransactionID(1),
0373: new BackReferences(), imo, false);
0374: objectManager.releaseAll(NULL_TRANSACTION, lookedUpObjects
0375: .values());
0376:
0377: ManagedObjectFacade facade;
0378:
0379: facade = objectManager.lookupFacade(id, -1);
0380: assertTrue(facade.isArray());
0381: assertFalse(facade.isInnerClass());
0382: assertFalse(facade.isMap());
0383: assertFalse(facade.isList());
0384: assertFalse(facade.isSet());
0385: assertEquals(3, facade.getArrayLength());
0386: assertTrue(Arrays.equals(new String[] { "0", "1", "2" }, facade
0387: .getFields()));
0388: assertEquals("[Ljava/lang/String;", facade.getClassName());
0389:
0390: for (int i = 0; i < 3; i++) {
0391: assertEquals("String", facade.getFieldType("" + i));
0392: }
0393:
0394: assertEquals("tim", facade.getFieldValue("0"));
0395: assertEquals("is", facade.getFieldValue("1"));
0396: assertEquals("here", facade.getFieldValue("2"));
0397:
0398: // test that limit is working okay
0399: facade = objectManager.lookupFacade(id, 1);
0400: assertEquals(1, facade.getArrayLength());
0401: assertEquals("tim", facade.getFieldValue("0"));
0402:
0403: facade = objectManager.lookupFacade(id, 19212);
0404: assertEquals(3, facade.getArrayLength());
0405: assertEquals("tim", facade.getFieldValue("0"));
0406: assertEquals("is", facade.getFieldValue("1"));
0407: assertEquals("here", facade.getFieldValue("2"));
0408: }
0409:
0410: public void testDateFacades() throws NoSuchObjectException {
0411: initObjectManager();
0412:
0413: ObjectID dateID = new ObjectID(1);
0414:
0415: Set ids = new HashSet();
0416: ids.add(dateID);
0417:
0418: TestResultsContext responseContext = new TestResultsContext(
0419: ids, ids);
0420: final Map lookedUpObjects = responseContext.objects;
0421:
0422: this .objectManager.lookupObjectsFor(null, responseContext);
0423: assertEquals(ids.size(), lookedUpObjects.size());
0424:
0425: ManagedObject dateManagedObject = (ManagedObject) lookedUpObjects
0426: .get(dateID);
0427:
0428: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0429: dateManagedObject.apply(new TestDateDNA("java.util.Date",
0430: dateID), new TransactionID(1), new BackReferences(),
0431: imo, false);
0432:
0433: objectManager.releaseAll(NULL_TRANSACTION, lookedUpObjects
0434: .values());
0435:
0436: ManagedObjectFacade facade;
0437:
0438: facade = objectManager.lookupFacade(dateID, 1);
0439: validateDateFacade(facade);
0440:
0441: }
0442:
0443: public void testLiteralFacades() throws NoSuchObjectException {
0444: initObjectManager();
0445:
0446: ObjectID literalID = new ObjectID(1);
0447:
0448: Set ids = new HashSet();
0449: ids.add(literalID);
0450:
0451: TestResultsContext responseContext = new TestResultsContext(
0452: ids, ids);
0453: final Map lookedUpObjects = responseContext.objects;
0454:
0455: this .objectManager.lookupObjectsFor(null, responseContext);
0456: assertEquals(ids.size(), lookedUpObjects.size());
0457:
0458: ManagedObject managedObject = (ManagedObject) lookedUpObjects
0459: .get(literalID);
0460:
0461: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0462: managedObject.apply(new TestLiteralValuesDNA(literalID),
0463: new TransactionID(1), new BackReferences(), imo, false);
0464:
0465: objectManager.releaseAll(NULL_TRANSACTION, lookedUpObjects
0466: .values());
0467:
0468: ManagedObjectFacade facade;
0469:
0470: facade = objectManager.lookupFacade(literalID, 1);
0471: validateLiteralFacade(facade);
0472:
0473: }
0474:
0475: private void validateLiteralFacade(ManagedObjectFacade literalFacade) {
0476: assertFalse(literalFacade.isArray());
0477: assertFalse(literalFacade.isMap());
0478: assertFalse(literalFacade.isSet());
0479: assertFalse(literalFacade.isList());
0480: assertEquals("java.lang.Integer", literalFacade.getClassName());
0481:
0482: Object value = literalFacade.getFieldValue("java.lang.Integer");
0483:
0484: assertTrue(value instanceof Integer);
0485: }
0486:
0487: public void testLogicalFacades() throws NoSuchObjectException {
0488: initObjectManager();
0489:
0490: ObjectID mapID = new ObjectID(1);
0491: ObjectID listID = new ObjectID(2);
0492: ObjectID setID = new ObjectID(3);
0493:
0494: Set ids = new HashSet();
0495: ids.add(mapID);
0496: ids.add(listID);
0497: ids.add(setID);
0498:
0499: TestResultsContext responseContext = new TestResultsContext(
0500: ids, ids);
0501: final Map lookedUpObjects = responseContext.objects;
0502:
0503: this .objectManager.lookupObjectsFor(null, responseContext);
0504: assertEquals(ids.size(), lookedUpObjects.size());
0505:
0506: ManagedObject list = (ManagedObject) lookedUpObjects
0507: .get(listID);
0508: ManagedObject set = (ManagedObject) lookedUpObjects.get(setID);
0509: ManagedObject map = (ManagedObject) lookedUpObjects.get(mapID);
0510:
0511: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0512: map.apply(new TestMapDNA(mapID), new TransactionID(1),
0513: new BackReferences(), imo, false);
0514: set.apply(new TestListSetDNA("java.util.HashSet", setID),
0515: new TransactionID(1), new BackReferences(), imo, false);
0516: list.apply(new TestListSetDNA("java.util.LinkedList", listID),
0517: new TransactionID(1), new BackReferences(), imo, false);
0518:
0519: objectManager.releaseAll(NULL_TRANSACTION, lookedUpObjects
0520: .values());
0521:
0522: ManagedObjectFacade facade;
0523:
0524: facade = objectManager.lookupFacade(mapID, -1);
0525: validateMapFacade(facade, 3, 3);
0526: facade = objectManager.lookupFacade(mapID, 5);
0527: validateMapFacade(facade, 3, 3);
0528: facade = objectManager.lookupFacade(mapID, 1);
0529: validateMapFacade(facade, 1, 3);
0530: facade = objectManager.lookupFacade(mapID, 0);
0531: validateMapFacade(facade, 0, 3);
0532:
0533: facade = objectManager.lookupFacade(setID, -1);
0534: validateSetFacade(facade, 3, 3);
0535: facade = objectManager.lookupFacade(setID, 5);
0536: validateSetFacade(facade, 3, 3);
0537: facade = objectManager.lookupFacade(setID, 1);
0538: validateSetFacade(facade, 1, 3);
0539: facade = objectManager.lookupFacade(setID, 0);
0540: validateSetFacade(facade, 0, 3);
0541:
0542: facade = objectManager.lookupFacade(listID, -1);
0543: validateListFacade(facade, 3, 3);
0544: facade = objectManager.lookupFacade(listID, 5);
0545: validateListFacade(facade, 3, 3);
0546: facade = objectManager.lookupFacade(listID, 1);
0547: validateListFacade(facade, 1, 3);
0548: facade = objectManager.lookupFacade(listID, 0);
0549: validateListFacade(facade, 0, 3);
0550:
0551: }
0552:
0553: private void validateListFacade(ManagedObjectFacade listFacade,
0554: int facadeSize, int totalSize) {
0555: assertFalse(listFacade.isArray());
0556: assertFalse(listFacade.isMap());
0557: assertFalse(listFacade.isSet());
0558: assertTrue(listFacade.isList());
0559: assertEquals("java.util.LinkedList", listFacade.getClassName());
0560: assertEquals(facadeSize, listFacade.getFacadeSize());
0561: assertEquals(totalSize, listFacade.getTrueObjectSize());
0562:
0563: for (int i = 0; i < facadeSize; i++) {
0564: String fName = String.valueOf(i);
0565: Object value = listFacade.getFieldValue(fName);
0566: assertTrue(value instanceof String);
0567: assertEquals("item" + (i + 1), value);
0568: }
0569: }
0570:
0571: private void validateSetFacade(ManagedObjectFacade setFacade,
0572: int facadeSize, int totalSize) {
0573: assertFalse(setFacade.isArray());
0574: assertFalse(setFacade.isMap());
0575: assertTrue(setFacade.isSet());
0576: assertFalse(setFacade.isList());
0577: assertEquals("java.util.HashSet", setFacade.getClassName());
0578: assertEquals(facadeSize, setFacade.getFacadeSize());
0579: assertEquals(totalSize, setFacade.getTrueObjectSize());
0580:
0581: Set expect = new HashSet();
0582: expect.add("item1");
0583: expect.add("item2");
0584: expect.add("item3");
0585:
0586: Set actual = new HashSet();
0587: for (int i = 0; i < facadeSize; i++) {
0588: String fName = String.valueOf(i);
0589: Object value = setFacade.getFieldValue(fName);
0590: assertTrue(value instanceof String);
0591: actual.add(value);
0592: }
0593:
0594: assertTrue(expect.containsAll(actual));
0595: }
0596:
0597: private void validateMapFacade(ManagedObjectFacade mapFacade,
0598: int facadeSize, int totalSize) {
0599: assertFalse(mapFacade.isArray());
0600: assertTrue(mapFacade.isMap());
0601: assertFalse(mapFacade.isSet());
0602: assertFalse(mapFacade.isList());
0603: assertEquals("java.util.HashMap", mapFacade.getClassName());
0604: assertEquals(facadeSize, mapFacade.getFacadeSize());
0605: assertEquals(totalSize, mapFacade.getTrueObjectSize());
0606:
0607: Map expect = new HashMap();
0608: expect.put("key1", "val1");
0609: expect.put("key2", "val2");
0610: expect.put("key3", "val3");
0611:
0612: Map actual = new HashMap();
0613:
0614: for (int i = 0; i < facadeSize; i++) {
0615: String fName = String.valueOf(i);
0616: Object value = mapFacade.getFieldValue(fName);
0617: assertTrue(value instanceof MapEntryFacade);
0618: MapEntryFacade entry = (MapEntryFacade) value;
0619: actual.put(entry.getKey(), entry.getValue());
0620: }
0621:
0622: for (Iterator iter = actual.keySet().iterator(); iter.hasNext();) {
0623: Object key = iter.next();
0624: assertEquals(expect.get(key), actual.get(key));
0625: }
0626: }
0627:
0628: private void validateDateFacade(ManagedObjectFacade dateFacade) {
0629: assertFalse(dateFacade.isArray());
0630: assertFalse(dateFacade.isMap());
0631: assertFalse(dateFacade.isSet());
0632: assertFalse(dateFacade.isList());
0633: assertEquals("java.util.Date", dateFacade.getClassName());
0634:
0635: Object value = dateFacade.getFieldValue("date");
0636:
0637: assertTrue(value instanceof Date);
0638: }
0639:
0640: private DBEnvironment newDBEnvironment(boolean paranoid)
0641: throws Exception {
0642: File dbHome;
0643: int count = 0;
0644: do {
0645: dbHome = new File(this .getTempDirectory(), getClass()
0646: .getName()
0647: + "db" + (++count));
0648: } while (dbHome.exists());
0649: dbHome.mkdir();
0650: assertTrue(dbHome.exists());
0651: assertTrue(dbHome.isDirectory());
0652: System.out.println("DB Home: " + dbHome);
0653: DBEnvironment env = new DBEnvironment(paranoid, dbHome);
0654: return env;
0655: }
0656:
0657: private Persistor newPersistor(DBEnvironment dbEnv,
0658: SerializationAdapterFactory serializationAdapterFactory)
0659: throws Exception {
0660: Persistor persistor = new SleepycatPersistor(logger, dbEnv,
0661: serializationAdapterFactory);
0662: return persistor;
0663: }
0664:
0665: private SerializationAdapterFactory newSleepycatSerializationAdapterFactory(
0666: DBEnvironment dbEnv) {
0667: return new SleepycatSerializationAdapterFactory();
0668: }
0669:
0670: private SerializationAdapterFactory newCustomSerializationAdapterFactory() {
0671: return new CustomSerializationAdapterFactory();
0672: }
0673:
0674: public void testLookupInPersistentContext() throws Exception {
0675: boolean paranoid = false;
0676: // sleepycat serializer, not paranoid
0677: DBEnvironment dbEnv = newDBEnvironment(paranoid);
0678: SerializationAdapterFactory saf = newSleepycatSerializationAdapterFactory(dbEnv);
0679: Persistor persistor = newPersistor(dbEnv, saf);
0680:
0681: testLookupInPersistentContext(persistor, paranoid);
0682:
0683: // custom serializer, not paranoid
0684: dbEnv = newDBEnvironment(paranoid);
0685: saf = newCustomSerializationAdapterFactory();
0686: persistor = newPersistor(dbEnv, saf);
0687: testLookupInPersistentContext(persistor, paranoid);
0688:
0689: // sleepycat serializer, paranoid
0690: paranoid = true;
0691: dbEnv = newDBEnvironment(paranoid);
0692: saf = newSleepycatSerializationAdapterFactory(dbEnv);
0693: persistor = newPersistor(dbEnv, saf);
0694: testLookupInPersistentContext(persistor, paranoid);
0695:
0696: // custom serializer, paranoid
0697: dbEnv = newDBEnvironment(paranoid);
0698: saf = newCustomSerializationAdapterFactory();
0699: persistor = newPersistor(dbEnv, saf);
0700: testLookupInPersistentContext(persistor, paranoid);
0701: }
0702:
0703: private void testLookupInPersistentContext(Persistor persistor,
0704: boolean paranoid) throws Exception {
0705: ManagedObjectPersistor mop = persistor
0706: .getManagedObjectPersistor();
0707: PersistenceTransactionProvider ptp = persistor
0708: .getPersistenceTransactionProvider();
0709: PersistentManagedObjectStore store = new PersistentManagedObjectStore(
0710: mop);
0711: TestSink faultSink = new TestSink();
0712: TestSink flushSink = new TestSink();
0713: config.paranoid = paranoid;
0714: objectManager = new ObjectManagerImpl(config,
0715: createThreadGroup(), clientStateManager, store,
0716: new LRUEvictionPolicy(100),
0717: persistenceTransactionProvider, faultSink, flushSink);
0718: new TestMOFaulter(this .objectManager, store, faultSink).start();
0719: new TestMOFlusher(this .objectManager, flushSink).start();
0720:
0721: ObjectID id = new ObjectID(1);
0722: Set ids = new HashSet();
0723: ids.add(id);
0724: ClientID key = new ClientID(new ChannelID(0));
0725:
0726: TestResultsContext responseContext = new TestResultsContext(
0727: ids, ids);
0728: Map lookedUpObjects = responseContext.objects;
0729:
0730: objectManager.lookupObjectsFor(key, responseContext);
0731:
0732: ManagedObject lookedUpViaLookupObjectsForCreateIfNecessary = (ManagedObject) lookedUpObjects
0733: .get(id);
0734:
0735: final String fieldName = "myField";
0736: final List countSlot = new ArrayList(1);
0737: countSlot.add(new Integer(1));
0738: final List fieldValueSlot = new ArrayList(1);
0739: fieldValueSlot.add(new ObjectID(100));
0740:
0741: DNACursor cursor = new DNACursor() {
0742: public LogicalAction getLogicalAction() {
0743: return null;
0744: }
0745:
0746: public PhysicalAction getPhysicalAction() {
0747: return new PhysicalAction(fieldName, fieldValueSlot
0748: .get(0), true);
0749: }
0750:
0751: public boolean next() {
0752: int count = ((Integer) countSlot.get(0)).intValue();
0753: count--;
0754: countSlot.set(0, new Integer(count));
0755: return count >= 0;
0756: }
0757:
0758: public boolean next(DNAEncoding encoding) {
0759: throw new ImplementMe();
0760: }
0761:
0762: public Object getAction() {
0763: throw new ImplementMe();
0764: }
0765:
0766: public int getActionCount() {
0767: return 1;
0768: }
0769:
0770: public void reset() throws UnsupportedOperationException {
0771: countSlot.set(0, new Integer(1));
0772: }
0773: };
0774:
0775: TestDNA dna = new TestDNA(cursor);
0776: dna.version = 5;
0777:
0778: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0779: lookedUpViaLookupObjectsForCreateIfNecessary.apply(dna,
0780: new TransactionID(1), new BackReferences(), imo, false);
0781:
0782: PersistenceTransaction tx = ptp.newTransaction();
0783: objectManager.release(tx,
0784: lookedUpViaLookupObjectsForCreateIfNecessary);
0785: tx.commit();
0786:
0787: ManagedObject lookedUpViaLookup = objectManager
0788: .getObjectByID(id);
0789: assertEquals(1, lookedUpViaLookupObjectsForCreateIfNecessary
0790: .getObjectReferences().size());
0791: assertEquals(lookedUpViaLookup.getObjectReferences(),
0792: lookedUpViaLookupObjectsForCreateIfNecessary
0793: .getObjectReferences());
0794:
0795: tx = ptp.newTransaction();
0796: objectManager.release(tx, lookedUpViaLookup);
0797: tx.commit();
0798:
0799: // now do another lookup, change, and commit cycle
0800: responseContext = new TestResultsContext(ids,
0801: Collections.EMPTY_SET);
0802: lookedUpObjects = responseContext.objects;
0803:
0804: objectManager.lookupObjectsFor(key, responseContext);
0805: lookedUpViaLookupObjectsForCreateIfNecessary = (ManagedObject) lookedUpObjects
0806: .get(id);
0807: countSlot.set(0, new Integer(1));
0808: ObjectID newReferenceID = new ObjectID(9324);
0809: fieldValueSlot.set(0, newReferenceID);
0810: dna = new TestDNA(cursor);
0811: dna.version = 10;
0812: dna.isDelta = true;
0813: lookedUpViaLookupObjectsForCreateIfNecessary.apply(dna,
0814: new TransactionID(2), new BackReferences(), imo, false);
0815: // lookedUpViaLookupObjectsForCreateIfNecessary.commit();
0816: tx = ptp.newTransaction();
0817: objectManager.release(tx,
0818: lookedUpViaLookupObjectsForCreateIfNecessary);
0819: tx.commit();
0820:
0821: lookedUpViaLookup = objectManager.getObjectByID(id);
0822: assertEquals(1, lookedUpViaLookupObjectsForCreateIfNecessary
0823: .getObjectReferences().size());
0824: assertTrue(lookedUpViaLookupObjectsForCreateIfNecessary
0825: .getObjectReferences().contains(newReferenceID));
0826:
0827: assertEquals(lookedUpViaLookup.getObjectReferences(),
0828: lookedUpViaLookupObjectsForCreateIfNecessary
0829: .getObjectReferences());
0830:
0831: close(persistor, store);
0832: }
0833:
0834: private static void close(Persistor persistor,
0835: PersistentManagedObjectStore store) {
0836: // to work around timing problem with this test, let's look up some object id...
0837: // this should block this thread until trasaction reading all object ids from bdb completes,
0838: // at which point, it's ok to close the DB
0839: persistor.getManagedObjectPersistor().getAllObjectIDs().size();
0840: try {
0841: store.shutdown();
0842: persistor.close();
0843: } catch (Throwable e) {
0844: System.err.println("\n### Error closing resources: " + e);
0845: e = e.getCause();
0846: while (e != null) {
0847: System.err.println("\n### Caused by: " + e);
0848: e = e.getCause();
0849: }
0850:
0851: }
0852: }
0853:
0854: public void testExplodingGarbageCollector() throws Exception {
0855: LinkedQueue exceptionQueue = new LinkedQueue();
0856: TestThreadGroup tg = new TestThreadGroup(exceptionQueue);
0857: initObjectManager(tg);
0858: RuntimeException toThrow = new RuntimeException();
0859: this .objectManager
0860: .setGarbageCollector(new ExplodingGarbageCollector(
0861: toThrow));
0862: this .objectManager.start();
0863: Object o = exceptionQueue.poll(30 * 1000);
0864: assertEquals(toThrow, o);
0865: }
0866:
0867: public void testObjectManagerBasics() {
0868: initObjectManager();
0869: final ObjectID id = new ObjectID(0);
0870: ManagedObject mo = new TestManagedObject(id, new ObjectID[0]);
0871: objectManager.createObject(mo);
0872: assertFalse(objectManager.isReferenced(id));
0873: ManagedObject mo2 = objectManager.getObjectByID(id);
0874: assertTrue(mo == mo2);
0875: assertTrue(objectManager.isReferenced(id));
0876: objectManager.release(NULL_TRANSACTION, mo);
0877: assertFalse(objectManager.isReferenced(id));
0878:
0879: objectManager.getObjectByID(id);
0880:
0881: final boolean[] gotIt = new boolean[1];
0882: gotIt[0] = false;
0883:
0884: Thread t = new Thread() {
0885: public void run() {
0886: objectManager.getObjectByID(id);
0887: gotIt[0] = true;
0888: }
0889: };
0890:
0891: t.start();
0892: ThreadUtil.reallySleep(1000);
0893: assertFalse(gotIt[0]);
0894: objectManager.release(NULL_TRANSACTION, mo);
0895: ThreadUtil.reallySleep(1000);
0896: assertTrue(gotIt[0]);
0897: }
0898:
0899: public void testPhysicalObjectFacade() throws Exception {
0900: testPhysicalObjectFacade(false);
0901: testPhysicalObjectFacade(true);
0902: }
0903:
0904: private void testPhysicalObjectFacade(boolean paranoid)
0905: throws Exception {
0906: DBEnvironment dbEnv = newDBEnvironment(paranoid);
0907: SerializationAdapterFactory saf = newCustomSerializationAdapterFactory();
0908: Persistor persistor = newPersistor(dbEnv, saf);
0909: PersistenceTransactionProvider ptp = persistor
0910: .getPersistenceTransactionProvider();
0911: PersistentManagedObjectStore persistantMOStore = new PersistentManagedObjectStore(
0912: persistor.getManagedObjectPersistor());
0913: this .objectStore = persistantMOStore;
0914: this .config.paranoid = paranoid;
0915: initObjectManager(new TCThreadGroup(new ThrowableHandler(
0916: TCLogging.getTestingLogger(getClass()))),
0917: new NullCache(), this .objectStore);
0918:
0919: HashSet oids = new HashSet();
0920: oids.add(new ObjectID(1));
0921:
0922: final TestResultsContext context = new TestResultsContext(oids,
0923: oids);
0924: this .objectManager.lookupObjectsFor(null, context);
0925: context.waitTillComplete();
0926: ManagedObject mo = (ManagedObject) (context.objects)
0927: .get(new ObjectID(1));
0928: assertTrue(mo.isNew());
0929: ObjectInstanceMonitor imo = new ObjectInstanceMonitorImpl();
0930: mo.apply(new TestPhysicalDNA(new ObjectID(1)),
0931: new TransactionID(1), new BackReferences(), imo, false);
0932:
0933: PersistenceTransaction tx = ptp.newTransaction();
0934: this .objectManager.release(tx, mo);
0935: tx.commit();
0936:
0937: ManagedObjectFacade facade;
0938: try {
0939: facade = this .objectManager.lookupFacade(new ObjectID(1),
0940: -1);
0941: } catch (NoSuchObjectException e1) {
0942: fail(e1.getMessage());
0943: return;
0944: }
0945:
0946: String[] fieldNames = facade.getFields();
0947: assertEquals(6, fieldNames.length);
0948: // NOTE: the order of the object fields should be alphabetic
0949: assertTrue(Arrays.asList(fieldNames).toString(), Arrays.equals(
0950: fieldNames, new String[] { "access$0", "this$0",
0951: "intField", "objField", "stringField",
0952: "zzzField" }));
0953: assertEquals("TestPhysicalDNA.class.name", facade
0954: .getClassName());
0955: assertEquals("Integer", facade.getFieldType("intField"));
0956: assertEquals("ObjectID", facade.getFieldType("objField"));
0957: assertEquals("Byte", facade.getFieldType("zzzField"));
0958: assertEquals("String", facade.getFieldType("stringField"));
0959: assertEquals(new Integer(42), facade.getFieldValue("intField"));
0960: assertEquals(new Byte((byte) 1), facade
0961: .getFieldValue("zzzField"));
0962: assertEquals(new ObjectID(696969), facade
0963: .getFieldValue("objField"));
0964: assertEquals("yo yo yo", facade.getFieldValue("stringField"));
0965: assertEquals(new ObjectID(1), facade.getObjectId());
0966: assertTrue(facade.isPrimitive("intField"));
0967: assertTrue(facade.isPrimitive("zzzField"));
0968: assertTrue(facade.isPrimitive("stringField"));
0969: assertFalse(facade.isPrimitive("objField"));
0970:
0971: try {
0972: facade.getFieldType("does not exist");
0973: fail();
0974: } catch (IllegalArgumentException iae) {
0975: // expected
0976: }
0977:
0978: try {
0979: facade.getFieldValue("does not exist");
0980: fail();
0981: } catch (IllegalArgumentException iae) {
0982: // expected
0983: }
0984:
0985: try {
0986: facade.isPrimitive("does not exist");
0987: fail();
0988: } catch (IllegalArgumentException iae) {
0989: // expected
0990: }
0991:
0992: close(persistor, persistantMOStore);
0993: // XXX: change the object again, make sure the facade is "stable" (ie.
0994: // doesn't change)
0995: }
0996:
0997: public void testObjectManagerAsync() {
0998: initObjectManager();
0999: final ObjectID id = new ObjectID(0);
1000: final ObjectID id1 = new ObjectID(1);
1001:
1002: Set objectIDs = new HashSet();
1003:
1004: ManagedObject mo = new TestManagedObject(id, new ObjectID[0]);
1005: ManagedObject mo1 = new TestManagedObject(id1, new ObjectID[0]);
1006: objectManager.createObject(mo);
1007: objectManager.createObject(mo1);
1008:
1009: assertFalse(objectManager.isReferenced(id));
1010:
1011: objectIDs.add(id);
1012:
1013: TestObjectManagerResultsContext context;
1014: assertTrue(objectManager.lookupObjectsAndSubObjectsFor(null,
1015: context = new TestObjectManagerResultsContext(
1016: new HashMap(), objectIDs), -1));
1017:
1018: ManagedObject retrievedMo = (ManagedObject) context
1019: .getResults().values().iterator().next();
1020: assertTrue(mo == retrievedMo);
1021: assertTrue(objectManager.isReferenced(id));
1022: objectManager.release(NULL_TRANSACTION, mo);
1023: assertFalse(objectManager.isReferenced(id));
1024:
1025: objectManager.getObjectByID(id);
1026:
1027: objectIDs.add(id1);
1028:
1029: boolean notPending = objectManager
1030: .lookupObjectsAndSubObjectsFor(null,
1031: context = new TestObjectManagerResultsContext(
1032: new HashMap(), objectIDs), -1);
1033: assertFalse(notPending);
1034: assertEquals(0, context.getResults().size());
1035: objectManager.release(NULL_TRANSACTION, mo);
1036: assertEquals(objectIDs.size(), context.getResults().size());
1037:
1038: Collection objs = context.getResults().values();
1039: assertTrue(objs.contains(mo));
1040: assertTrue(objs.contains(mo1));
1041: assertTrue(objs.size() == 2);
1042: }
1043:
1044: public void testNewObjectCounter() {
1045: initObjectManager();
1046: objectManager.setStatsListener(stats);
1047: createObjects(666);
1048: assertEquals(666, stats.getTotalObjectsCreated());
1049: assertEquals(666, newObjectCounter.getValue());
1050:
1051: // roots count as "new" objects too
1052: objectManager.createRoot("root", new ObjectID(4444));
1053: assertEquals(667, stats.getTotalObjectsCreated());
1054: assertEquals(667, newObjectCounter.getValue());
1055: }
1056:
1057: public void testCacheStats() throws Exception {
1058: config.paranoid = true;
1059: initObjectManager(new TCThreadGroup(new ThrowableHandler(
1060: TCLogging.getTestingLogger(getClass()))),
1061: new LRUEvictionPolicy(-1));
1062: objectManager.setStatsListener(this .stats);
1063:
1064: assertEquals(0, stats.getTotalRequests());
1065: assertEquals(0, stats.getTotalCacheHits());
1066: assertEquals(0, stats.getTotalCacheMisses());
1067:
1068: createObjects(50, 10);
1069: Set ids = makeObjectIDSet(0, 10);
1070: // ThreadUtil.reallySleep(5000);
1071: TestResultsContext results = new TestResultsContext(ids,
1072: Collections.EMPTY_SET);
1073:
1074: objectManager.lookupObjectsAndSubObjectsFor(null, results, -1);
1075: results.waitTillComplete();
1076: objectManager.releaseAll(NULL_TRANSACTION, results.objects
1077: .values());
1078:
1079: assertEquals(10, stats.getTotalRequests());
1080: assertEquals(0, stats.getTotalCacheHits());
1081: assertEquals(10, stats.getTotalCacheMisses());
1082:
1083: results = new TestResultsContext(ids, Collections.EMPTY_SET);
1084: objectManager.lookupObjectsAndSubObjectsFor(null, results, -1);
1085: results.waitTillComplete();
1086: objectManager.releaseAll(NULL_TRANSACTION, results.objects
1087: .values());
1088: assertEquals(20, stats.getTotalRequests());
1089: assertEquals(10, stats.getTotalCacheHits());
1090: assertEquals(10, stats.getTotalCacheMisses());
1091:
1092: ids = makeObjectIDSet(10, 20);
1093: results = new TestResultsContext(ids, Collections.EMPTY_SET);
1094: objectManager.lookupObjectsAndSubObjectsFor(null, results, -1);
1095: results.waitTillComplete();
1096: objectManager.releaseAll(NULL_TRANSACTION, results.objects
1097: .values());
1098: assertEquals(30, stats.getTotalRequests());
1099: assertEquals(10, stats.getTotalCacheHits());
1100: assertEquals(20, stats.getTotalCacheMisses());
1101:
1102: evictCache(10);
1103:
1104: ids = makeObjectIDSet(14, 4);
1105: results = new TestResultsContext(ids, Collections.EMPTY_SET);
1106: objectManager.lookupObjectsAndSubObjectsFor(null, results, -1);
1107: results.waitTillComplete();
1108: objectManager.releaseAll(NULL_TRANSACTION, results.objects
1109: .values());
1110: assertEquals(40, stats.getTotalRequests());
1111: assertEquals(15, stats.getTotalCacheHits());
1112: assertEquals(25, stats.getTotalCacheMisses());
1113:
1114: double hitRate = ((double) 15) / ((double) 40);
1115: assertEquals(hitRate, stats.getCacheHitRatio(), 0D);
1116: }
1117:
1118: private void evictCache(int inCache) {
1119: TestCacheStats tc = new TestCacheStats();
1120: tc.toKeep = inCache;
1121: objectManager.evictCache(tc);
1122: tc.validate();
1123: }
1124:
1125: private void createObjects(int num, int inCache) {
1126: createObjects(num);
1127: evictCache(inCache);
1128: }
1129:
1130: private Set makeObjectIDSet(int begin, int end) {
1131: Set rv = new HashSet();
1132:
1133: if (begin > end) {
1134: for (int i = begin; i > end; i--) {
1135: rv.add(new ObjectID(i));
1136: }
1137: } else {
1138: for (int i = begin; i < end; i++) {
1139: rv.add(new ObjectID(i));
1140: }
1141: }
1142: return rv;
1143: }
1144:
1145: private void createObjects(int num) {
1146: for (int i = 0; i < num; i++) {
1147: TestManagedObject mo = new TestManagedObject(
1148: new ObjectID(i), new ObjectID[] {});
1149: objectManager.createObject(mo);
1150: }
1151: }
1152:
1153: public void testGCStats() {
1154: initObjectManager();
1155:
1156: // this should disable the internal gc thread, allowing us to control when
1157: // objMgr.gc() happens
1158: this .config.myGCThreadSleepTime = -1;
1159:
1160: GarbageCollector gc = new MarkAndSweepGarbageCollector(
1161: objectManager, clientStateManager, true);
1162: objectManager.setGarbageCollector(gc);
1163: objectManager.start();
1164:
1165: Listener listener = new Listener();
1166: this .objectManager.addListener(listener);
1167:
1168: objectManager.createRoot("root-me", new ObjectID(0));
1169: ManagedObject root = new TestManagedObject(new ObjectID(0),
1170: new ObjectID[] { new ObjectID(1) });
1171: objectManager.createObject(root);
1172:
1173: TestManagedObject mo1 = new TestManagedObject(new ObjectID(1),
1174: new ObjectID[] { new ObjectID(2) });
1175: TestManagedObject mo2 = new TestManagedObject(new ObjectID(2),
1176: new ObjectID[] { new ObjectID(3) });
1177: TestManagedObject mo3 = new TestManagedObject(new ObjectID(3),
1178: new ObjectID[] {});
1179: objectManager.createObject(mo1);
1180: objectManager.createObject(mo2);
1181: objectManager.createObject(mo3);
1182:
1183: ClientID cid1 = new ClientID(new ChannelID(1));
1184: clientStateManager.addReference(cid1, root.getID());
1185: clientStateManager.addReference(cid1, mo1.getID());
1186: clientStateManager.addReference(cid1, mo2.getID());
1187: clientStateManager.addReference(cid1, mo3.getID());
1188:
1189: assertEquals(0, objectManager.getGarbageCollectorStats().length);
1190: assertEquals(0, listener.gcEvents.size());
1191:
1192: long start = System.currentTimeMillis();
1193:
1194: objectManager.getGarbageCollector().gc();
1195:
1196: assertEquals(1, objectManager.getGarbageCollectorStats().length);
1197: assertEquals(1, listener.gcEvents.size());
1198:
1199: GCStats stats1 = (GCStats) listener.gcEvents.get(0);
1200: final int firstIterationNumber = stats1.getIteration();
1201: assertSame(stats1, objectManager.getGarbageCollectorStats()[0]);
1202: assertTrue("external: " + start + ", reported: "
1203: + stats1.getStartTime(), stats1.getStartTime() >= start);
1204: assertTrue(String.valueOf(stats1.getElapsedTime()), stats1
1205: .getElapsedTime() >= 0);
1206: assertEquals(4, stats1.getBeginObjectCount());
1207: assertEquals(0, stats1.getCandidateGarbageCount());
1208: assertEquals(0, stats1.getActualGarbageCount());
1209:
1210: listener.gcEvents.clear();
1211: objectManager.getGarbageCollector().gc();
1212: assertEquals(2, objectManager.getGarbageCollectorStats().length);
1213: assertEquals(1, listener.gcEvents.size());
1214: assertEquals(firstIterationNumber + 1, objectManager
1215: .getGarbageCollectorStats()[0].getIteration());
1216:
1217: listener.gcEvents.clear();
1218: Set removed = new HashSet();
1219: removed.add(mo3.getID());
1220: clientStateManager.removeReferences(cid1, removed);
1221: mo2.setReferences(new ObjectID[] {});
1222: objectManager.getGarbageCollector().gc();
1223: assertEquals(3, objectManager.getGarbageCollectorStats().length);
1224: assertEquals(1, listener.gcEvents.size());
1225: GCStats stats3 = (GCStats) listener.gcEvents.get(0);
1226: assertEquals(4, stats3.getBeginObjectCount());
1227: assertEquals(1, stats3.getActualGarbageCount());
1228: assertEquals(1, stats3.getCandidateGarbageCount());
1229: }
1230:
1231: public void testLookupFacadeForMissingObject() {
1232: initObjectManager();
1233:
1234: try {
1235: this .objectManager.lookupFacade(new ObjectID(1), -1);
1236: fail("lookup didn't throw exception");
1237: } catch (NoSuchObjectException e) {
1238: // expected
1239: }
1240: }
1241:
1242: public void testObjectManagerGC() throws Exception {
1243: initObjectManager();
1244: // this should disable the gc thread.
1245: this .config.myGCThreadSleepTime = -1;
1246: TestGarbageCollector gc = new TestGarbageCollector(
1247: objectManager);
1248: objectManager.setGarbageCollector(gc);
1249: objectManager.start();
1250: final ObjectID id = new ObjectID(0);
1251: ManagedObject mo = new TestManagedObject(id, new ObjectID[3]);
1252: objectManager.createObject(mo);
1253:
1254: assertFalse(gc.isCollected());
1255:
1256: gc.allow_blockUntilReadyToGC_ToProceed();
1257:
1258: objectManager.getGarbageCollector().gc();
1259: assertTrue(gc.isCollected());
1260:
1261: gc.reset();
1262:
1263: // call lookup to check out an object...
1264: objectManager.getObjectByID(id);
1265:
1266: // make sure our queues are clean
1267: assertFalse(gc.collectWasCalled());
1268: assertFalse(gc.blockUntilReadyToGC_WasCalled());
1269:
1270: Thread gcCaller = new Thread(new GCCaller(), "GCCaller");
1271: gcCaller.start();
1272:
1273: // give the thread some time to start and call collect()...
1274: assertTrue(gc.waitForCollectToBeCalled(5000));
1275:
1276: // give the thread some time to call blockUntilReadyToGC()...
1277: assertTrue(gc.waitFor_blockUntilReadyToGC_ToBeCalled(5000));
1278:
1279: // ////////////////////////////////////////////////////
1280: // now call release and make sure it calls the appropriate GC methods...
1281:
1282: assertFalse(gc.notifyReadyToGC_WasCalled());
1283: objectManager.release(NULL_TRANSACTION, mo);
1284:
1285: // make sure release calls notifyReadyToGC
1286: assertTrue(gc.waitFor_notifyReadyToGC_ToBeCalled(5000));
1287:
1288: // unblock the caller...
1289: gc.allow_blockUntilReadyToGC_ToProceed();
1290:
1291: // make sure the object manager calls notifyGCComplete
1292: assertTrue(gc.waitFor_notifyGCComplete_ToBeCalled(5000));
1293: gcCaller.join();
1294: }
1295:
1296: /**
1297: * This test is written to expose an case which used to trigger an assertion error in ObjectManager when GC initiates
1298: * recall in TransactionalObjectManager in persistence mode
1299: */
1300: public void testRecallNewObjects() throws Exception {
1301: DBEnvironment dbEnv = newDBEnvironment(true);
1302: SerializationAdapterFactory saf = newCustomSerializationAdapterFactory();
1303: Persistor persistor = newPersistor(dbEnv, saf);
1304: PersistenceTransactionProvider ptp = persistor
1305: .getPersistenceTransactionProvider();
1306: PersistentManagedObjectStore persistentMOStore = new PersistentManagedObjectStore(
1307: persistor.getManagedObjectPersistor());
1308: this .objectStore = persistentMOStore;
1309: this .config.paranoid = true;
1310: initObjectManager(new TCThreadGroup(new ThrowableHandler(
1311: TCLogging.getTestingLogger(getClass()))),
1312: new NullCache(), this .objectStore);
1313: initObjectManager();
1314: initTransactionObjectManager();
1315:
1316: // this should disable the gc thread.
1317: this .config.myGCThreadSleepTime = -1;
1318: TestGarbageCollector gc = new TestGarbageCollector(
1319: objectManager);
1320: objectManager.setGarbageCollector(gc);
1321: objectManager.start();
1322:
1323: /**
1324: * STEP 1: Create an New object and check it out
1325: */
1326: Map changes = new HashMap();
1327:
1328: changes.put(new ObjectID(1), new TestDNA(new ObjectID(1)));
1329:
1330: ServerTransaction stxn1 = new ServerTransactionImpl(gtxMgr,
1331: new TxnBatchID(1), new TransactionID(1),
1332: new SequenceID(1), new LockID[0], new ClientID(
1333: new ChannelID(2)), new ArrayList(changes
1334: .values()), new ObjectStringSerializer(),
1335: Collections.EMPTY_MAP, TxnType.NORMAL,
1336: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
1337: List txns = new ArrayList();
1338: txns.add(stxn1);
1339:
1340: txObjectManager.addTransactions(txns);
1341:
1342: // Lookup context should have been fired
1343: LookupEventContext loc = (LookupEventContext) coordinator.lookupSink.queue
1344: .remove(0);
1345: assertNotNull(loc);
1346: assertTrue(coordinator.lookupSink.queue.isEmpty());
1347:
1348: txObjectManager.lookupObjectsForTransactions();
1349:
1350: // Apply should have been called as we have Object 1
1351: ApplyTransactionContext aoc = (ApplyTransactionContext) coordinator.applySink.queue
1352: .remove(0);
1353: assertTrue(stxn1 == aoc.getTxn());
1354: assertNotNull(aoc);
1355: assertTrue(coordinator.applySink.queue.isEmpty());
1356:
1357: // Apply and initate commit the txn
1358: txObjectManager.applyTransactionComplete(stxn1
1359: .getServerTransactionID());
1360: ApplyCompleteEventContext acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
1361: .remove(0);
1362: assertNotNull(acec);
1363: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
1364:
1365: txObjectManager.processApplyComplete();
1366: CommitTransactionContext ctc1 = (CommitTransactionContext) coordinator.commitSink.queue
1367: .remove(0);
1368: assertNotNull(ctc1);
1369: assertTrue(coordinator.commitSink.queue.isEmpty());
1370:
1371: txObjectManager.commitTransactionsComplete(ctc1);
1372: Collection applied = ctc1.getAppliedServerTransactionIDs();
1373: assertTrue(applied.size() == 1);
1374: assertEquals(stxn1.getServerTransactionID(), applied.iterator()
1375: .next());
1376: Collection objects = ctc1.getObjects();
1377: assertTrue(objects.size() == 1);
1378:
1379: /**
1380: * STEP 2: Dont check back Object 1 yet, make another transaction with yet another object
1381: */
1382: changes.clear();
1383: changes.put(new ObjectID(2), new TestDNA(new ObjectID(2)));
1384:
1385: ServerTransaction stxn2 = new ServerTransactionImpl(gtxMgr,
1386: new TxnBatchID(2), new TransactionID(2),
1387: new SequenceID(1), new LockID[0], new ClientID(
1388: new ChannelID(2)), new ArrayList(changes
1389: .values()), new ObjectStringSerializer(),
1390: Collections.EMPTY_MAP, TxnType.NORMAL,
1391: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
1392:
1393: txns.clear();
1394: txns.add(stxn2);
1395:
1396: txObjectManager.addTransactions(txns);
1397:
1398: // Lookup context should have been fired
1399: loc = (LookupEventContext) coordinator.lookupSink.queue
1400: .remove(0);
1401: assertNotNull(loc);
1402: assertTrue(coordinator.lookupSink.queue.isEmpty());
1403:
1404: txObjectManager.lookupObjectsForTransactions();
1405:
1406: // Apply should have been called as we have Object 2
1407: aoc = (ApplyTransactionContext) coordinator.applySink.queue
1408: .remove(0);
1409: assertTrue(stxn2 == aoc.getTxn());
1410: assertNotNull(aoc);
1411: assertTrue(coordinator.applySink.queue.isEmpty());
1412:
1413: /**
1414: * STEP 3: Create a txn with Objects 1,2 and a new object 3
1415: */
1416: changes.clear();
1417: changes
1418: .put(new ObjectID(1),
1419: new TestDNA(new ObjectID(1), true));
1420: changes
1421: .put(new ObjectID(2),
1422: new TestDNA(new ObjectID(2), true));
1423: changes.put(new ObjectID(3), new TestDNA(new ObjectID(3)));
1424:
1425: ServerTransaction stxn3 = new ServerTransactionImpl(gtxMgr,
1426: new TxnBatchID(2), new TransactionID(2),
1427: new SequenceID(1), new LockID[0], new ClientID(
1428: new ChannelID(2)), new ArrayList(changes
1429: .values()), new ObjectStringSerializer(),
1430: Collections.EMPTY_MAP, TxnType.NORMAL,
1431: new LinkedList(), DmiDescriptor.EMPTY_ARRAY);
1432:
1433: txns.clear();
1434: txns.add(stxn3);
1435:
1436: txObjectManager.addTransactions(txns);
1437:
1438: // Lookup context should have been fired
1439: loc = (LookupEventContext) coordinator.lookupSink.queue
1440: .remove(0);
1441: assertNotNull(loc);
1442: assertTrue(coordinator.lookupSink.queue.isEmpty());
1443:
1444: // This lookup should go pending since we don't have Object 1, since 2 is already checkedout only 1,3 should be
1445: // requested.
1446: txObjectManager.lookupObjectsForTransactions();
1447:
1448: // Apply should not have been called as we don't have Object 1
1449: assertTrue(coordinator.applySink.queue.isEmpty());
1450:
1451: /**
1452: * STEP 4: Commit but not release Object 2 so even when we check object 1 back stxn3 is still pending
1453: */
1454: // Apply and initiate commit the txn for object 2
1455: txObjectManager.applyTransactionComplete(stxn2
1456: .getServerTransactionID());
1457: acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
1458: .remove(0);
1459: assertNotNull(acec);
1460: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
1461:
1462: txObjectManager.processApplyComplete();
1463: CommitTransactionContext ctc2 = (CommitTransactionContext) coordinator.commitSink.queue
1464: .remove(0);
1465: assertNotNull(ctc2);
1466: assertTrue(coordinator.commitSink.queue.isEmpty());
1467:
1468: txObjectManager.commitTransactionsComplete(ctc2);
1469: applied = ctc2.getAppliedServerTransactionIDs();
1470: assertTrue(applied.size() == 1);
1471: assertEquals(stxn2.getServerTransactionID(), applied.iterator()
1472: .next());
1473: objects = ctc2.getObjects();
1474: assertTrue(objects.size() == 1);
1475:
1476: /**
1477: * STEP 4: Check in Object 1 thus releasing the blocked lookup for Object 1, 3
1478: */
1479:
1480: // Now check back Object 1
1481: objectManager.releaseAll(ptp.nullTransaction(), ctc1
1482: .getObjects());
1483:
1484: // Lookup context should have been fired
1485: loc = (LookupEventContext) coordinator.lookupSink.queue
1486: .remove(0);
1487: assertNotNull(loc);
1488: assertTrue(coordinator.lookupSink.queue.isEmpty());
1489:
1490: /**
1491: * STEP 5 : Before lookup is initiated, initiate a GC pause
1492: */
1493: gc.requestGCPause();
1494: // Doing in a separate thread since this will block
1495: final CyclicBarrier cb = new CyclicBarrier(2);
1496: Thread t = new Thread("GC Thread - testRecallNewObjects") {
1497: public void run() {
1498: objectManager.waitUntilReadyToGC();
1499: try {
1500: cb.await();
1501: } catch (Exception e) {
1502: e.printStackTrace();
1503: throw new AssertionError(e);
1504: }
1505: }
1506: };
1507: t.start();
1508: ThreadUtil.reallySleep(5000);
1509:
1510: // Recall request should have be added.
1511: RecallObjectsContext roc = (RecallObjectsContext) coordinator.recallSink.queue
1512: .remove(0);
1513: assertNotNull(roc);
1514: assertTrue(coordinator.recallSink.queue.isEmpty());
1515:
1516: assertTrue(roc.recallAll());
1517:
1518: // do recall - This used to cause an assertion error in persistent mode
1519: txObjectManager.recallCheckedoutObject(roc);
1520:
1521: // Check in Object 2 to make the GC go to paused state
1522: objectManager.releaseAll(ptp.nullTransaction(), ctc2
1523: .getObjects());
1524:
1525: cb.await();
1526:
1527: assertTrue(gc.isPaused());
1528:
1529: // Complete gc
1530: objectManager.notifyGCComplete(Collections.EMPTY_SET);
1531: assertFalse(gc.isPausingOrPaused());
1532: assertFalse(gc.isPaused());
1533:
1534: // Lookup context should have been fired
1535: loc = (LookupEventContext) coordinator.lookupSink.queue
1536: .remove(0);
1537: assertNotNull(loc);
1538: assertTrue(coordinator.lookupSink.queue.isEmpty());
1539:
1540: txObjectManager.lookupObjectsForTransactions();
1541:
1542: // Apply should have been called for txn 3
1543: aoc = (ApplyTransactionContext) coordinator.applySink.queue
1544: .remove(0);
1545: assertTrue(stxn3 == aoc.getTxn());
1546: assertNotNull(aoc);
1547: assertTrue(coordinator.applySink.queue.isEmpty());
1548:
1549: // Apply and initate commit the txn
1550: txObjectManager.applyTransactionComplete(stxn3
1551: .getServerTransactionID());
1552: acec = (ApplyCompleteEventContext) coordinator.applyCompleteSink.queue
1553: .remove(0);
1554: assertNotNull(acec);
1555: assertTrue(coordinator.applyCompleteSink.queue.isEmpty());
1556:
1557: txObjectManager.processApplyComplete();
1558: CommitTransactionContext ctc3 = (CommitTransactionContext) coordinator.commitSink.queue
1559: .remove(0);
1560: assertNotNull(ctc3);
1561: assertTrue(coordinator.commitSink.queue.isEmpty());
1562:
1563: txObjectManager.commitTransactionsComplete(ctc3);
1564: applied = ctc3.getAppliedServerTransactionIDs();
1565: assertTrue(applied.size() == 1);
1566: assertEquals(stxn3.getServerTransactionID(), applied.iterator()
1567: .next());
1568: objects = ctc3.getObjects();
1569: assertTrue(objects.size() == 3);
1570:
1571: // Now check back the objects
1572: objectManager.releaseAll(ptp.nullTransaction(), ctc3
1573: .getObjects());
1574:
1575: assertEquals(0, objectManager.getCheckedOutCount());
1576: assertFalse(objectManager.isReferenced(new ObjectID(1)));
1577: assertFalse(objectManager.isReferenced(new ObjectID(2)));
1578: assertFalse(objectManager.isReferenced(new ObjectID(3)));
1579:
1580: close(persistor, persistentMOStore);
1581: }
1582:
1583: private static class TestArrayDNA implements DNA {
1584:
1585: private static int _version;
1586:
1587: private final ObjectID id;
1588: private int version;
1589:
1590: private boolean delta;
1591:
1592: public TestArrayDNA(ObjectID id) {
1593: this (id, false);
1594: }
1595:
1596: public TestArrayDNA(ObjectID id, boolean delta) {
1597: this .id = id;
1598: this .delta = delta;
1599: this .version = getNextVersion();
1600: }
1601:
1602: private static int getNextVersion() {
1603: return _version++;
1604: }
1605:
1606: public long getVersion() {
1607: return version;
1608: }
1609:
1610: public boolean hasLength() {
1611: return true;
1612: }
1613:
1614: public int getArraySize() {
1615: return 3;
1616: }
1617:
1618: public String getDefiningLoaderDescription() {
1619: return "";
1620: }
1621:
1622: public String getTypeName() {
1623: return "[Ljava/lang/String;";
1624: }
1625:
1626: public ObjectID getObjectID() throws DNAException {
1627: return id;
1628: }
1629:
1630: public ObjectID getParentObjectID() throws DNAException {
1631: return ObjectID.NULL_ID;
1632: }
1633:
1634: public DNACursor getCursor() {
1635: return new DNACursor() {
1636: int count = 0;
1637:
1638: public boolean next() {
1639: count++;
1640: return count <= 2;
1641: }
1642:
1643: public LogicalAction getLogicalAction() {
1644: throw new ImplementMe();
1645: }
1646:
1647: public Object getAction() {
1648: throw new ImplementMe();
1649: }
1650:
1651: public PhysicalAction getPhysicalAction() {
1652: switch (count) {
1653: case 1:
1654: return new PhysicalAction(new String[] { "tim",
1655: "was", "here" });
1656: case 2:
1657: return new PhysicalAction(1, "is", false);
1658: default:
1659: throw new RuntimeException("bad count: "
1660: + count);
1661: }
1662: }
1663:
1664: public boolean next(DNAEncoding encoding) {
1665: throw new ImplementMe();
1666: }
1667:
1668: public int getActionCount() {
1669: return 2;
1670: }
1671:
1672: public void reset()
1673: throws UnsupportedOperationException {
1674: throw new ImplementMe();
1675: }
1676: };
1677: }
1678:
1679: public boolean isDelta() {
1680: return delta;
1681: }
1682: }
1683:
1684: private static class TestListSetDNA implements DNA {
1685:
1686: final ObjectID setID;
1687: final String className;
1688:
1689: public TestListSetDNA(String className, ObjectID setID) {
1690: this .className = className;
1691: this .setID = setID;
1692: }
1693:
1694: public long getVersion() {
1695: return 0;
1696: }
1697:
1698: public boolean hasLength() {
1699: return false;
1700: }
1701:
1702: public int getArraySize() {
1703: return -1;
1704: }
1705:
1706: public String getDefiningLoaderDescription() {
1707: return "";
1708: }
1709:
1710: public String getTypeName() {
1711: return this .className;
1712: }
1713:
1714: public ObjectID getObjectID() throws DNAException {
1715: return this .setID;
1716: }
1717:
1718: public ObjectID getParentObjectID() throws DNAException {
1719: return ObjectID.NULL_ID;
1720: }
1721:
1722: public DNACursor getCursor() {
1723: return new DNACursor() {
1724: int count;
1725:
1726: public boolean next() {
1727: count++;
1728: return count <= 3;
1729: }
1730:
1731: public LogicalAction getLogicalAction() {
1732: switch (count) {
1733: case 1:
1734: case 2:
1735: case 3:
1736: Object item = new UTF8ByteDataHolder("item"
1737: + count);
1738: return new LogicalAction(SerializationUtil.ADD,
1739: new Object[] { item });
1740: default:
1741: throw new RuntimeException("bad count: "
1742: + count);
1743: }
1744: }
1745:
1746: public PhysicalAction getPhysicalAction() {
1747: throw new ImplementMe();
1748: }
1749:
1750: public boolean next(DNAEncoding encoding) {
1751: throw new ImplementMe();
1752: }
1753:
1754: public Object getAction() {
1755: throw new ImplementMe();
1756: }
1757:
1758: public int getActionCount() {
1759: return 3;
1760: }
1761:
1762: public void reset()
1763: throws UnsupportedOperationException {
1764: throw new ImplementMe();
1765: }
1766: };
1767: }
1768:
1769: public boolean isDelta() {
1770: return false;
1771: }
1772:
1773: }
1774:
1775: private static class TestMapDNA implements DNA {
1776:
1777: final ObjectID objectID;
1778:
1779: TestMapDNA(ObjectID id) {
1780: this .objectID = id;
1781: }
1782:
1783: public long getVersion() {
1784: return 0;
1785: }
1786:
1787: public boolean hasLength() {
1788: return false;
1789: }
1790:
1791: public int getArraySize() {
1792: return -1;
1793: }
1794:
1795: public String getDefiningLoaderDescription() {
1796: return "";
1797: }
1798:
1799: public String getTypeName() {
1800: return "java.util.HashMap";
1801: }
1802:
1803: public ObjectID getObjectID() throws DNAException {
1804: return this .objectID;
1805: }
1806:
1807: public ObjectID getParentObjectID() throws DNAException {
1808: return ObjectID.NULL_ID;
1809: }
1810:
1811: public DNACursor getCursor() {
1812: return new DNACursor() {
1813:
1814: int count = 0;
1815:
1816: public boolean next() {
1817: count++;
1818: return count <= 3;
1819: }
1820:
1821: public LogicalAction getLogicalAction() {
1822: switch (count) {
1823: case 1:
1824: case 2:
1825: case 3:
1826: Object key = new UTF8ByteDataHolder("key"
1827: + count);
1828: Object val = new UTF8ByteDataHolder("val"
1829: + count);
1830: return new LogicalAction(SerializationUtil.PUT,
1831: new Object[] { key, val });
1832: default:
1833: throw new RuntimeException("bad count: "
1834: + count);
1835: }
1836: }
1837:
1838: public PhysicalAction getPhysicalAction() {
1839: throw new ImplementMe();
1840: }
1841:
1842: public boolean next(DNAEncoding encoding) {
1843: throw new ImplementMe();
1844: }
1845:
1846: public Object getAction() {
1847: throw new ImplementMe();
1848: }
1849:
1850: public int getActionCount() {
1851: return 3;
1852: }
1853:
1854: public void reset()
1855: throws UnsupportedOperationException {
1856: throw new ImplementMe();
1857: }
1858: };
1859: }
1860:
1861: public boolean isDelta() {
1862: return false;
1863: }
1864:
1865: }
1866:
1867: private static class TestDateDNA implements DNA {
1868:
1869: final ObjectID setID;
1870: final String className;
1871:
1872: public TestDateDNA(String className, ObjectID setID) {
1873: this .className = className;
1874: this .setID = setID;
1875: }
1876:
1877: public long getVersion() {
1878: return 0;
1879: }
1880:
1881: public boolean hasLength() {
1882: return false;
1883: }
1884:
1885: public int getArraySize() {
1886: return -1;
1887: }
1888:
1889: public String getDefiningLoaderDescription() {
1890: return "";
1891: }
1892:
1893: public String getTypeName() {
1894: return this .className;
1895: }
1896:
1897: public ObjectID getObjectID() throws DNAException {
1898: return this .setID;
1899: }
1900:
1901: public ObjectID getParentObjectID() throws DNAException {
1902: return ObjectID.NULL_ID;
1903: }
1904:
1905: public DNACursor getCursor() {
1906: return new DNACursor() {
1907: int count;
1908:
1909: public boolean next() {
1910: count++;
1911: return count <= 1;
1912: }
1913:
1914: public LogicalAction getLogicalAction() {
1915: switch (count) {
1916: case 1:
1917: return new LogicalAction(
1918: SerializationUtil.SET_TIME,
1919: new Object[] { new Long(System
1920: .currentTimeMillis()) });
1921: default:
1922: throw new RuntimeException("bad count: "
1923: + count);
1924: }
1925: }
1926:
1927: public PhysicalAction getPhysicalAction() {
1928: throw new ImplementMe();
1929: }
1930:
1931: public boolean next(DNAEncoding encoding) {
1932: throw new ImplementMe();
1933: }
1934:
1935: public Object getAction() {
1936: throw new ImplementMe();
1937: }
1938:
1939: public int getActionCount() {
1940: return 1;
1941: }
1942:
1943: public void reset()
1944: throws UnsupportedOperationException {
1945: throw new ImplementMe();
1946: }
1947: };
1948: }
1949:
1950: public boolean isDelta() {
1951: return false;
1952: }
1953:
1954: }
1955:
1956: private static class TestResultsContext implements
1957: ObjectManagerResultsContext {
1958: public Map objects = new HashMap();
1959: boolean complete = false;
1960: private final Set ids;
1961: private final Set newIDS;
1962:
1963: public TestResultsContext(Set ids, Set newIDS) {
1964: this .ids = ids;
1965: this .newIDS = newIDS;
1966: }
1967:
1968: public synchronized void waitTillComplete() {
1969: while (!complete) {
1970: try {
1971: wait();
1972: } catch (InterruptedException e) {
1973: throw new AssertionError(e);
1974: }
1975: }
1976: }
1977:
1978: public synchronized void setResults(
1979: ObjectManagerLookupResults results) {
1980: complete = true;
1981: this .objects.putAll(results.getObjects());
1982: notifyAll();
1983: }
1984:
1985: public Set getLookupIDs() {
1986: return ids;
1987: }
1988:
1989: public Set getNewObjectIDs() {
1990: return newIDS;
1991: }
1992:
1993: public void missingObject(ObjectID oid) {
1994: throw new AssertionError("Missing Object : " + oid);
1995: }
1996:
1997: }
1998:
1999: private static class TestPhysicalDNA implements DNA {
2000: private final ObjectID id;
2001:
2002: TestPhysicalDNA(ObjectID id) {
2003: this .id = id;
2004: }
2005:
2006: public long getVersion() {
2007: return 0;
2008: }
2009:
2010: public boolean hasLength() {
2011: return false;
2012: }
2013:
2014: public String getDefiningLoaderDescription() {
2015: return "System";
2016: }
2017:
2018: public int getArraySize() {
2019: return -1;
2020: }
2021:
2022: public String getTypeName() {
2023: return "TestPhysicalDNA.class.name";
2024: }
2025:
2026: public ObjectID getObjectID() throws DNAException {
2027: return this .id;
2028: }
2029:
2030: public ObjectID getParentObjectID() throws DNAException {
2031: return new ObjectID(25);
2032: }
2033:
2034: public void setHeaderInformation(ObjectID id,
2035: ObjectID parentID, String typeName, int length,
2036: long version) {
2037: //
2038: }
2039:
2040: public void addLogicalAction(int method, Object[] parameters) {
2041: //
2042: }
2043:
2044: public void addPhysicalAction(String field, Object value)
2045: throws DNAException {
2046: //
2047: }
2048:
2049: public DNACursor getCursor() {
2050: return new DNACursor() {
2051:
2052: int count = 0;
2053:
2054: public boolean next() {
2055: count++;
2056: return count < 7;
2057: }
2058:
2059: public LogicalAction getLogicalAction() {
2060: return null;
2061: }
2062:
2063: public Object getAction() {
2064: throw new ImplementMe();
2065: }
2066:
2067: public PhysicalAction getPhysicalAction() {
2068: switch (count) {
2069: case 1: {
2070: return new PhysicalAction("intField",
2071: new Integer(42), false);
2072: }
2073: case 2: {
2074: return new PhysicalAction("zzzField", new Byte(
2075: (byte) 1), false);
2076: }
2077: case 3: {
2078: return new PhysicalAction("objField",
2079: new ObjectID(696969), true);
2080: }
2081: case 4: {
2082: return new PhysicalAction("this$0",
2083: new ObjectID(25), true);
2084: }
2085: case 5: {
2086: return new PhysicalAction("access$0",
2087: new Float(2.4), false);
2088: }
2089: case 6: {
2090: return new PhysicalAction("stringField",
2091: new UTF8ByteDataHolder("yo yo yo"),
2092: false);
2093: }
2094: default: {
2095: throw new RuntimeException();
2096: }
2097: }
2098:
2099: }
2100:
2101: public boolean next(DNAEncoding encoding) {
2102: throw new ImplementMe();
2103: }
2104:
2105: public int getActionCount() {
2106: return 6;
2107: }
2108:
2109: public void reset()
2110: throws UnsupportedOperationException {
2111: count = 0;
2112: }
2113:
2114: };
2115: }
2116:
2117: public boolean isDelta() {
2118: return false;
2119: }
2120: }
2121:
2122: private static class TestLiteralValuesDNA implements DNA {
2123: private final ObjectID id;
2124:
2125: TestLiteralValuesDNA(ObjectID id) {
2126: this .id = id;
2127: }
2128:
2129: public long getVersion() {
2130: return 0;
2131: }
2132:
2133: public boolean hasLength() {
2134: return false;
2135: }
2136:
2137: public String getDefiningLoaderDescription() {
2138: return "";
2139: }
2140:
2141: public int getArraySize() {
2142: return -1;
2143: }
2144:
2145: public String getTypeName() {
2146: return "java.lang.Integer";
2147: }
2148:
2149: public ObjectID getObjectID() throws DNAException {
2150: return this .id;
2151: }
2152:
2153: public ObjectID getParentObjectID() throws DNAException {
2154: return new ObjectID(25);
2155: }
2156:
2157: public void setHeaderInformation(ObjectID id,
2158: ObjectID parentID, String typeName, int length,
2159: long version) {
2160: //
2161: }
2162:
2163: public void addLogicalAction(int method, Object[] parameters) {
2164: //
2165: }
2166:
2167: public void addPhysicalAction(String field, Object value)
2168: throws DNAException {
2169: //
2170: }
2171:
2172: public DNACursor getCursor() {
2173: return new DNACursor() {
2174:
2175: int count = 0;
2176:
2177: public boolean next() {
2178: count++;
2179: return count < 2;
2180: }
2181:
2182: public LogicalAction getLogicalAction() {
2183: return null;
2184: }
2185:
2186: public Object getAction() {
2187: switch (count) {
2188: case 1: {
2189: return new LiteralAction(new Integer(42));
2190: }
2191: default: {
2192: throw new RuntimeException();
2193: }
2194: }
2195: }
2196:
2197: public PhysicalAction getPhysicalAction() {
2198: throw new ImplementMe();
2199: }
2200:
2201: public boolean next(DNAEncoding encoding) {
2202: throw new ImplementMe();
2203: }
2204:
2205: public int getActionCount() {
2206: return 1;
2207: }
2208:
2209: public void reset()
2210: throws UnsupportedOperationException {
2211: throw new ImplementMe();
2212: }
2213: };
2214: }
2215:
2216: public boolean isDelta() {
2217: return false;
2218: }
2219:
2220: }
2221:
2222: private static class Listener implements ObjectManagerEventListener {
2223: final List gcEvents = new ArrayList();
2224:
2225: public void garbageCollectionComplete(GCStats stats, Set deleted) {
2226: gcEvents.add(stats);
2227: }
2228:
2229: }
2230:
2231: private class ExplodingGarbageCollector implements GarbageCollector {
2232:
2233: private final RuntimeException toThrow;
2234: private LifeCycleState gcState;
2235:
2236: public ExplodingGarbageCollector(RuntimeException toThrow) {
2237: this .toThrow = toThrow;
2238: }
2239:
2240: public boolean isPausingOrPaused() {
2241: return false;
2242: }
2243:
2244: public boolean isPaused() {
2245: return false;
2246: }
2247:
2248: public void notifyReadyToGC() {
2249: return;
2250: }
2251:
2252: public void requestGCPause() {
2253: return;
2254: }
2255:
2256: public void notifyGCComplete() {
2257: return;
2258: }
2259:
2260: public void notifyGCDeleteStarted() {
2261: return;
2262: }
2263:
2264: public void blockUntilReadyToGC() {
2265: return;
2266: }
2267:
2268: public Set collect(Filter traverser, Collection roots,
2269: Set managedObjectIds) {
2270: throw toThrow;
2271: }
2272:
2273: public PrettyPrinter prettyPrint(PrettyPrinter out) {
2274: return out.print(getClass().getName());
2275: }
2276:
2277: public Set collect(Filter traverser, Collection roots,
2278: Set managedObjectIds, LifeCycleState state) {
2279: return collect(traverser, roots, managedObjectIds);
2280: }
2281:
2282: public void changed(ObjectID changedObject,
2283: ObjectID oldReference, ObjectID newReference) {
2284: // do nothing
2285:
2286: }
2287:
2288: public void gc() {
2289: throw toThrow;
2290: }
2291:
2292: public void addNewReferencesTo(Set rescueIds) {
2293: // do nothing
2294:
2295: }
2296:
2297: public void start() {
2298: gcState.start();
2299: }
2300:
2301: public void stop() {
2302: // do nothing
2303: }
2304:
2305: public void setState(StoppableThread st) {
2306: this .gcState = st;
2307: }
2308:
2309: public void addListener(ObjectManagerEventListener listener) {
2310: // do nothing
2311: }
2312:
2313: public GCStats[] getGarbageCollectorStats() {
2314: return null;
2315: }
2316:
2317: public boolean disableGC() {
2318: return false;
2319: }
2320:
2321: public void enableGC() {
2322: // do nothing
2323: }
2324:
2325: public boolean isDisabled() {
2326: return false;
2327: }
2328:
2329: public boolean isStarted() {
2330: return false;
2331: }
2332:
2333: }
2334:
2335: private class TestThreadGroup extends ThreadGroup {
2336:
2337: private final LinkedQueue exceptionQueue;
2338:
2339: public TestThreadGroup(LinkedQueue exceptionQueue) {
2340: super ("test thread group");
2341: this .exceptionQueue = exceptionQueue;
2342: }
2343:
2344: public void uncaughtException(Thread t, Throwable e) {
2345: try {
2346: exceptionQueue.put(e);
2347: } catch (InterruptedException ie) {
2348: fail(ie);
2349: }
2350: }
2351:
2352: }
2353:
2354: private class GCCaller implements Runnable {
2355:
2356: public void run() {
2357: objectManager.getGarbageCollector().gc();
2358: }
2359: }
2360:
2361: /*
2362: * @see TestCase#tearDown()
2363: */
2364: protected void tearDown() throws Exception {
2365: super .tearDown();
2366: }
2367:
2368: private static class TestObjectManagerConfig extends
2369: ObjectManagerConfig {
2370:
2371: public long myGCThreadSleepTime = 100;
2372: public boolean paranoid;
2373:
2374: public TestObjectManagerConfig() {
2375: super (10000, true, true, true, 1000);
2376: }
2377:
2378: TestObjectManagerConfig(long gcThreadSleepTime, boolean doGC) {
2379: super (gcThreadSleepTime, doGC, true, true, 1000);
2380: throw new RuntimeException("Don't use me.");
2381: }
2382:
2383: public long gcThreadSleepTime() {
2384: return myGCThreadSleepTime;
2385: }
2386:
2387: public boolean paranoid() {
2388: return paranoid;
2389: }
2390: }
2391:
2392: private static class TestMOFaulter extends Thread {
2393:
2394: private final ObjectManagerImpl objectManager;
2395: private final ManagedObjectStore store;
2396: private final TestSink faultSink;
2397:
2398: public TestMOFaulter(ObjectManagerImpl objectManager,
2399: ManagedObjectStore store, TestSink faultSink) {
2400: this .store = store;
2401: this .faultSink = faultSink;
2402: this .objectManager = objectManager;
2403: setName("TestMOFaulter");
2404: setDaemon(true);
2405: }
2406:
2407: public void run() {
2408: while (true) {
2409: try {
2410: ManagedObjectFaultingContext ec = (ManagedObjectFaultingContext) faultSink
2411: .take();
2412: objectManager.addFaultedObject(ec.getId(), store
2413: .getObjectByID(ec.getId()), ec
2414: .isRemoveOnRelease());
2415: } catch (InterruptedException e) {
2416: throw new AssertionError(e);
2417: }
2418: }
2419: }
2420: }
2421:
2422: private static class TestMOFlusher extends Thread {
2423:
2424: private final ObjectManagerImpl objectManager;
2425: private final TestSink flushSink;
2426:
2427: public TestMOFlusher(ObjectManagerImpl objectManager,
2428: TestSink flushSink) {
2429: this .objectManager = objectManager;
2430: this .flushSink = flushSink;
2431: setName("TestMOFlusher");
2432: setDaemon(true);
2433: }
2434:
2435: public void run() {
2436: while (true) {
2437: try {
2438: ManagedObjectFlushingContext ec = (ManagedObjectFlushingContext) flushSink
2439: .take();
2440: objectManager.flushAndEvict(ec.getObjectToFlush());
2441: } catch (InterruptedException e) {
2442: throw new AssertionError(e);
2443: }
2444: }
2445: }
2446: }
2447: }
|