001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.objectserver.persistence.sleepycat;
005:
006: import com.tc.logging.TCLogging;
007: import com.tc.object.ObjectID;
008: import com.tc.objectserver.core.api.ManagedObject;
009: import com.tc.objectserver.core.api.ManagedObjectState;
010: import com.tc.objectserver.managedobject.ManagedObjectChangeListener;
011: import com.tc.objectserver.managedobject.ManagedObjectChangeListenerProviderImpl;
012: import com.tc.objectserver.managedobject.ManagedObjectStateFactory;
013: import com.tc.objectserver.persistence.api.ClassPersistor;
014: import com.tc.objectserver.persistence.api.ClientStatePersistor;
015: import com.tc.objectserver.persistence.api.ManagedObjectPersistor;
016: import com.tc.objectserver.persistence.api.TransactionPersistor;
017: import com.tc.objectserver.persistence.impl.StringIndexImpl;
018: import com.tc.util.Assert;
019: import com.tc.util.SyncObjectIdSet;
020:
021: import gnu.trove.TObjectLongHashMap;
022:
023: import java.io.File;
024: import java.io.IOException;
025: import java.util.Collection;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.Map;
029: import java.util.Set;
030:
031: public class SleepycatTCDBDiff {
032:
033: private static final String VERSION_STRING = "SleepycatTCDBDiff [ Ver 0.2]";
034:
035: private final SleepycatPersistor sdb1;
036: private final SleepycatPersistor sdb2;
037: private final File d1;
038: private final File d2;
039: private final boolean moDiff;
040: private final ManagedObjectStateFactory mosf1;
041: private final ManagedObjectStateFactory mosf2;
042:
043: public SleepycatTCDBDiff(File d1, File d2, boolean moDiff)
044: throws TCDatabaseException, IOException {
045: this .d1 = d1;
046: this .d2 = d2;
047: this .moDiff = moDiff;
048: this .sdb1 = new SleepycatPersistor(TCLogging
049: .getLogger(SleepycatTCDBDiff.class), new DBEnvironment(
050: true, d1), new CustomSerializationAdapterFactory());
051: this .sdb2 = new SleepycatPersistor(TCLogging
052: .getLogger(SleepycatTCDBDiff.class), new DBEnvironment(
053: true, d2), new CustomSerializationAdapterFactory());
054:
055: // Since we dont create any new MOState Objects in this program, we use 1 of the 2 persistor.
056: ManagedObjectChangeListenerProviderImpl moclp = new ManagedObjectChangeListenerProviderImpl();
057: moclp.setListener(new ManagedObjectChangeListener() {
058:
059: public void changed(ObjectID changedObject,
060: ObjectID oldReference, ObjectID newReference) {
061: // NOP
062: }
063:
064: });
065: ManagedObjectStateFactory.disableSingleton(true);
066: mosf1 = ManagedObjectStateFactory.createInstance(moclp, sdb1);
067: mosf2 = ManagedObjectStateFactory.createInstance(moclp, sdb2);
068:
069: }
070:
071: public void diff() {
072: log("Diffing [1] " + d1 + " and [2] " + d2);
073: diffStringIndexer((StringIndexImpl) sdb1.getStringIndex(),
074: (StringIndexImpl) sdb2.getStringIndex());
075: diffManagedObjects(sdb1.getManagedObjectPersistor(), sdb2
076: .getManagedObjectPersistor());
077: diffClientStates(sdb1.getClientStatePersistor(), sdb2
078: .getClientStatePersistor());
079: diffTransactions(sdb1.getTransactionPersistor(), sdb2
080: .getTransactionPersistor());
081: diffGeneratedClasses(sdb1.getClassPersistor(), sdb2
082: .getClassPersistor());
083: }
084:
085: private void diffGeneratedClasses(ClassPersistor cp1,
086: ClassPersistor cp2) {
087: log("Diffing Generated Classes...(Partial implementation)");
088: Map m1 = cp1.retrieveAllClasses();
089: Map m2 = cp2.retrieveAllClasses();
090: if (!m1.keySet().equals(m2.keySet())) {
091: log("*** [1] containing " + m1.size()
092: + " generated classes differs from [2] containing "
093: + m2.size());
094: }
095: }
096:
097: private void diffTransactions(TransactionPersistor tp1,
098: TransactionPersistor tp2) {
099: log("Diffing Transactions...");
100: Collection txns1 = tp1.loadAllGlobalTransactionDescriptors();
101: Collection txns2 = tp2.loadAllGlobalTransactionDescriptors();
102: if (!txns1.equals(txns2)) {
103: log("*** [1] containing " + txns1.size()
104: + " Transactions differs from [2] containing "
105: + txns2.size() + " Transactions");
106: }
107: }
108:
109: private void diffClientStates(ClientStatePersistor cp1,
110: ClientStatePersistor cp2) {
111: log("Diffing ClientStates...");
112: Set cids1 = cp1.loadClientIDs();
113: Set cids2 = cp2.loadClientIDs();
114: if (!cids1.equals(cids2)) {
115: log("*** [1] containing " + cids1.size()
116: + " ClientIDs differs from [2] containing "
117: + cids2.size() + " ClientIDs");
118: }
119: }
120:
121: private void diffManagedObjects(ManagedObjectPersistor mp1,
122: ManagedObjectPersistor mp2) {
123: log("Diffing ManagedObjects...(Partial implementation)");
124: SyncObjectIdSet oids1 = mp1.getAllObjectIDs();
125: SyncObjectIdSet oids2 = mp2.getAllObjectIDs();
126: if (!oids1.equals(oids2)) {
127: log("*** [1] containing " + oids1.size()
128: + " ObjectIDs differs from [2] containing "
129: + oids2.size() + " ObjectIDs");
130: }
131:
132: if (!moDiff)
133: return;
134:
135: // The diff only makes sense if the sequence in which the objects created are same.
136: // First diff the common set
137: Set common = new HashSet(oids1);
138: common.retainAll(oids2);
139: for (Iterator i = common.iterator(); i.hasNext();) {
140: ObjectID oid = (ObjectID) i.next();
141: ManagedObjectStateFactory.setInstance(mosf1);
142: ManagedObject mo1 = mp1.loadObjectByID(oid);
143: ManagedObjectStateFactory.setInstance(mosf2);
144: ManagedObject mo2 = mp2.loadObjectByID(oid);
145: Assert.assertEquals(mo1.getID(), mo2.getID());
146: ManagedObjectState ms1 = mo1.getManagedObjectState();
147: ManagedObjectState ms2 = mo2.getManagedObjectState();
148: if (!ms1.equals(ms2)) {
149: log("****** [1] " + ms1 + " differs from [2] " + ms2);
150: }
151: }
152:
153: // Unique
154: oids1.removeAll(common);
155: if (!oids1.isEmpty()) {
156: log("****** [1] contains " + oids1 + " not in [2]");
157: }
158: oids2.removeAll(common);
159: if (!oids2.isEmpty()) {
160: log("****** [2] contains " + oids2 + " not in [1]");
161: }
162: }
163:
164: private static void log(String message) {
165: System.out.println(message);
166: }
167:
168: private void diffStringIndexer(StringIndexImpl stringIndex1,
169: StringIndexImpl stringIndex2) {
170: log("Diffing StringIndexes...");
171: TObjectLongHashMap map1 = stringIndex1.getString2LongMappings();
172: TObjectLongHashMap map2 = stringIndex2.getString2LongMappings();
173: if (!map1.equals(map2)) {
174: log("*** [1] containing " + map1.size()
175: + " mapping differs from [2] containing "
176: + map2.size() + " mapping");
177: }
178: }
179:
180: public static void main(String[] args) {
181: boolean moDiff = false;
182:
183: log(VERSION_STRING);
184: if (args == null || args.length < 2) {
185: usage();
186: System.exit(-1);
187: } else if (args.length > 2) {
188: Assert.assertEquals("-mo", args[2]);
189: moDiff = true;
190: }
191: try {
192: File d1 = new File(args[0]);
193: validateDir(d1);
194: File d2 = new File(args[1]);
195: validateDir(d2);
196:
197: SleepycatTCDBDiff sdiff = new SleepycatTCDBDiff(d1, d2,
198: moDiff);
199: sdiff.diff();
200: } catch (Exception ex) {
201: ex.printStackTrace();
202: System.exit(-2);
203: }
204: }
205:
206: private static void validateDir(File dir) {
207: if (!dir.exists() || !dir.isDirectory()) {
208: throw new RuntimeException("Not a valid directory : " + dir);
209: }
210: }
211:
212: private static void usage() {
213: log("Usage: SleepycatTCDBDiff <environment home directory1> <environment home directory2> [-mo]");
214: }
215:
216: }
|