diff options
Diffstat (limited to 'java/src')
-rw-r--r-- | java/src/Freeze/Application.java | 82 | ||||
-rw-r--r-- | java/src/Freeze/DBCursorI.java | 307 | ||||
-rw-r--r-- | java/src/Freeze/DBEnvironmentI.java | 327 | ||||
-rw-r--r-- | java/src/Freeze/DBI.java | 747 | ||||
-rw-r--r-- | java/src/Freeze/DBTransactionI.java | 128 | ||||
-rw-r--r-- | java/src/Freeze/EvictionStrategyI.java | 88 | ||||
-rw-r--r-- | java/src/Freeze/EvictorI.java | 1323 | ||||
-rw-r--r-- | java/src/Freeze/EvictorIteratorI.java | 155 | ||||
-rw-r--r-- | java/src/Freeze/IdleStrategyI.java | 112 | ||||
-rw-r--r-- | java/src/Freeze/Map.java | 1094 | ||||
-rw-r--r-- | java/src/Freeze/SharedDbEnv.java | 368 | ||||
-rw-r--r-- | java/src/Freeze/Util.java | 17 | ||||
-rw-r--r-- | java/src/Ice/PropertiesI.java | 3 | ||||
-rw-r--r-- | java/src/IceBox/ServiceManagerI.java | 42 |
14 files changed, 2313 insertions, 2480 deletions
diff --git a/java/src/Freeze/Application.java b/java/src/Freeze/Application.java deleted file mode 100644 index 3bbf724fa81..00000000000 --- a/java/src/Freeze/Application.java +++ /dev/null @@ -1,82 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -public abstract class Application extends Ice.Application -{ - public - Application(String dbEnvName) - { - _dbEnvName = dbEnvName; - } - - public int - run(String[] args) - { - int status; - DBEnvironment dbEnv = null; - - try - { - dbEnv = Freeze.Util.initialize(communicator(), _dbEnvName); - status = runFreeze(args, dbEnv); - } - catch(DBException ex) - { - System.err.println(appName() + ": " + ex + ": " + ex.message); - status = 1; - } - catch(Ice.LocalException ex) - { - System.err.println(appName() + ": " + ex); - ex.printStackTrace(); - status = 1; - } - catch(Exception ex) - { - System.err.println(appName() + ": unknown exception"); - ex.printStackTrace(); - status = 1; - } - - if(dbEnv != null) - { - try - { - dbEnv.close(); - } - catch(DBException ex) - { - System.err.println(appName() + ": " + ex + ": " + ex.message); - ex.printStackTrace(); - status = 1; - } - catch(Exception ex) - { - System.err.println(appName() + ": unknown exception"); - ex.printStackTrace(); - status = 1; - } - dbEnv = null; - } - - return status; - } - - public abstract int - runFreeze(String[] args, DBEnvironment dbEnv); - - private String _dbEnvName; -} diff --git a/java/src/Freeze/DBCursorI.java b/java/src/Freeze/DBCursorI.java deleted file mode 100644 index e67c6be3718..00000000000 --- a/java/src/Freeze/DBCursorI.java +++ /dev/null @@ -1,307 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -class DBCursorI extends Ice.LocalObjectImpl implements DBCursor -{ - public Ice.Communicator - getCommunicator() - { - // immutable - return _communicator; - } - - synchronized public void - curr(KeyHolder k, ValueHolder v) - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "reading current value from database \"" + _name + "\""); - } - - try - { - int rc = _cursor.get(dbKey, dbData, com.sleepycat.db.Db.DB_CURRENT); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Dbc.get: DB_NOTFOUND"; - throw ex; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - - // - // Copy the data from the read key & data - // - k.value = dbKey.get_data(); - v.value = dbData.get_data(); - } - - synchronized public void - set(byte[] v) - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - // - // TODO: Although the API docs say that the key argument to Dbc.put() - // is ignored, an exception is raised if the Dbt object isn't initialized. - // Sleepycat has acknowledged that this is a bug. - // - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(new byte[0]); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(v); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "setting current value in database \"" + _name + "\""); - } - - try - { - int rc = _cursor.put(dbKey, dbData, com.sleepycat.db.Db.DB_CURRENT); - /* Since the underlying data is btree this cannot occur. - * - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Dbc.put: DB_NOTFOUND"; - throw ex; - } - */ - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.put: " + e.getMessage(); - throw ex; - } - } - - synchronized public boolean - next() - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); - dbKey.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - dbData.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "moving to next value in database \"" + _name + "\""); - } - - try - { - int rc = _cursor.get(dbKey, dbData, com.sleepycat.db.Db.DB_NEXT); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - return false; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - - return true; - } - - synchronized public boolean - prev() - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); - dbKey.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - dbData.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "moving to previous value in database \"" + _name + "\""); - } - - try - { - int rc = _cursor.get(dbKey, dbData, com.sleepycat.db.Db.DB_PREV); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - return false; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - - return true; - } - - synchronized public void - del() - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "removing the current element in database \"" + _name + "\""); - } - - try - { - int rc = _cursor.del(0); - if(rc == com.sleepycat.db.Db.DB_KEYEMPTY) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "Dbc.del: DB_KEYEMPTY"; - throw ex; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - } - - synchronized public DBCursor - _clone() - { - if(_cursor == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbc cursor; - try - { - cursor = _cursor.dup(com.sleepycat.db.Db.DB_POSITION); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.close: " + e.getMessage(); - throw ex; - } - return new DBCursorI(_communicator, _name, cursor); - } - - synchronized public void - close() - { - if(_cursor == null) - { - return; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "closing cursor \"" + _name + "\""); - } - - try - { - _cursor.close(); - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.close: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.close: " + e.getMessage(); - throw ex; - } - - _cursor = null; - } - - DBCursorI(Ice.Communicator communicator, String name, com.sleepycat.db.Dbc cursor) - { - _communicator = communicator; - _name = name; - _cursor = cursor; - _errorPrefix = "Freeze::DBCursor(\"" + _name + "\"): "; - _trace = _communicator.getProperties().getPropertyAsInt("Freeze.Trace.DB"); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "creating cursor for \"" + _name + "\""); - } - } - - private Ice.Communicator _communicator; - private int _trace = 0; - - private String _name; - private String _errorPrefix; - - private com.sleepycat.db.Dbc _cursor; -} diff --git a/java/src/Freeze/DBEnvironmentI.java b/java/src/Freeze/DBEnvironmentI.java deleted file mode 100644 index 974e10b1e31..00000000000 --- a/java/src/Freeze/DBEnvironmentI.java +++ /dev/null @@ -1,327 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -class DBEnvironmentI extends Ice.LocalObjectImpl implements DBEnvironment, com.sleepycat.db.DbErrcall -{ - public String - getName() - { - // No mutex lock necessary, _name is immutable - return _name; - } - - public Ice.Communicator - getCommunicator() - { - // No mutex lock necessary, _communicator is immutable - return _communicator; - } - - synchronized public DB - openDB(String name, boolean create) - { - return openDBImpl(null, name, create); - } - - synchronized public DB - openDBWithTxn(DBTransaction t, String name, boolean create) - { - DBTransaction txn = t; - if(t == null) - { - txn = startTransaction(); - } - - DB db = openDBImpl(((DBTransactionI)txn).getTxnId(), name, create); - - if(t == null) - { - txn.commit(); - } - - return db; - } - - public DBTransaction - startTransaction() - { - return new DBTransactionI(_communicator, _dbEnv, _name); - } - - synchronized public void - close() - { - if(_dbEnv == null) - { - return; - } - - // - // Build a list of values from the iterator. The iterator - // cannot be used directly since closing each database - // modifies the content of the map (hence invalidating the - // iterator). - // - java.util.List dbs = new java.util.ArrayList(); - java.util.Iterator p = _dbMap.values().iterator(); - while(p.hasNext()) - { - dbs.add(p.next()); - } - - p = dbs.iterator(); - while(p.hasNext()) - { - DB db = (DB)p.next(); - db.close(); - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "closing database environment \"" + _name + "\""); - } - - try - { - _dbEnv.close(0); - } - catch(com.sleepycat.db.DbException e) - { - _dbEnv = null; - - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbEnv.close: " + e.getMessage(); - throw ex; - } - - _dbEnv = null; - } - - synchronized public void - sync() - { - if(_dbEnv == null) - { - return; - } - - java.util.Iterator p = _dbMap.values().iterator(); - while(p.hasNext()) - { - DB db = (DB)p.next(); - db.sync(); - } - } - - protected DB - openDBImpl(com.sleepycat.db.DbTxn txn, String name, boolean create) - { - if(_dbEnv == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - DB p = (DB)_dbMap.get(name); - if(p != null) - { - return p; - } - - com.sleepycat.db.Db db; - - try - { - db = new com.sleepycat.db.Db(_dbEnv, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.Db: " + e.getMessage(); - throw ex; - } - - try - { - return new DBI(_communicator, this, db, txn, name, create); - } - catch(DBException e) - { - try - { - db.close(0); - } - catch(com.sleepycat.db.DbException ignore) - { - } - throw e; - } - } - - synchronized protected void - add(String name, DB db) - { - _dbMap.put(name, db); - } - - synchronized protected void - remove(String name) - { - _dbMap.remove(name); - } - - synchronized protected void - eraseDB(String name) - { - // - // The database should not be open. - // - assert(_dbMap.get(name) == null); - - com.sleepycat.db.Db db; - try - { - db = new com.sleepycat.db.Db(_dbEnv, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.Db: " + e.getMessage(); - throw ex; - } - - try - { - // - // Any failure in remove will cause the database to be - // closed. - // - db.remove(name, null, 0); - } - catch(java.io.FileNotFoundException e) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.remove: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.remove: " + e.getMessage(); - throw ex; - } - } - - DBEnvironmentI(Ice.Communicator communicator, String name, boolean txn) - { - _communicator = communicator; - _name = name; - _errorPrefix = "Freeze::DBEnvironment(\"" + _name + "\"): "; - _trace = getCommunicator().getProperties().getPropertyAsInt("Freeze.Trace.DB"); - - try - { - _dbEnv = new com.sleepycat.db.DbEnv(0); - // - // This is a portability workaround. The DbEnv constructor - // is declared as throwing DbException in version 4.1.x, - // but not in earlier versions. Without a bogus throw - // statement, the compiler will complain. - // - if(_dbEnv == null) - { - throw new com.sleepycat.db.DbException(""); - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbEnv.init: " + e.getMessage(); - throw ex; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "opening database environment \"" + _name + "\""); - } - - int flags = com.sleepycat.db.Db.DB_CREATE | com.sleepycat.db.Db.DB_INIT_LOCK | - com.sleepycat.db.Db.DB_INIT_MPOOL; - - if(txn) - { - flags = flags | com.sleepycat.db.Db.DB_INIT_LOG | com.sleepycat.db.Db.DB_INIT_TXN | - com.sleepycat.db.Db.DB_RECOVER; - } - - // - // Use process-private memory and mutexes. In the way we can use a - // Berkeley DB built using the POSIX thread library on Linux, like the - // Berkeley DB that comes with RedHat 9. - // - // TODO: make setting or not setting DB_PRIVATE configurable. - // When DB_PRIVATE is set, only one process can use a DB environment - // at a time. - // - - flags |= com.sleepycat.db.Db.DB_PRIVATE; - - try - { - _dbEnv.open(_name, flags, 0); //TODO: FREEZE_DB_MODE) - } - catch(java.io.FileNotFoundException e) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbEnv.open: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbEnv.open: " + e.getMessage(); - throw ex; - } - - _dbEnv.set_errcall(this); - } - - // - // com.sleepycat.db.DbErrcall interface implementation. - // - public void - errcall(String errorPrefix, String message) - { - _communicator.getLogger().error("Freeze database error: " + _name + ": " + message); - } - - private Ice.Communicator _communicator; - private int _trace = 0; - private com.sleepycat.db.DbEnv _dbEnv; - private String _name; - private String _errorPrefix; - - private java.util.HashMap _dbMap = new java.util.HashMap(); -} diff --git a/java/src/Freeze/DBI.java b/java/src/Freeze/DBI.java deleted file mode 100644 index 155d82c7c23..00000000000 --- a/java/src/Freeze/DBI.java +++ /dev/null @@ -1,747 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -class DBI extends Ice.LocalObjectImpl implements DB -{ - public String - getName() - { - // No mutex lock necessary, _name is immutable - return _name; - } - - public Ice.Communicator - getCommunicator() - { - // No mutex lock necessary, _communicator is immutable - return _communicator; - } - - synchronized public long - getNumberOfRecords() - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - // - // TODO: DB_FAST_STAT doesn't seem to do what the - // documentation says... - // - try - { - com.sleepycat.db.DbBtreeStat s = (com.sleepycat.db.DbBtreeStat)_db.stat(0); - return s.bt_ndata; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.stat: " + e.getMessage(); - throw ex; - } - } - - synchronized public DBCursor - getCursor() - { - return getCursorImpl(null); - } - - synchronized public DBCursor - getCursorAtKey(byte[] key) - { - return getCursorAtKeyImpl(null, key); - } - - synchronized public void - put(byte[] key, byte[] value) - { - putImpl(null, key, value); - } - - synchronized public boolean - contains(byte[] key) - { - return containsImpl(null, key); - } - - synchronized public byte[] - get(byte[] key) - { - return getImpl(null, key); - } - - synchronized public void - del(byte[] key) - { - delImpl(null, key); - } - - synchronized public DBCursor - getCursorWithTxn(DBTransaction txn) - { - assert txn != null; - return getCursorImpl(((DBTransactionI)txn).getTxnId()); - } - - synchronized public DBCursor - getCursorAtKeyWithTxn(DBTransaction txn, byte[] key) - { - assert txn != null; - return getCursorAtKeyImpl(((DBTransactionI)txn).getTxnId(), key); - } - - synchronized public void - putWithTxn(DBTransaction txn, byte[] key, byte[] value) - { - assert txn != null; - putImpl(((DBTransactionI)txn).getTxnId(), key, value); - } - - synchronized public boolean - containsWithTxn(DBTransaction txn, byte[] key) - { - assert txn != null; - return containsImpl(((DBTransactionI)txn).getTxnId(), key); - } - - synchronized public byte[] - getWithTxn(DBTransaction txn, byte[] key) - { - assert txn != null; - return getImpl(((DBTransactionI)txn).getTxnId(), key); - } - - synchronized public void - delWithTxn(DBTransaction txn, byte[] key) - { - assert txn != null; - delImpl(((DBTransactionI)txn).getTxnId(), key); - } - - synchronized public void - clear() - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - int count; // ignored - try - { - _db.truncate(null, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.truncate: " + e.getMessage(); - throw ex; - } - } - - synchronized public void - close() - { - if(_db == null) - { - return; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "closing database \"" + _name + "\""); - } - - try - { - _db.close(0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.truncate: " + e.getMessage(); - throw ex; - } - - _dbEnvObj.remove(_name); - _dbEnvObj = null; - _db = null; - } - - synchronized public void - remove() - { - if(_db == null) - { - return; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "removing database \"" + _name + "\""); - } - - // - // Remove first needs to close the database object. It's not - // possible to remove an open database. - // - try - { - _db.close(0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.remove: " + e.getMessage(); - throw ex; - } - - // - // Take a copy of the DBEnvironment to make cleanup easier. - // - DBEnvironmentI dbEnvCopy = _dbEnvObj; - - _dbEnvObj.remove(_name); - _dbEnvObj = null; - _db = null; - - // - // Ask the DBEnvironment to erase the database. - // - dbEnvCopy.eraseDB(_name); - } - - synchronized public void - sync() - { - if(_db == null) - { - return; - } - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "synchronizing database \"" + _name + "\""); - } - - try - { - _db.sync(0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.sync: " + e.getMessage(); - throw ex; - } - } - - public EvictionStrategy - createEvictionStrategy() - { - return new EvictionStrategyI(); - } - - public IdleStrategy - createIdleStrategy() - { - return new IdleStrategyI(); - } - - synchronized public Evictor - createEvictor(PersistenceStrategy strategy) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - return new EvictorI(this, strategy); - } - - DBI(Ice.Communicator communicator, DBEnvironmentI dbEnvObj, com.sleepycat.db.Db db, com.sleepycat.db.DbTxn txn, - String name, boolean create) - { - _communicator = communicator; - _dbEnvObj = dbEnvObj; - _db = db; - _name = name; - _errorPrefix = "Freeze::DB(\"" + _name + "\"): "; - _trace = _communicator.getProperties().getPropertyAsInt("Freeze.Trace.DB"); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB","opening database \"" + _name + "\" in environment \"" + - _dbEnvObj.getName() + "\""); - } - - int flags = (create) ? com.sleepycat.db.Db.DB_CREATE : 0; - try - { - // - // The signature for the open() method changed in version 4.1. - // We use reflection to invoke it with the proper arguments. - // - java.lang.reflect.Method m; - Class[] types; - Object[] args; - if(com.sleepycat.db.Db.DB_VERSION_MAJOR > 4 || - (com.sleepycat.db.Db.DB_VERSION_MAJOR == 4 && com.sleepycat.db.Db.DB_VERSION_MINOR >= 1)) - { - types = new Class[6]; - types[0] = com.sleepycat.db.DbTxn.class; - types[1] = String.class; - types[2] = String.class; - types[3] = Integer.TYPE; - types[4] = Integer.TYPE; - types[5] = Integer.TYPE; - args = new Object[6]; - args[0] = txn; - args[1] = _name; - args[2] = null; - args[3] = new Integer(com.sleepycat.db.Db.DB_BTREE); - args[4] = new Integer(flags); - args[5] = new Integer(0); - // - // Equivalent to: - // - //_db.open(null, _name, null, com.sleepycat.db.Db.DB_BTREE, flags, 0); - } - else - { - types = new Class[5]; - types[0] = String.class; - types[1] = String.class; - types[2] = Integer.TYPE; - types[3] = Integer.TYPE; - types[4] = Integer.TYPE; - args = new Object[5]; - args[0] = _name; - args[1] = null; - args[2] = new Integer(com.sleepycat.db.Db.DB_BTREE); - args[3] = new Integer(flags); - args[4] = new Integer(0); - // - // Equivalent to: - // - //_db.open(_name, null, com.sleepycat.db.Db.DB_BTREE, flags, 0); - } - - m = com.sleepycat.db.Db.class.getDeclaredMethod("open", types); - m.invoke(_db, args); - //TODO: FREEZE_DB_MODE - } - catch(NoSuchMethodException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = "reflection error"; - throw ex; - } - catch(IllegalAccessException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = "reflection error"; - throw ex; - } - catch(IllegalArgumentException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = "reflection error"; - throw ex; - } - catch(java.lang.reflect.InvocationTargetException e) - { - Throwable t = e.getCause(); - if(t instanceof java.io.FileNotFoundException) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.initCause(t); - ex.message = _errorPrefix + "Db.open: " + t.getMessage(); - throw ex; - } - else if(t instanceof com.sleepycat.db.DbException) - { - DBException ex = new DBException(); - ex.initCause(t); - ex.message = _errorPrefix + "Db.open: " + t.getMessage(); - throw ex; - } - else - { - DBException ex = new DBException(); - ex.initCause(t); - ex.message = "Db.open: unexpected exception"; - throw ex; - } - } - - _dbEnvObj.add(_name, this); - } - - private DBCursor - getCursorImpl(com.sleepycat.db.DbTxn txn) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbc cursor; - - try - { - cursor = _db.cursor(txn, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.cursor: " + e.getMessage(); - throw ex; - } - - // - // Note that the read of the data is partial (that is the data - // will not actually be read into memory since it isn't needed - // yet). - // - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - dbData.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); - dbKey.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - - try - { - try - { - int rc = cursor.get(dbKey, dbData, com.sleepycat.db.Db.DB_FIRST); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Dbc.get: DB_NOTFOUND"; - throw ex; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - } - catch(DBException e) - { - // - // Cleanup on failure. - // - try - { - cursor.close(); - } - catch(com.sleepycat.db.DbException ignore) - { - // Ignore - } - throw e; - } - - return new DBCursorI(_communicator, _name, cursor); - } - - private DBCursor - getCursorAtKeyImpl(com.sleepycat.db.DbTxn txn, byte[] key) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbc cursor; - - try - { - cursor = _db.cursor(txn, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.cursor: " + e.getMessage(); - throw ex; - } - - // - // Move to the requested record - // - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - - // - // Note that the read of the data is partial (that is the data - // will not actually be read into memory since it isn't needed - // yet). - // - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - dbData.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - - try - { - try - { - int rc = cursor.get(dbKey, dbData, com.sleepycat.db.Db.DB_SET); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Dbc.get: DB_NOTFOUND"; - throw ex; - } - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Dbc.get: " + e.getMessage(); - throw ex; - } - } - catch(DBException e) - { - // - // Cleanup on failure. - // - try - { - cursor.close(); - } - catch(com.sleepycat.db.DbException ignore) - { - // Ignore - } - throw e; - } - - return new DBCursorI(_communicator, _name, cursor); - } - - private void - putImpl(com.sleepycat.db.DbTxn txn, byte[] key, byte[] value) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - // - // TODO: This can be optimized so that these only need to be - // allocated once. - // - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(value); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "writing value in database \"" + _name + "\""); - } - - try - { - _db.put(txn, dbKey, dbData, 0); - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.put: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.put: " + e.getMessage(); - throw ex; - } - } - - private boolean - containsImpl(com.sleepycat.db.DbTxn txn, byte[] key) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - dbData.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "checking key in database \"" + _name + "\""); - } - - try - { - int rc =_db.get(txn, dbKey, dbData, 0); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - return false; - } - else - { - assert(rc == 0); - return true; - } - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.get: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.get: " + e.getMessage(); - throw ex; - } - } - - private byte[] - getImpl(com.sleepycat.db.DbTxn txn, byte[] key) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - com.sleepycat.db.Dbt dbData = new com.sleepycat.db.Dbt(); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "reading value from database \"" + _name + "\""); - } - - try - { - int rc =_db.get(txn, dbKey, dbData, 0); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Db.get: DB_NOTFOUND"; - throw ex; - } - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.get: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.get: " + e.getMessage(); - throw ex; - } - - return dbData.get_data(); - } - - private void - delImpl(com.sleepycat.db.DbTxn txn, byte[] key) - { - if(_db == null) - { - DBException ex = new DBException(); - ex.message = _errorPrefix + "\"" + _name + "\" has been closed"; - throw ex; - } - - com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); - - if(_trace >= 1) - { - _communicator.getLogger().trace("DB", "deleting value from database \"" + _name + "\""); - } - - try - { - int rc =_db.del(txn, dbKey, 0); - if(rc == com.sleepycat.db.Db.DB_NOTFOUND) - { - DBNotFoundException ex = new DBNotFoundException(); - ex.message = _errorPrefix + "Db.del: DB_NOTFOUND"; - throw ex; - } - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.del: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "Db.del: " + e.getMessage(); - throw ex; - } - } - - private Ice.Communicator _communicator; - private int _trace = 0; - - private DBEnvironmentI _dbEnvObj; - private com.sleepycat.db.Db _db; - - private String _name; - private String _errorPrefix; -} diff --git a/java/src/Freeze/DBTransactionI.java b/java/src/Freeze/DBTransactionI.java deleted file mode 100644 index 1e31ad9a13a..00000000000 --- a/java/src/Freeze/DBTransactionI.java +++ /dev/null @@ -1,128 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -class DBTransactionI extends Ice.LocalObjectImpl implements DBTransaction -{ - public synchronized void - commit() - { - if(_tid == null) - { - String s = _errorPrefix + "transaction has already been committed or aborted"; - DBException ex = new DBException(); - ex.message = s; - throw ex; - } - - if(_trace >= 2) - { - _communicator.getLogger().trace("DB", "committing transaction for environment \"" + _name + "\""); - } - - try - { - _tid.commit(0); - } - catch(com.sleepycat.db.DbDeadlockException e) - { - DBDeadlockException ex = new DBDeadlockException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbTxn.commit: " + e.getMessage(); - throw ex; - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbTxn.commit: " + e.getMessage(); - throw ex; - } - - _tid = null; - } - - public synchronized void - abort() - { - if(_tid == null) - { - String s = _errorPrefix + "transaction has already been committed or aborted"; - DBException ex = new DBException(); - ex.message = s; - throw ex; - } - - if(_trace >= 2) - { - _communicator.getLogger().trace("DB", "aborting transaction for environment \"" + _name + - "\" due to deadlock"); - } - - try - { - _tid.abort(); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbTxn.abort: " + e.getMessage(); - throw ex; - } - - _tid = null; - } - - com.sleepycat.db.DbTxn - getTxnId() - { - return _tid; - } - - - DBTransactionI(Ice.Communicator communicator, com.sleepycat.db.DbEnv dbEnv, String name) - { - _communicator = communicator; - _name = name; - _errorPrefix = "Freeze::DBTransaction(\"" + _name + "\"): "; - _trace = _communicator.getProperties().getPropertyAsInt("Freeze.Trace.DB"); - - if(_trace >= 2) - { - _communicator.getLogger().trace("DB", "starting transaction for environment \"" + _name + "\""); - } - - try - { - _tid = dbEnv.txn_begin(null, 0); - } - catch(com.sleepycat.db.DbException e) - { - DBException ex = new DBException(); - ex.initCause(e); - ex.message = _errorPrefix + "DbEnv.txn_begin: " + e.getMessage(); - throw ex; - } - } - - private Ice.Communicator _communicator; - private int _trace = 0; - - private com.sleepycat.db.DbTxn _tid; - - private String _name; - private String _errorPrefix; -} diff --git a/java/src/Freeze/EvictionStrategyI.java b/java/src/Freeze/EvictionStrategyI.java deleted file mode 100644 index f95fe0c1f72..00000000000 --- a/java/src/Freeze/EvictionStrategyI.java +++ /dev/null @@ -1,88 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -public final class EvictionStrategyI extends Ice.LocalObjectImpl implements EvictionStrategy -{ - public - EvictionStrategyI() - { - } - - public Ice.LocalObject - activatedObject(Ice.Identity ident, Ice.Object servant) - { - return new Cookie(); - } - - public void - destroyedObject(Ice.Identity ident, Ice.LocalObject cookie) - { - // Nothing to do - } - - public void - evictedObject(ObjectStore store, Ice.Identity ident, Ice.Object servant, Ice.LocalObject cookie) - { - // - // Only store the object's persistent state if it has been mutated. - // - Cookie c = (Cookie)cookie; - if(c.mutated) - { - store.save(ident, servant); - c.mutated = false; - } - } - - public void - savedObject(ObjectStore store, Ice.Identity ident, Ice.Object servant, Ice.LocalObject cookie, int usageCount) - { - assert(usageCount > 0); - - if(usageCount == 1) - { - Cookie c = (Cookie)cookie; - c.mutated = false; - } - } - - public void - preOperation(ObjectStore store, Ice.Identity ident, Ice.Object servant, boolean mutating, Ice.LocalObject cookie) - { - if(mutating) - { - Cookie c = (Cookie)cookie; - c.mutated = true; - } - } - - public void - postOperation(ObjectStore store, Ice.Identity ident, Ice.Object servant, boolean mutating, Ice.LocalObject cookie) - { - // Nothing to do - } - - public void - destroy() - { - // Nothing to do - } - - private static class Cookie extends Ice.LocalObjectImpl - { - boolean mutated = false; - } -} diff --git a/java/src/Freeze/EvictorI.java b/java/src/Freeze/EvictorI.java index 9a80a82122c..77b6084e3b6 100644 --- a/java/src/Freeze/EvictorI.java +++ b/java/src/Freeze/EvictorI.java @@ -14,30 +14,37 @@ package Freeze; -class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore +class EvictorI extends Ice.LocalObjectImpl implements Evictor, Runnable { - synchronized public DB - getDB() + public EvictorI(Ice.Communicator communicator, String envName, + String dbName, boolean createDb) { - if(_deactivated) - { - throw new EvictorDeactivatedException(); - } + _communicator = communicator; + _dbEnvHolder = SharedDbEnv.get(communicator, envName); + _dbEnv = _dbEnvHolder; - return _db; + init(envName, dbName, createDb); } - synchronized public PersistenceStrategy - getPersistenceStrategy() + public EvictorI(Ice.Communicator communicator, com.sleepycat.db.DbEnv dbEnv, + String dbName, boolean createDb) + { + _communicator = communicator; + _dbEnvHolder = null; + _dbEnv = dbEnv; + + init("External", dbName, createDb); + } + + protected void + finalize() { - if(_deactivated) + if(!_deactivated) { - throw new EvictorDeactivatedException(); + _communicator.getLogger().warning("evictor has not been deactivated"); } - - return _strategy; } - + synchronized public void setSize(int evictorSize) { @@ -77,6 +84,17 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore } synchronized public void + saveNow() + { + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + saveNowNoSync(); + } + + synchronized public void createObject(Ice.Identity ident, Ice.Object servant) { if(_deactivated) @@ -85,39 +103,113 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore } // - // Copy the identity. This is necessary for add(). + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) // Ice.Identity identCopy = new Ice.Identity(); identCopy.name = ident.name; identCopy.category = ident.category; + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + if(element != null) + { + synchronized(element) + { + switch(element.status) + { + case clean: + { + element.status = modified; + addToModifiedQueue(identCopy, element); + break; + } + case created: + case modified: + { + // + // Nothing to do. + // No need to push it on the modified queue as a created resp + // modified element is either already on the queue or about + // to be saved. When saved, it becomes clean. + // + break; + } + case destroyed: + { + element.status = modified; + // + // No need to push it on the modified queue, as a destroyed element + // is either already on the queue or about to be saved. When saved, + // it becomes dead. + // + break; + } + case dead: + { + element.status = created; + addToModifiedQueue(identCopy, element); + break; + } + default: + { + assert(false); + break; + } + } + element.rec.servant = servant; + } - ObjectRecord rec = new ObjectRecord(); - rec.servant = servant; - rec.stats = new Statistics(); - rec.stats.creationTime = System.currentTimeMillis(); - rec.stats.lastSaveTime = 0; - rec.stats.avgSaveTime = 0; - - // - // Save the Ice object's initial state and add it to the queue. - // - _dict.fastPut(ident, rec); - add(identCopy, rec); - - if(_trace >= 1) + element.position.remove(); + _evictorList.addFirst(identCopy); + element.position = _evictorList.iterator(); + } + else { - _db.getCommunicator().getLogger().trace("Freeze::Evictor", - "created \"" + Ice.Util.identityToString(ident) + "\""); + // + // Create a new object + // + + ObjectRecord rec = new ObjectRecord(); + rec.servant = servant; + rec.stats = new Statistics(); + rec.stats.creationTime = System.currentTimeMillis(); + rec.stats.lastSaveTime = 0; + rec.stats.avgSaveTime = 0; + + // + // Add an Ice object with its servant to the evictor queue. + // + element = new EvictorElement(); + element.rec = rec; + element.usageCount = 0; + element.status = created; + + _evictorMap.put(identCopy, element); + _evictorList.addFirst(identCopy); + + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + + addToModifiedQueue(identCopy, element); + + // + // Evict as many elements as necessary. + // + evict(); } - // - // Evict as many elements as necessary. - // - evict(); + if(_trace >= 1) + { + _communicator.getLogger().trace("Freeze::Evictor", + "created \"" + Ice.Util.identityToString(ident) + "\""); + } } synchronized public void - saveObject(Ice.Identity ident) + destroyObject(Ice.Identity ident) { if(_deactivated) { @@ -125,46 +217,110 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore } EvictorElement element = (EvictorElement)_evictorMap.get(ident); - if(element == null) + if(element != null) { - throw new ObjectDestroyedException(); - } - assert(!element.destroyed); + synchronized(element) + { + switch(element.status) + { + case clean: + { + element.status = destroyed; - save(ident, element.rec.servant); - _strategy.savedObject(this, ident, element.rec.servant, element.strategyCookie, element.usageCount); - } + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; + + addToModifiedQueue(identCopy, element); + break; + } + case created: + { + element.status = dead; + break; + } + case modified: + { + element.status = destroyed; + // + // Not necessary to push it on the modified queue, as a modified + // element is either on the queue already or about to be saved + // (at which point it becomes clean) + // + break; + } + case destroyed: + case dead: + { + // + // Nothing to do! + // + break; + } + default: + { + assert(false); + break; + } + } + } + } + else + { + // + // Set a real ObjectRecord in case this object gets recreated + // + ObjectRecord rec = new ObjectRecord(); + rec.servant = null; + rec.stats = new Statistics(); + rec.stats.creationTime = System.currentTimeMillis(); + rec.stats.lastSaveTime = 0; + rec.stats.avgSaveTime = 0; - synchronized public void - destroyObject(Ice.Identity ident) - { - if(_deactivated) - { - throw new EvictorDeactivatedException(); + // + // Add an Ice object with its servant to the evictor queue. + // + element = new EvictorElement(); + element.rec = rec; + element.usageCount = 0; + element.status = destroyed; + + + // + // Make a copy of ident in case the user later changes it + // (used when inserting into list or map) + // + Ice.Identity identCopy = new Ice.Identity(); + identCopy.name = ident.name; + identCopy.category = ident.category; + + _evictorMap.put(identCopy, element); + _evictorList.addFirst(identCopy); + + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + + addToModifiedQueue(identCopy, element); + + // + // Evict as many elements as necessary. + // + evict(); } - - EvictorElement element = remove(ident); - if(element != null) + + if(_trace >= 1) { - element.destroyed = true; - - // - // Notify the persistence strategy. - // - _strategy.destroyedObject(ident, element.strategyCookie); - - if(_trace >= 1) - { - _db.getCommunicator().getLogger().trace("Freeze::Evictor", "destroyed \"" + - Ice.Util.identityToString(ident) + "\""); - } + _communicator.getLogger().trace("Freeze::Evictor", "destroyed \"" + + Ice.Util.identityToString(ident) + "\""); } - - // - // Delete the Ice object from the database. - // - _dict.fastRemove(ident); } synchronized public void @@ -178,239 +334,671 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore _initializer = initializer; } - synchronized public EvictorIterator + public EvictorIterator getIterator() { - if(_deactivated) + synchronized(this) { - throw new EvictorDeactivatedException(); + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + saveNowNoSync(); } - return new EvictorIteratorI(_dict.entrySet().iterator()); + return new EvictorIteratorI(_db, _communicator, _errorPrefix); } synchronized public boolean hasObject(Ice.Identity ident) { - if(_deactivated) + synchronized(this) { - throw new EvictorDeactivatedException(); + if(_deactivated) + { + throw new EvictorDeactivatedException(); + } + + EvictorElement element = (EvictorElement)_evictorMap.get(ident); + if(element != null) + { + synchronized(element) + { + return (element.status != destroyed && element.status != dead); + } + } } - return _dict.containsKey(ident); + return dbHasObject(ident); } - synchronized public Ice.Object + public Ice.Object locate(Ice.Current current, Ice.LocalObjectHolder cookie) { - assert(_db != null); - - // - // If this operation is called on a deactivated servant locator, - // it's a bug in Ice. // - assert(!_deactivated); - - // - // First copy current.identity. This is necessary since this - // identity is later added to the evictor list (and - // potentially the map). + // Need to copy current.id, as Ice caches and reuses it // Ice.Identity ident = new Ice.Identity(); ident.name = current.id.name; ident.category = current.id.category; - - EvictorElement element = (EvictorElement)_evictorMap.get(ident); - if(element != null) + + ObjectRecord rec = null; + + for(;;) { - if(_trace >= 2) + EvictorElement element; + + synchronized(this) { - _db.getCommunicator().getLogger().trace("Freeze::Evictor", - "found \"" + Ice.Util.identityToString(ident) + - "\" in the queue"); - } - - // - // Ice object found in evictor map. Push it to the front of - // the evictor list, so that it will be evicted last. - // - element.position.remove(); - _evictorList.addFirst(ident); - element.position = _evictorList.iterator(); + // + // If this operation is called on a deactivated servant locator, + // it's a bug in Ice. + // + assert(!_deactivated); - // - // Position the iterator "on" the element. - // - element.position.next(); - } - else - { - if(_trace >= 2) + element = (EvictorElement)_evictorMap.get(ident); + + if(element != null) + { + // + // Ice object found in evictor map. Push it to the front of + // the evictor list, so that it will be evicted last. + // + element.position.remove(); + _evictorList.addFirst(ident); + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + + element.usageCount++; + cookie.value = (Ice.LocalObject)element; + + // + // Later (after releasing the mutex), check that this + // object is not dead or destroyed + // + } + else if(rec != null) + { + // + // Proceed with the object loaded in the previous loop + // + + // + // If an initializer is installed, call it now. + // + if(_initializer != null) + { + _initializer.initialize(current.adapter, ident, rec.servant); + } + + // + // Add an Ice object with its servant to the evictor queue. + // + + element = new EvictorElement(); + element.rec = rec; + element.usageCount = 1; + element.status = clean; + + _evictorMap.put(ident, element); + _evictorList.addFirst(ident); + + element.position = _evictorList.iterator(); + // + // Position the iterator "on" the element. + // + element.position.next(); + + cookie.value = (Ice.LocalObject)element; + + // + // Evict as many elements as necessary. + // + evict(); + + return rec.servant; + } + // + // Else fall to the after-sync processing + // + } + + if(element != null) { - _db.getCommunicator().getLogger().trace( - "Freeze::Evictor", - "couldn't find \"" + Ice.Util.identityToString(ident) + "\" in the queue\n" - + "loading \"" + Ice.Util.identityToString(ident) + "\" from the database"); + if(_trace >= 2) + { + _communicator.getLogger().trace("Freeze::Evictor", + "found \"" + Ice.Util.identityToString(ident) + + "\" in the queue"); + } + + // + // Return servant if object not dead or destroyed + // + synchronized(element) + { + if(element.status != destroyed && element.status != dead) + { + return element.rec.servant; + } + } + + // + // Object is destroyed or dead: clean-up + // + if(_trace >= 2) + { + _communicator.getLogger().trace("Freeze::Evictor", + "\"" + Ice.Util.identityToString(ident) + + "\" was dead or destroyed"); + } + synchronized(this) + { + element.usageCount--; + return null; + } } - - // - // Load the Ice object from the database and add a - // servant for it. - // - ObjectRecord rec = (ObjectRecord)_dict.get(ident); - if(rec == null) + else { // - // The Ice object with the given identity does not exist, - // client will get an ObjectNotExistException. + // Load object now and loop + // + + if(_trace >= 2) + { + _communicator.getLogger().trace( + "Freeze::Evictor", + "couldn't find \"" + Ice.Util.identityToString(ident) + "\" in the queue\n" + + "loading \"" + Ice.Util.identityToString(ident) + "\" from the database"); + } + + rec = getObject(ident); + + if(rec == null) + { + // + // The Ice object with the given identity does not exist, + // client will get an ObjectNotExistException. + // + return null; + } + // + // Else loop // - return null; } + } + } - // - // If an initializer is installed, call it now. - // - if(_initializer != null) + + public void + finished(Ice.Current current, Ice.Object servant, Ice.LocalObject cookie) + { + assert(servant != null); + + EvictorElement element = (EvictorElement)cookie; + boolean enqueue = false; + + if(current.mode != Ice.OperationMode.Nonmutating) + { + synchronized(element) { - _initializer.initialize(current.adapter, ident, rec.servant); + if(element.status == clean) + { + // + // Assume this operation updated the object + // + element.status = modified; + enqueue = true; + } } + } + + synchronized(this) + { + assert(!_deactivated); // - // Add the new servant to the evictor queue. + // Decrease the usage count of the evictor queue element. // - element = add(ident, rec); + assert(element.usageCount >= 1); + element.usageCount--; + + if(enqueue) + { + // + // Need to copy current.id, as Ice caches and reuses it + // + Ice.Identity ident = new Ice.Identity(); + ident.name = current.id.name; + ident.category = current.id.category; + + addToModifiedQueue(ident, element); + } + else + { + // + // Evict as many elements as necessary. + // + evict(); + } } - - // - // Increase the usage count of the evictor queue element. - // - ++element.usageCount; - - // - // Notify the persistence strategy about the operation. - // - _strategy.preOperation(this, ident, element.rec.servant, current.mode != Ice.OperationMode.Nonmutating, - element.strategyCookie); - - // - // Evict as many elements as necessary. - // - evict(); - - // - // Set the cookie and return the servant for the Ice object. - // - cookie.value = (Ice.LocalObject)element; - return element.rec.servant; } - synchronized public void - finished(Ice.Current current, Ice.Object servant, Ice.LocalObject cookie) + public void + deactivate(String category) { - assert(_db != null); - assert(servant != null); - - // - // It's possible that the locator has been deactivated already. In - // this case, _evictorSize is set to zero. - // - assert(!_deactivated || _evictorSize == 0); - - // - // Decrease the usage count of the evictor queue element. - // - EvictorElement element = (EvictorElement)cookie; - assert(element.usageCount >= 1); - --element.usageCount; - - // - // If the object has not been destroyed, notify the persistence - // strategy about the operation. - // - if(!element.destroyed) - { - _strategy.postOperation(this, current.id, servant, current.mode != Ice.OperationMode.Nonmutating, - element.strategyCookie); - } + boolean joinAndClose = false; + + synchronized(this) + { + if(!_deactivated) + { + if(_trace >= 1) + { + _communicator.getLogger().trace( + "Freeze::Evictor", + "deactivating, saving unsaved Ice objects to the database"); + } + + saveNowNoSync(); + + // + // Set the evictor size to zero, meaning that we will evict + // everything possible. + // + _evictorSize = 0; + evict(); + + _deactivated = true; + notifyAll(); + joinAndClose = true; + } + } - // - // Evict as many elements as necessary. - // - evict(); + if(joinAndClose) + { + for(;;) + { + try + { + _thread.join(); + break; + } + catch(InterruptedException ex) + { + } + } + + try + { + _db.close(0); + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.close: " + dx.getMessage(); + throw ex; + } + _db = null; + if(_dbEnvHolder != null) + { + _dbEnvHolder.close(); + _dbEnvHolder = null; + } + _dbEnv = null; + } } - synchronized public void - deactivate(String category) + public void + run() { - if(!_deactivated) + for(;;) { - _deactivated = true; + java.util.List allObjects; + int saveNowThreadsSize = 0; - if(_trace >= 1) + synchronized(this) { - _db.getCommunicator().getLogger().trace("Freeze::Evictor", - "deactivating, saving unsaved Ice objects to the database"); + while((!_deactivated) && + (_saveNowThreads.size() == 0) && + (_saveSizeTrigger < 0 || _modifiedQueue.size() < _saveSizeTrigger)) + { + try + { + if(_savePeriod == 0) + { + wait(); + } + else + { + long preSave = System.currentTimeMillis(); + wait(_savePeriod); + if(System.currentTimeMillis() > preSave + _savePeriod) + { + break; + } + } + } + catch(InterruptedException ex) + { + } + } + + saveNowThreadsSize = _saveNowThreads.size(); + + if(_deactivated) + { + assert(_modifiedQueue.size() == 0); + if(saveNowThreadsSize > 0) + { + _saveNowThreads.clear(); + notifyAll(); + } + break; // for(;;) + } + + // + // Check first if there is something to do! + // + if(_modifiedQueue.size() == 0) + { + if(saveNowThreadsSize > 0) + { + _saveNowThreads.clear(); + notifyAll(); + } + continue; // for(;;) + } + + allObjects = _modifiedQueue; + _modifiedQueue = new java.util.ArrayList(); } + int size = allObjects.size(); + // - // Set the evictor size to zero, meaning that we will evict - // everything possible. + // Usage count release // - _evictorSize = 0; - evict(); + java.util.List releaseAfterStreaming = new java.util.ArrayList(); + java.util.List releaseAfterCommit = new java.util.ArrayList(); + + java.util.List streamedObjectQueue = new java.util.ArrayList(); + + long saveStart = System.currentTimeMillis(); + + // + // Stream each element + // + for(int i = 0; i < size; i++) + { + EvictorElement element = (EvictorElement)_evictorMap.get((Ice.Identity)allObjects.get(i)); + + synchronized(element) + { + ObjectRecord rec = element.rec; + + boolean streamIt = true; + byte status = element.status; + + switch(status) + { + case created: + { + element.status = clean; + releaseAfterCommit.add(element); + break; + } + case modified: + { + element.status = clean; + releaseAfterStreaming.add(element); + break; + } + case destroyed: + { + element.status = dead; + releaseAfterCommit.add(element); + break; + } + default: + { + // + // Nothing to do (could be a duplicate) + // + streamIt = false; + releaseAfterStreaming.add(element); + break; + } + } + + if(streamIt) + { + int index = streamedObjectQueue.size(); + StreamedObject obj = new StreamedObject(); + streamedObjectQueue.add(obj); + + obj.key = IdentityObjectRecordDict.encodeKeyImpl(allObjects.get(i), _communicator); + obj.status = status; + if(status != destroyed) + { + synchronized(rec.servant) + { + + obj.value = writeObjectRecordToValue(saveStart, rec); + } + } + } + } + } + + allObjects.clear(); + + if(releaseAfterStreaming.size() > 0) + { + synchronized(this) + { + for(int i = 0; i < releaseAfterStreaming.size(); i++) + { + EvictorElement element = (EvictorElement)releaseAfterStreaming.get(i); + element.usageCount--; + } + } + releaseAfterStreaming.clear(); + } + + // + // Now let's save all these streamed objects to disk using a transaction + // + + // + // Each time we get a deadlock, we reduce the number of objects to save + // per transaction + // + int txSize = streamedObjectQueue.size(); + boolean tryAgain; + + do + { + tryAgain = false; + + while(streamedObjectQueue.size() > 0) + { + if(txSize > streamedObjectQueue.size()) + { + txSize = streamedObjectQueue.size(); + } + + try + { + com.sleepycat.db.DbTxn tx = _dbEnv.txn_begin(null, 0); + try + { + for(int i = 0; i < txSize; i++) + { + StreamedObject obj = (StreamedObject) streamedObjectQueue.get(i); + + if(obj.status == destroyed) + { + // + // May not exist in the database + // + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); + + int err = _db.del(tx, dbKey, 0); + if(err != 0 && err != com.sleepycat.db.Db.DB_NOTFOUND) + { + // + // Bug in Freeze + // + throw new DBException(); + } + } + else + { + // + // We can't use NOOVERWRITE as some 'created' objects may + // actually be already in the database + // + + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(obj.key); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(obj.value); + + int err = _db.put(tx, dbKey, dbValue, 0); + if(err != 0) + { + // + // Bug in Freeze + // + throw new DBException(); + } + } + } + } + catch(com.sleepycat.db.DbException dx) + { + tx.abort(); + throw dx; + } + tx.commit(0); + + for(int i = 0; i < txSize; i++) + { + streamedObjectQueue.remove(0); + } + + if(_trace >= 2) + { + long now = System.currentTimeMillis(); + _communicator.getLogger().trace( + "Freeze::Evictor", + "saved " + txSize + " objects in " + (now - saveStart) + " ms"); + saveStart = now; + } + } + catch(com.sleepycat.db.DbDeadlockException deadlock) + { + tryAgain = true; + txSize = (txSize + 1)/2; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "saving: " + dx.getMessage(); + throw ex; + } + } + } while(tryAgain); + + + synchronized(this) + { + + for(int i = 0; i < releaseAfterCommit.size(); i++) + { + EvictorElement element = (EvictorElement)releaseAfterCommit.get(i); + element.usageCount--; + } + releaseAfterCommit.clear(); + + if(saveNowThreadsSize > 0) + { + for(int i = 0; i < saveNowThreadsSize; i++) + { + _saveNowThreads.remove(0); + } + notifyAll(); + } + } + + _lastSave = System.currentTimeMillis(); } } - public void - save(Ice.Identity ident, Ice.Object servant) + private void + init(String envName, String dbName, boolean createDb) { - // - // NOTE: This operation is not mutex-protected, therefore it may - // only be invoked while the evictor is already locked. For - // example, it is safe to call this operation from a persistence - // strategy implementation, iff the persistence strategy is in - // the thread context of a locked evictor operation. - // - EvictorElement element = (EvictorElement)_evictorMap.get(ident); - assert(element != null); - - // - // Update statistics before saving. - // - long now = System.currentTimeMillis(); - long diff = now - (element.rec.stats.creationTime + element.rec.stats.lastSaveTime); - if(element.rec.stats.lastSaveTime == 0) - { - element.rec.stats.lastSaveTime = diff; - element.rec.stats.avgSaveTime = diff; - } - else - { - element.rec.stats.lastSaveTime = now - element.rec.stats.creationTime; - element.rec.stats.avgSaveTime = (long)(element.rec.stats.avgSaveTime * 0.95 + diff * 0.05); - } + _trace = _communicator.getProperties().getPropertyAsInt( + "Freeze.Trace.Evictor"); - _dict.fastPut(ident, element.rec); - } + _errorPrefix = "Freeze Evictor DbEnv(\"" + envName + "\") Db(\"" + + dbName + "\") :"; - EvictorI(DB db, PersistenceStrategy strategy) - { - _db = db; - _dict = new IdentityObjectRecordDict(db); - _strategy = strategy; - _trace = _db.getCommunicator().getProperties().getPropertyAsInt("Freeze.Trace.Evictor"); - } + String propertyPrefix = "Freeze.Evictor." + envName + '.' + dbName; + + // + // By default, we save every minute or when the size of the modified + // queue reaches 10. + // - protected void - finalize() - throws Throwable - { - if(!_deactivated) - { - _db.getCommunicator().getLogger().warning("evictor has not been deactivated"); - } + _saveSizeTrigger = _communicator.getProperties().getPropertyAsIntWithDefault( + propertyPrefix + ".SaveSizeTrigger", 10); - _strategy.destroy(); + _savePeriod = _communicator.getProperties().getPropertyAsIntWithDefault( + propertyPrefix + ".SavePeriod", 60 * 1000); + + try + { + int flags = com.sleepycat.db.Db.DB_AUTO_COMMIT; + if(createDb) + { + flags |= com.sleepycat.db.Db.DB_CREATE; + } + + _db = new com.sleepycat.db.Db(_dbEnv, 0); + _db.open(null, dbName, null, com.sleepycat.db.Db.DB_BTREE, + flags, 0); + + // + // TODO: FREEZE_DB_MODE + // + } + catch(java.io.FileNotFoundException dx) + { + DBNotFoundException ex = new DBNotFoundException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + + _lastSave = System.currentTimeMillis(); + + // + // Start saving thread + // + _thread = new Thread(this); + _thread.start(); } private void @@ -432,11 +1020,6 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore // assert(ident != null && element != null); - // - // Notify the persistence strategy about the evicted object. - // - _strategy.evictedObject(this, ident, element.rec.servant, element.strategyCookie); - // // Remove element from the evictor queue. // @@ -445,7 +1028,7 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore if(_trace >= 2) { - _db.getCommunicator().getLogger().trace( + _communicator.getLogger().trace( "Freeze::Evictor", "evicted \"" + Ice.Util.identityToString(ident) + "\" from the queue\n" + "number of elements in the queue: " + @@ -453,77 +1036,205 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore } } } - - // - // If we're deactivated and there are no more elements to - // evict, it's not necessary in Java to set _db to zero to - // break cyclic dependencies. - // } - private EvictorElement - add(Ice.Identity ident, ObjectRecord rec) + private boolean + dbHasObject(Ice.Identity ident) { - // - // Ignore the request if the Ice object is already in the queue. - // - EvictorElement element = (EvictorElement)_evictorMap.get(ident); - if(element != null) + for(;;) { - return element; - } - - // - // Add an Ice object with its servant to the evictor queue. - // - _evictorList.addFirst(ident); + try + { + byte[] key = IdentityObjectRecordDict.encodeKeyImpl(ident, _communicator); + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); + + // + // Keep 0 length since we're not interested in the data + // + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_USERMEM | + com.sleepycat.db.Db.DB_DBT_PARTIAL); + + int err = _db.get(null, dbKey, dbValue, 0); + + if(err == 0) + { + return true; + } + else if(err == com.sleepycat.db.Db.DB_NOTFOUND) + { + return false; + } + else + { + assert(false); + throw new DBException(); + } + } + catch(com.sleepycat.db.DbDeadlockException deadlock) + { + // + // Ignored, try again + // + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.get: " + dx.getMessage(); + throw ex; + } + } + } - element = new EvictorElement(); - element.rec = rec; - element.position = _evictorList.iterator(); - element.usageCount = 0; - element.destroyed = false; - element.strategyCookie = _strategy.activatedObject(ident, rec.servant); + private ObjectRecord + getObject(Ice.Identity ident) + { + byte[] key = IdentityObjectRecordDict.encodeKeyImpl(ident, _communicator); + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(key); + + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); - // - // Position the iterator "on" the element. - // - element.position.next(); + for(;;) + { + try + { + int err = _db.get(null, dbKey, dbValue, 0); + + if(err == 0) + { + return (ObjectRecord) IdentityObjectRecordDict.decodeValueImpl( + dbValue.get_data(), _communicator); + } + else if(err == com.sleepycat.db.Db.DB_NOTFOUND) + { + return null; + } + else + { + assert(false); + throw new DBException(); + } + } + catch(com.sleepycat.db.DbDeadlockException deadlock) + { + // + // Ignored, try again + // + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.get: " + dx.getMessage(); + throw ex; + } + } + } - _evictorMap.put(ident, element); - return element; + private void + addToModifiedQueue(Ice.Identity ident, EvictorElement element) + { + element.usageCount++; + _modifiedQueue.add(ident); + + if(_saveSizeTrigger >= 0 && _modifiedQueue.size() >= _saveSizeTrigger) + { + notifyAll(); + } } + + private void + saveNowNoSync() + { + Thread myself = Thread.currentThread(); - private EvictorElement - remove(Ice.Identity ident) + _saveNowThreads.add(myself); + notifyAll(); + do + { + try + { + wait(); + } + catch(InterruptedException ex) + { + } + } while(_saveNowThreads.contains(myself)); + } + + private byte[] + writeObjectRecordToValue(long saveStart, ObjectRecord rec) { // - // If the Ice object is currently in the evictor, remove it. + // Update stats first // - EvictorElement element = (EvictorElement)_evictorMap.remove(ident); - if(element != null) + Statistics stats = rec.stats; + long diff = saveStart - (stats.creationTime + stats.lastSaveTime); + if(stats.lastSaveTime == 0) { - element.position.remove(); + stats.lastSaveTime = diff; + stats.avgSaveTime = diff; } - return element; + else + { + stats.lastSaveTime = saveStart - stats.creationTime; + stats.avgSaveTime = (long)(stats.avgSaveTime * 0.95 + diff * 0.05); + } + return IdentityObjectRecordDict.encodeValueImpl(rec, _communicator); } + class StreamedObject + { + byte[] key; + byte[] value; + byte status; + }; + + class EvictorElement extends Ice.LocalObjectImpl { + byte status; ObjectRecord rec; java.util.Iterator position; int usageCount; - boolean destroyed; - Ice.LocalObject strategyCookie; }; + + // + // Clean object; can become modified or destroyed + // + private static final byte clean = 0; + + // + // New objects; can become clean, dead or destroyed + // + private static final byte created = 1; + + // + // Modified object; can become clean or destroyed + // + private static final byte modified = 2; + + // + // Being saved. Can become dead or created + // + private static final byte destroyed = 3; + + // + // Exists only in the Evictor; for example the object was created + // and later destroyed (without a save in between), or it was + // destroyed on disk but is still in use. Can become created. + // + private static final byte dead = 4; // // Map of Ice.Identity to EvictorElement // private java.util.Map _evictorMap = new java.util.HashMap(); + private int _evictorSize = 10; // - // The C++ Evictor uses std::list<Ice::Identity> which allows + // The C++ Evictor uses std::list<EvictorMap::iterator> which allows // holding of iterators across list changes. Unfortunately, Java // iterators are invalidated as soon as the underlying collection // is changed, so it's not possible to use the same technique. @@ -532,12 +1243,32 @@ class EvictorI extends Ice.LocalObjectImpl implements Evictor, ObjectStore // private Freeze.LinkedList _evictorList = new Freeze.LinkedList(); - private int _evictorSize = 10; + // + // The _modifiedQueue contains a queue of all modified objects + // Each element in the queue "owns" a usage count, to ensure the + // pointed element remains in the map. + // + private java.util.List _modifiedQueue = new java.util.ArrayList(); + private boolean _deactivated = false; - private IdentityObjectRecordDict _dict; - - private DB _db; - private PersistenceStrategy _strategy; + + private Ice.Communicator _communicator; + private SharedDbEnv _dbEnvHolder; + private com.sleepycat.db.DbEnv _dbEnv; + private com.sleepycat.db.Db _db; private ServantInitializer _initializer; private int _trace = 0; + + // + // Threads that have requested a "saveNow" and are waiting for + // its completion + // + private java.util.List _saveNowThreads = new java.util.ArrayList(); + + private int _saveSizeTrigger; + private long _savePeriod; + private long _lastSave; + + private Thread _thread; + private String _errorPrefix; } diff --git a/java/src/Freeze/EvictorIteratorI.java b/java/src/Freeze/EvictorIteratorI.java index fdf403be19b..90df6a6d976 100644 --- a/java/src/Freeze/EvictorIteratorI.java +++ b/java/src/Freeze/EvictorIteratorI.java @@ -16,55 +16,136 @@ package Freeze; class EvictorIteratorI extends Ice.LocalObjectImpl implements EvictorIterator { - EvictorIteratorI(java.util.Iterator iterator) - { - // - // Copy the identities from the map iterator, to allow - // this iterator to continue to function even if the - // database is accessed and the map iterator is invalidated. - // - while(iterator.hasNext()) - { - java.util.Map.Entry entry = (java.util.Map.Entry)iterator.next(); - _identities.add(entry.getKey()); - } - - // - // Close the iterator explicitly. We don't want to wait for - // the garbage collection to destroy the iterator since the - // iterator consumes resources (database locks for instance). - // - ((Freeze.Map.EntryIterator)iterator).close(); - - _iterator = _identities.iterator(); - } - public boolean hasNext() { - return _iterator != null && _iterator.hasNext(); + if(_dbc == null) + { + throw new IteratorDestroyedException(); + } + + if(_current != null) + { + return true; + } + else + { + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); + + // + // Keep 0 length since we're not interested in the data + // + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_USERMEM | + com.sleepycat.db.Db.DB_DBT_PARTIAL); + + try + { + if(_dbc.get(dbKey, dbValue, com.sleepycat.db.Db.DB_NEXT) == 0) + { + _current = (Ice.Identity) IdentityObjectRecordDict.decodeKeyImpl(dbKey.get_data(), _communicator); + return true; + } + else + { + return false; + } + } + catch(com.sleepycat.db.DbDeadlockException dx) + { + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + } } public Ice.Identity next() { - if(_iterator != null) - { - return (Ice.Identity)_iterator.next(); - } - else - { - throw new Freeze.NoSuchElementException(); - } + if(hasNext()) + { + Ice.Identity result = _current; + _current = null; + return result; + } + else + { + throw new NoSuchElementException(); + } } public void destroy() { - _identities = null; - _iterator = null; + if(_dbc == null) + { + throw new IteratorDestroyedException(); + } + else + { + try + { + _dbc.close(); + } + catch(com.sleepycat.db.DbDeadlockException deadlock) + { + // + // Ignored + // + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.cursor: " + dx.getMessage(); + throw ex; + } + + _dbc = null; + _current = null; + _communicator = null; + } + } + + EvictorIteratorI(com.sleepycat.db.Db db, Ice.Communicator communicator, String errorPrefix) + { + _communicator = communicator; + _errorPrefix = errorPrefix; + + try + { + _dbc = db.cursor(null, 0); + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.cursor: " + dx.getMessage(); + throw ex; + } } - - private java.util.ArrayList _identities = new java.util.ArrayList(); - private java.util.Iterator _iterator; + + protected void + finalize() + { + if(_dbc != null) + { + destroy(); + } + } + + + private com.sleepycat.db.Dbc _dbc; + private Ice.Identity _current = null; + private Ice.Communicator _communicator; + private String _errorPrefix; } diff --git a/java/src/Freeze/IdleStrategyI.java b/java/src/Freeze/IdleStrategyI.java deleted file mode 100644 index 7f8e6d1036c..00000000000 --- a/java/src/Freeze/IdleStrategyI.java +++ /dev/null @@ -1,112 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003 -// ZeroC, Inc. -// Billerica, MA, USA -// -// All Rights Reserved. -// -// Ice is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License version 2 as published by -// the Free Software Foundation. -// -// ********************************************************************** - -package Freeze; - -public final class IdleStrategyI extends Ice.LocalObjectImpl implements IdleStrategy -{ - public - IdleStrategyI() - { - } - - public Ice.LocalObject - activatedObject(Ice.Identity ident, Ice.Object servant) - { - return new Cookie(); - } - - public void - destroyedObject(Ice.Identity ident, Ice.LocalObject cookie) - { - // Nothing to do - } - - public void - evictedObject(ObjectStore store, Ice.Identity ident, Ice.Object servant, Ice.LocalObject cookie) - { - // - // The object must reach the idle state in order for it to be - // evicted, therefore the object should have already been saved - // by postOperation. - // - Cookie c = (Cookie)cookie; - assert(!c.mutated); - assert(c.mutatingCount == 0); - } - - public void - savedObject(ObjectStore store, Ice.Identity ident, Ice.Object servant, Ice.LocalObject cookie, int usageCount) - { - assert(usageCount > 0); - - if(usageCount == 1) - { - Cookie c = (Cookie)cookie; - c.mutated = false; - } - } - - public void - preOperation(ObjectStore store, Ice.Identity ident, Ice.Object servant, boolean mutating, Ice.LocalObject cookie) - { - Cookie c = (Cookie)cookie; - if(mutating) - { - ++c.mutatingCount; - c.mutated = true; - } - else if(c.mutatingCount == 0 && c.mutated) - { - // - // Only store the object's persistent state if the object is idle - // and it has been mutated. - // - store.save(ident, servant); - c.mutated = false; - } - } - - public void - postOperation(ObjectStore store, Ice.Identity ident, Ice.Object servant, boolean mutating, Ice.LocalObject cookie) - { - Cookie c = (Cookie)cookie; - if(mutating) - { - assert(c.mutatingCount >= 1); - --c.mutatingCount; - } - if(c.mutatingCount == 0 && c.mutated) - { - // - // Only store the object's persistent state if the object is idle - // and it has been mutated. - // - store.save(ident, servant); - c.mutated = false; - } - } - - public void - destroy() - { - // Nothing to do - } - - private static class Cookie extends Ice.LocalObjectImpl - { - int mutatingCount = 0; - boolean mutated = false; - } -} diff --git a/java/src/Freeze/Map.java b/java/src/Freeze/Map.java index 5ca1bd5560e..af0272e68f0 100644 --- a/java/src/Freeze/Map.java +++ b/java/src/Freeze/Map.java @@ -17,10 +17,62 @@ package Freeze; public abstract class Map extends java.util.AbstractMap { public - Map(DB db) + Map(Ice.Communicator communicator, String envName, String dbName, boolean createDb) { - _db = db; - _communicator = db.getCommunicator(); + _communicator = communicator; + _dbEnvHolder = SharedDbEnv.get(communicator, envName); + _dbEnv = _dbEnvHolder; + _dbName = dbName; + _errorPrefix = "Freeze DB DbEnv(\"" + envName + "\") Db(\"" + dbName + "\") :"; + + openDb(createDb); + } + + public + Map(Ice.Communicator communicator, com.sleepycat.db.DbEnv dbEnv, String dbName, boolean createDb) + { + _communicator = communicator; + _dbEnvHolder = null; + _dbEnv = dbEnv; + _dbName = dbName; + _errorPrefix = "Freeze DB DbEnv(\"External\") Db(\"" + dbName + "\") :"; + + openDb(createDb); + } + + public void + close() + { + if(_db != null) + { + try + { + _db.close(0); + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.stat: " + e.getMessage(); + throw ex; + } + finally + { + _db = null; + } + } + + if(_dbEnvHolder != null) + { + try + { + _dbEnvHolder.close(); + } + finally + { + _dbEnvHolder = null; + } + } } // @@ -36,14 +88,12 @@ public abstract class Map extends java.util.AbstractMap public int size() { - // - // It's not necessary to close outstanding iterators. - // - // If it was it would be a problem - it doesn't change the Map - // - therefore open iterators should not be invalidated - // (according the Java spec). - // - // closeIterators(); + if(_db == null) + { + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } // // The number of records cannot be cached and then adjusted by @@ -52,130 +102,178 @@ public abstract class Map extends java.util.AbstractMap // the size adjusted) and the transaction aborted then the // cached map size() would be incorrect. // - return (int)_db.getNumberOfRecords(); + + // + // TODO: DB_FAST_STAT doesn't seem to do what the + // documentation says... + // + try + { + com.sleepycat.db.DbBtreeStat s = (com.sleepycat.db.DbBtreeStat)_db.stat(0); + return s.bt_ndata; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.stat: " + e.getMessage(); + throw ex; + } } public boolean containsValue(Object value) { - // - // It's not necessary to close outstanding iterators. - // - // If it was it would be a problem - it doesn't change the Map - // - therefore open iterators should not be invalidated - // (according the Java spec). - // - // closeIterators(); - - EntryIterator p = (EntryIterator)entrySet().iterator(); - if(value == null) + for(;;) { - while(p.hasNext()) + EntryIterator p = null; + try { - Entry e = (Entry)p.next(); - if(e.getValue() == null) + p = (EntryIterator)entrySet().iterator(); + + if(value == null) { - return true; + while(p.hasNext()) + { + Entry e = (Entry)p.next(); + if(e.getValue() == null) + { + p.close(); + return true; + } + } + } + else + { + while(p.hasNext()) + { + Entry e = (Entry)p.next(); + if(value.equals(e.getValue())) + { + p.close(); + return true; + } + } } + return false; } - } - else - { - while(p.hasNext()) + catch(DBDeadlockException ex) + { + // + // Try again + // + } + finally { - Entry e = (Entry)p.next(); - if(value.equals(e.getValue())) + if(p != null) { - return true; + p.close(); } } } - p.close(); - - return false; } public boolean containsKey(Object key) { - // - // It's not necessary to close outstanding iterators. - // - // If it was it would be a problem - it doesn't change the Map - // - therefore open iterators should not be invalidated - // (according the Java spec). - // - //closeIterators(); + if(_db == null) + { + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } byte[] k = encodeKey(key, _communicator); - return _db.contains(k); + + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_PARTIAL); + + if(_trace >= 1) + { + _communicator.getLogger().trace("DB", "checking key in database \"" + _dbName + "\""); + } + + for(;;) + { + try + { + int rc = _db.get(null, dbKey, dbValue, 0); + if(rc == com.sleepycat.db.Db.DB_NOTFOUND) + { + return false; + } + else + { + assert(rc == 0); + return true; + } + } + catch(com.sleepycat.db.DbDeadlockException e) + { + // + // Try again + // + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.get: " + e.getMessage(); + throw ex; + } + } } public Object get(Object key) { - // - // It's not necessary to close outstanding iterators. - // - // If it was it would be a problem - it doesn't change the Map - // - therefore open iterators should not be invalidated - // (according the Java spec). - // - //closeIterators(); - byte[] k = encodeKey(key, _communicator); - try + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + byte[] v = getImpl(dbKey); + if(v == null) { - byte[] v = _db.get(k); - return decodeValue(v, _communicator); + return null; } - catch(DBNotFoundException e) + else { - return null; + return decodeValue(v, _communicator); } } public Object put(Object key, Object value) { - closeIterators(); - byte[] k = encodeKey(key, _communicator); - Object o; - - try + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + byte[] v = getImpl(dbKey); + Object o = null; + if(v != null) { - byte[] v = _db.get(k); o = decodeValue(v, _communicator); } - catch(DBNotFoundException e) - { - o = null; - } - byte[] v = encodeValue(value, _communicator); - _db.put(k, v); - + putImpl(dbKey, value); return o; } public Object remove(Object key) { - closeIterators(); - byte[] k = encodeKey(key, _communicator); - Object o; - try + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + byte[] v = getImpl(dbKey); + + if(v != null && removeImpl(dbKey)) { - byte[] v = _db.get(k); - o = decodeValue(v, _communicator); + return decodeValue(v, _communicator); } - catch(DBNotFoundException e) + else { - o = null; + DBNotFoundException ex = new DBNotFoundException(); + ex.message = _errorPrefix + "Db.del: DB_NOTFOUND"; + throw ex; } - _db.del(k); - return o; } // @@ -186,11 +284,9 @@ public abstract class Map extends java.util.AbstractMap public void fastPut(Object key, Object value) { - closeIterators(); - byte[] k = encodeKey(key, _communicator); - byte[] v = encodeValue(value, _communicator); - _db.put(k, v); + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + putImpl(dbKey, value); } // @@ -199,28 +295,44 @@ public abstract class Map extends java.util.AbstractMap public boolean fastRemove(Object key) { - closeIterators(); - byte[] k = encodeKey(key, _communicator); - try - { - _db.del(k); - } - catch(Freeze.DBNotFoundException e) - { - return false; - } - return true; + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(k); + return removeImpl(dbKey); } public void clear() { - closeIterators(); + if(_db == null) + { + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } - _db.clear(); + for(;;) + { + try + { + _db.truncate(null, com.sleepycat.db.Db.DB_AUTO_COMMIT); + break; + } + catch(com.sleepycat.db.DbDeadlockException e) + { + // + // Try again + // + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.truncate: " + e.getMessage(); + throw ex; + } + } } - + public java.util.Set entrySet() { @@ -231,9 +343,7 @@ public abstract class Map extends java.util.AbstractMap public java.util.Iterator iterator() { - EntryIterator p = new EntryIterator(); - _iterators.add(new java.lang.ref.WeakReference(p)); - return p; + return new EntryIterator(); } public boolean @@ -246,8 +356,8 @@ public abstract class Map extends java.util.AbstractMap Map.Entry entry = (Map.Entry)o; Object value = entry.getValue(); - Entry p = getEntry(entry.getKey()); - return p != null && valEquals(p.getValue(), value); + byte[] v = getImpl(entry.getDbKey()); + return v != null && valEquals(decodeValue(v, _communicator), value); } public boolean @@ -260,13 +370,10 @@ public abstract class Map extends java.util.AbstractMap Map.Entry entry = (Map.Entry)o; Object value = entry.getValue(); - Entry p = getEntry(entry.getKey()); - if(p != null && valEquals(p.getValue(), value)) + byte[] v = getImpl(entry.getDbKey()); + if(v != null && valEquals(decodeValue(v, _communicator), value)) { - closeIterators(); - byte[] k = encodeKey(p.getKey(), _communicator); - _db.del(k); - return true; + return removeImpl(entry.getDbKey()); } return false; } @@ -288,69 +395,183 @@ public abstract class Map extends java.util.AbstractMap return _entrySet; } - // - // Because of the way that Berkeley DB cursors implement their - // locking it's necessary to ensure that all cursors are closed - // prior to doing a database operation otherwise self-deadlocks - // will occur. See "Berkeley DB Transactional Data Store locking - // conventions" section in the Berkeley DB reference guide for - // details. - // - private void - closeIterators() + protected void + finalize() { - closeIteratorsExcept(null); + close(); } - private void - closeIteratorsExcept(java.util.Iterator i) + private static boolean + valEquals(Object o1, Object o2) { - java.util.Iterator p = _iterators.iterator(); - while(p.hasNext()) + return (o1 == null ? o2 == null : o1.equals(o2)); + } + + private byte[] + getImpl(com.sleepycat.db.Dbt dbKey) + { + if(_db == null) + { + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } + + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + + if(_trace >= 1) { - java.lang.ref.WeakReference ref = (java.lang.ref.WeakReference)p.next(); - EntryIterator q = (EntryIterator)ref.get(); - if(q != null && q != i) + _communicator.getLogger().trace("DB", "reading value from database \"" + _dbName + "\""); + } + + for(;;) + { + try { - q.close(); + int rc = _db.get(null, dbKey, dbValue, 0); + if(rc == com.sleepycat.db.Db.DB_NOTFOUND) + { + return null; + } + else + { + return dbValue.get_data(); + } + } + catch(com.sleepycat.db.DbDeadlockException e) + { + // + // Try again + // + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.get: " + e.getMessage(); + throw ex; } } + } - // - // This is more efficient than removing the list items element - // by element in the iteration loop. - // - _iterators.clear(); - if(i != null) + private void + putImpl(com.sleepycat.db.Dbt dbKey, Object value) + { + if(_db == null) { - _iterators.add(new java.lang.ref.WeakReference(i)); + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } + + byte[] v = encodeValue(value, _communicator); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(v); + + if(_trace >= 1) + { + _communicator.getLogger().trace("DB", "writing value in database \"" + _dbName + "\""); + } + + for(;;) + { + try + { + _db.put(null, dbKey, dbValue, com.sleepycat.db.Db.DB_AUTO_COMMIT); + break; + } + catch(com.sleepycat.db.DbDeadlockException e) + { + // + // Try again + // + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.put: " + e.getMessage(); + throw ex; + } } } - private Entry - getEntry(Object key) + private boolean + removeImpl(com.sleepycat.db.Dbt dbKey) { - // - // It's not necessary to close outstanding iterators. - // - // If it was it would be a problem - it doesn't change the Map - // - therefore open iterators should not be invalidated - // (according the Java spec). - // - // closeIterators(); + if(_db == null) + { + DBException ex = new DBException(); + ex.message = _errorPrefix + "\"" + _dbName + "\" has been closed"; + throw ex; + } - byte[] k = encodeKey(key, _communicator); - byte[] v = _db.get(k); + if(_trace >= 1) + { + _communicator.getLogger().trace("DB", "deleting value from database \"" + _dbName + "\""); + } - return new Entry(this, _communicator, key, v); + for(;;) + { + try + { + int rc = _db.del(null, dbKey, com.sleepycat.db.Db.DB_AUTO_COMMIT); + return (rc == 0); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + // + // Try again + // + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Db.del: " + e.getMessage(); + throw ex; + } + } } - private static boolean - valEquals(Object o1, Object o2) + private void + openDb(boolean createDb) { - return (o1 == null ? o2 == null : o1.equals(o2)); + _trace = _communicator.getProperties().getPropertyAsInt("Freeze.Trace.DB"); + + try + { + int flags = com.sleepycat.db.Db.DB_AUTO_COMMIT; + + if(createDb) + { + flags |= com.sleepycat.db.Db.DB_CREATE; + } + + _db = new com.sleepycat.db.Db(_dbEnv, 0); + _db.open(null, _dbName, null, com.sleepycat.db.Db.DB_BTREE, + flags, 0); + + // + // TODO: FREEZE_DB_MODE + // + } + catch(java.io.FileNotFoundException dx) + { + DBNotFoundException ex = new DBNotFoundException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Db.open: " + dx.getMessage(); + throw ex; + } } + /** * * The entry iterator class needs to be public to allow clients to @@ -362,76 +583,191 @@ public abstract class Map extends java.util.AbstractMap { EntryIterator() { - try - { - _cursor = _db.getCursor(); - _next = getEntry(); - } - catch(DBNotFoundException e) - { - // Database is empty. - } + if(_trace >= 3) + { + _communicator.getLogger().trace("DB", "starting transaction for cursor on database \"" + _dbName + "\""); + } + + try + { + // + // Start transaction + // + _tx = _dbEnv.txn_begin(null, 0); + + // + // Open cursor with this transaction + // + _cursor = _db.cursor(_tx, 0); + } + catch(com.sleepycat.db.DbDeadlockException dx) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(dx); + ex.message = _errorPrefix + "EntryIterator constructor: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "EntryIterator constructor: " + dx.getMessage(); + throw ex; + } } public boolean hasNext() { - return getNext(); + if(_current == null || _current == _lastReturned) + { + // + // Move _cursor, set _current + // + + com.sleepycat.db.Dbt dbKey = new com.sleepycat.db.Dbt(); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + + try + { + if(_cursor.get(dbKey, dbValue, com.sleepycat.db.Db.DB_NEXT) == 0) + { + _current = new Entry(this, Map.this, _communicator, dbKey, dbValue.get_data()); + return true; + } + else + { + close(); + return false; + } + } + catch(com.sleepycat.db.DbDeadlockException dx) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = _errorPrefix + "Dbc.get: " + dx.getMessage(); + throw ex; + } + } + else + { + return true; + } } - + public Object next() { - if(!getNext()) - { - throw new java.util.NoSuchElementException(); - } - assert(_next != null); - - if(_prev != null) - { - _prev.invalidateCursor(); - } - - _prev = _next; - _next = null; - return _prev; + if(hasNext()) + { + _lastReturned = _current; + return _lastReturned; + } + else + { + throw new java.util.NoSuchElementException(); + } } public void remove() { - if(_prev == null) - { - throw new IllegalStateException(); - } - - closeIteratorsExcept(this); - - // - // Clone the cursor so that error handling is simpler. - // - assert _cursor != null; - DBCursor clone = _cursor._clone(); - - try - { - clone.del(); - _prev.invalidateCursor(); - _prev = null; - _next = null; - } - finally - { - try - { - clone.close(); - } - catch(DBException ignore) - { - // Ignore - } - } + // + // Removes the last object returned by next() + // + if(_lastReturned == null) + { + throw new IllegalStateException(); + } + + if(_lastReturned == _current) + { + try + { + if(_cursor.del(0) == com.sleepycat.db.Db.DB_KEYEMPTY) + { + throw new IllegalStateException(); + } + } + catch(com.sleepycat.db.DbDeadlockException e) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.del: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.del: " + e.getMessage(); + throw ex; + } + } + else + { + // + // Duplicate the cursor and move the _lastReturned + // element to delete it (using the duplicate) + // + + com.sleepycat.db.Dbc clone = null; + + try + { + clone = _cursor.dup(com.sleepycat.db.Db.DB_POSITION); + + // + // No interested in data + // + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(); + dbValue.set_flags(com.sleepycat.db.Db.DB_DBT_USERMEM | + com.sleepycat.db.Db.DB_DBT_PARTIAL); + + int rc = clone.get(_lastReturned.getDbKey(), dbValue, com.sleepycat.db.Db.DB_SET); + + if(rc == com.sleepycat.db.Db.DB_NOTFOUND) + { + throw new IllegalStateException(); + } + if(clone.del(0) == com.sleepycat.db.Db.DB_KEYEMPTY) + { + throw new IllegalStateException(); + } + } + catch(com.sleepycat.db.DbDeadlockException e) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "EntryIterator.remove: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "EntryIterator.remove: " + e.getMessage(); + throw ex; + } + finally + { + if(clone != null) + { + closeCursor(clone); + } + } + } } // @@ -440,86 +776,227 @@ public abstract class Map extends java.util.AbstractMap public void close() { - DBCursor copy = _cursor; - - // - // Clear the internal iterator state. - // - _cursor = null; - _next = null; - _prev = null; - - if(copy != null) - { - copy.close(); - } - } + if(_cursor != null) + { + com.sleepycat.db.Dbc cursor = _cursor; + _cursor = null; + closeCursor(cursor); + } + + if(_tx != null) + { + if(_trace >= 3) + { + _communicator.getLogger().trace("DB", "committing transaction for cursor on database \"" + _dbName + "\""); + } - protected void + try + { + _tx.commit(0); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "DbTxn.commit: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "DbTxn.commit: " + e.getMessage(); + throw ex; + } + finally + { + _tx = null; + } + } + + } + + protected void finalize() { close(); } - private Entry - getEntry() - { - assert _cursor != null; - _cursor.curr(_keyHolder, _valueHolder); - return new Entry(Map.this, _cursor, _keyHolder.value, _valueHolder.value); - } + void + setValue(Map.Entry entry, Object value) + { + // + // Are we trying to update the current value? + // + if(_current == entry) + { + // + // Yes, update it directly + // + byte[] v = encodeValue(value, _communicator); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(v); + + try + { + _cursor.put(entry.getDbKey(), dbValue, com.sleepycat.db.Db.DB_CURRENT); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.put: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.put: " + e.getMessage(); + throw ex; + } + } + else + { + // + // Duplicate the cursor and move the entry + // element to update it (using the duplicate cursor) + // + + com.sleepycat.db.Dbc clone = null; - private boolean - getNext() - { - if(_next == null && _cursor != null) - { - if(_cursor.next()) - { - try - { - _next = getEntry(); - } - catch(DBNotFoundException ex) - { - // No element found. - } - } - } - return _next != null; - } + try + { + clone = _cursor.dup(com.sleepycat.db.Db.DB_POSITION); + + // + // Not interested in data + // + com.sleepycat.db.Dbt dummy = new com.sleepycat.db.Dbt(); + dummy.set_flags(com.sleepycat.db.Db.DB_DBT_USERMEM | + com.sleepycat.db.Db.DB_DBT_PARTIAL); + + int rc = clone.get(entry.getDbKey(), dummy, com.sleepycat.db.Db.DB_SET); - private DBCursor _cursor; - private Entry _next; - private Entry _prev; - private Freeze.KeyHolder _keyHolder = new Freeze.KeyHolder(); - private Freeze.ValueHolder _valueHolder = new Freeze.ValueHolder(); + if(rc == com.sleepycat.db.Db.DB_NOTFOUND) + { + DBNotFoundException ex = new DBNotFoundException(); + ex.message = _errorPrefix + "Dbc.get: DB_NOTFOUND"; + throw ex; + } + + byte[] v = encodeValue(value, _communicator); + com.sleepycat.db.Dbt dbValue = new com.sleepycat.db.Dbt(v); + clone.put(entry.getDbKey(), dbValue, com.sleepycat.db.Db.DB_CURRENT); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "EntryIterator.setValue: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "EntryIterator.setValue: " + e.getMessage(); + throw ex; + } + finally + { + if(clone != null) + { + closeCursor(clone); + } + } + } + } + + + private void + closeCursor(com.sleepycat.db.Dbc cursor) + { + try + { + cursor.close(); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + dead(); + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.close: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "Dbc.close: " + e.getMessage(); + throw ex; + } + } + + private void + dead() + { + if(_cursor != null) + { + com.sleepycat.db.Dbc cursor = _cursor; + _cursor = null; + closeCursor(cursor); + } + + if(_tx != null) + { + if(_trace >= 3) + { + _communicator.getLogger().trace("DB", "rolling back transaction for cursor on database \"" + _dbName + "\""); + } + + try + { + _tx.abort(); + } + catch(com.sleepycat.db.DbDeadlockException e) + { + DBDeadlockException ex = new DBDeadlockException(); + ex.initCause(e); + ex.message = _errorPrefix + "DbTxn.abort: " + e.getMessage(); + throw ex; + } + catch(com.sleepycat.db.DbException e) + { + DBException ex = new DBException(); + ex.initCause(e); + ex.message = _errorPrefix + "DbTxn.abort: " + e.getMessage(); + throw ex; + } + finally + { + _tx = null; + } + } + } + + private com.sleepycat.db.DbTxn _tx = null; + private com.sleepycat.db.Dbc _cursor = null; + private Entry _current = null; + private Entry _lastReturned = null; } static class Entry implements java.util.Map.Entry { public - Entry(Map map, DBCursor cursor, byte[] keyData, byte[] valueData) - { - _map = map; - _cursor = cursor; - _communicator = cursor.getCommunicator(); - _keyData = keyData; - _haveKey = false; - _valueData = valueData; - _haveValue = false; - } - - public - Entry(Map map, Ice.Communicator communicator, Object key, byte[] valueData) + Entry(Map.EntryIterator iterator, Map map, Ice.Communicator communicator, com.sleepycat.db.Dbt dbKey, byte[] valueBytes) { - _map = map; - _cursor = null; - _communicator = communicator; - _key = key; - _haveKey = true; - _valueData = valueData; - _haveValue = false; + _iterator = iterator; + _map = map; + _communicator = communicator; + _dbKey = dbKey; + _valueBytes = valueBytes; } public Object @@ -527,8 +1004,8 @@ public abstract class Map extends java.util.AbstractMap { if(!_haveKey) { - assert(_keyData != null); - _key = _map.decodeKey(_keyData, _communicator); + assert(_dbKey != null); + _key = _map.decodeKey(_dbKey.get_data(), _communicator); _haveKey = true; } return _key; @@ -539,9 +1016,13 @@ public abstract class Map extends java.util.AbstractMap { if(!_haveValue) { - assert(_valueData != null); - _value = _map.decodeValue(_valueData, _communicator); + assert(_valueBytes != null); + _value = _map.decodeValue(_valueBytes, _communicator); _haveValue = true; + // + // Not needed anymore + // + _valueBytes = null; } return _value; } @@ -549,17 +1030,9 @@ public abstract class Map extends java.util.AbstractMap public Object setValue(Object value) { - Object old = getValue(); - if(_cursor != null) - { - byte[] v = _map.encodeValue(value, _communicator); - _cursor.set(v); - } - else - { - _map.put(getKey(), value); // Invalidates iterators. - } - _value = value; + Object old = getValue(); + _iterator.setValue(this, value); + _value = value; _haveValue = true; return old; } @@ -588,11 +1061,10 @@ public abstract class Map extends java.util.AbstractMap return getKey() + "=" + getValue(); } - void - invalidateCursor() - { - _cursor = null; - } + com.sleepycat.db.Dbt getDbKey() + { + return _dbKey; + } private /*static*/ boolean eq(Object o1, Object o2) @@ -600,19 +1072,23 @@ public abstract class Map extends java.util.AbstractMap return (o1 == null ? o2 == null : o1.equals(o2)); } - private Map _map; - private DBCursor _cursor; - private Ice.Communicator _communicator; - private Object _key; - private byte[] _keyData; - private boolean _haveKey; - private Object _value; - private byte[] _valueData; - private boolean _haveValue; + private Map.EntryIterator _iterator = null; + private Map _map = null; + private Ice.Communicator _communicator = null; + private com.sleepycat.db.Dbt _dbKey = null; + private byte[] _valueBytes = null; + private Object _key = null; + private boolean _haveKey = false; + private Object _value = null; + private boolean _haveValue = false; } - private java.util.Set _entrySet; - private DB _db; - private Ice.Communicator _communicator; - private java.util.List _iterators = new java.util.LinkedList(); + private java.util.Set _entrySet = null; + private SharedDbEnv _dbEnvHolder = null; + private com.sleepycat.db.DbEnv _dbEnv = null; + private com.sleepycat.db.Db _db = null; + private String _dbName = null; + private Ice.Communicator _communicator = null; + private String _errorPrefix = null; + private int _trace = 0; } diff --git a/java/src/Freeze/SharedDbEnv.java b/java/src/Freeze/SharedDbEnv.java new file mode 100644 index 00000000000..0c94c1e3a7b --- /dev/null +++ b/java/src/Freeze/SharedDbEnv.java @@ -0,0 +1,368 @@ +// ********************************************************************** +// +// Copyright (c) 2003 +// ZeroC, Inc. +// Billerica, MA, USA +// +// All Rights Reserved. +// +// Ice is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 2 as published by +// the Free Software Foundation. +// +// ********************************************************************** + +package Freeze; + +class SharedDbEnv extends com.sleepycat.db.DbEnv implements com.sleepycat.db.DbErrcall, Runnable +{ + public static SharedDbEnv + get(Ice.Communicator communicator, String envName) + { + MapKey key = new MapKey(envName, communicator); + + synchronized(_map) + { + SharedDbEnv result = (SharedDbEnv) _map.get(key); + if(result == null) + { + try + { + result = new SharedDbEnv(key); + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = errorPrefix(envName) + "creation: " + dx.getMessage(); + throw ex; + } + + Object previousValue = _map.put(key, result); + assert(previousValue == null); + } + else + { + result._refCount++; + } + return result; + } + } + + public String + getEnvName() + { + return _key.envName; + } + + public Ice.Communicator + getCommunicator() + { + return _key.communicator; + } + + public void + close() + { + synchronized(_map) + { + if(--_refCount == 0) + { + // + // Remove from map + // + Object value = _map.remove(_key); + assert(value == this); + + // + // Join thread + // + synchronized(this) + { + _done = true; + notify(); + } + + for(;;) + { + try + { + _thread.join(); + break; + } + catch(InterruptedException ex) + { + } + } + + if(_trace >= 1) + { + _key.communicator.getLogger().trace("DB", "closing database environment \"" + _key.envName + "\""); + } + + // + // Keep lock to prevent somebody else to re-open this DbEnv + // before it's closed. + // + try + { + super.close(0); + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = errorPrefix(_key.envName) + "close: " + dx.getMessage(); + throw ex; + } + } + } + } + + + synchronized public void + deleteOldLogs() + { + try + { + String[] list = log_archive(com.sleepycat.db.Db.DB_ARCH_ABS); + + for(int i = 0; i < list.length; i++) + { + // + // Remove each file + // + java.io.File file = new java.io.File(list[i]); + boolean ok = file.delete(); + if(!ok) + { + _key.communicator.getLogger().warning( + "could not delete file \"" + list[i] + "\""); + } + } + } + catch(com.sleepycat.db.DbException dx) + { + DBException ex = new DBException(); + ex.initCause(dx); + ex.message = errorPrefix(_key.envName) + "log_archive: " + dx.getMessage(); + throw ex; + } + } + + synchronized public void + moveOldLogs() + { + // + // Not yet implemented + // + assert(false); + } + + public void + run() + { + for(;;) + { + synchronized(this) + { + while(!_done) + { + try + { + wait(_checkpointPeriod); + } + catch(InterruptedException ex) + { + continue; + } + // + // Loop + // + } + if(_done) + { + return; + } + } + + try + { + txn_checkpoint(_kbyte, 0, 0); + } + catch(com.sleepycat.db.DbException dx) + { + _key.communicator.getLogger().warning( + "checkpoint on DbEnv \"" + _key.envName + "\" raised DbException: " + + dx.getMessage()); + } + + if(_autoDelete) + { + try + { + deleteOldLogs(); + } + catch(DBException ex) + { + _key.communicator.getLogger().warning( + "checkpoint on DbEnv \"" + _key.envName + "\" raised DBException: " + + ex.getMessage()); + } + + } + } + } + + public void + errcall(String errorPrefix, String message) + { + _key.communicator.getLogger().error("Freeze database error in DbEnv \"" + _key.envName + "\" :" + message); + } + + protected void + finalize() + { + assert(_refCount == 0); + } + + private SharedDbEnv(MapKey key) throws com.sleepycat.db.DbException + { + super(0); + _key = key; + + Ice.Properties properties = key.communicator.getProperties(); + _trace = properties.getPropertyAsInt("Freeze.Trace.DB"); + + if(_trace >= 1) + { + _key.communicator.getLogger().trace("DB", "opening database environment \"" + _key.envName + "\""); + } + + String propertyPrefix = "Freeze." + _key.envName; + + set_errcall(this); + + // + // Deadlock detection + // + set_lk_detect(com.sleepycat.db.Db.DB_LOCK_MINLOCKS); + + // + // Async tx + // + set_flags(com.sleepycat.db.Db.DB_TXN_NOSYNC, true); + + int flags = com.sleepycat.db.Db.DB_INIT_LOCK | + com.sleepycat.db.Db.DB_INIT_LOG | + com.sleepycat.db.Db.DB_INIT_MPOOL | + com.sleepycat.db.Db.DB_INIT_TXN; + + if(properties.getPropertyAsInt( + propertyPrefix + ".DbRecoverFatal") != 0) + { + flags |= com.sleepycat.db.Db.DB_RECOVER_FATAL | + com.sleepycat.db.Db.DB_CREATE; + } + else + { + flags |= com.sleepycat.db.Db. DB_RECOVER | + com.sleepycat.db.Db.DB_CREATE; + } + + if(properties.getPropertyAsIntWithDefault( + propertyPrefix + ".DbPrivate", 1) != 0) + { + flags |= com.sleepycat.db.Db.DB_PRIVATE; + } + + String dbHome = properties.getPropertyWithDefault( + propertyPrefix + ".DbHome", _key.envName); + + // + // TODO: FREEZE_DB_MODE + // + + try + { + open(dbHome, flags, 0); + } + catch(java.io.FileNotFoundException dx) + { + DBNotFoundException ex = new DBNotFoundException(); + ex.initCause(dx); + ex.message = errorPrefix(_key.envName) + "open: " + dx.getMessage(); + throw ex; + } + + // + // Default checkpoint period is every 10 minutes + // + _checkpointPeriod = properties.getPropertyAsIntWithDefault( + propertyPrefix + ".CheckpointPeriod", 10) * 60 * 1000; + + _kbyte = properties.getPropertyAsInt( + propertyPrefix + ".PeriodicCheckpointMinSize"); + + _autoDelete = (properties.getPropertyAsIntWithDefault( + propertyPrefix + ".OldLogsAutoDelete", 1) != 0); + + _thread = new Thread(this); + _thread.start(); + + _refCount = 1; + } + + private static String + errorPrefix(String envName) + { + return "DbEnv(\"" + envName + "\"): "; + } + + private static class MapKey + { + final String envName; + final Ice.Communicator communicator; + + MapKey(String envName, Ice.Communicator communicator) + { + this.envName = envName; + this.communicator = communicator; + } + + public boolean + equals(Object o) + { + try + { + MapKey k = (MapKey)o; + return (communicator == k.communicator) && envName.equals(k.envName); + } + catch(ClassCastException ex) + { + communicator.getLogger().trace("DB", "equals cast failed"); + return false; + } + } + + public int hashCode() + { + return envName.hashCode() ^ communicator.hashCode(); + } + } + + private MapKey _key; + private int _refCount = 0; + private boolean _done = false; + private int _trace = 0; + private long _checkpointPeriod = 0; + private int _kbyte = 0; + private boolean _autoDelete = false; + private Thread _thread; + + // + // Hash map of (MapKey, SharedDbEnv) + // + private static java.util.Map _map = new java.util.HashMap(); +} + diff --git a/java/src/Freeze/Util.java b/java/src/Freeze/Util.java index 35bda9949ce..a1f46c3ac90 100644 --- a/java/src/Freeze/Util.java +++ b/java/src/Freeze/Util.java @@ -16,16 +16,17 @@ package Freeze; public class Util { - public static DBEnvironment - initialize(Ice.Communicator communicator, String name) + + public static Evictor + createEvictor(Ice.Communicator communicator, String envName, String dbName, boolean createDb) { - return new DBEnvironmentI(communicator, name, false); - } + return new EvictorI(communicator, envName, dbName, createDb); + } - public static DBEnvironment - initializeWithTxn(Ice.Communicator communicator, String name) + public static Evictor + createEvictor(Ice.Communicator communicator, com.sleepycat.db.DbEnv dbEnv, String dbName, boolean createDb) { - return new DBEnvironmentI(communicator, name, true); - } + return new EvictorI(communicator, dbEnv, dbName, createDb); + } } diff --git a/java/src/Ice/PropertiesI.java b/java/src/Ice/PropertiesI.java index 14a6fc61fcb..6929a31924e 100644 --- a/java/src/Ice/PropertiesI.java +++ b/java/src/Ice/PropertiesI.java @@ -523,7 +523,8 @@ final class PropertiesI extends LocalObjectImpl implements Properties private static final String _freezeProps[] = { "Trace.DB", - "Trace.Evictor" + "Trace.Evictor", + "Evictor.*" }; private static final class ValidProps diff --git a/java/src/IceBox/ServiceManagerI.java b/java/src/IceBox/ServiceManagerI.java index ef8715d3025..1a93a70df4b 100644 --- a/java/src/IceBox/ServiceManagerI.java +++ b/java/src/IceBox/ServiceManagerI.java @@ -286,7 +286,7 @@ public final class ServiceManagerI extends _ServiceManagerDisp // IceBox::Service // Service s = (Service)info.service; - info.dbEnv = null; + info.envName = null; s.start(service, communicator, serviceArgs); } catch(ClassCastException e) @@ -299,10 +299,9 @@ public final class ServiceManagerI extends _ServiceManagerDisp // FreezeService fs = (FreezeService)info.service; - info.dbEnv = Freeze.Util.initialize(communicator, - properties.getProperty("IceBox.DBEnvName." + service)); + info.envName = properties.getProperty("IceBox.DBEnvName." + service); - fs.start(service, communicator, serviceArgs, info.dbEnv); + fs.start(service, communicator, serviceArgs, info.envName); } _services.put(service, info); } @@ -351,22 +350,6 @@ public final class ServiceManagerI extends _ServiceManagerDisp pw.flush(); _logger.warning("ServiceManager: exception in stop for service " + name + "\n" + sw.toString()); } - - if(info.dbEnv != null) - { - try - { - info.dbEnv.sync(); - } - catch(Exception e) - { - java.io.StringWriter sw = new java.io.StringWriter(); - java.io.PrintWriter pw = new java.io.PrintWriter(sw); - e.printStackTrace(pw); - pw.flush(); - _logger.warning("ServiceManager: exception in stop for service " + name + "\n" + sw.toString()); - } - } } // @@ -397,22 +380,6 @@ public final class ServiceManagerI extends _ServiceManagerDisp _logger.warning("ServiceManager: exception in stop for service " + name + "\n" + sw.toString()); } } - - if(info.dbEnv != null) - { - try - { - info.dbEnv.close(); - } - catch(Exception e) - { - java.io.StringWriter sw = new java.io.StringWriter(); - java.io.PrintWriter pw = new java.io.PrintWriter(sw); - e.printStackTrace(pw); - pw.flush(); - _logger.warning("ServiceManager: exception in stop for service " + name + "\n" + sw.toString()); - } - } if(info.communicator != null) { @@ -438,12 +405,11 @@ public final class ServiceManagerI extends _ServiceManagerDisp { public ServiceBase service; public Ice.Communicator communicator = null; - Freeze.DBEnvironment dbEnv; + String envName; } private Ice.Application _server; private Ice.Logger _logger; private String[] _argv; // Filtered server argument vector private java.util.HashMap _services = new java.util.HashMap(); - private java.util.HashMap _dbEnvs = new java.util.HashMap(); } |