diff options
author | Bernard Normier <bernard@zeroc.com> | 2007-12-12 12:03:04 -0500 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2007-12-12 12:03:04 -0500 |
commit | 28c22de9b812daeffa630656818da6ec5411a7da (patch) | |
tree | a3b5142c2144ead6aafb62dd71baf0657296e014 /java | |
parent | Fixed bug #2546 (diff) | |
download | ice-28c22de9b812daeffa630656818da6ec5411a7da.tar.bz2 ice-28c22de9b812daeffa630656818da6ec5411a7da.tar.xz ice-28c22de9b812daeffa630656818da6ec5411a7da.zip |
Fixed bug #2557 (closing database within transaction)
Diffstat (limited to 'java')
-rw-r--r-- | java/demo/Freeze/transform/README | 2 | ||||
-rw-r--r-- | java/src/Freeze/Map.java | 130 | ||||
-rwxr-xr-x | java/src/Freeze/MapDb.java | 433 | ||||
-rwxr-xr-x | java/src/Freeze/SharedDb.java | 622 | ||||
-rw-r--r-- | java/src/Freeze/SharedDbEnv.java | 402 | ||||
-rw-r--r-- | java/test/Freeze/dbmap/Client.java | 14 |
6 files changed, 739 insertions, 864 deletions
diff --git a/java/demo/Freeze/transform/README b/java/demo/Freeze/transform/README index b0abd0de942..6bcdd5b4ebd 100644 --- a/java/demo/Freeze/transform/README +++ b/java/demo/Freeze/transform/README @@ -67,7 +67,7 @@ Running the demo $ transformdb --old ContactData.ice --new NewContactData.ice \ -f transform.xml db dbnew - - read the transformend contacts map: + - read the transformed contacts map: $ java ReadNew You'll notice the sort order (looks random), and the corrupt index. The index is actually created by ReadNew when it opens diff --git a/java/src/Freeze/Map.java b/java/src/Freeze/Map.java index 1977865c6e4..131cc48ef5f 100644 --- a/java/src/Freeze/Map.java +++ b/java/src/Freeze/Map.java @@ -20,6 +20,7 @@ public abstract class Map extends java.util.AbstractMap boolean createDb, java.util.Comparator comparator) { _connection = (ConnectionI)connection; + _dbName = dbName; _comparator = (comparator == null) ? null : new Comparator(comparator); _errorPrefix = "Freeze DB DbEnv(\"" + _connection.envName() + "\") Db(\"" + dbName + "\"): "; @@ -32,6 +33,7 @@ public abstract class Map extends java.util.AbstractMap Map(Connection connection, String dbName, java.util.Comparator comparator) { _connection = (ConnectionI)connection; + _dbName = dbName; _comparator = (comparator == null) ? null : new Comparator(comparator); _errorPrefix = "Freeze DB DbEnv(\"" + _connection.envName() + "\") Db(\"" + dbName + "\"): "; @@ -48,7 +50,7 @@ public abstract class Map extends java.util.AbstractMap if(dbName.equals(Util.catalogName()) || dbName.equals(Util.catalogIndexListName())) { - throw new DatabaseException(errorPrefix(envName, dbName) + "You cannot destroy recreate the \"" + throw new DatabaseException(errorPrefix(envName, dbName) + "You cannot recreate the \"" + dbName + "\" database"); } @@ -65,7 +67,7 @@ public abstract class Map extends java.util.AbstractMap com.sleepycat.db.DatabaseEntry valueEntry = new com.sleepycat.db.DatabaseEntry(); com.sleepycat.db.Database oldDb = null; - SharedDb newDb = null; + MapDb newDb = null; for(;;) { @@ -123,7 +125,7 @@ public abstract class Map extends java.util.AbstractMap oldDb = connection.dbEnv().getEnv().openDatabase(txn, oldDbName, null, oldDbConfig); - newDb = SharedDb.create(connection, dbName, key, value, indices, map._comparator, indexComparators); + newDb = new MapDb(connection, dbName, key, value, map._comparator, indices, indexComparators, true); map.init(newDb, indices); @@ -259,13 +261,12 @@ public abstract class Map extends java.util.AbstractMap init(Freeze.Map.Index[] indices, String dbName, String key, String value, boolean createDb, java.util.Map indexComparators) { - init(SharedDb.get(_connection, dbName, key, - value, indices, createDb, _comparator, - indexComparators), indices); + init(_connection.dbEnv().getSharedMapDb(dbName, key, value, _comparator, indices, indexComparators, createDb), + indices); } protected void - init(SharedDb db, Freeze.Map.Index[] indices) + init(MapDb db, Freeze.Map.Index[] indices) { _db = db; _token = _connection.registerMap(this); @@ -286,6 +287,13 @@ public abstract class Map extends java.util.AbstractMap close(false); } + public void + closeDb() + { + close(false); + _connection.dbEnv().removeSharedMapDb(_dbName); + } + // // SortedMap methods // @@ -851,27 +859,24 @@ public abstract class Map extends java.util.AbstractMap throw new DatabaseException(_errorPrefix + "You cannot destroy the \"" + dbName + "\" database"); } + if(_connection.currentTransaction() != null) + { + throw new DatabaseException(_errorPrefix + "You cannot destroy a database within an active transaction"); + } + if(_trace >= 1) { _connection.communicator().getLogger().trace("Freeze.Map", "destroying \"" + dbName + "\""); } - - close(); - - Transaction tx = _connection.currentTransaction(); - boolean ownTx = (tx == null); + closeDb(); for(;;) { + Transaction tx = null; try { - if(ownTx) - { - tx = null; - tx = _connection.beginTransaction(); - } - + tx = _connection.beginTransaction(); com.sleepycat.db.Transaction txn = _connection.dbTxn(); @@ -892,67 +897,44 @@ public abstract class Map extends java.util.AbstractMap } - if(ownTx) - { - tx.commit(); - } + tx.commit(); + break; // for(;;) } catch(java.io.FileNotFoundException dx) { - if(ownTx) + try { - if(ownTx) - { - try - { - tx.rollback(); - } - catch(DatabaseException e) - { - } - } + tx.rollback(); } - + catch(DatabaseException e) + { + } + DatabaseException e = new DatabaseException(_errorPrefix + "file not found"); e.initCause(dx); throw e; } catch(com.sleepycat.db.DeadlockException dx) { - if(ownTx) - { - if(_connection.deadlockWarning()) - { - _connection.communicator().getLogger().warning("Deadlock in Freeze.Map.destroy on Db \"" + - dbName + "\"; retrying..."); - } - - // - // Ignored, try again - // - } - else + if(_connection.deadlockWarning()) { - DeadlockException e = new DeadlockException(_errorPrefix + dx.getMessage(), tx); - e.initCause(dx); - throw e; + _connection.communicator().getLogger().warning("Deadlock in Freeze.Map.destroy on Db \"" + + dbName + "\"; retrying..."); } + + // + // Ignored, try again + // } catch(com.sleepycat.db.DatabaseException dx) - { - if(ownTx) + { + try + { + tx.rollback(); + } + catch(DatabaseException e) { - if(ownTx) - { - try - { - tx.rollback(); - } - catch(DatabaseException e) - { - } - } } DatabaseException e = new DatabaseException(_errorPrefix + dx.getMessage()); @@ -960,17 +942,15 @@ public abstract class Map extends java.util.AbstractMap throw e; } catch(RuntimeException rx) - { - if(ownTx && tx != null) + { + try { - try - { - tx.rollback(); - } - catch(DatabaseException e) - { - } + tx.rollback(); } + catch(DatabaseException e) + { + } + throw rx; } } @@ -1011,10 +991,9 @@ public abstract class Map extends java.util.AbstractMap { if(_db != null) { - closeAllIteratorsExcept(null, finalizing); try { - _db.close(); + closeAllIteratorsExcept(null, finalizing); } finally { @@ -1563,7 +1542,7 @@ public abstract class Map extends java.util.AbstractMap void close() { // - // close() is called by SharedDb only on the "main" index + // close() is called by MapDb only on the "main" index // (the one that was associated) // @@ -2501,9 +2480,10 @@ public abstract class Map extends java.util.AbstractMap protected ConnectionI _connection; private final Comparator _comparator; + private final String _dbName; protected java.util.Iterator _token; - protected SharedDb _db; + protected MapDb _db; protected String _errorPrefix; protected int _trace; diff --git a/java/src/Freeze/MapDb.java b/java/src/Freeze/MapDb.java new file mode 100755 index 00000000000..8579b670870 --- /dev/null +++ b/java/src/Freeze/MapDb.java @@ -0,0 +1,433 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2007 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; + +// +// A MapDb represents the Db object underneath Freeze Maps. Several Freeze Maps often +// share the very same MapDb object; SharedDbEnv manages these shared MapDb objects. +// + +class MapDb +{ + + MapDb(ConnectionI connection, String dbName, String key, String value, + java.util.Comparator comparator, Map.Index[] indices, java.util.Map indexComparators, + boolean createDb) + { + _communicator = connection.communicator(); + _dbName = dbName; + _errorPrefix = "Freeze DB DbEnv(\"" + connection.dbEnv().getEnvName() + "\") Db(\"" + dbName + "\"): "; + _indices = indices; + _trace = connection.trace(); + + Catalog catalog = new Catalog(connection, Util.catalogName(), true); + CatalogData catalogData = (CatalogData)catalog.get(_dbName); + if(catalogData != null) + { + if(catalogData.evictor) + { + throw new DatabaseException(_errorPrefix + "is not an evictor"); + } + _key = catalogData.key; + _value = catalogData.value; + checkTypes(key, value); + } + else + { + _key = key; + _value = value; + } + + com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); + + + config.setAllowCreate(createDb); + config.setType(com.sleepycat.db.DatabaseType.BTREE); + + if(comparator != null) + { + config.setBtreeComparator(comparator); + } + Ice.Properties properties = _communicator.getProperties(); + String propPrefix = "Freeze.Map." + _dbName + "."; + + int btreeMinKey = properties.getPropertyAsInt(propPrefix + "BtreeMinKey"); + if(btreeMinKey > 2) + { + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "Setting \"" + _dbName + "\"'s btree minkey to " + btreeMinKey); + } + config.setBtreeMinKey(btreeMinKey); + } + + boolean checksum = properties.getPropertyAsInt(propPrefix + "Checksum") > 0; + if(checksum) + { + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "Turning checksum on for \"" + _dbName + "\""); + } + + config.setChecksum(true); + } + + int pageSize = properties.getPropertyAsInt(propPrefix + "PageSize"); + if(pageSize > 0) + { + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "Setting \"" + _dbName + "\"'s pagesize to " + pageSize); + } + config.setPageSize(pageSize); + } + + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze.Map", "opening Db \"" + _dbName + "\""); + } + + Transaction tx = connection.currentTransaction(); + boolean ownTx = (tx == null); + + for(;;) + { + try + { + if(ownTx) + { + tx = null; + tx = connection.beginTransaction(); + } + + com.sleepycat.db.Transaction txn = Util.getTxn(tx); + + _db = connection.dbEnv().getEnv().openDatabase(txn, _dbName, null, config); + + String[] oldIndices = null; + java.util.List<String> newIndices = new java.util.LinkedList<String>(); + + CatalogIndexList catalogIndexList = new CatalogIndexList(connection, Util.catalogIndexListName(), true); + + if(createDb) + { + oldIndices = (String[])catalogIndexList.get(_dbName); + } + + + if(_indices != null) + { + for(int i = 0; i < _indices.length; ++i) + { + String indexName = _indices[i].name(); + + java.util.Comparator indexComparator = null; + if(indexComparators != null) + { + indexComparator = (java.util.Comparator)indexComparators.get(indexName); + } + + _indices[i].associate(_dbName, _db, txn, createDb, indexComparator); + + if(createDb) + { + if(oldIndices != null) + { + int j = java.util.Arrays.asList(oldIndices).indexOf(indexName); + if(j != -1) + { + oldIndices[j] = null; + } + } + newIndices.add(indexName); + } + } + } + + if(catalogData == null) + { + catalogData = new CatalogData(); + catalogData.evictor = false; + catalogData.key = key; + catalogData.value = value; + catalog.put(_dbName, catalogData); + } + + if(createDb) + { + boolean indexRemoved = false; + + if(oldIndices != null) + { + // + // Remove old indices and write the new ones + // + for(int i = 0; i < oldIndices.length; ++i) + { + String index = oldIndices[i]; + if(index != null) + { + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "removing old index \"" + index + "\" on Db \"" + _dbName + "\""); + } + + indexRemoved = true; + + try + { + connection.removeMapIndex(_dbName, index); + } + catch(IndexNotFoundException ife) + { + // Ignored + + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "index \"" + index + "\" on Db \"" + _dbName + "\" does not exist"); + } + } + } + } + } + + int oldSize = oldIndices == null ? 0 : oldIndices.length; + + if(indexRemoved || newIndices.size() != oldSize) + { + if(newIndices.size() == 0) + { + catalogIndexList.remove(_dbName); + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "Removed catalogIndexList entry for Db \"" + _dbName + "\""); + } + + } + else + { + catalogIndexList.put(_dbName, newIndices.toArray(new String[0])); + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze.Map", "Updated catalogIndexList entry for Db \"" + _dbName + "\""); + } + } + } + } + + if(ownTx) + { + try + { + tx.commit(); + } + finally + { + tx = null; + } + } + break; // for(;;) + } + catch(java.io.FileNotFoundException dx) + { + clearIndices(); + NotFoundException ex = new NotFoundException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DeadlockException dx) + { + if(ownTx) + { + if(connection.deadlockWarning()) + { + connection.communicator().getLogger().warning( + "Deadlock in Freeze.Shared.Shared on Db \"" + + _dbName + "\"; retrying ..."); + } + tx = null; + } + else + { + clearIndices(); + DeadlockException ex = new DeadlockException(_errorPrefix + "Db.open: " + dx.getMessage(), tx); + ex.initCause(dx); + throw ex; + } + } + catch(com.sleepycat.db.DatabaseException dx) + { + clearIndices(); + DatabaseException ex = new DatabaseException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + finally + { + if(ownTx && tx != null) + { + try + { + tx.rollback(); + } + catch(DatabaseException de) + { + } + } + } + } + } + + + // + // The constructor for catalogs + // + + MapDb(Ice.Communicator communicator, String envName, String dbName, String key, String value, + com.sleepycat.db.Environment dbEnv) + throws com.sleepycat.db.DatabaseException + { + _communicator = communicator; + _dbName = dbName; + _errorPrefix = "Freeze DB DbEnv(\"" + envName + "\") Db(\"" + dbName + "\"): "; + _key = key; + _value = value; + _trace = _communicator.getProperties().getPropertyAsInt("Freeze.Trace.Map"); + + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze.Map", "opening Db \"" + _dbName + "\""); + } + + com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); + config.setAllowCreate(true); + config.setType(com.sleepycat.db.DatabaseType.BTREE); + config.setTransactional(true); + + try + { + _db = dbEnv.openDatabase(null, _dbName, null, config); + } + catch(java.io.FileNotFoundException dx) + { + // + // This should never happen + // + NotFoundException ex = new NotFoundException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + } + + void close() + { + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze.Map", "closing Db \"" + _dbName + "\""); + } + + clearIndices(); + + if(_db != null) + { + try + { + _db.close(); + } + catch(com.sleepycat.db.DatabaseException dx) + { + DatabaseException ex = new DatabaseException(); + ex.initCause(dx); + ex.message = _errorPrefix + "close: " + dx.getMessage(); + throw ex; + } + finally + { + _db = null; + } + } + } + + + void + connectIndices(Map.Index[] indices) + { + if(indices != null) + { + assert(_indices != null && indices.length == _indices.length); + + for(int i = 0; i < indices.length; ++i) + { + indices[i].init(_indices[i]); + } + } + } + + void + clearIndices() + { + if(_indices != null) + { + for(int i = 0; i < _indices.length; ++i) + { + _indices[i].close(); + } + _indices = null; + } + } + + + com.sleepycat.db.Database + db() + { + return _db; + } + + String + dbName() + { + return _dbName; + } + + void + checkTypes(String key, String value) + { + if(!key.equals(_key)) + { + throw new DatabaseException(_errorPrefix + _dbName + "'s key type is " + _key + + ", not " + key); + } + + if(!value.equals(_value)) + { + throw new DatabaseException(_errorPrefix + _dbName + "'s value type is " + _value + + ", not " + value); + } + } + + private com.sleepycat.db.Database _db; + private final Ice.Communicator _communicator; + private final String _dbName; + private final String _errorPrefix; + private String _key; + private String _value; + private final int _trace; + private Map.Index[] _indices; +} diff --git a/java/src/Freeze/SharedDb.java b/java/src/Freeze/SharedDb.java deleted file mode 100755 index b8fa5eaad2c..00000000000 --- a/java/src/Freeze/SharedDb.java +++ /dev/null @@ -1,622 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2007 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 SharedDb -{ - public static SharedDb - get(ConnectionI connection, String dbName, String key, String value, - Map.Index[] indices, boolean createDb, java.util.Comparator comparator, - java.util.Map indexComparators) - { - MapKey mapKey = new MapKey(connection.envName(), connection.communicator(), dbName); - - if(dbName.equals(Util.catalogName())) - { - // - // We don't want to lock the _map to retrieve the catalog - // - SharedDb result = connection.dbEnv().getCatalog(); - checkTypes(result, key, value); - result._refCount++; - return result; - } - else if(dbName.equals(Util.catalogIndexListName())) - { - SharedDb result = connection.dbEnv().getCatalogIndexList(); - checkTypes(result, key, value); - result._refCount++; - return result; - } - - synchronized(_map) - { - SharedDb result = (SharedDb)_map.get(mapKey); - if(result == null) - { - ConnectionI insertConnection = (ConnectionI)Util.createConnection(mapKey.communicator, mapKey.envName); - - try - { - result = new SharedDb(mapKey, key, value, insertConnection, - indices, createDb, comparator, indexComparators); - } - finally - { - insertConnection.close(); - } - - Object previousValue = _map.put(mapKey, result); - assert(previousValue == null); - result._inMap = true; - } - else - { - checkTypes(result, key, value); - result.connectIndices(indices); - result._refCount++; - } - return result; - } - } - - public static SharedDb - create(ConnectionI connection, String dbName, String key, String value, - Map.Index[] indices, java.util.Comparator comparator, - java.util.Map indexComparators) - { - - MapKey mapKey = new MapKey(connection.envName(), connection.communicator(), dbName); - - return new SharedDb(mapKey, key, value, connection, - indices, true, comparator, indexComparators); - - } - - public static SharedDb[] - openCatalogs(SharedDbEnv dbEnv) - { - MapKey catalogMapKey = new MapKey(dbEnv.getEnvName(), dbEnv.getCommunicator(), Util.catalogName()); - MapKey catalogIndexListMapKey = - new MapKey(dbEnv.getEnvName(), dbEnv.getCommunicator(), Util.catalogIndexListName()); - - synchronized(_map) - { - SharedDb[] result = new SharedDb[2]; - - if(_map.get(catalogMapKey) != null) - { - throw new DatabaseException(errorPrefix(catalogMapKey) + "Catalog already opened"); - } - - if(_map.get(catalogIndexListMapKey) != null) - { - throw new DatabaseException(errorPrefix(catalogIndexListMapKey) + "Catalog already opened"); - } - - try - { - result[0] = new SharedDb(catalogMapKey, "string", "::Freeze::CatalogData", dbEnv.getEnv()); - } - catch(com.sleepycat.db.DatabaseException dx) - { - DatabaseException ex = new DatabaseException(errorPrefix(catalogMapKey) - + "creation: " + dx.getMessage()); - ex.initCause(dx); - throw ex; - } - - try - { - result[1] = new SharedDb(catalogIndexListMapKey, "string", "::Ice::StringSeq", dbEnv.getEnv()); - } - catch(com.sleepycat.db.DatabaseException dx) - { - DatabaseException ex = new DatabaseException(errorPrefix(catalogIndexListMapKey) - + "creation: " + dx.getMessage()); - ex.initCause(dx); - throw ex; - } - - Object previousValue = _map.put(catalogMapKey, result[0]); - assert(previousValue == null); - result[0]._inMap = true; - previousValue = _map.put(catalogIndexListMapKey, result[1]); - assert(previousValue == null); - result[1]._inMap = true; - - return result; - } - } - - public com.sleepycat.db.Database - db() - { - return _db; - } - - public String - dbName() - { - return _mapKey.dbName; - } - - public void - close() - { - synchronized(_map) - { - if(--_refCount == 0) - { - - if(_inMap) - { - // - // Remove from map - // - - Object value = _map.remove(_mapKey); - assert(value == this); - } - - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace("Freeze.Map", "closing Db \"" + _mapKey.dbName + "\""); - } - - // - // Keep lock to prevent somebody else from re-opening this Db - // before it's closed. - // - try - { - cleanupIndices(); - - _db.close(); - } - catch(com.sleepycat.db.DatabaseException dx) - { - DatabaseException ex = new DatabaseException(); - ex.initCause(dx); - ex.message = errorPrefix(_mapKey) + "close: " + dx.getMessage(); - throw ex; - } - } - } - } - - protected void - finalize() - { - assert(_refCount == 0); - } - - private SharedDb(MapKey mapKey, String key, String value, ConnectionI connection, Map.Index[] indices, - boolean createDb, java.util.Comparator comparator, java.util.Map indexComparators) - { - _mapKey = mapKey; - _indices = indices; - _trace = connection.trace(); - - - Catalog catalog = new Catalog(connection, Util.catalogName(), true); - CatalogData catalogData = (CatalogData)catalog.get(_mapKey.dbName); - if(catalogData != null) - { - if(catalogData.evictor) - { - DatabaseException ex = new DatabaseException(); - ex.message = errorPrefix(_mapKey) + "is not an evictor"; - throw ex; - } - _key = catalogData.key; - _value = catalogData.value; - checkTypes(this, key, value); - } - else - { - _key = key; - _value = value; - } - - com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); - - - config.setAllowCreate(createDb); - config.setType(com.sleepycat.db.DatabaseType.BTREE); - - if(comparator != null) - { - config.setBtreeComparator(comparator); - } - Ice.Properties properties = _mapKey.communicator.getProperties(); - String propPrefix = "Freeze.Map." + _mapKey.dbName + "."; - - int btreeMinKey = properties.getPropertyAsInt(propPrefix + "BtreeMinKey"); - if(btreeMinKey > 2) - { - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "Setting \"" + _mapKey.dbName + "\"'s btree minkey to " + btreeMinKey); - } - config.setBtreeMinKey(btreeMinKey); - } - - boolean checksum = properties.getPropertyAsInt(propPrefix + "Checksum") > 0; - if(checksum) - { - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "Turning checksum on for \"" + _mapKey.dbName + "\""); - } - - config.setChecksum(true); - } - - int pageSize = properties.getPropertyAsInt(propPrefix + "PageSize"); - if(pageSize > 0) - { - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "Setting \"" + _mapKey.dbName + "\"'s pagesize to " + pageSize); - } - config.setPageSize(pageSize); - } - - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace("Freeze.Map", "opening Db \"" + _mapKey.dbName + "\""); - } - - Transaction tx = connection.currentTransaction(); - boolean ownTx = (tx == null); - - for(;;) - { - try - { - if(ownTx) - { - tx = null; - tx = connection.beginTransaction(); - } - - com.sleepycat.db.Transaction txn = Util.getTxn(tx); - - _db = connection.dbEnv().getEnv().openDatabase(txn, mapKey.dbName, null, config); - - String[] oldIndices = null; - java.util.List<String> newIndices = new java.util.LinkedList<String>(); - - CatalogIndexList catalogIndexList = new CatalogIndexList(connection, Util.catalogIndexListName(), true); - - if(createDb) - { - oldIndices = (String[])catalogIndexList.get(_mapKey.dbName); - } - - - if(_indices != null) - { - for(int i = 0; i < _indices.length; ++i) - { - String indexName = _indices[i].name(); - - java.util.Comparator indexComparator = null; - if(indexComparators != null) - { - indexComparator = (java.util.Comparator)indexComparators.get(indexName); - } - - _indices[i].associate(mapKey.dbName, _db, txn, createDb, indexComparator); - - if(createDb) - { - if(oldIndices != null) - { - int j = java.util.Arrays.asList(oldIndices).indexOf(indexName); - if(j != -1) - { - oldIndices[j] = null; - } - } - newIndices.add(indexName); - } - } - } - - if(catalogData == null) - { - catalogData = new CatalogData(); - catalogData.evictor = false; - catalogData.key = key; - catalogData.value = value; - catalog.put(_mapKey.dbName, catalogData); - } - - if(createDb) - { - boolean indexRemoved = false; - - if(oldIndices != null) - { - // - // Remove old indices and write the new ones - // - for(int i = 0; i < oldIndices.length; ++i) - { - String index = oldIndices[i]; - if(index != null) - { - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "removing old index \"" + index + "\" on Db \"" + _mapKey.dbName + "\""); - } - - indexRemoved = true; - - try - { - connection.removeMapIndex(mapKey.dbName, index); - } - catch(IndexNotFoundException ife) - { - // Ignored - - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "index \"" + index + "\" on Db \"" + _mapKey.dbName + "\" does not exist"); - } - } - } - } - } - - int oldSize = oldIndices == null ? 0 : oldIndices.length; - - if(indexRemoved || newIndices.size() != oldSize) - { - if(newIndices.size() == 0) - { - catalogIndexList.remove(_mapKey.dbName); - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "Removed catalogIndexList entry for Db \"" + _mapKey.dbName + "\""); - } - - } - else - { - catalogIndexList.put(_mapKey.dbName, newIndices.toArray(new String[0])); - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace( - "Freeze.Map", "Updated catalogIndexList entry for Db \"" + _mapKey.dbName + "\""); - } - } - } - } - - if(ownTx) - { - try - { - tx.commit(); - } - finally - { - tx = null; - } - } - break; // for(;;) - - // - // TODO: FREEZE_DB_MODE - // - } - catch(java.io.FileNotFoundException dx) - { - cleanupIndices(); - NotFoundException ex = new NotFoundException(); - ex.initCause(dx); - ex.message = errorPrefix(_mapKey) + "Db.open: " + dx.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DeadlockException dx) - { - if(ownTx) - { - if(connection.deadlockWarning()) - { - connection.communicator().getLogger().warning( - "Deadlock in Freeze.Shared.Shared on Db \"" - + mapKey.dbName + "\"; retrying ..."); - } - tx = null; - } - else - { - cleanupIndices(); - DeadlockException ex = new DeadlockException(errorPrefix(_mapKey) + "Db.open: " + dx.getMessage(), tx); - ex.initCause(dx); - throw ex; - } - } - catch(com.sleepycat.db.DatabaseException dx) - { - cleanupIndices(); - DatabaseException ex = new DatabaseException(); - ex.initCause(dx); - ex.message = errorPrefix(_mapKey) + "Db.open: " + dx.getMessage(); - throw ex; - } - finally - { - if(ownTx && tx != null) - { - try - { - tx.rollback(); - } - catch(DatabaseException de) - { - } - } - } - } - _refCount = 1; - } - - - private SharedDb(MapKey mapKey, String key, String value, com.sleepycat.db.Environment dbEnv) - throws com.sleepycat.db.DatabaseException - { - _mapKey = mapKey; - _key = key; - _value = value; - _trace = _mapKey.communicator.getProperties().getPropertyAsInt("Freeze.Trace.Map"); - - if(_trace >= 1) - { - _mapKey.communicator.getLogger().trace("Freeze.Map", "opening Db \"" + _mapKey.dbName + "\""); - } - - com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); - config.setAllowCreate(true); - config.setType(com.sleepycat.db.DatabaseType.BTREE); - config.setTransactional(true); - - try - { - _db = dbEnv.openDatabase(null, mapKey.dbName, null, config); - } - catch(java.io.FileNotFoundException dx) - { - // - // This should never happen - // - NotFoundException ex = new NotFoundException(); - ex.initCause(dx); - ex.message = errorPrefix(_mapKey) + "Db.open: " + dx.getMessage(); - throw ex; - } - _refCount = 1; - } - - private void - connectIndices(Map.Index[] indices) - { - if(indices != null) - { - assert(_indices != null && indices.length == _indices.length); - - for(int i = 0; i < indices.length; ++i) - { - indices[i].init(_indices[i]); - } - } - } - - private void - cleanupIndices() - { - if(_indices != null) - { - for(int i = 0; i < _indices.length; ++i) - { - _indices[i].close(); - } - _indices = null; - } - } - - private static void - checkTypes(SharedDb sharedDb, String key, String value) - { - if(!key.equals(sharedDb._key)) - { - DatabaseException ex = new DatabaseException(); - ex.message = errorPrefix(sharedDb._mapKey) + sharedDb.dbName() + "'s key type is " + sharedDb._key + - ", not " + key; - throw ex; - } - if(!value.equals(sharedDb._value)) - { - DatabaseException ex = new DatabaseException(); - ex.message = errorPrefix(sharedDb._mapKey) + sharedDb.dbName() + "'s value type is " + sharedDb._value + - ", not " + value; - throw ex; - } - } - - private static String - errorPrefix(MapKey k) - { - return "Freeze DB DbEnv(\"" + k.envName + "\") Db(\"" + k.dbName + "\"): "; - } - - private static class MapKey - { - final String envName; - final Ice.Communicator communicator; - final String dbName; - - MapKey(String envName, Ice.Communicator communicator, String dbName) - { - assert(envName != null); - assert(communicator != null); - assert(dbName != null); - - this.envName = envName; - this.communicator = communicator; - this.dbName = dbName; - } - - public boolean - equals(Object o) - { - try - { - MapKey k = (MapKey)o; - return (dbName.equals(k.dbName)) && (communicator == k.communicator) && envName.equals(k.envName); - } - catch(ClassCastException ex) - { - communicator.getLogger().trace("Freeze.Map", "equals cast failed"); - return false; - } - } - - public int hashCode() - { - return dbName.hashCode() ^ envName.hashCode() ^ communicator.hashCode(); - } - } - - private com.sleepycat.db.Database _db; - private MapKey _mapKey; - private String _key; - private String _value; - private int _refCount = 0; - private int _trace; - private Map.Index[] _indices; - private boolean _inMap = false; - -// -// Hash map of (MapKey, SharedDb) -// - private static java.util.Map _map = new java.util.HashMap(); -} diff --git a/java/src/Freeze/SharedDbEnv.java b/java/src/Freeze/SharedDbEnv.java index d8dabe8a385..807b7ac88b7 100644 --- a/java/src/Freeze/SharedDbEnv.java +++ b/java/src/Freeze/SharedDbEnv.java @@ -23,34 +23,81 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable result = (SharedDbEnv)_map.get(key); if(result == null) { + result = new SharedDbEnv(key, dbEnv); + + Object previousValue = _map.put(key, result); + assert(previousValue == null); + } + else + { + result._refCount++; + } + } + + return result; + } + + // + // Returns a shared map Db; the caller should NOT close this Db. + // + MapDb getSharedMapDb(String dbName, String key, String value, + java.util.Comparator comparator, Map.Index[] indices, java.util.Map indexComparators, + boolean createDb) + { + if(dbName.equals(_catalog.dbName())) + { + _catalog.checkTypes(key, value); + return _catalog; + } + else if(dbName.equals(_catalogIndexList.dbName())) + { + _catalogIndexList.checkTypes(key, value); + return _catalogIndexList; + } + + synchronized(_sharedDbMap) + { + MapDb db = _sharedDbMap.get(dbName); + if(db == null) + { + ConnectionI insertConnection = (ConnectionI)Util.createConnection(_key.communicator, _key.envName); + try { - result = new SharedDbEnv(key, dbEnv); + db = new MapDb(insertConnection, dbName, key, value, comparator, indices, indexComparators, createDb); } - catch(com.sleepycat.db.DatabaseException dx) + finally { - DatabaseException ex = new DatabaseException(); - ex.initCause(dx); - ex.message = errorPrefix(envName) + "creation: " + dx.getMessage(); - throw ex; + insertConnection.close(); } - Object previousValue = _map.put(key, result); + Object previousValue = _sharedDbMap.put(dbName, db); assert(previousValue == null); } else { - result._refCount++; + db.checkTypes(key, value); + db.connectIndices(indices); } + return db; } + } - // - // Make sure the result if fully initialized - // - result.init(); - return result; + // + // Tell SharedDbEnv to close and remove this Shared Db from the map + // + void removeSharedMapDb(String dbName) + { + synchronized(_sharedDbMap) + { + MapDb db = _sharedDbMap.remove(dbName); + if(db != null) + { + db.close(); + } + } } - + public String getEnvName() { @@ -68,20 +115,7 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable { return _dbEnv; } - - public SharedDb - getCatalog() - { - return _catalog; - } - - public SharedDb - getCatalogIndexList() - { - return _catalogIndexList; - } - - + public void close() { @@ -96,66 +130,9 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable assert(value == this); // - // Join thread - // - synchronized(this) - { - _done = true; - notify(); - } - - for(;;) - { - if(_thread != null) - { - try - { - _thread.join(); - _thread = null; - break; - } - catch(InterruptedException ex) - { - } - } - } - - // - // Release catalogs - // - if(_catalog != null) - { - _catalog.close(); - _catalog = null; - } - - if(_catalogIndexList != null) - { - _catalogIndexList.close(); - _catalogIndexList = null; - } - - if(_trace >= 1) - { - _key.communicator.getLogger().trace("Freeze.DbEnv", "closing database environment \"" + - _key.envName + "\""); - } - - // - // Keep lock to prevent somebody else from re-opening this DbEnv - // before it's closed. + // Cleanup with _map locked to prevent concurrent cleanup of the same dbEnv // - try - { - _dbEnv.close(); - } - catch(com.sleepycat.db.DatabaseException dx) - { - DatabaseException ex = new DatabaseException(); - ex.initCause(dx); - ex.message = errorPrefix(_key.envName) + "close: " + dx.getMessage(); - throw ex; - } + cleanup(); } } } @@ -287,7 +264,6 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable private SharedDbEnv(MapKey key, com.sleepycat.db.Environment dbEnv) - throws com.sleepycat.db.DatabaseException { _key = key; _dbEnv = dbEnv; @@ -296,104 +272,198 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable Ice.Properties properties = key.communicator.getProperties(); _trace = properties.getPropertyAsInt("Freeze.Trace.DbEnv"); - if(_ownDbEnv) + try { - com.sleepycat.db.EnvironmentConfig config = new com.sleepycat.db.EnvironmentConfig(); + if(_ownDbEnv) + { + com.sleepycat.db.EnvironmentConfig config = new com.sleepycat.db.EnvironmentConfig(); + + config.setErrorHandler(this); + config.setInitializeLocking(true); + config.setInitializeLogging(true); + config.setInitializeCache(true); + config.setAllowCreate(true); + config.setTransactional(true); - config.setErrorHandler(this); - config.setInitializeLocking(true); - config.setInitializeLogging(true); - config.setInitializeCache(true); - config.setAllowCreate(true); - config.setTransactional(true); + // + // Deadlock detection + // + config.setLockDetectMode(com.sleepycat.db.LockDetectMode.YOUNGEST); - // - // Deadlock detection - // - config.setLockDetectMode(com.sleepycat.db.LockDetectMode.YOUNGEST); + String propertyPrefix = "Freeze.DbEnv." + _key.envName; + if(properties.getPropertyAsInt(propertyPrefix + ".DbRecoverFatal") != 0) + { + config.setRunFatalRecovery(true); + } + else + { + config.setRunRecovery(true); + } - String propertyPrefix = "Freeze.DbEnv." + _key.envName; - if(properties.getPropertyAsInt(propertyPrefix + ".DbRecoverFatal") != 0) + if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".DbPrivate", 1) != 0) + { + config.setPrivate(true); + } + + if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".OldLogsAutoDelete", 1) != 0) + { + config.setLogAutoRemove(true); + } + + if(_trace >= 1) + { + _key.communicator.getLogger().trace("Freeze.DbEnv", "opening database environment \"" + + _key.envName + "\""); + } + + try + { + String dbHome = properties.getPropertyWithDefault(propertyPrefix + ".DbHome", _key.envName); + java.io.File home = new java.io.File(dbHome); + _dbEnv = new com.sleepycat.db.Environment(home, config); + } + catch(java.io.FileNotFoundException dx) + { + NotFoundException ex = new NotFoundException(); + ex.initCause(dx); + ex.message = errorPrefix(_key.envName) + "open: " + dx.getMessage(); + throw ex; + } + + // + // Default checkpoint period is every 120 seconds + // + _checkpointPeriod = + properties.getPropertyAsIntWithDefault(propertyPrefix + ".CheckpointPeriod", 120) * 1000; + + _kbyte = properties.getPropertyAsIntWithDefault(propertyPrefix + ".PeriodicCheckpointMinSize", 0); + + String threadName; + String programName = properties.getProperty("Ice.ProgramName"); + if(programName.length() > 0) + { + threadName = programName + "-"; + } + else + { + threadName = ""; + } + threadName += "FreezeCheckpointThread(" + _key.envName + ")"; + + if(_checkpointPeriod > 0) + { + _thread = new Thread(this, threadName); + _thread.start(); + } + } + + _catalog = new MapDb(_key.communicator, _key.envName, Util.catalogName(), "string", "::Freeze::CatalogData", _dbEnv); + _catalogIndexList = new MapDb(_key.communicator, _key.envName, Util.catalogIndexListName(), + "string", "::Ice::StringSeq", _dbEnv); + } + catch(com.sleepycat.db.DatabaseException dx) + { + cleanup(); + DatabaseException ex = new DatabaseException(); + ex.initCause(dx); + ex.message = errorPrefix(_key.envName) + "creation: " + dx.getMessage(); + throw ex; + } + catch(java.lang.RuntimeException ex) + { + cleanup(); + throw ex; + } + + _refCount = 1; + } + + private void + cleanup() + { + // + // Join thread + // + synchronized(this) + { + _done = true; + notify(); + } + + for(;;) + { + if(_thread != null) { - config.setRunFatalRecovery(true); + try + { + _thread.join(); + _thread = null; + break; + } + catch(InterruptedException ex) + { + } } - else + } + + // + // Release catalogs + // + if(_catalog != null) + { + try { - config.setRunRecovery(true); + _catalog.close(); } - - if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".DbPrivate", 1) != 0) + finally { - config.setPrivate(true); + _catalog = null; } - - if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".OldLogsAutoDelete", 1) != 0) + } + + if(_catalogIndexList != null) + { + try { - config.setLogAutoRemove(true); + _catalogIndexList.close(); } - - if(_trace >= 1) + finally { - _key.communicator.getLogger().trace("Freeze.DbEnv", "opening database environment \"" + - _key.envName + "\""); + _catalogIndexList = null; } - - // - // TODO: FREEZE_DB_MODE - // - + } + + // + // Close Dbs + // + for(MapDb db: _sharedDbMap.values()) + { + db.close(); + } + + if(_trace >= 1) + { + _key.communicator.getLogger().trace("Freeze.DbEnv", "closing database environment \"" + + _key.envName + "\""); + } + + if(_ownDbEnv && _dbEnv != null) + { try { - String dbHome = properties.getPropertyWithDefault(propertyPrefix + ".DbHome", _key.envName); - java.io.File home = new java.io.File(dbHome); - _dbEnv = new com.sleepycat.db.Environment(home, config); + _dbEnv.close(); } - catch(java.io.FileNotFoundException dx) + catch(com.sleepycat.db.DatabaseException dx) { - NotFoundException ex = new NotFoundException(); + DatabaseException ex = new DatabaseException(); ex.initCause(dx); - ex.message = errorPrefix(_key.envName) + "open: " + dx.getMessage(); + ex.message = errorPrefix(_key.envName) + "close: " + dx.getMessage(); throw ex; } - - // - // Default checkpoint period is every 120 seconds - // - _checkpointPeriod = - properties.getPropertyAsIntWithDefault(propertyPrefix + ".CheckpointPeriod", 120) * 1000; - - _kbyte = properties.getPropertyAsIntWithDefault(propertyPrefix + ".PeriodicCheckpointMinSize", 0); - - String threadName; - String programName = properties.getProperty("Ice.ProgramName"); - if(programName.length() > 0) + finally { - threadName = programName + "-"; + _dbEnv = null; } - else - { - threadName = ""; - } - threadName += "FreezeCheckpointThread(" + _key.envName + ")"; - - if(_checkpointPeriod > 0) - { - _thread = new Thread(this, threadName); - _thread.start(); - } - } - - _refCount = 1; - } - - private synchronized void - init() - { - if(_catalog == null) - { - SharedDb[] catalogs = SharedDb.openCatalogs(this); - _catalog = catalogs[0]; - _catalogIndexList = catalogs[1]; } } @@ -438,8 +508,8 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable private MapKey _key; private com.sleepycat.db.Environment _dbEnv; private boolean _ownDbEnv; - private SharedDb _catalog; - private SharedDb _catalogIndexList; + private MapDb _catalog; + private MapDb _catalogIndexList; private int _refCount = 0; // protected by _map! private boolean _done = false; private int _trace = 0; @@ -449,6 +519,8 @@ class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable private java.util.Map _ctxMap = new java.util.HashMap(); + private java.util.Map<String, MapDb> _sharedDbMap = new java.util.HashMap<String, MapDb>(); + // // Hash map of (MapKey, SharedDbEnv) // diff --git a/java/test/Freeze/dbmap/Client.java b/java/test/Freeze/dbmap/Client.java index 869a8166caf..f36500e133c 100644 --- a/java/test/Freeze/dbmap/Client.java +++ b/java/test/Freeze/dbmap/Client.java @@ -200,6 +200,18 @@ public class Client { Freeze.Connection connection = Freeze.Util.createConnection(communicator, envName); + // + // Open/close db within transaction + // + { + Transaction tx = connection.beginTransaction(); + ByteIntMap m = new ByteIntMap(connection, dbName, true); + + m.put(new Byte((byte)'a'), new Integer(1)); + m.close(); + tx.rollback(); + } + java.util.Map m = new ByteIntMap(connection, dbName, true); // @@ -614,7 +626,7 @@ public class Client } } tx.commit(); - iim.close(); + iim.closeDb(); } { |