// ********************************************************************** // // Copyright (c) 2003-2007 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** package Freeze; class SharedDbEnv implements com.sleepycat.db.ErrorHandler, Runnable { public static SharedDbEnv get(Ice.Communicator communicator, String envName, com.sleepycat.db.Environment dbEnv) { MapKey key = new MapKey(envName, communicator); SharedDbEnv result; synchronized(_map) { result = (SharedDbEnv)_map.get(key); if(result == null) { try { result = new SharedDbEnv(key, dbEnv); } catch(com.sleepycat.db.DatabaseException dx) { DatabaseException ex = new DatabaseException(); ex.initCause(dx); ex.message = errorPrefix(envName) + "creation: " + dx.getMessage(); throw ex; } Object previousValue = _map.put(key, result); assert(previousValue == null); } else { result._refCount++; } } // // Make sure the result if fully initialized // result.init(); return result; } public String getEnvName() { return _key.envName; } public Ice.Communicator getCommunicator() { return _key.communicator; } public com.sleepycat.db.Environment getEnv() { return _dbEnv; } public SharedDb getCatalog() { return _catalog; } 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(;;) { if(_thread != null) { try { _thread.join(); _thread = null; break; } catch(InterruptedException ex) { } } } // // Release catalog // if(_catalog != null) { _catalog.close(); _catalog = null; } if(_trace >= 1) { _key.communicator.getLogger().trace("Freeze.DbEnv", "closing database environment \"" + _key.envName + "\""); } // // Keep lock to prevent somebody else from re-opening this DbEnv // before it's closed. // try { _dbEnv.close(); } catch(com.sleepycat.db.DatabaseException dx) { DatabaseException ex = new DatabaseException(); ex.initCause(dx); ex.message = errorPrefix(_key.envName) + "close: " + dx.getMessage(); throw ex; } } } } public void run() { for(;;) { synchronized(this) { while(!_done) { try { wait(_checkpointPeriod); } catch(InterruptedException ex) { continue; } break; } if(_done) { return; } } if(_trace >= 2) { _key.communicator.getLogger().trace("Freeze.DbEnv", "checkpointing environment \"" + _key.envName + "\""); } try { com.sleepycat.db.CheckpointConfig config = new com.sleepycat.db.CheckpointConfig(); config.setKBytes(_kbyte); _dbEnv.checkpoint(config); } catch(com.sleepycat.db.DatabaseException dx) { _key.communicator.getLogger().warning("checkpoint on DbEnv \"" + _key.envName + "\" raised DbException: " + dx.getMessage()); } } } public void error(com.sleepycat.db.Environment env, 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, com.sleepycat.db.Environment dbEnv) throws com.sleepycat.db.DatabaseException { _key = key; _dbEnv = dbEnv; _ownDbEnv = (dbEnv == null); Ice.Properties properties = key.communicator.getProperties(); _trace = properties.getPropertyAsInt("Freeze.Trace.DbEnv"); if(_ownDbEnv) { com.sleepycat.db.EnvironmentConfig config = new com.sleepycat.db.EnvironmentConfig(); config.setErrorHandler(this); config.setInitializeLocking(true); config.setInitializeLogging(true); config.setInitializeCache(true); config.setAllowCreate(true); config.setTransactional(true); // // Deadlock detection // config.setLockDetectMode(com.sleepycat.db.LockDetectMode.YOUNGEST); String propertyPrefix = "Freeze.DbEnv." + _key.envName; if(properties.getPropertyAsInt(propertyPrefix + ".DbRecoverFatal") != 0) { config.setRunFatalRecovery(true); } else { config.setRunRecovery(true); } if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".DbPrivate", 1) != 0) { config.setPrivate(true); } if(properties.getPropertyAsIntWithDefault(propertyPrefix + ".OldLogsAutoDelete", 1) != 0) { config.setLogAutoRemove(true); } if(_trace >= 1) { _key.communicator.getLogger().trace("Freeze.DbEnv", "opening database environment \"" + _key.envName + "\""); } // // TODO: FREEZE_DB_MODE // try { String dbHome = properties.getPropertyWithDefault(propertyPrefix + ".DbHome", _key.envName); java.io.File home = new java.io.File(dbHome); _dbEnv = new com.sleepycat.db.Environment(home, config); } catch(java.io.FileNotFoundException dx) { NotFoundException ex = new NotFoundException(); ex.initCause(dx); ex.message = errorPrefix(_key.envName) + "open: " + dx.getMessage(); throw ex; } // // Default checkpoint period is every 120 seconds // _checkpointPeriod = properties.getPropertyAsIntWithDefault(propertyPrefix + ".CheckpointPeriod", 120) * 1000; _kbyte = properties.getPropertyAsIntWithDefault(propertyPrefix + ".PeriodicCheckpointMinSize", 0); String threadName; String programName = properties.getProperty("Ice.ProgramName"); if(programName.length() > 0) { threadName = programName + "-"; } else { threadName = ""; } threadName += "FreezeCheckpointThread(" + _key.envName + ")"; if(_checkpointPeriod > 0) { _thread = new Thread(this, threadName); _thread.start(); } } _refCount = 1; } private synchronized void init() { if(_catalog == null) { _catalog = SharedDb.openCatalog(this); } } 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("Freeze.DbEnv", "equals cast failed"); return false; } } public int hashCode() { return envName.hashCode() ^ communicator.hashCode(); } } private MapKey _key; private com.sleepycat.db.Environment _dbEnv; private boolean _ownDbEnv; private SharedDb _catalog; private int _refCount = 0; private boolean _done = false; private int _trace = 0; private long _checkpointPeriod = 0; private int _kbyte = 0; private Thread _thread; // // Hash map of (MapKey, SharedDbEnv) // private static java.util.Map _map = new java.util.HashMap(); }