001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.persistence.impl;
006:
007: import com.tc.exception.TCRuntimeException;
008: import com.tc.logging.TCLogger;
009: import com.tc.memorydatastore.client.MemoryDataStoreClient;
010: import com.tc.memorydatastore.message.TCByteArrayKeyValuePair;
011: import com.tc.object.ObjectID;
012: import com.tc.objectserver.core.api.ManagedObject;
013: import com.tc.objectserver.core.api.ManagedObjectState;
014: import com.tc.objectserver.managedobject.MapManagedObjectState;
015: import com.tc.objectserver.persistence.api.ManagedObjectPersistor;
016: import com.tc.objectserver.persistence.api.PersistenceTransaction;
017: import com.tc.text.PrettyPrinter;
018: import com.tc.util.Assert;
019: import com.tc.util.Conversion;
020: import com.tc.util.ObjectIDSet2;
021: import com.tc.util.SyncObjectIdSet;
022: import com.tc.util.SyncObjectIdSetImpl;
023: import com.tc.util.sequence.MutableSequence;
024:
025: import java.io.ByteArrayInputStream;
026: import java.io.ByteArrayOutputStream;
027: import java.io.IOException;
028: import java.io.ObjectInputStream;
029: import java.io.ObjectOutputStream;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Map;
035: import java.util.Set;
036:
037: public final class MemoryStoreManagedObjectPersistor implements
038: ManagedObjectPersistor {
039: private final MemoryDataStoreClient objectDB;
040: private final MutableSequence objectIDSequence;
041: private final MemoryDataStoreClient rootDB;
042: private long saveCount;
043: private final TCLogger logger;
044: private final MemoryStoreCollectionsPersistor collectionsPersistor;
045:
046: public MemoryStoreManagedObjectPersistor(TCLogger logger,
047: MemoryDataStoreClient objectDB,
048: MutableSequence objectIDSequence,
049: MemoryDataStoreClient rootDB,
050: MemoryStoreCollectionsPersistor collectionsPersistor) {
051: this .logger = logger;
052: this .objectDB = objectDB;
053: this .objectIDSequence = objectIDSequence;
054: this .rootDB = rootDB;
055: this .collectionsPersistor = collectionsPersistor;
056: }
057:
058: public long nextObjectIDBatch(int batchSize) {
059: return objectIDSequence.nextBatch(batchSize);
060: }
061:
062: public void setNextAvailableObjectID(long startID) {
063: objectIDSequence.setNext(startID);
064: }
065:
066: public void addRoot(PersistenceTransaction tx, String name,
067: ObjectID id) {
068: validateID(id);
069: this .rootDB.put(name.getBytes(), objectIDToData(id));
070: }
071:
072: public ObjectID loadRootID(String name) {
073: if (name == null)
074: throw new AssertionError(
075: "Attempt to retrieve a null root name");
076: byte[] value = this .rootDB.get(name.getBytes());
077: if (value == null)
078: return ObjectID.NULL_ID;
079: ObjectID rv = dataToObjectID(value);
080: if (rv == null)
081: return ObjectID.NULL_ID;
082: return rv;
083: }
084:
085: public Set loadRoots() {
086: Set rv = new HashSet();
087: Collection txns = rootDB.getAll();
088: for (Iterator i = txns.iterator(); i.hasNext();) {
089: TCByteArrayKeyValuePair pair = (TCByteArrayKeyValuePair) i
090: .next();
091: rv.add(dataToObjectID(pair.getValue()));
092: }
093: return rv;
094: }
095:
096: public SyncObjectIdSet getAllObjectIDs() {
097: SyncObjectIdSet rv = new SyncObjectIdSetImpl();
098: rv.startPopulating();
099: Thread t = new Thread(new ObjectIdReader(rv),
100: "ObjectIdReaderThread");
101: t.setDaemon(true);
102: t.start();
103: return rv;
104: }
105:
106: public Set loadRootNames() {
107: Set rv = new HashSet();
108: Collection txns = rootDB.getAll();
109: for (Iterator i = txns.iterator(); i.hasNext();) {
110: TCByteArrayKeyValuePair pair = (TCByteArrayKeyValuePair) i
111: .next();
112: rv.add(pair.getKey().toString());
113: }
114: return rv;
115: }
116:
117: public Map loadRootNamesToIDs() {
118: Map rv = new HashMap();
119: Collection txns = rootDB.getAll();
120: for (Iterator i = txns.iterator(); i.hasNext();) {
121: TCByteArrayKeyValuePair pair = (TCByteArrayKeyValuePair) i
122: .next();
123: rv.put(pair.getKey().toString(), dataToObjectID(pair
124: .getValue()));
125: }
126: return rv;
127: }
128:
129: public ManagedObject loadObjectByID(ObjectID id) {
130: validateID(id);
131: try {
132: byte[] value = this .objectDB.get(objectIDToData(id));
133: ManagedObject mo = dataToManagedObject(value);
134: loadCollection(mo);
135: return mo;
136: } catch (Exception e) {
137: throw new TCRuntimeException(e);
138: }
139: }
140:
141: private void loadCollection(ManagedObject mo) throws IOException,
142: ClassNotFoundException {
143: ManagedObjectState state = mo.getManagedObjectState();
144: if (state.getType() == ManagedObjectState.MAP_TYPE
145: || state.getType() == ManagedObjectState.PARTIAL_MAP_TYPE) {
146: MapManagedObjectState mapState = (MapManagedObjectState) state;
147: Assert.assertNull(mapState.getMap());
148: mapState.setMap(collectionsPersistor.loadMap(mo.getID()));
149: }
150: }
151:
152: public void saveObject(
153: PersistenceTransaction persistenceTransaction,
154: ManagedObject managedObject) {
155: Assert.assertNotNull(managedObject);
156: validateID(managedObject.getID());
157: try {
158: basicSaveObject(managedObject);
159: } catch (IOException e) {
160: throw new TCRuntimeException(e);
161: }
162: }
163:
164: private boolean basicSaveObject(ManagedObject managedObject)
165: throws IOException {
166: if (!managedObject.isDirty())
167: return true;
168: this .objectDB.put(objectIDToData(managedObject.getID()),
169: managedObjectToData(managedObject));
170: basicSaveCollection(managedObject);
171: managedObject.setIsDirty(false);
172: saveCount++;
173: if (saveCount == 1 || saveCount % (100 * 1000) == 0) {
174: logger.debug("saveCount: " + saveCount);
175: }
176: return true;
177: }
178:
179: private void basicSaveCollection(ManagedObject managedObject)
180: throws IOException {
181: ManagedObjectState state = managedObject
182: .getManagedObjectState();
183: if (state.getType() == ManagedObjectState.MAP_TYPE
184: || state.getType() == ManagedObjectState.PARTIAL_MAP_TYPE) {
185: MapManagedObjectState mapState = (MapManagedObjectState) state;
186: MemoryStorePersistableMap map = (MemoryStorePersistableMap) mapState
187: .getMap();
188: collectionsPersistor.saveMap(map);
189: }
190: }
191:
192: public void saveAllObjects(
193: PersistenceTransaction persistenceTransaction,
194: Collection managedObjects) {
195: long t0 = System.currentTimeMillis();
196: if (managedObjects.isEmpty())
197: return;
198: Object failureContext = null;
199: try {
200: for (Iterator i = managedObjects.iterator(); i.hasNext();) {
201: final ManagedObject managedObject = (ManagedObject) i
202: .next();
203:
204: final boolean status = basicSaveObject(managedObject);
205:
206: if (!status) {
207: failureContext = new Object() {
208: public String toString() {
209: return "Unable to save ManagedObject: "
210: + managedObject + "; status: "
211: + status;
212: }
213: };
214: break;
215: }
216: }
217: } catch (IOException e) {
218: throw new TCRuntimeException(e);
219: }
220:
221: if (failureContext != null)
222: throw new TCRuntimeException(failureContext.toString());
223:
224: long delta = System.currentTimeMillis() - t0;
225: saveAllElapsed += delta;
226: saveAllCount++;
227: saveAllObjectCount += managedObjects.size();
228: if (saveAllCount % (100 * 1000) == 0) {
229: double avg = ((double) saveAllObjectCount / (double) saveAllElapsed) * 1000;
230: logger.debug("save time: " + delta + ", "
231: + managedObjects.size() + " objects; avg: " + avg
232: + "/sec");
233: }
234: }
235:
236: private long saveAllCount = 0;
237: private long saveAllObjectCount = 0;
238: private long saveAllElapsed = 0;
239:
240: private void deleteObjectByID(PersistenceTransaction tx, ObjectID id) {
241: validateID(id);
242: byte[] key = objectIDToData(id);
243: if (objectDB.get(key) != null) {
244: objectDB.remove(objectIDToData(id));
245: } else {
246: collectionsPersistor.deleteCollection(id);
247: }
248: }
249:
250: public void deleteAllObjectsByID(PersistenceTransaction tx,
251: Collection objectIDs) {
252: for (Iterator i = objectIDs.iterator(); i.hasNext();) {
253: deleteObjectByID(tx, (ObjectID) i.next());
254: }
255: }
256:
257: /*********************************************************************************************************************
258: * Private stuff
259: */
260:
261: private void validateID(ObjectID id) {
262: Assert.assertNotNull(id);
263: Assert.eval(!ObjectID.NULL_ID.equals(id));
264: }
265:
266: private byte[] objectIDToData(ObjectID objectID) {
267: return (Conversion.long2Bytes(objectID.toLong()));
268: }
269:
270: private byte[] managedObjectToData(ManagedObject mo)
271: throws IOException {
272: ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
273: new ObjectOutputStream(byteStream).writeObject(mo);
274: return (byteStream.toByteArray());
275: }
276:
277: private ObjectID dataToObjectID(byte[] entry) {
278: return new ObjectID(Conversion.bytes2Long(entry));
279: }
280:
281: private ManagedObject dataToManagedObject(byte[] value)
282: throws IOException, ClassNotFoundException {
283: ByteArrayInputStream byteStream = new ByteArrayInputStream(
284: value);
285: ObjectInputStream objStream = new ObjectInputStream(byteStream);
286: return ((ManagedObject) objStream.readObject());
287: }
288:
289: public void prettyPrint(PrettyPrinter out) {
290: out.println(this .getClass().getName());
291: out = out.duplicateAndIndent();
292: out.println("db: " + objectDB);
293: }
294:
295: class ObjectIdReader implements Runnable {
296: private final SyncObjectIdSet set;
297:
298: public ObjectIdReader(SyncObjectIdSet set) {
299: this .set = set;
300: }
301:
302: public void run() {
303: ObjectIDSet2 tmp = new ObjectIDSet2(objectDB.getAll());
304: set.stopPopulating(tmp);
305: }
306:
307: }
308: }
|