package com.sleepycat.je;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.DbEnvPool;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.txn.Locker;
import com.sleepycat.je.txn.LockerFactory;
import com.sleepycat.je.utilint.Tracer;
import de.ovgu.cide.jakutil.*;
/**
* Javadoc for this public class is generated via the doc templates in the
* doc_src directory.
*/
public class Environment {
private static final String PROPFILE_NAME="je.properties";
protected EnvironmentImpl environmentImpl;
private TransactionConfig defaultTxnConfig;
private EnvironmentMutableConfig handleConfig;
private Set referringDbs;
private Set referringDbTxns;
private boolean valid;
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public Environment( File envHome, EnvironmentConfig configuration) throws DatabaseException {
environmentImpl=null;
referringDbs=Collections.synchronizedSet(new HashSet());
referringDbTxns=Collections.synchronizedSet(new HashSet());
valid=false;
DatabaseUtil.checkForNullParam(envHome,"envHome");
EnvironmentConfig baseConfig=(configuration == null) ? EnvironmentConfig.DEFAULT : configuration;
EnvironmentConfig useConfig=baseConfig.cloneConfig();
applyFileConfig(envHome,useConfig);
copyToHandleConfig(useConfig,useConfig);
DbEnvPool.EnvironmentImplInfo envInfo=DbEnvPool.getInstance().getEnvironment(envHome,useConfig);
environmentImpl=envInfo.envImpl;
environmentImpl.checkIfInvalid();
if (!envInfo.firstHandle && configuration != null) {
synchronized (environmentImpl) {
environmentImpl.checkImmutablePropsForEquality(useConfig);
}
}
if (!valid) {
valid=true;
}
environmentImpl.incReferenceCount();
}
/**
* Get an Environment for an existing EnvironmentImpl. Used by utilities
* such as the JMX MBean which don't want to open the environment or be
* reference counted. The calling application must take care not to retain
* the the doc templates in the doc_src directory.
*/
Environment( File envHome) throws DatabaseException {
environmentImpl=null;
valid=false;
DbEnvPool.EnvironmentImplInfo envInfo=DbEnvPool.getInstance().getExistingEnvironment(envHome);
EnvironmentImpl foundImpl=envInfo.envImpl;
if (foundImpl != null) {
foundImpl.checkIfInvalid();
environmentImpl=foundImpl;
environmentImpl.incReferenceCount();
EnvironmentConfig useConfig=EnvironmentConfig.DEFAULT.cloneConfig();
applyFileConfig(envHome,useConfig);
copyToHandleConfig(useConfig,useConfig);
referringDbs=Collections.synchronizedSet(new HashSet());
valid=true;
}
}
/**
* Apply the configurations specified in the je.properties file to override
* any programatically set configurations.
*/
private void applyFileConfig( File envHome, EnvironmentMutableConfig useConfig) throws IllegalArgumentException {
if (useConfig.getLoadPropertyFile()) {
File paramFile=null;
try {
paramFile=new File(envHome,PROPFILE_NAME);
Properties fileProps=new Properties();
FileInputStream fis=new FileInputStream(paramFile);
fileProps.load(fis);
fis.close();
useConfig.validateProperties(fileProps);
Iterator iter=fileProps.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry propPair=(Map.Entry)iter.next();
String name=(String)propPair.getKey();
String value=(String)propPair.getValue();
useConfig.setConfigParam(name,value);
}
}
catch ( FileNotFoundException e) {
}
catch ( IOException e) {
IllegalArgumentException e2=new IllegalArgumentException("An error occurred when reading " + paramFile);
e2.initCause(e);
throw e2;
}
}
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public synchronized void close() throws DatabaseException {
checkHandleIsValid();
try {
checkEnv();
}
catch ( RunRecoveryException e) {
if (environmentImpl != null) {
environmentImpl.closeAfterRunRecovery();
}
return;
}
StringBuffer errors=new StringBuffer();
try {
if (referringDbs != null) {
int nDbs=referringDbs.size();
if (nDbs != 0) {
errors.append("There ");
if (nDbs == 1) {
errors.append("is 1 open Database in the Environment.\n");
}
else {
errors.append("are ");
errors.append(nDbs);
errors.append(" open Database in the Environment.\n");
}
errors.append("Closing the following databases:\n");
Iterator iter=referringDbs.iterator();
while (iter.hasNext()) {
Database db=(Database)iter.next();
String dbName=db.getDebugName();
errors.append(dbName).append(" ");
try {
db.close();
}
catch ( RunRecoveryException e) {
throw e;
}
catch ( DatabaseException DBE) {
errors.append("\nWhile closing Database ");
errors.append(dbName);
errors.append(" encountered exception: ");
errors.append(DBE).append("\n");
}
}
}
}
if (referringDbTxns != null) {
int nTxns=referringDbTxns.size();
if (nTxns != 0) {
Iterator iter=referringDbTxns.iterator();
errors.append("There ");
if (nTxns == 1) {
errors.append("is 1 existing transaction opened against");
errors.append(" the Environment.\n");
}
else {
errors.append("are ");
errors.append(nTxns);
errors.append(" existing transactions opened against");
errors.append(" the Environment.\n");
}
errors.append("Aborting open transactions ...\n");
while (iter.hasNext()) {
Transaction txn=(Transaction)iter.next();
try {
txn.abort();
}
catch ( RunRecoveryException e) {
throw e;
}
catch ( DatabaseException DBE) {
errors.append("\nWhile aborting transaction ");
errors.append(txn.getId());
errors.append(" encountered exception: ");
errors.append(DBE).append("\n");
}
}
}
}
try {
environmentImpl.close();
}
catch ( RunRecoveryException e) {
throw e;
}
catch ( DatabaseException DBE) {
errors.append("\nWhile closing Environment encountered exception: ");
errors.append(DBE).append("\n");
}
}
finally {
environmentImpl=null;
valid=false;
if (errors.length() > 0) {
throw new DatabaseException(errors.toString());
}
}
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public synchronized Database openDatabase( Transaction txn, String databaseName, DatabaseConfig dbConfig) throws DatabaseException {
if (dbConfig == null) {
dbConfig=DatabaseConfig.DEFAULT;
}
Database db=new Database(this);
openDb(txn,db,databaseName,dbConfig,false);
return db;
}
/**
* Javadoc for this public class is generated via the doc templates in the
* doc_src directory.
*/
public synchronized SecondaryDatabase openSecondaryDatabase( Transaction txn, String databaseName, Database primaryDatabase, SecondaryConfig dbConfig) throws DatabaseException {
if (dbConfig == null) {
dbConfig=SecondaryConfig.DEFAULT;
}
SecondaryDatabase db=new SecondaryDatabase(this,dbConfig,primaryDatabase);
openDb(txn,db,databaseName,dbConfig,dbConfig.getAllowPopulate());
return db;
}
private void openDb( Transaction txn, Database newDb, String databaseName, DatabaseConfig dbConfig, boolean needWritableLockerForInit) throws DatabaseException {
checkEnv();
DatabaseUtil.checkForNullParam(databaseName,"databaseName");
this.hook58(databaseName,dbConfig);
validateDbConfigAgainstEnv(dbConfig,databaseName);
Locker locker=null;
boolean operationOk=false;
boolean dbIsClosing=false;
try {
boolean isWritableLocker=true;
if (needWritableLockerForInit) {
locker=LockerFactory.getWritableLocker(this,txn,dbConfig.getTransactional(),true,null);
isWritableLocker=true;
}
else {
locker=LockerFactory.getReadableLocker(this,txn,dbConfig.getTransactional(),true,false);
isWritableLocker=!dbConfig.getTransactional() || locker.isTransactional();
}
DatabaseImpl database=environmentImpl.getDb(locker,databaseName,newDb);
boolean databaseExists=false;
databaseExists=this.hook59(database,databaseExists);
if (databaseExists) {
if (dbConfig.getAllowCreate() && dbConfig.getExclusiveCreate()) {
dbIsClosing=true;
throw new DatabaseException("Database " + databaseName + " already exists");
}
newDb.initExisting(this,locker,database,dbConfig);
}
else {
if (dbConfig.getAllowCreate()) {
if (!isWritableLocker) {
locker.operationEnd(OperationStatus.SUCCESS);
locker=LockerFactory.getWritableLocker(this,txn,dbConfig.getTransactional(),true,null);
isWritableLocker=true;
}
newDb.initNew(this,locker,databaseName,dbConfig);
}
else {
throw new DatabaseNotFoundException("Database " + databaseName + " not found.");
}
}
operationOk=true;
addReferringHandle(newDb);
}
finally {
if (locker != null) {
locker.setHandleLockOwner(operationOk,newDb,dbIsClosing);
locker.operationEnd(operationOk);
}
}
}
private void validateDbConfigAgainstEnv( DatabaseConfig dbConfig, String databaseName) throws DatabaseException {
if (dbConfig.getTransactional() && !(environmentImpl.isTransactional())) {
throw new DatabaseException("Attempted to open Database " + databaseName + " transactionally, but parent Environment is"+ " not transactional");
}
if (environmentImpl.isReadOnly() && (!dbConfig.getReadOnly())) {
throw new DatabaseException("Attempted to open Database " + databaseName + " as writable but parent Environment is read only ");
}
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public File getHome() throws DatabaseException {
checkHandleIsValid();
return environmentImpl.getEnvironmentHome();
}
/**
* Returns the default txn config for this environment handle.
*/
TransactionConfig getDefaultTxnConfig(){
return defaultTxnConfig;
}
/**
* Copies the handle properties out of the config properties, and
* initializes the default transaction config.
*/
private void copyToHandleConfig( EnvironmentMutableConfig useConfig, EnvironmentConfig initStaticConfig) throws DatabaseException {
EnvironmentMutableConfig newHandleConfig=new EnvironmentMutableConfig();
useConfig.copyHandlePropsTo(newHandleConfig);
this.handleConfig=newHandleConfig;
TransactionConfig newTxnConfig=TransactionConfig.DEFAULT.cloneConfig();
newTxnConfig.setNoSync(handleConfig.getTxnNoSync());
newTxnConfig.setWriteNoSync(handleConfig.getTxnWriteNoSync());
if (initStaticConfig != null) {
newTxnConfig.setSerializableIsolation(initStaticConfig.getTxnSerializableIsolation());
newTxnConfig.setReadCommitted(initStaticConfig.getTxnReadCommitted());
}
else {
newTxnConfig.setSerializableIsolation(defaultTxnConfig.getSerializableIsolation());
newTxnConfig.setReadCommitted(defaultTxnConfig.getReadCommitted());
}
this.defaultTxnConfig=newTxnConfig;
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public Transaction beginTransaction( Transaction parent, TransactionConfig txnConfig) throws DatabaseException {
checkHandleIsValid();
checkEnv();
if (!environmentImpl.isTransactional()) {
throw new DatabaseException("Transactions can not be used in a non-transactional " + "environment");
}
if (txnConfig != null && ((txnConfig.getSerializableIsolation() && txnConfig.getReadUncommitted()) || (txnConfig.getSerializableIsolation() && txnConfig.getReadCommitted()) || (txnConfig.getReadUncommitted() && txnConfig.getReadCommitted()))) {
throw new IllegalArgumentException("Only one may be specified: SerializableIsolation, " + "ReadCommitted or ReadUncommitted");
}
TransactionConfig useConfig=null;
if (txnConfig == null) {
useConfig=defaultTxnConfig;
}
else {
if (defaultTxnConfig.getNoSync() || defaultTxnConfig.getWriteNoSync()) {
if (!txnConfig.getNoSync() && !txnConfig.getSync() && !txnConfig.getWriteNoSync()) {
useConfig=txnConfig.cloneConfig();
if (defaultTxnConfig.getWriteNoSync()) {
useConfig.setWriteNoSync(true);
}
else {
useConfig.setNoSync(true);
}
}
}
if (!txnConfig.getSerializableIsolation() && !txnConfig.getReadCommitted() && !txnConfig.getReadUncommitted()) {
if (defaultTxnConfig.getSerializableIsolation()) {
if (useConfig == null) {
useConfig=txnConfig.cloneConfig();
}
useConfig.setSerializableIsolation(true);
}
else if (defaultTxnConfig.getReadCommitted()) {
if (useConfig == null) {
useConfig=txnConfig.cloneConfig();
}
useConfig.setReadCommitted(true);
}
}
if (useConfig == null) {
useConfig=txnConfig;
}
}
Transaction txn=new Transaction(this,environmentImpl.txnBegin(parent,useConfig));
addReferringHandle(txn);
return txn;
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public void checkpoint( CheckpointConfig ckptConfig) throws DatabaseException {
checkHandleIsValid();
checkEnv();
CheckpointConfig useConfig=(ckptConfig == null) ? CheckpointConfig.DEFAULT : ckptConfig;
environmentImpl.invokeCheckpoint(useConfig,false,"api");
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public void sync() throws DatabaseException {
checkHandleIsValid();
checkEnv();
CheckpointConfig config=new CheckpointConfig();
config.setForce(true);
environmentImpl.invokeCheckpoint(config,true,"sync");
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public int cleanLog() throws DatabaseException {
checkHandleIsValid();
checkEnv();
return environmentImpl.invokeCleaner();
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public EnvironmentConfig getConfig() throws DatabaseException {
checkHandleIsValid();
EnvironmentConfig config=environmentImpl.cloneConfig();
handleConfig.copyHandlePropsTo(config);
config.fillInEnvironmentGeneratedProps(environmentImpl);
return config;
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public void setMutableConfig( EnvironmentMutableConfig mutableConfig) throws DatabaseException {
checkHandleIsValid();
DatabaseUtil.checkForNullParam(mutableConfig,"mutableConfig");
environmentImpl.setMutableConfig(mutableConfig);
copyToHandleConfig(mutableConfig,null);
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public EnvironmentMutableConfig getMutableConfig() throws DatabaseException {
checkHandleIsValid();
EnvironmentMutableConfig config=environmentImpl.cloneMutableConfig();
handleConfig.copyHandlePropsTo(config);
return config;
}
/**
* Not public yet, since there's nothing to upgrade.
*/
void upgrade() throws DatabaseException {
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public List getDatabaseNames() throws DatabaseException {
checkHandleIsValid();
checkEnv();
return environmentImpl.getDbNames();
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public Transaction getThreadTransaction() throws DatabaseException {
return (Transaction)environmentImpl.getTxnManager().getTxnForThread();
}
/**
* Javadoc for this public method is generated via the doc templates in the
* doc_src directory.
*/
public void setThreadTransaction( Transaction txn){
environmentImpl.getTxnManager().setTxnForThread(txn);
}
void addReferringHandle( Database db){
referringDbs.add(db);
}
/**
* Let the Environment remember what's opened against it.
*/
void addReferringHandle( Transaction txn){
referringDbTxns.add(txn);
}
/**
* The referring db has been closed.
*/
void removeReferringHandle( Database db){
referringDbs.remove(db);
}
/**
* The referring Transaction has been closed.
*/
void removeReferringHandle( Transaction txn){
referringDbTxns.remove(txn);
}
/**
* Internal entrypoint.
*/
EnvironmentImpl getEnvironmentImpl(){
return environmentImpl;
}
protected void checkHandleIsValid() throws DatabaseException {
if (!valid) {
throw new DatabaseException("Attempt to use non-open Environment object().");
}
}
/**
* Throws if the environmentImpl is invalid.
*/
protected void checkEnv() throws DatabaseException, RunRecoveryException {
if (environmentImpl == null) {
return;
}
environmentImpl.checkIfInvalid();
environmentImpl.checkNotClosed();
}
protected void hook58( String databaseName, DatabaseConfig dbConfig) throws DatabaseException {
}
protected boolean hook59( DatabaseImpl database, boolean databaseExists) throws DatabaseException {
return databaseExists;
}
}