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.sleepycat.je.Cursor;
007: import com.sleepycat.je.CursorConfig;
008: import com.sleepycat.je.Database;
009: import com.sleepycat.je.DatabaseEntry;
010: import com.sleepycat.je.DatabaseException;
011: import com.sleepycat.je.LockMode;
012: import com.sleepycat.je.OperationStatus;
013: import com.tc.io.serializer.DSOSerializerPolicy;
014: import com.tc.io.serializer.TCObjectInputStream;
015: import com.tc.io.serializer.TCObjectOutputStream;
016: import com.tc.io.serializer.api.BasicSerializer;
017: import com.tc.logging.TCLogger;
018: import com.tc.object.ObjectID;
019: import com.tc.objectserver.persistence.api.PersistenceTransaction;
020: import com.tc.objectserver.persistence.sleepycat.SleepycatPersistor.SleepycatPersistorBase;
021: import com.tc.util.Conversion;
022:
023: import java.io.ByteArrayInputStream;
024: import java.io.ByteArrayOutputStream;
025: import java.io.IOException;
026: import java.io.ObjectInput;
027:
028: public class SleepycatCollectionsPersistor extends
029: SleepycatPersistorBase {
030:
031: private final Database database;
032: private final BasicSerializer serializer;
033: private final ByteArrayOutputStream bao;
034: private final SleepycatCollectionFactory collectionFactory;
035: private final TCObjectOutputStream oo;
036:
037: public SleepycatCollectionsPersistor(TCLogger logger,
038: Database mapsDatabase,
039: SleepycatCollectionFactory sleepycatCollectionFactory) {
040: this .database = mapsDatabase;
041: this .collectionFactory = sleepycatCollectionFactory;
042: DSOSerializerPolicy policy = new DSOSerializerPolicy();
043: this .serializer = new BasicSerializer(policy);
044: this .bao = new ByteArrayOutputStream(1024);
045: this .oo = new TCObjectOutputStream(bao);
046: }
047:
048: public void saveMap(PersistenceTransaction tx,
049: SleepycatPersistableMap map) throws IOException,
050: DatabaseException {
051: map.commit(this , tx, database);
052: }
053:
054: public synchronized byte[] serialize(long id, Object o)
055: throws IOException {
056: oo.writeLong(id);
057: serializer.serializeTo(o, oo);
058: oo.flush();
059: byte b[] = bao.toByteArray();
060: bao.reset();
061: return b;
062: }
063:
064: public synchronized byte[] serialize(Object o) throws IOException {
065: serializer.serializeTo(o, oo);
066: oo.flush();
067: byte b[] = bao.toByteArray();
068: bao.reset();
069: return b;
070: }
071:
072: public SleepycatPersistableMap loadMap(PersistenceTransaction tx,
073: ObjectID id) throws IOException, ClassNotFoundException,
074: DatabaseException {
075: SleepycatPersistableMap map = (SleepycatPersistableMap) collectionFactory
076: .createPersistentMap(id);
077: map.load(this , tx, database);
078: return map;
079: }
080:
081: public Object deserialize(int start, byte[] data)
082: throws IOException, ClassNotFoundException {
083: if (start >= data.length)
084: return null;
085: ByteArrayInputStream bai = new ByteArrayInputStream(data,
086: start, data.length - start);
087: ObjectInput ois = new TCObjectInputStream(bai);
088: return serializer.deserializeFrom(ois);
089: }
090:
091: public Object deserialize(byte[] data) throws IOException,
092: ClassNotFoundException {
093: return deserialize(0, data);
094: }
095:
096: /**
097: * This method is slightly dubious in that it assumes that the ObjectID is the first 8 bytes of the Key in the entire
098: * collections database.(which is true, but that logic is spread elsewhere)
099: *
100: * @throws DatabaseException
101: */
102: public boolean deleteCollection(PersistenceTransaction tx,
103: ObjectID id) throws DatabaseException {
104: // XXX:: Since we read in one direction and since we have to read the first record of the next map to break out, we
105: // need this to avoid deadlocks between commit thread and GC thread. Hence READ_COMMITTED
106: Cursor c = database.openCursor(pt2nt(tx),
107: CursorConfig.READ_COMMITTED);
108: try {
109: boolean found = false;
110: byte idb[] = Conversion.long2Bytes(id.toLong());
111: DatabaseEntry key = new DatabaseEntry();
112: key.setData(idb);
113: DatabaseEntry value = new DatabaseEntry();
114: value.setPartial(0, 0, true);
115: if (c.getSearchKeyRange(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
116: do {
117: if (partialMatch(idb, key.getData())) {
118: found = true;
119: c.delete();
120: } else {
121: break;
122: }
123: } while (c.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS);
124: }
125: return found;
126: } finally {
127: c.close();
128: }
129: }
130:
131: private boolean partialMatch(byte[] idbytes, byte[] key) {
132: if (key.length < idbytes.length)
133: return false;
134: for (int i = 0; i < idbytes.length; i++) {
135: if (idbytes[i] != key[i])
136: return false;
137: }
138: return true;
139: }
140:
141: }
|