All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.Environment Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je;

import java.io.Closeable;
import java.io.File;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;

import javax.transaction.xa.Xid;

import com.sleepycat.je.Durability.ReplicaAckPolicy;
import com.sleepycat.je.cleaner.ExtinctionScanner;
import com.sleepycat.je.dbi.DatabaseImpl;
import com.sleepycat.je.dbi.DbConfigManager;
import com.sleepycat.je.dbi.DbEnvPool;
import com.sleepycat.je.dbi.DbTree;
import com.sleepycat.je.dbi.DbTree.TruncateDbResult;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.dbi.RepConfigProxy;
import com.sleepycat.je.dbi.StartupTracker.Phase;
import com.sleepycat.je.dbi.TriggerManager;
import com.sleepycat.je.txn.HandleLocker;
import com.sleepycat.je.txn.Locker;
import com.sleepycat.je.txn.LockerFactory;
import com.sleepycat.je.txn.Txn;
import com.sleepycat.je.utilint.DatabaseUtil;
import com.sleepycat.je.utilint.LoggerUtils;
import com.sleepycat.je.utilint.Pair;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A database environment.  Environments include support for some or all of
 * caching, locking, logging and transactions.
 *
 * 

To open an existing environment with default attributes the application * may use a default environment configuration object or null: *

*
 *      // Open an environment handle with default attributes.
 *     Environment env = new Environment(home, new EnvironmentConfig());
 *     
*
* or *
 *     Environment env = new Environment(home, null);
 * 
*

Note that many Environment objects may access a single environment.

*

To create an environment or customize attributes, the application should * customize the configuration class. For example:

*
 *     EnvironmentConfig envConfig = new EnvironmentConfig();
 *     envConfig.setTransactional(true);
 *     envConfig.setAllowCreate(true);
 *     envConfig.setCacheSize(1000000);
 *     Environment newlyCreatedEnv = new Environment(home, envConfig);
 * 
* *

Note that environment configuration parameters can also be set through * the <environment home>/je.properties file. This file takes precedence * over any programmatically specified configuration parameters so that * configuration changes can be made without recompiling. Environment * configuration follows this order of precedence:

* *
    *
  1. Configuration parameters specified in * <environment home>/je.properties take first precedence. *
  2. Configuration parameters set in the EnvironmentConfig object used at * Environment construction e tameters not set by the application are set to * system defaults, described along with the parameter name String constants * in the EnvironmentConfig class. *
* *

An environment handle is an Environment instance. More than one * Environment instance may be created for the same physical directory, which * is the same as saying that more than one Environment handle may be open at * one time for a given environment.

