diff options
Diffstat (limited to 'java/src/Freeze/ObjectStore.java')
-rw-r--r-- | java/src/Freeze/ObjectStore.java | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/java/src/Freeze/ObjectStore.java b/java/src/Freeze/ObjectStore.java new file mode 100644 index 00000000000..3424e5fad27 --- /dev/null +++ b/java/src/Freeze/ObjectStore.java @@ -0,0 +1,667 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +package Freeze; + +class ObjectStore implements IceUtil.Store +{ + ObjectStore(String facet, String facetType, boolean createDb, EvictorI evictor, java.util.List<Index> indices, + boolean populateEmptyIndices) + { + _cache = new IceUtil.Cache(this); + + _facet = facet; + + _evictor = evictor; + _indices = indices; + _communicator = evictor.communicator(); + + if(facet.equals("")) + { + _dbName = EvictorI.defaultDb; + } + else + { + _dbName = facet; + } + + if(facetType != null) + { + // + // Create a sample servant with this type + // + Ice.ObjectFactory factory = _communicator.findObjectFactory(facetType); + if(factory == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "No object factory registered for type-id '" + + facetType + "'"); + } + + _sampleServant = factory.create(facetType); + } + + Connection connection = Util.createConnection(_communicator, evictor.dbEnv().getEnvName()); + + try + { + Catalog catalog = new Catalog(connection, Util.catalogName(), true); + CatalogData catalogData = catalog.get(evictor.filename()); + + if(catalogData != null && catalogData.evictor == false) + { + DatabaseException ex = new DatabaseException(); + ex.message = _evictor.errorPrefix() + evictor.filename() + " is not an evictor database"; + throw ex; + } + + com.sleepycat.db.Environment dbEnv = evictor.dbEnv().getEnv(); + + // + // TODO: FREEZE_DB_MODE + // + com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); + config.setType(com.sleepycat.db.DatabaseType.BTREE); + config.setAllowCreate(createDb); + + Ice.Properties properties = _evictor.communicator().getProperties(); + String propPrefix = "Freeze.Evictor." + _evictor.filename() + "."; + + int btreeMinKey = properties.getPropertyAsInt(propPrefix + _dbName + ".BtreeMinKey"); + if(btreeMinKey > 2) + { + if(_evictor.trace() >= 1) + { + _evictor.communicator().getLogger().trace( + "Freeze.Evictor", "Setting \"" + _evictor.filename() + "." + _dbName + + "\"'s btree minkey to " + btreeMinKey); + } + config.setBtreeMinKey(btreeMinKey); + } + + boolean checksum = properties.getPropertyAsInt(propPrefix + "Checksum") > 0; + if(checksum) + { + if(_evictor.trace() >= 1) + { + _evictor.communicator().getLogger().trace( + "Freeze.Evictor", "Turning checksum on for \"" + _evictor.filename() + "\""); + } + + config.setChecksum(true); + } + + int pageSize = properties.getPropertyAsInt(propPrefix + "PageSize"); + if(pageSize > 0) + { + if(_evictor.trace() >= 1) + { + _evictor.communicator().getLogger().trace( + "Freeze.Evictor", "Setting \"" + _evictor.filename() + "\"'s pagesize to " + pageSize); + } + config.setPageSize(pageSize); + } + + try + { + Transaction tx = connection.beginTransaction(); + com.sleepycat.db.Transaction txn = Util.getTxn(tx); + + _db = dbEnv.openDatabase(txn, evictor.filename(), _dbName, config); + + for(Index index : _indices) + { + index.associate(this, txn, createDb, populateEmptyIndices); + } + + if(catalogData == null) + { + catalogData = new CatalogData(); + catalogData.evictor = true; + catalog.put(evictor.filename(), catalogData); + } + + tx.commit(); + } + catch(java.io.FileNotFoundException dx) + { + throw new NotFoundException(_evictor.errorPrefix() + "Db.open: " + dx.getMessage(), dx); + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.open: " + dx.getMessage(), dx); + } + finally + { + Transaction tx = connection.currentTransaction(); + if(tx != null) + { + try + { + tx.rollback(); + } + catch(DatabaseException de) + { + } + } + } + } + finally + { + connection.close(); + } + } + + void + close() + { + try + { + _db.close(); + + for(Index index : _indices) + { + index.close(); + } + _indices.clear(); + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.close: " + dx.getMessage(), dx); + } + _db = null; + } + + boolean + dbHasObject(Ice.Identity ident, TransactionI transaction) + { + com.sleepycat.db.Transaction tx = null; + + if(transaction != null) + { + tx = transaction.dbTxn(); + if(tx == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "inactive transaction"); + } + } + + byte[] key = marshalKey(ident, _communicator); + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(key); + + // + // Keep 0 length since we're not interested in the data + // + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(); + dbValue.setPartial(true); + + for(;;) + { + try + { + com.sleepycat.db.OperationStatus err = _db.get(tx, dbKey, dbValue, null); + + if(err == com.sleepycat.db.OperationStatus.SUCCESS) + { + return true; + } + else if(err == com.sleepycat.db.OperationStatus.NOTFOUND) + { + return false; + } + else + { + throw new DatabaseException(); + } + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.dhHasObject while reading " + + "Db \"" + _evictor.filename() + "/" + _dbName + "\""); + } + + if(tx != null) + { + throw new DeadlockException(_evictor.errorPrefix() + "Db.get: " + dx.getMessage(), transaction, dx); + } + // + // Otherwise try again + // + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.get: " + dx.getMessage(), dx); + } + } + } + + void + save(byte[] key, byte[] value, byte status, com.sleepycat.db.Transaction tx) + throws com.sleepycat.db.DatabaseException + { + assert tx != null; + + switch(status) + { + case BackgroundSaveEvictorI.created: + case BackgroundSaveEvictorI.modified: + { + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(key); + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(value); + com.sleepycat.db.OperationStatus err; + if(status == BackgroundSaveEvictorI.created) + { + err = _db.putNoOverwrite(tx, dbKey, dbValue); + } + else + { + err = _db.put(tx, dbKey, dbValue); + } + if(err != com.sleepycat.db.OperationStatus.SUCCESS) + { + throw new DatabaseException(); + } + break; + } + case BackgroundSaveEvictorI.destroyed: + { + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(key); + com.sleepycat.db.OperationStatus err = _db.delete(tx, dbKey); + if(err != com.sleepycat.db.OperationStatus.SUCCESS) + { + throw new DatabaseException(); + } + break; + } + default: + { + assert false; + } + } + } + + static byte[] + marshalKey(Ice.Identity v, Ice.Communicator communicator) + { + IceInternal.BasicStream os = + new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false); + v.__write(os); + IceInternal.Buffer buf = os.prepareWrite(); + byte[] r = new byte[buf.size()]; + buf.b.get(r); + return r; + } + + static Ice.Identity + unmarshalKey(byte[] b, Ice.Communicator communicator) + { + IceInternal.BasicStream is = + new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false); + is.resize(b.length, true); + IceInternal.Buffer buf = is.getBuffer(); + buf.b.position(0); + buf.b.put(b); + buf.b.position(0); + Ice.Identity key = new Ice.Identity(); + key.__read(is); + return key; + } + + static byte[] + marshalValue(ObjectRecord v, Ice.Communicator communicator) + { + IceInternal.BasicStream os = + new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false); + os.startWriteEncaps(); + v.__write(os); + os.writePendingObjects(); + os.endWriteEncaps(); + IceInternal.Buffer buf = os.prepareWrite(); + byte[] r = new byte[buf.size()]; + buf.b.get(r); + return r; + } + + static ObjectRecord + unmarshalValue(byte[] b, Ice.Communicator communicator) + { + IceInternal.BasicStream is = + new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false); + is.sliceObjects(false); + is.resize(b.length, true); + IceInternal.Buffer buf = is.getBuffer(); + buf.b.position(0); + buf.b.put(b); + buf.b.position(0); + ObjectRecord rec= new ObjectRecord(); + is.startReadEncaps(); + rec.__read(is); + is.readPendingObjects(); + is.endReadEncaps(); + return rec; + } + + final IceUtil.Cache + cache() + { + return _cache; + } + + final com.sleepycat.db.Database + db() + { + return _db; + } + + final Ice.Communicator + communicator() + { + return _communicator; + } + + final EvictorI + evictor() + { + return _evictor; + } + + final String + facet() + { + return _facet; + } + + final String + dbName() + { + return _dbName; + } + + final Ice.Object + sampleServant() + { + return _sampleServant; + } + + // + // Load a servant from the database; will end up in the cache associated with + // this ObjectStore. This load is not transactional. + // + public Object + load(Object identObj) + { + Ice.Identity ident = (Ice.Identity)identObj; + + byte[] key = marshalKey(ident, _communicator); + + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(key); + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(); + + for(;;) + { + try + { + com.sleepycat.db.OperationStatus rs = _db.get(null, dbKey, dbValue, null); + + if(rs == com.sleepycat.db.OperationStatus.NOTFOUND) + { + return null; + } + else if (rs != com.sleepycat.db.OperationStatus.SUCCESS) + { + assert false; + throw new DatabaseException(); + } + break; + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.load while reading Db \"" + + _evictor.filename() + "/" + _dbName + "\"; retrying..."); + } + + // + // Ignored, try again + // + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.get: " + dx.getMessage(), dx); + } + } + + ObjectRecord rec = unmarshalValue(dbValue.getData(), _communicator); + _evictor.initialize(ident, _facet, rec.servant); + + Object result = _evictor.createEvictorElement(ident, rec, this); + return result; + } + + // + // Load a servant from the database using the given transaction; this servant + // is NOT cached in the ObjectStore associated cache + // + ObjectRecord + load(Ice.Identity ident, TransactionI transaction) + { + if(transaction == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "no active transaction"); + } + com.sleepycat.db.Transaction tx = transaction.dbTxn(); + if(tx == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "inactive transaction"); + } + + byte[] key = marshalKey(ident, _communicator); + + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(key); + com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(); + + try + { + com.sleepycat.db.OperationStatus rs = _db.get(tx, dbKey, dbValue, null); + + if(rs == com.sleepycat.db.OperationStatus.NOTFOUND) + { + return null; + } + else if(rs != com.sleepycat.db.OperationStatus.SUCCESS) + { + assert false; + throw new DatabaseException(); + } + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.load while reading Db \"" + + _evictor.filename() + "/" + _dbName + "\""); + } + + throw new DeadlockException(_evictor.errorPrefix() + "Db.get: " + dx.getMessage(), transaction, dx); + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.get: " + dx.getMessage(), dx); + } + + ObjectRecord rec = unmarshalValue(dbValue.getData(), _communicator); + _evictor.initialize(ident, _facet, rec.servant); + return rec; + } + + void + update(Ice.Identity ident, ObjectRecord objectRecord, TransactionI transaction) + { + if(transaction == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "no active transaction"); + } + com.sleepycat.db.Transaction tx = transaction.dbTxn(); + if(tx == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "inactive transaction"); + } + + if(_sampleServant != null && !objectRecord.servant.ice_id().equals(_sampleServant.ice_id())) + { + String msg = _evictor.errorPrefix() + "Attempting to save a '" + objectRecord.servant.ice_id() + + "' servant in a database of '" + _sampleServant.ice_id() + "' servants"; + + throw new DatabaseException(msg); + } + + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(marshalKey(ident, _communicator)); + com.sleepycat.db.DatabaseEntry dbValue = + new com.sleepycat.db.DatabaseEntry(marshalValue(objectRecord, _communicator)); + + try + { + com.sleepycat.db.OperationStatus err = _db.put(tx, dbKey, dbValue); + if(err != com.sleepycat.db.OperationStatus.SUCCESS) + { + throw new DatabaseException(); + } + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.update while updating Db \"" + + _evictor.filename() + "/" + _dbName + "\""); + } + + throw new DeadlockException(_evictor.errorPrefix() + "Db.put: " + dx.getMessage(), transaction, dx); + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.put: " + dx.getMessage(), dx); + } + } + + boolean + insert(Ice.Identity ident, ObjectRecord objectRecord, TransactionI transaction) + { + com.sleepycat.db.Transaction tx = null; + + if(transaction != null) + { + tx = transaction.dbTxn(); + if(tx == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "invalid transaction"); + } + } + + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(marshalKey(ident, _communicator)); + com.sleepycat.db.DatabaseEntry dbValue = + new com.sleepycat.db.DatabaseEntry(marshalValue(objectRecord, _communicator)); + + if(_sampleServant != null && !objectRecord.servant.ice_id().equals(_sampleServant.ice_id())) + { + String msg = _evictor.errorPrefix() + "Attempting to save a '" + objectRecord.servant.ice_id() + + "' servant in a database of '" + _sampleServant.ice_id() + "' servants"; + + throw new DatabaseException(msg); + } + + for(;;) + { + try + { + return _db.putNoOverwrite(tx, dbKey, dbValue) == com.sleepycat.db.OperationStatus.SUCCESS; + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.update while updating Db \"" + + _evictor.filename() + "/" + _dbName + "\""); + } + + if(tx != null) + { + throw new DeadlockException(_evictor.errorPrefix() + "Db.putNoOverwrite: " + dx.getMessage(), + transaction, dx); + } + // + // Otherwise retry + // + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.putNoOverwrite: " + dx.getMessage(), dx); + } + } + } + + boolean + remove(Ice.Identity ident, TransactionI transaction) + { + com.sleepycat.db.Transaction tx = null; + + if(transaction != null) + { + tx = transaction.dbTxn(); + if(tx == null) + { + throw new DatabaseException(_evictor.errorPrefix() + "invalid transaction"); + } + } + + com.sleepycat.db.DatabaseEntry dbKey = new com.sleepycat.db.DatabaseEntry(marshalKey(ident, _communicator)); + + for(;;) + { + try + { + return _db.delete(tx, dbKey) == com.sleepycat.db.OperationStatus.SUCCESS; + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(_evictor.deadlockWarning()) + { + _communicator.getLogger().warning("Deadlock in Freeze.ObjectStore.remove while updating Db \"" + + _evictor.filename() + "/" + _dbName + "\""); + } + + if(tx != null) + { + throw new DeadlockException(_evictor.errorPrefix() + "Db.delete: " + dx.getMessage(), transaction, + dx); + } + + // + // Otherwise retry + // + + } + catch(com.sleepycat.db.DatabaseException dx) + { + throw new DatabaseException(_evictor.errorPrefix() + "Db.delete: " + dx.getMessage(), dx); + } + } + } + + private final IceUtil.Cache _cache; + private final String _facet; + private final String _dbName; + private final EvictorI _evictor; + private final java.util.List<Index> _indices; + private final Ice.Communicator _communicator; + + private com.sleepycat.db.Database _db; + private Ice.Object _sampleServant; +} |