* * The Environment handle should not be closed while any other handle remains * open that is using it as a reference (for example, {@link * com.sleepycat.je.Database Database} or {@link com.sleepycat.je.Transaction * Transaction}. Once {@link com.sleepycat.je.Environment#close * Environment.close} is called, this object may not be accessed again. */ public class Environment implements Closeable { /** * envImpl is a reference to the shared underlying environment. * * The envImpl field is set to null during close to avoid OOME. It * should normally only be accessed via the checkOpen and * getNonNullEnvImpl methods. During close, while synchronized, it is safe * to access it directly. */ private volatile EnvironmentImpl environmentImpl; /* * If the env was invalided (even if the env is now closed) this contains * the first EFE that invalidated it. Contains null if the env was not * invalidated. * * This reference is shared with EnvironmentImpl, to allow the invalidating * exception to be returned after close, when environmentImpl is null. * The EFE does not reference the EnvironmentImpl, so GC is not effected. * * This field cannot be declared as final because it is initialized by * methods called by the ctor. However, after construction it is non-null * and should be treated as final. */ private AtomicReference invalidatingEFE; private TransactionConfig defaultTxnConfig; private EnvironmentMutableConfig handleConfig; private final EnvironmentConfig appliedFinalConfig; private final Map referringDbs; private final Map referringDbTxns; /** * @hidden * The name of the cleaner daemon thread. This constant is passed to an * ExceptionEvent's threadName argument when an exception is thrown in the * cleaner daemon thread. */ public static final String CLEANER_NAME = "Cleaner"; /** * @hidden * The name of the IN Compressor daemon thread. This constant is passed to * an ExceptionEvent's threadName argument when an exception is thrown in * the IN Compressor daemon thread. */ public static final String INCOMP_NAME = "INCompressor"; /** * @hidden * The name of the Checkpointer daemon thread. This constant is passed to * an ExceptionEvent's threadName argument when an exception is thrown in * the Checkpointer daemon thread. */ public static final String CHECKPOINTER_NAME = "Checkpointer"; /** * @hidden * The name of the StatCapture daemon thread. This constant is passed to * an ExceptionEvent's threadName argument when an exception is thrown in * the StatCapture daemon thread. */ public static final String STATCAPTURE_NAME = "StatCapture"; /** * @hidden * The name of the log flusher daemon thread. */ public static final String LOG_FLUSHER_NAME = "LogFlusher"; /** * @hidden * The name of the deletion detector daemon thread. */ public static final String FILE_DELETION_DETECTOR_NAME = "FileDeletionDetector"; /** * @hidden * The name of the data corruption verifier daemon thread. */ public static final String DATA_CORRUPTION_VERIFIER_NAME = "DataCorruptionVerifier"; /** * Creates a database environment handle. * * @param envHome The database environment's home directory. * * @param configuration The database environment attributes. If null, * default attributes are used. * * @throws EnvironmentNotFoundException if the environment does not exist * (does not contain at least one log file) and the {@code * EnvironmentConfig AllowCreate} parameter is false. * * @throws EnvironmentLockedException when an environment cannot be opened * for write access because another process has the same environment open * for write access. Warning: This exception should be * handled when an environment is opened by more than one process. * * @throws VersionMismatchException when the existing log is not compatible * with the version of JE that is running. This occurs when a later * version of JE was used to create the log. Warning: * This exception should be handled when more than one version of JE may be * used to access an environment. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this environment was previously * opened for replication and is not being opened read-only. * * @throws IllegalArgumentException if an invalid parameter is specified, * for example, an invalid {@code EnvironmentConfig} parameter. */ public Environment(File envHome, EnvironmentConfig configuration) throws EnvironmentNotFoundException, EnvironmentLockedException, VersionMismatchException, DatabaseException, IllegalArgumentException { this(envHome, configuration, null /*repConfigProxy*/, null /*envImplParam*/); } /** * @hidden * Internal common constructor. * * @param envImpl is non-null only when used by EnvironmentImpl to * create an InternalEnvironment. */ protected Environment(File envHome, EnvironmentConfig envConfig, RepConfigProxy repConfigProxy, EnvironmentImpl envImpl) { referringDbs = new ConcurrentHashMap(); referringDbTxns = new ConcurrentHashMap(); DatabaseUtil.checkForNullParam(envHome, "envHome"); appliedFinalConfig = setupHandleConfig(envHome, envConfig, repConfigProxy); if (envImpl != null) { /* We're creating an InternalEnvironment in EnvironmentImpl. */ environmentImpl = envImpl; } else { /* Open a new or existing environment in the shared pool. */ environmentImpl = makeEnvironmentImpl(envHome, envConfig, repConfigProxy); /* Standalone env initialization is now fully complete. */ if (!environmentImpl.isReplicated()) { environmentImpl.fullyInitialized(); } } } /** * @hidden * makeEnvironmentImpl() is called both by the Environment constructor and * by the ReplicatedEnvironment constructor when recreating the environment * for a hard recovery. */ protected EnvironmentImpl makeEnvironmentImpl( File envHome, EnvironmentConfig envConfig, RepConfigProxy repConfigProxy) { environmentImpl = DbEnvPool.getInstance().getEnvironment( envHome, appliedFinalConfig, envConfig != null /*checkImmutableParams*/, setupRepConfig(envHome, repConfigProxy, envConfig)); environmentImpl.registerMBean(this); invalidatingEFE = environmentImpl.getInvalidatingExceptionReference(); return environmentImpl; } /** * Validate the parameters specified in the environment config. Applies * the configurations specified in the je.properties file to override any * programmatically set configurations. Create a copy to save in this * handle. The main reason to return a config instead of using the * handleConfig field is to return an EnvironmentConfig instead of a * EnvironmentMutableConfig. */ private EnvironmentConfig setupHandleConfig(File envHome, EnvironmentConfig envConfig, RepConfigProxy repConfig) throws IllegalArgumentException { /* If the user specified a null object, use the default */ EnvironmentConfig baseConfig = (envConfig == null) ? EnvironmentConfig.DEFAULT : envConfig; /* Make a copy, apply je.properties, and init the handle config. */ EnvironmentConfig useConfig = baseConfig.clone(); /* Apply the je.properties file. */ if (useConfig.getLoadPropertyFile()) { DbConfigManager.applyFileConfig(envHome, DbInternal.getProps(useConfig), false); // forReplication } copyToHandleConfig(useConfig, useConfig, repConfig); return useConfig; } /** * @hidden * Obtain a validated replication configuration. In a non-HA environment, * return null. */ protected RepConfigProxy setupRepConfig(final File envHome, final RepConfigProxy repConfigProxy, final EnvironmentConfig envConfig) { return null; } /** * The Environment.close method closes the Berkeley DB environment. * *

When the last environment handle is closed, allocated resources are * freed, and daemon threads are stopped, even if they are performing work. * For example, if the cleaner is still cleaning the log, it will be * stopped at the next reasonable opportunity and perform no more cleaning * operations. After stopping background threads, a final checkpoint is * performed by this method, in order to reduce the time to recover the * next time the environment is opened.

* *

When minimizing recovery time is desired, it is often useful to stop * all application activity and perform an additional checkpoint prior to * calling {@code close}. This additional checkpoint will write most of * dirty Btree information, so that that the final checkpoint is very * small (and recovery is fast). To ensure that recovery time is minimized, * the log cleaner threads should also be stopped prior to the extra * checkpoint. This prevents log cleaning from dirtying the Btree, which * can make the final checkpoint larger (and recovery time longer). The * recommended procedure for minimizing recovery time is:

* *
     *     // Stop/finish all application operations that are using JE.
     *     ...
     *
     *     // Stop the cleaner daemon threads.
     *     EnvironmentMutableConfig config = env.getMutableConfig();
     *     config.setConfigParam(EnvironmentConfig.ENV_RUN_CLEANER, "false");
     *     env.setMutableConfig(config);
     *
     *     // Perform an extra checkpoint
     *     env.checkpoint(new CheckpointConfig().setForce(true));
     *
     *     // Finally, close the environment.
     *     env.close();
     * 
* *

The Environment handle should not be closed while any other handle * that refers to it is not yet closed; for example, database environment * handles must not be closed while database handles remain open, or * transactions in the environment have not yet committed or aborted. * Specifically, this includes {@link com.sleepycat.je.Database Database}, * and {@link com.sleepycat.je.Transaction Transaction} handles.

* *

If this handle has already been closed, this method does nothing and * returns without throwing an exception.

* *

In multithreaded applications, only a single thread should call * Environment.close.

* *

The environment handle may not be used again after this method has * been called, regardless of the method's success or failure, with one * exception: the {@code close} method itself may be called any number of * times.

* *

WARNING: To guard against memory leaks, the application should * discard all references to the closed handle. While BDB makes an effort * to discard references from closed objects to the allocated memory for an * environment, this behavior is not guaranteed. The safe course of action * for an application is to discard all references to closed BDB * objects.

* * @throws EnvironmentWedgedException when the current process must be * shut down and restarted before re-opening the Environment. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws DiskLimitException if the final checkpoint cannot be performed * because a disk limit has been violated. The Environment will be closed, * but this exception will be thrown so that the application is aware that * a checkpoint was not performed. * * @throws IllegalStateException if any open databases or transactions * refer to this handle. The Environment will be closed, but this exception * will be thrown so that the application is aware that not all databases * and transactions were closed. */ public synchronized void close() throws DatabaseException { if (environmentImpl == null) { return; } if (!environmentImpl.isValid()) { /* * We're trying to close on an environment that has seen a fatal * exception. Try to do the minimum, such as closing file * descriptors, to support re-opening the environment in the same * JVM. */ try { environmentImpl.closeAfterInvalid(); } finally { clearEnvImpl(); for (Database db : referringDbs.keySet()) { db.minimalClose(Database.DbState.CLOSED, null); } } return; } final StringBuilder errors = new StringBuilder(); try { checkForCloseErrors(errors); try { environmentImpl.close(); } catch (DatabaseException e) { e.addErrorMessage(errors.toString()); throw e; } catch (RuntimeException e) { if (errors.length() > 0) { throw new IllegalStateException(errors.toString(), e); } throw e; } if (errors.length() > 0) { throw new IllegalStateException(errors.toString()); } } finally { clearEnvImpl(); } } /** * Set environmentImpl to null during close, to allow GC when the app may * hold on to a reference to the Environment handle for some time period. */ void clearEnvImpl() { environmentImpl = null; } /** * Close an InternalEnvironment handle. We do not call * EnvironmentImpl.close here, since an InternalEnvironment is not * registered like a non-internal handle. However, we must call * checkForCloseErrors to auto-close internal databases, as well as check * for errors. */ synchronized void closeInternalHandle() { final StringBuilder errors = new StringBuilder(); checkForCloseErrors(errors); if (errors.length() > 0) { throw new IllegalStateException(errors.toString()); } } private void checkForCloseErrors(StringBuilder errors) { checkOpenDbs(errors); checkOpenTxns(errors); if (!isInternalHandle()) { /* * Only check for open XA transactions against user created * environment handles. */ checkOpenXATransactions(errors); } } /** * Appends error messages to the errors argument if there are * open XA transactions associated with the underlying EnvironmentImpl. */ private void checkOpenXATransactions(final StringBuilder errors) { Xid[] openXids = getNonNullEnvImpl().getTxnManager().XARecover(); if (openXids != null && openXids.length > 0) { errors.append("There "); int nXATxns = openXids.length; if (nXATxns == 1) { errors.append("is 1 existing XA transaction opened"); errors.append(" in the Environment.\n"); errors.append("It"); } else { errors.append("are "); errors.append(nXATxns); errors.append(" existing transactions opened in"); errors.append(" the Environment.\n"); errors.append("They"); } errors.append(" will be left open ...\n"); } } /** * Appends error messages to the errors argument if there are open * transactions associated with the environment. */ private void checkOpenTxns(final StringBuilder errors) { int nTxns = (referringDbTxns == null) ? 0 : referringDbTxns.size(); if (nTxns == 0) { return; } errors.append("There "); if (nTxns == 1) { errors.append("is 1 existing transaction opened"); errors.append(" against 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"); for (Transaction txn : referringDbTxns.keySet()) { try { errors.append("aborting " + txn); txn.abort(); } catch (RuntimeException e) { if (!environmentImpl.isValid()) { /* Propagate if env is invalidated. */ throw e; } errors.append("\nWhile aborting transaction "); errors.append(txn.getId()); errors.append(" encountered exception: "); errors.append(e).append("\n"); } } } /** * Appends error messages to the errors argument if there are open database * handles associated with the environment. */ private void checkOpenDbs(final StringBuilder errors) { if (referringDbs.isEmpty()) { return; } int nOpenUserDbs = 0; for (Database db : referringDbs.keySet()) { String dbName = ""; try { /* * Save the db name before we attempt the close, it's * unavailable after the close. */ dbName = db.getDatabaseName(); if (!db.getDbImpl().isInternalDb()) { nOpenUserDbs += 1; errors.append("Unclosed Database: "); errors.append(dbName).append("\n"); } db.close(); } catch (RuntimeException e) { if (!environmentImpl.isValid()) { /* Propagate if env is invalidated. */ throw e; } errors.append("\nWhile closing Database "); errors.append(dbName); errors.append(" encountered exception: "); errors.append(LoggerUtils.getStackTrace(e)).append("\n"); } } if (nOpenUserDbs > 0) { errors.append("Databases left open: "); errors.append(nOpenUserDbs).append("\n"); } } /** * Opens, and optionally creates, a Database. * * @param txn For a transactional database, an explicit transaction may be * specified, or null may be specified to use auto-commit. For a * non-transactional database, null must be specified. * * @param databaseName The name of the database. * * @param dbConfig The database attributes. If null, default attributes * are used. * * @return Database handle. * * @throws DatabaseExistsException if the database already exists and the * {@code DatabaseConfig ExclusiveCreate} parameter is true. * * @throws DatabaseNotFoundException if the database does not exist and the * {@code DatabaseConfig AllowCreate} parameter is false. * * @throws OperationFailureException if one of the Read Operation * Failures occurs. If the database does not exist and the {@link * DatabaseConfig#setAllowCreate AllowCreate} parameter is true, then one * of the Write * Operation Failures may also occur. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified, * for example, an invalid {@code DatabaseConfig} property. * * @throws IllegalStateException if DatabaseConfig properties are changed * and there are other open handles for this database. */ public synchronized Database openDatabase(Transaction txn, String databaseName, DatabaseConfig dbConfig) throws DatabaseNotFoundException, DatabaseExistsException, IllegalArgumentException, IllegalStateException { final EnvironmentImpl envImpl = checkOpen(); if (dbConfig == null) { dbConfig = DatabaseConfig.DEFAULT; } try { final Database db = new Database(this); setupDatabase( envImpl, txn, db, databaseName, dbConfig, false /*isInternalDb*/); return db; } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Opens and optionally creates a SecondaryDatabase. * *

Note that the associations between primary and secondary databases * are not stored persistently. Whenever a primary database is opened for * write access by the application, the appropriate associated secondary * databases should also be opened by the application. This is necessary * to ensure data integrity when changes are made to the primary * database.

* * @param txn For a transactional database, an explicit transaction may be * specified, or null may be specified to use auto-commit. For a * non-transactional database, null must be specified. * * @param databaseName The name of the database. * * @param primaryDatabase the primary database with which the secondary * database will be associated. The primary database must not be * configured for duplicates. * * @param dbConfig The secondary database attributes. If null, default * attributes are used. * * @return Database handle. * * @throws DatabaseExistsException if the database already exists and the * {@code DatabaseConfig ExclusiveCreate} parameter is true. * * @throws DatabaseNotFoundException if the database does not exist and the * {@code DatabaseConfig AllowCreate} parameter is false. * * @throws OperationFailureException if one of the Read Operation * Failures occurs. If the database does not exist and the {@link * DatabaseConfig#setAllowCreate AllowCreate} parameter is true, then one * of the Write * Operation Failures may also occur. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified, * for example, an invalid {@code SecondaryConfig} property. * * @throws IllegalStateException if DatabaseConfig properties are changed * and there are other open handles for this database. */ public synchronized SecondaryDatabase openSecondaryDatabase( Transaction txn, String databaseName, Database primaryDatabase, SecondaryConfig dbConfig) throws DatabaseNotFoundException, DatabaseExistsException, DatabaseException, IllegalArgumentException, IllegalStateException { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.getSecondaryAssociationLock(). writeLock().lockInterruptibly(); } catch (InterruptedException e) { throw new ThreadInterruptedException(envImpl, e); } try { if (dbConfig == null) { dbConfig = SecondaryConfig.DEFAULT; } final SecondaryDatabase db = new SecondaryDatabase(this, dbConfig, primaryDatabase); setupDatabase( envImpl, txn, db, databaseName, dbConfig, false /*isInternalDb*/); return db; } catch (Error E) { envImpl.invalidate(E); throw E; } finally { envImpl.getSecondaryAssociationLock().writeLock().unlock(); } } /** * The meat of open database processing. * * Currently, only external DBs are opened via this method, but we may * allow internal DB opens in the future. * * @param txn may be null * @param newDb is the Database handle which houses this database * * @throws IllegalArgumentException via openDatabase and * openSecondaryDatabase * * @see HandleLocker */ private void setupDatabase(EnvironmentImpl envImpl, Transaction txn, Database newDb, String databaseName, DatabaseConfig dbConfig, boolean isInternalDb) throws DatabaseNotFoundException, DatabaseExistsException { DatabaseUtil.checkForNullParam(databaseName, "databaseName"); LoggerUtils.envLogMsg(Level.FINEST, envImpl, "Environment.open: " + " name=" + databaseName + " dbConfig=" + dbConfig); final boolean autoTxnIsReplicated = dbConfig.getReplicated() && envImpl.isReplicated(); /* * Check that the open configuration is valid and doesn't conflict with * the envImpl configuration. */ dbConfig.validateOnDbOpen(databaseName, autoTxnIsReplicated); validateDbConfigAgainstEnv( envImpl, dbConfig, databaseName, isInternalDb); /* Perform eviction before each operation that allocates memory. */ envImpl.criticalEviction(false /*backgroundIO*/); DatabaseImpl database = null; boolean operationOk = false; HandleLocker handleLocker = null; final Locker locker = LockerFactory.getWritableLocker (this, txn, isInternalDb, dbConfig.getTransactional(), autoTxnIsReplicated, null); try { /* * Create the handle locker and lock the NameLN of an existing * database. A read lock on the NameLN is acquired for both locker * and handleLocker. Note: getDb may return a deleted database. */ handleLocker = newDb.initHandleLocker(envImpl, locker); database = envImpl.getDbTree().getDb(locker, databaseName, handleLocker, false); boolean dbCreated = false; final boolean databaseExists = (database != null) && !database.isDeleting(); if (databaseExists) { if (dbConfig.getAllowCreate() && dbConfig.getExclusiveCreate()) { throw new DatabaseExistsException ("Database " + databaseName + " already exists"); } newDb.initExisting(this, locker, database, databaseName, dbConfig); } else { /* Release deleted DB. [#13415] */ envImpl.getDbTree().releaseDb(database); database = null; if (!isInternalDb && DbTree.isReservedDbName(databaseName)) { throw new IllegalArgumentException (databaseName + " is a reserved database name."); } if (!dbConfig.getAllowCreate()) { throw new DatabaseNotFoundException("Database " + databaseName + " not found."); } /* * Init a new DB. This calls DbTree.createDb and the new * database is returned. A write lock on the NameLN is * acquired by locker and a read lock by the handleLocker. */ database = newDb.initNew(this, locker, databaseName, dbConfig); dbCreated = true; } /* * The open is successful. We add the opened database handle to * this environment to track open handles in general, and to the * locker so that it can be invalidated by a user txn abort. */ operationOk = true; addReferringHandle(newDb); locker.addOpenedDatabase(newDb); /* Run triggers before any subsequent auto commits. */ final boolean firstWriteHandle = newDb.isWritable() && (newDb.getDbImpl().noteWriteHandleOpen() == 1); if (dbCreated || firstWriteHandle) { TriggerManager.runOpenTriggers(locker, newDb, dbCreated); } } finally { /* * If the open fails, decrement the DB usage count, release * handle locks and remove references from other objects. In other * cases this is done by Database.close() or invalidate(), the * latter in the case of a user txn abort. */ if (!operationOk) { envImpl.getDbTree().releaseDb(database); if (handleLocker != null) { handleLocker.operationEnd(false); } newDb.removeReferringAssociations(); } /* * Tell the locker that this operation is over. Some types of * lockers (BasicLocker and auto Txn) will actually finish. */ locker.operationEnd(operationOk); } } /** * @throws IllegalArgumentException via openDatabase and * openSecondaryDatabase */ private void validateDbConfigAgainstEnv(EnvironmentImpl envImpl, DatabaseConfig dbConfig, String databaseName, boolean isInternalDb) throws IllegalArgumentException { /* * R/W database handles on a replicated database must be transactional, * for now. In the future we may support non-transactional database * handles. */ if (envImpl.isReplicated() && dbConfig.getReplicated() && !dbConfig.getReadOnly()) { if (!dbConfig.getTransactional()) { throw new IllegalArgumentException ("Read/Write Database instances for replicated " + "database " + databaseName + " must be transactional."); } } /* Check operation's transactional status against the Environment */ if (!isInternalDb && dbConfig.getTransactional() && !(envImpl.isTransactional())) { throw new IllegalArgumentException ("Attempted to open Database " + databaseName + " transactionally, but parent Environment is" + " not transactional"); } /* Check read/write status */ if (envImpl.isReadOnly() && (!dbConfig.getReadOnly())) { throw new IllegalArgumentException ("Attempted to open Database " + databaseName + " as writable but parent Environment is read only "); } } /** * Removes a database from the environment, discarding all records in the * database and removing the database name itself. * *

Compared to deleting all the records in a database individually, * {@code removeDatabase} is a very efficient operation. Some internal * housekeeping information is updated, but the database records are not * read or written, and very little I/O is needed.

* *

When called on a database configured with secondary indices, the * application is responsible for also removing all associated secondary * indices. To guarantee integrity, a primary database and all of its * secondary databases should be removed atomically using a single * transaction.

* *

Applications should not remove a database with open {@link Database * Database} handles. If the database is open with the same transaction as * passed in the {@code txn} parameter, {@link IllegalStateException} is * thrown by this method. If the database is open using a different * transaction, this method will block until all database handles are * closed, or until the conflict is resolved by throwing {@link * LockConflictException}.

* * @param txn For a transactional environment, an explicit transaction * may be specified or null may be specified to use auto-commit. For a * non-transactional environment, null must be specified. * * @param databaseName The database to be removed. * * @throws DatabaseNotFoundException if the database does not exist. * * @throws OperationFailureException if one of the Write * Operation Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only * environment. * * @throws IllegalStateException if the database is currently open using * the transaction passed in the {@code txn} parameter, or if this handle * or the underlying environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified. */ public void removeDatabase(final Transaction txn, final String databaseName) throws DatabaseNotFoundException { DatabaseUtil.checkForNullParam(databaseName, "databaseName"); new DbNameOperation(txn) { Pair runWork(final Locker locker) throws DatabaseNotFoundException, DbTree.NeedRepLockerException { final DatabaseImpl dbImpl = dbTree.dbRemove(locker, databaseName, null /*checkId*/); return new Pair<>(dbImpl, null); } void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { TriggerManager.runRemoveTriggers(locker, dbImpl); } }.run(); } /** * Renames a database, without removing the records it contains. * *

Applications should not rename a database with open {@link Database * Database} handles. If the database is open with the same transaction as * passed in the {@code txn} parameter, {@link IllegalStateException} is * thrown by this method. If the database is open using a different * transaction, this method will block until all database handles are * closed, or until the conflict is resolved by throwing {@link * LockConflictException}.

* * @param txn For a transactional environment, an explicit transaction * may be specified or null may be specified to use auto-commit. For a * non-transactional environment, null must be specified. * * @param databaseName The new name of the database. * * @throws DatabaseNotFoundException if the database does not exist. * * @throws OperationFailureException if one of the Write * Operation Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only * environment. * * @throws IllegalStateException if the database is currently open using * the transaction passed in the {@code txn} parameter, or if this handle * or the underlying environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified. */ public void renameDatabase(final Transaction txn, final String databaseName, final String newName) throws DatabaseNotFoundException { DatabaseUtil.checkForNullParam(databaseName, "databaseName"); DatabaseUtil.checkForNullParam(newName, "newName"); new DbNameOperation(txn) { Pair runWork(final Locker locker) throws DatabaseNotFoundException, DbTree.NeedRepLockerException { final DatabaseImpl dbImpl = dbTree.dbRename(locker, databaseName, newName); return new Pair<>(dbImpl, null); } void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { TriggerManager.runRenameTriggers(locker, dbImpl, newName); } }.run(); } /** * Empties the database, discarding all the records it contains, without * removing the database name. * *

Compared to deleting all the records in a database individually, * {@code truncateDatabase} is a very efficient operation. Some internal * housekeeping information is updated, but the database records are not * read or written, and very little I/O is needed.

* *

When called on a database configured with secondary indices, the * application is responsible for also truncating all associated secondary * indices. To guarantee integrity, a primary database and all of its * secondary databases should be truncated atomically using a single * transaction.

* *

Applications should not truncate a database with open {@link Database * Database} handles. If the database is open with the same transaction as * passed in the {@code txn} parameter, {@link IllegalStateException} is * thrown by this method. If the database is open using a different * transaction, this method will block until all database handles are * closed, or until the conflict is resolved by throwing {@link * LockConflictException}.

* * @param txn For a transactional environment, an explicit transaction may * be specified or null may be specified to use auto-commit. For a * non-transactional environment, null must be specified. * * @param databaseName The database to be truncated. * * @param returnCount If true, count and return the number of records * discarded. * * @return The number of records discarded, or -1 if returnCount is false. * * @throws DatabaseNotFoundException if the database does not exist. * * @throws OperationFailureException if one of the Write * Operation Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only * environment. * * @throws IllegalStateException if the database is currently open using * the transaction passed in the {@code txn} parameter, or if this handle * or the underlying environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified. */ public long truncateDatabase(final Transaction txn, final String databaseName, final boolean returnCount) throws DatabaseNotFoundException { DatabaseUtil.checkForNullParam(databaseName, "databaseName"); return (new DbNameOperation(txn) { Pair runWork(final Locker locker) throws DatabaseNotFoundException, DbTree.NeedRepLockerException { final TruncateDbResult result = dbTree.truncate(locker, databaseName, returnCount); return new Pair<>(result.newDb, result.recordCount); } void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { TriggerManager.runTruncateTriggers(locker, dbImpl); } }).run(); } /** * Runs a DB naming operation: remove, truncate or rename. The common code * is factored out here. In particular this class handles non-replicated * DBs in a replicated environment, when auto-commit is used. *

* For a non-replicated DB, an auto-commit txn must be created by calling * LockerFactory.getWritableLocker with the autoTxnIsReplicated param set * to false. If autoTxnIsReplicated is set to true in a replicated * environment, HA consistency checks will be made when the txn is begun * and acks will be enforced at commit. For example, for an HA node in an * unknown state, the consistency checks would fail and prevent performing * the operation on the local/non-replicated DB. *

* Unfortunately, we need to create a txn/locker in order to query the DB * metadata, to determine whether it is replicated. Therefore, we always * attempt the operation initially with autoTxnIsReplicated set to false. * The DbTree name operation methods (see DbTree.lockNameLN) will throw an * internal exception (NeedRepLockerException) if a non-replicated * auto-commit txn is used on a replicated DB. That signals this class to * retry the operation with autoTxnIsReplicated set to true. *

* Via an unlikely series of DB renaming it is possible that on the 2nd try * with a replicated txn, we find that the DB is non-replicated. However, * there is little harm in proceeding, since the consistency check is * already done. */ private abstract class DbNameOperation { private final EnvironmentImpl envImpl; private final Transaction txn; final DbTree dbTree; DbNameOperation(final Transaction txn) { this.txn = txn; this.envImpl = checkOpen(); checkWritable(envImpl); dbTree = envImpl.getDbTree(); } /** Run the DB name operation. */ abstract Pair runWork(final Locker locker) throws DatabaseNotFoundException, DbTree.NeedRepLockerException; /** Run triggers after a successful DB name operation. */ abstract void runTriggers(final Locker locker, final DatabaseImpl dbImpl); /** * Try the operation with autoTxnIsReplicated=false, and then again * with autoTxnIsReplicated=true if NeedRepLockerException is thrown. */ R run() throws DatabaseNotFoundException { try { return runOnce(getWritableLocker(false)); } catch (DbTree.NeedRepLockerException e) { try { return runOnce(getWritableLocker(true)); } catch (DbTree.NeedRepLockerException e2) { /* Should never happen. */ throw EnvironmentFailureException.unexpectedException( envImpl, e); } } } private R runOnce(final Locker locker) throws DatabaseNotFoundException, DbTree.NeedRepLockerException { boolean success = false; try { final Pair results = runWork(locker); final DatabaseImpl dbImpl = results.first(); if (dbImpl == null) { /* Should never happen. */ throw EnvironmentFailureException.unexpectedState(envImpl); } success = true; runTriggers(locker, dbImpl); return results.second(); } catch (Error E) { envImpl.invalidate(E); throw E; } finally { locker.operationEnd(success); } } private Locker getWritableLocker(boolean autoTxnIsReplicated) { return LockerFactory.getWritableLocker( Environment.this, txn, false /*isInternalDb*/, envImpl.isTransactional(), autoTxnIsReplicated); } } /** * For unit testing. Returns the current memory usage in bytes for all * btrees in the envImpl. */ long getMemoryUsage() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); return envImpl.getMemoryBudget().getCacheMemoryUsage(); } /** * Returns the database environment's home directory. * * This method may be called when the environment has been invalidated, but * not yet closed. In other words, {@link EnvironmentFailureException} is * never thrown by this method. * * @return The database environment's home directory. * environment-wide failure occurs. * * @throws IllegalStateException if this handle has been closed. */ public File getHome() throws DatabaseException { final EnvironmentImpl envImpl = getNonNullEnvImpl(); return envImpl.getEnvironmentHome(); } /* * Transaction management */ /** * 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, RepConfigProxy initRepConfig) { /* * Create the new objects, initialize them, then change the instance * fields. This avoids synchronization issues. */ EnvironmentMutableConfig newHandleConfig = new EnvironmentMutableConfig(); useConfig.copyHandlePropsTo(newHandleConfig); this.handleConfig = newHandleConfig; TransactionConfig newTxnConfig = TransactionConfig.DEFAULT.clone(); newTxnConfig.setNoSync(handleConfig.getTxnNoSync()); newTxnConfig.setWriteNoSync(handleConfig.getTxnWriteNoSync()); newTxnConfig.setDurability(handleConfig.getDurability()); if (initStaticConfig != null) { newTxnConfig.setSerializableIsolation (initStaticConfig.getTxnSerializableIsolation()); newTxnConfig.setReadCommitted (initStaticConfig.getTxnReadCommitted()); } else { newTxnConfig.setSerializableIsolation (defaultTxnConfig.getSerializableIsolation()); newTxnConfig.setReadCommitted (defaultTxnConfig.getReadCommitted()); newTxnConfig.setConsistencyPolicy (defaultTxnConfig.getConsistencyPolicy()); } if (initRepConfig != null) { newTxnConfig.setConsistencyPolicy (initRepConfig.getConsistencyPolicy()); } this.defaultTxnConfig = newTxnConfig; } /** * Creates a new transaction in the database environment. * *

Transaction handles are free-threaded; transactions handles may be * used concurrently by multiple threads.

* *

Cursors may not span transactions; that is, each cursor must be * opened and closed within a single transaction. The parent parameter is a * placeholder for nested transactions, and must currently be null.

* * @param txnConfig The transaction attributes. If null, default * attributes are used. * * @return The newly created transaction's handle. * * @throws com.sleepycat.je.rep.InsufficientReplicasException if the Master * in a replicated environment could not contact a quorum of replicas as * determined by the {@link ReplicaAckPolicy}. * * @throws com.sleepycat.je.rep.ReplicaConsistencyException if a replica * in a replicated environment cannot become consistent within the timeout * period. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is not a transactional * environment. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @throws IllegalArgumentException if an invalid parameter is specified, * for example, an invalid {@code TransactionConfig} parameter. */ public Transaction beginTransaction(Transaction parent, TransactionConfig txnConfig) throws DatabaseException, IllegalArgumentException { try { return beginTransactionInternal(parent, txnConfig, false /*isInternalTxn*/); } catch (Error E) { invalidate(E); throw E; } } /** * Like beginTransaction, but does not require that the Environment is * transactional. */ Transaction beginInternalTransaction(TransactionConfig txnConfig) { return beginTransactionInternal(null /*parent*/, txnConfig, true /*isInternalTxn*/); } /** * @throws IllegalArgumentException via beginTransaction. * @throws UnsupportedOperationException via beginTransaction. */ private Transaction beginTransactionInternal(Transaction parent, TransactionConfig txnConfig, boolean isInternalTxn ) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (parent != null) { throw new IllegalArgumentException ("Parent txn is non-null. " + "Nested transactions are not supported."); } if (!isInternalTxn && !envImpl.isTransactional()) { throw new UnsupportedOperationException ("Transactions can not be used in a non-transactional " + "environment"); } checkTxnConfig(txnConfig); /* * Apply txn config defaults. We don't need to clone unless we have to * apply the env default, since we don't hold onto a txn config * reference. */ TransactionConfig useConfig = null; if (txnConfig == null) { useConfig = defaultTxnConfig; } else { if (defaultTxnConfig.getNoSync() || defaultTxnConfig.getWriteNoSync()) { /* * The environment sync settings have been set, check if any * were set in the user's txn config. If none were set in the * user's config, apply the environment defaults */ if (!txnConfig.getNoSync() && !txnConfig.getSync() && !txnConfig.getWriteNoSync()) { useConfig = txnConfig.clone(); if (defaultTxnConfig.getWriteNoSync()) { useConfig.setWriteNoSync(true); } else { useConfig.setNoSync(true); } } } if ((defaultTxnConfig.getDurability() != null) && (txnConfig.getDurability() == null)) { /* * Inherit transaction durability from the environment in the * absence of an explicit transaction config durability. */ if (useConfig == null) { useConfig = txnConfig.clone(); } useConfig.setDurability(defaultTxnConfig.getDurability()); } if ((defaultTxnConfig.getConsistencyPolicy() != null) && (txnConfig.getConsistencyPolicy() == null)) { if (useConfig == null) { useConfig = txnConfig.clone(); } useConfig.setConsistencyPolicy (defaultTxnConfig.getConsistencyPolicy()); } /* Apply isolation level default. */ if (!txnConfig.getSerializableIsolation() && !txnConfig.getReadCommitted() && !txnConfig.getReadUncommitted()) { if (defaultTxnConfig.getSerializableIsolation()) { if (useConfig == null) { useConfig = txnConfig.clone(); } useConfig.setSerializableIsolation(true); } else if (defaultTxnConfig.getReadCommitted()) { if (useConfig == null) { useConfig = txnConfig.clone(); } useConfig.setReadCommitted(true); } } /* No environment level defaults applied. */ if (useConfig == null) { useConfig = txnConfig; } } Txn internalTxn = envImpl.txnBegin(parent, useConfig); Transaction txn = new Transaction(this, internalTxn); addReferringHandle(txn); return txn; } /** * Checks the txnConfig object to ensure that its correctly configured and * is compatible with the configuration of the Environment. * * @param txnConfig the configuration being checked. * * @throws IllegalArgumentException via beginTransaction */ private void checkTxnConfig(TransactionConfig txnConfig) throws IllegalArgumentException { if (txnConfig == null) { return; } if ((txnConfig.getSerializableIsolation() && txnConfig.getReadUncommitted()) || (txnConfig.getSerializableIsolation() && txnConfig.getReadCommitted()) || (txnConfig.getReadUncommitted() && txnConfig.getReadCommitted())) { throw new IllegalArgumentException ("Only one may be specified: SerializableIsolation, " + "ReadCommitted or ReadUncommitted"); } if ((txnConfig.getDurability() != null) && ((defaultTxnConfig.getSync() || defaultTxnConfig.getNoSync() || defaultTxnConfig.getWriteNoSync()))) { throw new IllegalArgumentException ("Mixed use of deprecated durability API for the " + "Environment with the new durability API for " + "TransactionConfig.setDurability()"); } if ((defaultTxnConfig.getDurability() != null) && ((txnConfig.getSync() || txnConfig.getNoSync() || txnConfig.getWriteNoSync()))) { throw new IllegalArgumentException ("Mixed use of new durability API for the " + "Environment with the deprecated durability API for " + "TransactionConfig."); } } /** * Synchronously checkpoint the database environment. *

* This is an optional action for the application since this activity * is, by default, handled by a database environment owned background * thread. *

* A checkpoint has the side effect of flushing all preceding * non-transactional write operations, as well as any preceding * transactions that were committed with {@link * Durability.SyncPolicy#NO_SYNC no-sync durability}. However, for best * performance, checkpoints should be used only to bound recovery time. * {@link #flushLog} can be used to write buffered data for durability * purposes. * * @param ckptConfig The checkpoint attributes. If null, default * attributes are used. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws DiskLimitException if the checkpoint cannot be performed * because a disk limit has been violated. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void checkpoint(CheckpointConfig ckptConfig) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (ckptConfig == null) { ckptConfig = CheckpointConfig.DEFAULT; } try { envImpl.invokeCheckpoint(ckptConfig, "api"); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Synchronously flushes database environment databases to stable storage. * Calling this method is equivalent to forcing a checkpoint and setting * {@link CheckpointConfig#setMinimizeRecoveryTime} to true. *

* A checkpoint has the side effect of flushing all preceding * non-transactional write operations, as well as any preceding * transactions that were committed with {@link * Durability.SyncPolicy#NO_SYNC no-sync durability}. However, for best * performance, checkpoints should be used only to bound recovery time. * {@link #flushLog} can be used to write buffered data for durability * purposes. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws DiskLimitException if the sync cannot be performed * because a disk limit has been violated. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void sync() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { final CheckpointConfig config = new CheckpointConfig(); config.setForce(true); config.setMinimizeRecoveryTime(true); envImpl.invokeCheckpoint(config, "sync"); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Writes buffered data to the log, and optionally performs an fsync to * guarantee that data is written to the physical device. *

* This method is used to make durable, by writing to the log, all * preceding non-transactional write operations, as well as any preceding * transactions that were committed with {@link * Durability.SyncPolicy#NO_SYNC no-sync durability}. If the {@code fsync} * parameter is true, it can also be used to flush all logged data to the * physical storage device, by performing an fsync. *

* Note that this method does not flush previously unwritten data * in deferred-write databases; that is done by calling {@link * Database#sync} or performing a checkpoint. * * @param fsync is true to perform an fsync as well as a file write, or * false to perform only a file write. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @see I/O Statistics: * Fsync and Group Commit */ public void flushLog(boolean fsync) { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.flushLog(fsync); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Synchronously invokes log file (data file) cleaning until the target * disk space utilization has been reached; this method is called * periodically by the cleaner background threads. * *

Zero or more log files will be cleaned as necessary to bring the * current {@link EnvironmentStats#getCurrentMinUtilization disk * utilization} of the environment above the configured {@link * EnvironmentConfig#CLEANER_MIN_UTILIZATION target utilization}. * *

Note that this method does not perform the complete task of cleaning * a log file. Eviction and checkpointing log Btree information that is * marked dirty by the cleaner, and a full checkpoint is necessary, * following cleaning, before cleaned files will be deleted. * Checkpoints occur periodically and when the environment is closed.

* *

This is an optional action for the application since this activity * is, by default, handled by one or more Environment-owned background * threads.

* *

The intended use case for the {@code cleanLog} method is when the * application wishes to disable the built-in cleaner threads using the * {@link EnvironmentConfig#ENV_RUN_CLEANER} property. To replace the * functionality of the cleaner threads, the application should call * {@code cleanLog} periodically.

* *

Note that because this method cleans multiple files before returning, * in an attempt to reach the target utilization, it may not return for a * long time when the {@link EnvironmentStats#getCurrentMinUtilization * current utilization} is significantly less than the target utilization * or the target utilization cannot be reached (see * Cleaner Statistics). * This method cannot be aborted except by closing the environment. If * the application needs the ability to abort the cleaning process, the * {@link #cleanLogFile} method should be used instead.

* *

Note that in certain unusual situations the cleaner may not be able * to make forward progress and the target utilization will never be * reached. For example, this can occur if the target utilization is set * too high or checkpoints are performed too often. To guard against * cleaning "forever", this method will return when all files have been * cleaned, even when the target utilization has not been reached.

* * @return The number of log files that were cleaned, and that will be * deleted when a qualifying checkpoint occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only or * memory-only environment. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @see Cleaner Statistics */ public int cleanLog() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { return envImpl.invokeCleaner(true /*cleanMultipleFiles*/); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Synchronously invokes cleaning of a single log file (data file), if * the target disk space utilization has not been reached. * *

One log file will be cleaned if the current {@link * EnvironmentStats#getCurrentMinUtilization disk utilization} of the * environment is below the configured {@link * EnvironmentConfig#CLEANER_MIN_UTILIZATION target utilization}. No * files will be cleaned if current utilization is above the target. The * lowest utilized file is selected for cleaning, since it has the * lowest cleaning cost.

* *

Note that this method does not perform the complete task of cleaning * a log file. Eviction and checkpointing log Btree information that is * marked dirty by the cleaner, and a full checkpoint is necessary, * following cleaning, before cleaned files will be deleted. * Checkpoints occur periodically and when the environment is closed.

* *

The intended use case for the {@code cleanLog} method is "batch * cleaning". This is when the application disables the cleaner threads * (using the {@link EnvironmentConfig#ENV_RUN_CLEANER} property) * for maximum performance during active periods, and calls {@code * cleanLog} during periods when the application is quiescent or less * active than usual. Similarly, there may be times when an application * wishes to perform cleaning explicitly until the target utilization * rather than relying on the cleaner's background threads. For example, * some applications may wish to perform batch cleaning prior to closing * the environment, to reclaim as much disk space as possible at that * time.

* *

To clean until the target utilization is reached, {@code * cleanLogFile} can be called in a loop until it returns {@code false}. * When {@link EnvironmentStats#getCurrentMinUtilization current * utilization} is significantly below the target utilization or the * target utilization cannot be reached (see * Cleaner Statistics), the * application may wish to limit the amount of cleaning. Batch cleaning * can be aborted simply by breaking out of the loop. The cleaning of a * single file is not a long operation; it should normally take less than * one minute. For example:

* *
     *     boolean cleaningAborted;
     *     boolean anyCleaned = false;
     *
     *     while (!cleaningAborted && env.cleanLogFile()) {
     *         anyCleaned = true;
     *     }
     * 
* *

Note that in certain unusual situations the cleaner may not be able * to make forward progress and the target utilization will never be * reached. For example, this can occur if the target utilization is set * too high or checkpoints are performed too often. To guard against * cleaning "forever", the application may wish to cancel the batch * cleaning (break out of the loop) when the cleaning time or number of * files cleaned exceeds some reasonable limit.

* *

As mentioned above, the cleaned log files will not be deleted until * the next full checkpoint. If the application wishes to reclaim this disk * space as soon as possible, an explicit checkpoint may be performed after * the batch cleaning operation. For example:

* *
     *     if (anyCleaned) {
     *         env.checkpoint(new CheckpointConfig().setForce(true));
     *     }
     * 
* *

However, even an explicit checkpoint is not guaranteed to delete the * cleaned log files. See Cleaner * Statistics for more information.

* *

When closing the environment and minimizing recovery time is desired * (see {@link #close}), as well as reclaiming disk space, the recommended * procedure is as follows:

*
     *     // Stop/finish all application operations that are using JE.
     *     ...
     *
     *     // Stop the cleaner daemon threads.
     *     EnvironmentMutableConfig config = env.getMutableConfig();
     *     config.setConfigParam(EnvironmentConfig.ENV_RUN_CLEANER, "false");
     *     env.setMutableConfig(config);
     *
     *     // Perform batch cleaning.
     *     while (!cleaningAborted && env.cleanLogFile()) {
     *     }
     *
     *     // Perform an extra checkpoint
     *     env.checkpoint(new CheckpointConfig().setForce(true));
     *
     *     // Finally, close the environment.
     *     env.close();
     * 
* * @return true if one log was cleaned, or false if none were cleaned. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only or * memory-only environment. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @see Cleaner Statistics */ public boolean cleanLogFile() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { return envImpl.invokeCleaner(false /*cleanMultipleFiles*/) > 0; } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Synchronously invokes the mechanism for keeping memory usage within the * cache size boundaries. * *

This is an optional action for the application since this activity * is, by default, handled by a database environment owned background * thread.

* * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void evictMemory() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.invokeEvictor(); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Synchronously invokes the compressor mechanism which compacts in memory * data structures after delete operations. * *

This is an optional action for the application since this activity * is, by default, handled by a database environment owned background * thread.

* * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void compress() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.invokeCompressor(); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Preloads the cache with multiple databases. This method should only be * called when there are no operations being performed on the specified * databases in other threads. Executing preload during concurrent updates * of the specified databases may result in some or all of the tree being * loaded into the JE cache. Executing preload during any other types of * operations may result in JE exceeding its allocated cache * size. preload() effectively locks all of the specified database and * therefore will lock out the checkpointer, cleaner, and compressor, as * well as not allow eviction to occur. If databases are replicated and * the environment is in the replica state, then the replica may become * temporarily disconnected from the master if the replica needs to replay * changes against the database and is locked out because the time taken by * the preload operation exceeds {@link * com.sleepycat.je.rep.ReplicationConfig#FEEDER_TIMEOUT}. * * @param config The PreloadConfig object that specifies the parameters * of the preload. * * @return A PreloadStats object with the result of the preload operation * and various statistics about the preload() operation. * * @throws OperationFailureException if one of the Read Operation * Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if any of the databases has been closed. * * @see Database#preload(PreloadConfig) */ public PreloadStats preload(final Database[] databases, PreloadConfig config) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); DatabaseUtil.checkForZeroLengthArrayParam(databases, "databases"); if (config == null) { config = new PreloadConfig(); } try { final int nDbs = databases.length; final DatabaseImpl[] dbImpls = new DatabaseImpl[nDbs]; for (int i = 0; i < nDbs; i += 1) { dbImpls[i] = DbInternal.getDbImpl(databases[i]); } return envImpl.preload(dbImpls, config); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * * Create a DiskOrderedCursor to iterate over the records of a given set * of databases. Because the retrieval is based on Log Sequence Number * (LSN) order rather than key order, records are returned in unsorted * order in exchange for generally faster retrieval. LSN order * approximates disk sector order. *

* See {@link DiskOrderedCursor} for more details and a description of the * consistency guarantees provided by the scan. *

* WARNING: After calling this method, deletion of log files by * the JE log cleaner will be disabled until {@link * DiskOrderedCursor#close()} is called. To prevent unbounded growth of * disk usage, be sure to call {@link DiskOrderedCursor#close()} to * re-enable log file deletion. * * @param databases An array containing the handles to the database that * are to be scanned. All these handles must be currently open. * Furthermore, all the databases must belong to this environments, and * they should all support duplicates or none of them should support * duplicates. Note: this method does not make a copy of this array, * and as a result, the contents of the array should not be modified * while the returned DiskOrderedCursor is still in use. * * @param config The DiskOrderedCursorConfig object that specifies the * parameters of the disk ordered scan. * * @return the new DiskOrderedCursor object. * * @throws IllegalArgumentException if (a) the databases parameter is * null or an empty array, or (b) any of the handles in the databases * parameter is null, or (c) the databases do not all belong to this * environment, or (d) some databases support duplicates and some don't. * * @throws IllegalStateException if any of the databases has been * closed or invalidated. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. */ public DiskOrderedCursor openDiskOrderedCursor( final Database[] databases, DiskOrderedCursorConfig config) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); DatabaseUtil.checkForZeroLengthArrayParam(databases, "databases"); if (config == null) { config = DiskOrderedCursorConfig.DEFAULT; } try { int nDbs = databases.length; for (int i = 0; i < nDbs; i += 1) { if (databases[i] == null) { throw new IllegalArgumentException( "The handle at position " + i + " of the databases " + "array is null."); } if (databases[i].getEnvironment() != this) { throw new IllegalArgumentException( "The handle at position " + i + " of the databases " + "array points to a database that does not belong " + "to this environment"); } } return new DiskOrderedCursor(databases, config); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns whether all nodes in the replication group have been upgraded * to JE 18.1 or later, and therefore the record extinction feature is * available. In a standalone JE environment, true is always returned. * * @return whether the record extinction feature is available. * * @since 18.1 */ public boolean isRecordExtinctionAvailable() { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.checkRecordExtinctionAvailable(); return true; } catch (IllegalStateException e) { return false; } } /** * Initiates asynchronous discarding of the specified extinct records. * If a txn parameter is specified, the operation will begin when the txn * commits, and if the txn aborts then the operation will not take place. * *

This method must be used in conjunction with a cooperating * {@link ExtinctionFilter}. See {@link ExtinctionFilter} for more * information about record extinction and the use of this method.

* *

Note that the scanFilter parameter, if specified, must be a * {@link java.io.Serializable} object, and it is stored in serialized * form in a JE metadata database. It will be materialized at various * times in order to be called by the JE cleaner. Be aware of the * following restrictions:

*
    *
  • Because it is stored, the serialized form of the scanFilter * should be as small as possible.
  • * *
  • Because it will be materialized at various times and is not * initialized by the application, the scanFilter cannot contain * transient references to other application objects.
  • * *
  • Materialization also requires that the scanFilter's classes are * present in the classpath whenever the JE environment is opened.
  • *
* * @param txn For a transactional database, an explicit transaction may be * specified, or null may be specified to use auto-commit. For a * non-transactional environment, null must be specified. * * @param dbNames the names of the databases containing the extinct * records to be discarded. Note that the inclusiveBeginKey, * exclusiveEndKey and scanFilter params apply to the keys in all of the * databases in the set. * * @param inclusiveBeginKey the inclusive starting key of the key range * of extinct records to be discarded. If null, the implied starting key * is the first record in the database. * * @param exclusiveEndKey the exclusive ending key of the key range of * the extinct records to be discarded. If null, the implied ending key * is the last record in the database. A ScanFilter may optionally be * used to terminate the key range. * * @param scanFilter a filter that can identify extinct records when not * all records of the key range are extinct, and can also be used to * terminate the key range. If non-null, the scanFilter object must * {@link java.io.Serializable}. If null, it is implied that all records * in the key range are extinct. * * @param label a human-readable description of the scan that will be * included in log messages. This label is stored in a metadata record, * and should be excessively long. If null, an empty string is implied. * * @return the ID of the record extinction, for debugging purposes. This * is always non-zero and is negative for replicated environments and * positive for non-replicated environments. It may be passed to * {@link #isRecordExtinctionActive(long)}. * * @throws DatabaseNotFoundException if a database in dbNames does not * exist. * * @throws OperationFailureException if one of the Write * Operation Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws UnsupportedOperationException if this is a read-only * environment. * * @throws IllegalStateException if {@link * EnvironmentConfig#ENV_RUN_EXTINCT_RECORD_SCANNER} has been set * to false, or not all nodes in the replication group have been upgraded * to JE 18.1 or later (see {@link #isRecordExtinctionAvailable()}), or * an {@link ExtinctionFilter} has not been * {@link EnvironmentConfig#setExtinctionFilter configured}. * * @see ExtinctionFilter * @since 18.1 */ public long discardExtinctRecords( @Nullable final Transaction txn, @NonNull final Set dbNames, @Nullable final DatabaseEntry inclusiveBeginKey, @Nullable final DatabaseEntry exclusiveEndKey, @Nullable final ScanFilter scanFilter, @Nullable final String label) { final EnvironmentImpl envImpl = checkOpen(); checkWritable(envImpl); envImpl.checkRecordExtinctionAvailable(); if (!envImpl.hasExtinctionFilter()) { throw new IllegalStateException( "An ExtinctionFilter is not configured"); } final ExtinctionScanner scanner = envImpl.getExtinctionScanner(); if (!scanner.isEnabled()) { throw new IllegalStateException( EnvironmentConfig.ENV_RUN_EXTINCT_RECORD_SCANNER + " is false"); } final Locker locker = LockerFactory.getWritableLocker( this, txn, true /*isInternalDb*/, envImpl.isTransactional(), envImpl.isReplicated() /*autoTxnIsReplicated*/); boolean success = false; try { final long id = scanner.discardExtinctRecords( locker, dbNames, inclusiveBeginKey, exclusiveEndKey, scanFilter, (label != null) ? label : ""); success = true; return id; } catch (Error E) { envImpl.invalidate(E); throw E; } finally { locker.operationEnd(success); } } /** * Returns whether the record extinction ID, previously returned by {@link * #discardExtinctRecords}, is still in progress on this node. * *

When an extinction ID is no longer active for a given ID, then it is * guaranteed that the records specified to {@code #discardExtinctRecords} * for that ID are no longer accessible on this node. However, this method * has important limitations (see below) and is mainly intended to support * testing and debugging.

* *
    *
  • In a replicated environment, an extinction ID may be active * on some nodes in a group and inactive on other nodes, because * records are discarded independently on each node.
  • * *
  • When an extinction ID becomes inactive, this does not mean that * all disk space for the extinct records has been reclaimed by the JE * cleaner, since cleaning is asynchronous itself and driven solely by * overall utilization of disk space. It does mean that the cleaner's * utilization levels have been adjusted to account for the extinct * records.
  • *
* * @return whether the extinction process for the given ID is complete on * the current node. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @since 18.1 */ public boolean isRecordExtinctionActive(final long id) { return checkOpen().getExtinctionScanner().isScanTaskActive(id); } /** * Returns this object's configuration. * * @return This object's configuration. * *

Unlike most Environment methods, this method may be called if the * environment is invalid, but not yet closed.

* * @throws IllegalStateException if this handle has been closed. */ public EnvironmentConfig getConfig() throws DatabaseException { final EnvironmentImpl envImpl = getNonNullEnvImpl(); try { final EnvironmentConfig config = envImpl.cloneConfig(); handleConfig.copyHandlePropsTo(config); config.fillInEnvironmentGeneratedProps(envImpl); return config; } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Sets database environment attributes. * *

Attributes only apply to a specific Environment object and are not * necessarily shared by other Environment objects accessing this * database environment.

* *

Unlike most Environment methods, this method may be called if the * environment is invalid, but not yet closed.

* * @param mutableConfig The database environment attributes. If null, * default attributes are used. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle has been closed. */ public synchronized void setMutableConfig( EnvironmentMutableConfig mutableConfig) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); DatabaseUtil.checkForNullParam(mutableConfig, "mutableConfig"); /* * This method is synchronized so that we atomically call both * EnvironmentImpl.setMutableConfig and copyToHandleConfig. This * ensures that the handle and the EnvironmentImpl properties match. */ try { /* * Change the mutable properties specified in the given * configuration. */ envImpl.setMutableConfig(mutableConfig); /* Reset the handle config properties. */ copyToHandleConfig(mutableConfig, null, null); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns database environment attributes. * *

Unlike most Environment methods, this method may be called if the * environment is invalid, but not yet closed.

* * @return Environment attributes. * * @throws IllegalStateException if this handle has been closed. */ public EnvironmentMutableConfig getMutableConfig() throws DatabaseException { final EnvironmentImpl envImpl = getNonNullEnvImpl(); try { final EnvironmentMutableConfig config = envImpl.cloneMutableConfig(); handleConfig.copyHandlePropsTo(config); config.fillInEnvironmentGeneratedProps(envImpl); return config; } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns the general database environment statistics. * * @param config The general statistics attributes. If null, default * attributes are used. * * @return The general database environment statistics. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public EnvironmentStats getStats(StatsConfig config) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (config == null) { config = StatsConfig.DEFAULT; } try { return envImpl.loadStats(config); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns the database environment's locking statistics. * * @param config The locking statistics attributes. If null, default * attributes are used. * * @return The database environment's locking statistics. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. * * @deprecated as of 4.0.10, replaced by {@link * Environment#getStats(StatsConfig)}. */ public LockStats getLockStats(StatsConfig config) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (config == null) { config = StatsConfig.DEFAULT; } try { return envImpl.lockStat(config); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns the database environment's transactional statistics. * * @param config The transactional statistics attributes. If null, * default attributes are used. * * @return The database environment's transactional statistics. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public TransactionStats getTransactionStats(StatsConfig config) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (config == null) { config = StatsConfig.DEFAULT; } try { return envImpl.txnStat(config); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns a List of database names for the database environment. * *

Each element in the list is a String.

* * @return A List of database names for the database environment. * * @throws OperationFailureException if one of the Read Operation * Failures occurs. * * @throws EnvironmentFailureException if an unexpected, internal or * environment-wide failure occurs. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public List getDatabaseNames() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { return envImpl.getDbTree().getDbNames(); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns if the database environment is consistent and correct. * *

Verification is an expensive operation that should normally only be * used for troubleshooting and debugging.

* * @param config The verification attributes. If null, default * attributes are used. * * @param out is unused. To specify the output stream for verification * information, use {@link VerifyConfig#setShowProgressStream}. * * @return true if the database environment is consistent and correct. * Currently true is always returned when this method returns normally, * i.e., when no exception is thrown. * * @throws EnvironmentFailureException if an environment corruption is * detected, or if an unexpected, internal or environment-wide failure * occurs. If a persistent corruption is detected, * {@link EnvironmentFailureException#isCorrupted()} will return true. * * @throws CorruptSecondariesException if an environment corruption is * not detected, but one more more corrupt {@link SecondaryDatabase}s is * detected. The exception contains information about the corrupt * databases. The Environment is not invalidated, but note that {@link * SecondaryIntegrityException} will be thrown when attempting to access * a corrupt {@code SecondaryDatabase} and it should be closed. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public boolean verify(VerifyConfig config, @SuppressWarnings("unused") PrintStream out) throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); if (config == null) { config = VerifyConfig.DEFAULT; } try { envImpl.verify(config); } catch (Error E) { envImpl.invalidate(E); throw E; } return true; } /** * Returns the transaction associated with this thread if implied * transactions are being used. Implied transactions are used in an XA or * JCA "Local Transaction" environment. In an XA environment the * XAEnvironment.start() entrypoint causes a transaction to be created and * become associated with the calling thread. Subsequent API calls * implicitly use that transaction. XAEnvironment.end() causes the * transaction to be disassociated with the thread. In a JCA Local * Transaction environment, the call to JEConnectionFactory.getConnection() * causes a new transaction to be created and associated with the calling * thread. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public Transaction getThreadTransaction() throws DatabaseException { final EnvironmentImpl envImpl = checkOpen(); try { return envImpl.getTxnManager().getTxnForThread(); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Sets the transaction associated with this thread if implied transactions * are being used. Implied transactions are used in an XA or JCA "Local * Transaction" environment. In an XA environment the * XAEnvironment.start() entrypoint causes a transaction to be created and * become associated with the calling thread. Subsequent API calls * implicitly use that transaction. XAEnvironment.end() causes the * transaction to be disassociated with the thread. In a JCA Local * Transaction environment, the call to JEConnectionFactory.getConnection() * causes a new transaction to be created and associated with the calling * thread. * * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void setThreadTransaction(Transaction txn) { final EnvironmentImpl envImpl = checkOpen(); try { envImpl.getTxnManager().setTxnForThread(txn); } catch (Error E) { envImpl.invalidate(E); throw E; } } /** * Returns whether this {@code Environment} is open, valid and can be used. * *

When an {@link EnvironmentFailureException}, or one of its * subclasses, is caught, the {@code isValid} method can be called to * determine whether the {@code Environment} can continue to be used, or * should be closed. Some EnvironmentFailureExceptions invalidate the * environment and others do not.

* *

If this method returns false, the environment may have been closed by * the application, or may have been invalidated by an exception and not * yet closed. The {@link #isClosed()} method may be used to distinguish * between these two cases, and {@link #getInvalidatingException()} can be * used to return the exception. Note that it is safe to call {@link * #close} redundantly, so it is safe to always call {@link #close} when * this method returns false.

*/ public boolean isValid() { final EnvironmentImpl envImpl = environmentImpl; return envImpl != null && envImpl.isValid(); } /** * Returns whether the environment has been closed by the application. * *

If this method returns true, {@link #close()}} has been called. If * the environment was previously invalidated by an exception, it will be * returned by {@link #getInvalidatingException()}.

* *

If this method returns false, the environment may or may not be * usable, since it may have been invalidated by an exception but not yet * closed. To determine whether it was invalidated, call {@link #isValid()} * or {@link #getInvalidatingException()}.

* * @return whether the environment has been closed by the application. * * @since 7.2 */ public boolean isClosed() { final EnvironmentImpl envImpl = environmentImpl; return envImpl == null || envImpl.isClosed(); } /** * Returns the exception that caused the environment to be invalidated, or * null if the environment was not invalidated by an exception. * *

This method may be used to determine whether the environment was * invalidated by an exception, by checking for a non-null return value. * This method will return the invalidating exception, regardless of * whether the environment is closed. Note that {@link #isValid()} will * return false when the environment is closed, even when it was not * invalidated by an exception.

* *

This method may also be used to identify and handle the original * invalidating exception, when more than one exception is thrown. When an * environment is first invalidated by an EnvironmentFailureException, the * exception is saved so that it can be returned by this method. Other * EnvironmentFailureExceptions may be thrown later as side effects of the * original problem, or possibly as separate problems. It is normally the * first invalidating exception that is most relevant.

* * @return the invalidating exception or null. * * @since 7.2 */ public EnvironmentFailureException getInvalidatingException() { assert invalidatingEFE != null; return invalidatingEFE.get(); } /** * Print a detailed report about the costs of different phases of * environment startup. This report is by default logged to the je.info * file if startup takes longer than je.env.startupThreshold. * *

Unlike most Environment methods, this method may be called if the * environment is invalid, but not yet closed.

* * @throws IllegalStateException if this handle or the underlying * environment has been closed. */ public void printStartupInfo(PrintStream out) { final EnvironmentImpl envImpl = getNonNullEnvImpl(); envImpl.getStartupTracker().displayStats(out, Phase.TOTAL_ENV_OPEN); } /* * Non public api -- helpers */ /** * Let the Environment remember what's opened against it. */ private void addReferringHandle(Database db) { referringDbs.put(db, db); } /** * Lets the Environment remember what's opened against it. */ private void addReferringHandle(Transaction txn) { referringDbTxns.put(txn, 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); } /** * @throws EnvironmentFailureException if the underlying environment is * invalid. * @throws IllegalStateException if the environment is not open. */ EnvironmentImpl checkOpen() { final EnvironmentImpl envImpl = getNonNullEnvImpl(); envImpl.checkOpen(); return envImpl; } /** * Returns the non-null, underlying EnvironmentImpl. * * This method is called to access the environmentImpl field, to guard * against NPE when the environment has been closed. * * This method does not check whether the env is valid. For API method * calls, checkOpen is called at API entry points to check validity. The * validity of the env should also be checked before critical operations * (e.g., disk writes), after idle periods, and periodically during time * consuming operations. * * @throws IllegalStateException if the env has been closed. */ EnvironmentImpl getNonNullEnvImpl() { final EnvironmentImpl envImpl = environmentImpl; if (envImpl == null) { throw new IllegalStateException("Environment is closed."); } return envImpl; } /** * Returns the underlying EnvironmentImpl, or null if the env has been * closed. * * WARNING: This method will be phased out over time and normally * getNonNullEnvImpl should be called instead. */ EnvironmentImpl getMaybeNullEnvImpl() { return environmentImpl; } /* Returns true, if this is a handle allocated internally by JE. */ protected boolean isInternalHandle() { return false; } /** * @throws UnsupportedOperationException via the database operation methods * (remove, truncate, rename) and potentially other methods that require a * writable environment. */ private void checkWritable(final EnvironmentImpl envImpl ) { if (envImpl.isReadOnly()) { throw new UnsupportedOperationException ("Environment is Read-Only."); } } void invalidate(Error e) { final EnvironmentImpl envImpl = environmentImpl; if (envImpl == null) { return; } envImpl.invalidate(e); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy