OPENDJ-1848: simplify DatabaseContainer and Storage APIs
* remove DatabaseContainer.storage
* remove Storage.closeTree()
* remove WriteableStorage.truncateTree() (use deleteTree() instead)
* it is now the responsibility of the Storage implementation to close individual databases if it needs to. This is the case for JE but not for most DBs.
| | |
| | | } |
| | | |
| | | @Override |
| | | public void truncateTree(final TreeName treeName) |
| | | { |
| | | try |
| | | { |
| | | getExchangeFromCache(treeName).removeAll(); |
| | | } |
| | | catch (final PersistitException e) |
| | | { |
| | | throw new StorageRuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean update(final TreeName treeName, final ByteSequence key, final UpdateFunction f) |
| | | { |
| | | try |
| | |
| | | DirectoryServer.deregisterAlertGenerator(this); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void closeTree(final TreeName treeName) |
| | | { |
| | | // nothing to do, in persistit you close the volume itself |
| | | } |
| | | |
| | | private BufferPoolConfiguration getBufferPoolCfg() |
| | | { |
| | | return dbCfg.getBufferPoolMap().get(BUFFER_SIZE); |
| | |
| | | import org.forgerock.opendj.ldap.schema.MatchingRule; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.meta.BackendIndexCfgDefn.IndexType; |
| | | import org.opends.server.admin.std.server.BackendIndexCfg; |
| | |
| | | indexConfig.addChangeListener(this); |
| | | } |
| | | |
| | | /** Closes the attribute index. */ |
| | | @Override |
| | | public void close() |
| | | { |
| | | Utils.closeSilently(nameToIndexes.values()); |
| | | indexConfig.removeChangeListener(this); |
| | | // The entryContainer is responsible for closing the JE databases. |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | * Create a DN2ID instance for the DN database in a given entryContainer. |
| | | * |
| | | * @param treeName The name of the DN database. |
| | | * @param env The JE environment. |
| | | * @param entryContainer The entryContainer of the DN database. |
| | | * @throws StorageRuntimeException If an error occurs in the JE database. |
| | | */ |
| | | DN2ID(TreeName treeName, Storage env, EntryContainer entryContainer) |
| | | throws StorageRuntimeException |
| | | DN2ID(TreeName treeName, EntryContainer entryContainer) throws StorageRuntimeException |
| | | { |
| | | super(treeName, env); |
| | | super(treeName); |
| | | prefixRDNComponents = entryContainer.getBaseDN().size(); |
| | | } |
| | | |
| | |
| | | import org.forgerock.util.Pair; |
| | | import org.opends.server.backends.pluggable.spi.Cursor; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | * |
| | | * @param treeName |
| | | * The name of the referral database. |
| | | * @param storage |
| | | * The JE environment. |
| | | * @param entryContainer |
| | | * The entryContainer of the DN database. |
| | | * @throws StorageRuntimeException |
| | | * If an error occurs in the JE database. |
| | | */ |
| | | DN2URI(TreeName treeName, Storage storage, EntryContainer entryContainer) |
| | | throws StorageRuntimeException |
| | | DN2URI(TreeName treeName, EntryContainer entryContainer) throws StorageRuntimeException |
| | | { |
| | | super(treeName, storage); |
| | | super(treeName); |
| | | prefixRDNComponents = entryContainer.getBaseDN().size(); |
| | | } |
| | | |
| | |
| | | */ |
| | | package org.opends.server.backends.pluggable; |
| | | |
| | | import java.io.Closeable; |
| | | |
| | | import org.opends.server.backends.pluggable.spi.Cursor; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | * This class is a wrapper around the JE database object and provides basic |
| | | * read and write methods for entries. |
| | | */ |
| | | abstract class DatabaseContainer implements Closeable |
| | | abstract class DatabaseContainer |
| | | { |
| | | /** The name of the database within the entryContainer. */ |
| | | private TreeName name; |
| | | |
| | | /** The reference to the JE Storage. */ |
| | | final Storage storage; |
| | | |
| | | /** |
| | | * Create a new DatabaseContainer object. |
| | | * |
| | | * @param treeName The name of the entry database. |
| | | * @param storage The JE Storage. |
| | | */ |
| | | DatabaseContainer(TreeName treeName, Storage storage) |
| | | DatabaseContainer(TreeName treeName) |
| | | { |
| | | this.storage = storage; |
| | | this.name = treeName; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Flush any cached database information to disk and close the |
| | | * database container. |
| | | * |
| | | * The database container should not be closed while other processes |
| | | * acquired the container. The container should not be closed |
| | | * while cursors handles into the database remain open, or |
| | | * transactions that include operations on the database have not yet |
| | | * been committed or aborted. |
| | | * |
| | | * The container may not be accessed again after this method is |
| | | * called, regardless of the method's success or failure. |
| | | * |
| | | * @throws StorageRuntimeException if an error occurs. |
| | | */ |
| | | @Override |
| | | public synchronized void close() throws StorageRuntimeException |
| | | { |
| | | // FIXME: is this method needed? |
| | | storage.closeTree(name); |
| | | } |
| | | |
| | | /** |
| | | * Get the count of key/data pairs in the database in a JE database. |
| | | * This is a simple wrapper around the JE Database.count method. |
| | | * @param txn The JE transaction handle, or null if none. |
| | |
| | | */ |
| | | package org.opends.server.backends.pluggable; |
| | | |
| | | import static org.forgerock.util.Utils.closeSilently; |
| | | import static org.opends.messages.JebMessages.*; |
| | | import static org.opends.server.backends.pluggable.JebFormat.*; |
| | | import static org.opends.server.core.DirectoryServer.*; |
| | |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.util.Utils; |
| | | import org.opends.server.admin.server.ConfigurationAddListener; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.server.ConfigurationDeleteListener; |
| | |
| | | config.isCompactEncoding(), |
| | | rootContainer.getCompressedSchema()); |
| | | |
| | | id2entry = new ID2Entry(getIndexName(ID2ENTRY_DATABASE_NAME), storage, entryDataConfig); |
| | | id2entry = new ID2Entry(getIndexName(ID2ENTRY_DATABASE_NAME), entryDataConfig); |
| | | id2entry.open(txn); |
| | | |
| | | dn2id = new DN2ID(getIndexName(DN2ID_DATABASE_NAME), storage, this); |
| | | dn2id = new DN2ID(getIndexName(DN2ID_DATABASE_NAME), this); |
| | | dn2id.open(txn); |
| | | |
| | | state = new State(getIndexName(STATE_DATABASE_NAME), storage); |
| | | state = new State(getIndexName(STATE_DATABASE_NAME)); |
| | | state.open(txn); |
| | | |
| | | if (config.isSubordinateIndexesEnabled()) |
| | |
| | | // subordinate indexes will fail. |
| | | id2children = openNewNullIndex(txn, ID2CHILDREN_DATABASE_NAME, new ID2CIndexer()); |
| | | id2subtree = openNewNullIndex(txn, ID2SUBTREE_DATABASE_NAME, new ID2SIndexer()); |
| | | |
| | | logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backend.getBackendID()); |
| | | } |
| | | |
| | | dn2uri = new DN2URI(getIndexName(REFERRAL_DATABASE_NAME), storage, this); |
| | | dn2uri = new DN2URI(getIndexName(REFERRAL_DATABASE_NAME), this); |
| | | dn2uri.open(txn); |
| | | |
| | | for (String idx : config.listBackendIndexes()) |
| | |
| | | |
| | | private NullIndex openNewNullIndex(WriteableStorage txn, String indexId, Indexer indexer) |
| | | { |
| | | final NullIndex index = new NullIndex(getIndexName(indexId), indexer, state, storage, txn, this); |
| | | final TreeName indexName = getIndexName(indexId); |
| | | final NullIndex index = new NullIndex(indexName, indexer, state, txn, this); |
| | | state.putIndexTrustState(txn, index, false); |
| | | txn.deleteTree(indexName); |
| | | index.open(txn); // No-op |
| | | return index; |
| | | } |
| | |
| | | @Override |
| | | public void close() throws StorageRuntimeException |
| | | { |
| | | // Close core indexes. |
| | | dn2id.close(); |
| | | id2entry.close(); |
| | | dn2uri.close(); |
| | | id2children.close(); |
| | | id2subtree.close(); |
| | | state.close(); |
| | | |
| | | Utils.closeSilently(attrIndexMap.values()); |
| | | |
| | | for (VLVIndex vlvIndex : vlvIndexMap.values()) |
| | | { |
| | | vlvIndex.close(); |
| | | } |
| | | closeSilently(attrIndexMap.values()); |
| | | closeSilently(vlvIndexMap.values()); |
| | | |
| | | // Deregister any listeners. |
| | | config.removePluggableChangeListener(this); |
| | |
| | | // The state database can not be removed individually. |
| | | return; |
| | | } |
| | | |
| | | database.close(); |
| | | txn.deleteTree(database.getName()); |
| | | if(database instanceof Index) |
| | | { |
| | |
| | | { |
| | | final List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>(); |
| | | listDatabases(databases); |
| | | |
| | | // close the containers. |
| | | for(DatabaseContainer db : databases) |
| | | { |
| | | db.close(); |
| | | } |
| | | |
| | | try |
| | | { |
| | | // Rename in transaction. |
| | |
| | | { |
| | | // Disabling subordinate indexes. Use a null index and ensure that |
| | | // future attempts to use the real indexes will fail. |
| | | id2children.close(); |
| | | id2children = openNewNullIndex(txn, ID2CHILDREN_DATABASE_NAME, new ID2CIndexer()); |
| | | |
| | | id2subtree.close(); |
| | | id2subtree = openNewNullIndex(txn, ID2SUBTREE_DATABASE_NAME, new ID2SIndexer()); |
| | | |
| | | logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, cfg.getBackendId()); |
| | | } |
| | | } |
| | |
| | | { |
| | | final List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>(); |
| | | listDatabases(databases); |
| | | |
| | | for(DatabaseContainer db : databases) |
| | | { |
| | | db.close(); |
| | | } |
| | | try |
| | | { |
| | | for (DatabaseContainer db : databases) |
| | | { |
| | | txn.truncateTree(db.getName()); |
| | | txn.deleteTree(db.getName()); |
| | | } |
| | | } |
| | | finally |
| | |
| | | void clearDatabase(WriteableStorage txn, DatabaseContainer database) |
| | | throws StorageRuntimeException |
| | | { |
| | | database.close(); |
| | | try |
| | | { |
| | | txn.deleteTree(database.getName()); |
| | |
| | | |
| | | private Index newIndex(WriteableStorage txn, String name, Indexer indexer) |
| | | { |
| | | final Index index = new Index(getIndexName(name), |
| | | storage, indexer, state, config.getIndexEntryLimit(), 0, true, txn, this); |
| | | final Index index = new Index(getIndexName(name), indexer, state, config.getIndexEntryLimit(), 0, true, txn, this); |
| | | index.open(txn); |
| | | if (!index.isTrusted()) |
| | | { |
| | |
| | | Index newIndexForAttribute(WriteableStorage txn, TreeName indexName, Indexer indexer, int indexEntryLimit) |
| | | { |
| | | final int cursorEntryLimit = 100000; |
| | | return new Index(indexName, storage, indexer, state, indexEntryLimit, cursorEntryLimit, false, txn, this); |
| | | return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, txn, this); |
| | | } |
| | | |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.api.CompressedSchema; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | * Create a new ID2Entry object. |
| | | * |
| | | * @param name The name of the entry database. |
| | | * @param storage The JE Storage. |
| | | * @param dataConfig The desired compression and encryption options for data |
| | | * stored in the entry database. |
| | | * @param entryContainer The entryContainer of the entry database. |
| | | * @throws StorageRuntimeException If an error occurs in the JE database. |
| | | * |
| | | */ |
| | | ID2Entry(TreeName name, Storage storage, DataConfig dataConfig) throws StorageRuntimeException |
| | | ID2Entry(TreeName name, DataConfig dataConfig) throws StorageRuntimeException |
| | | { |
| | | super(name, storage); |
| | | super(name); |
| | | this.dataConfig = dataConfig; |
| | | } |
| | | |
| | |
| | | import org.opends.server.backends.pluggable.IndexBuffer.BufferedIndexValues; |
| | | import org.opends.server.backends.pluggable.spi.Cursor; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | /** |
| | | * Create a new index object. |
| | | * @param name The name of the index database within the entryContainer. |
| | | * @param storage The JE Storage |
| | | * @param indexer The indexer object to construct index keys from LDAP |
| | | * attribute values. |
| | | * @param state The state database to persist index state info. |
| | |
| | | * @param entryContainer The database entryContainer holding this index. |
| | | * @throws StorageRuntimeException If an error occurs in the JE database. |
| | | */ |
| | | Index(TreeName name, Storage storage, Indexer indexer, |
| | | State state, int indexEntryLimit, int cursorEntryLimit, |
| | | boolean maintainCount, WriteableStorage txn, EntryContainer entryContainer) |
| | | throws StorageRuntimeException |
| | | Index(TreeName name, Indexer indexer, State state, int indexEntryLimit, int cursorEntryLimit, boolean maintainCount, |
| | | WriteableStorage txn, EntryContainer entryContainer) throws StorageRuntimeException |
| | | { |
| | | super(name, storage); |
| | | super(name); |
| | | this.indexer = indexer; |
| | | this.indexEntryLimit = indexEntryLimit; |
| | | this.cursorEntryLimit = cursorEntryLimit; |
| | |
| | | load(txn); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Closes the databases and releases any resources held by this compressed |
| | | * schema manager. |
| | | */ |
| | | public void close() |
| | | { |
| | | storage.closeTree(adTreeName); |
| | | storage.closeTree(ocTreeName); |
| | | |
| | | storage = null; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | protected void storeAttribute(final byte[] encodedAttribute, |
| | |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | final class NullIndex extends Index |
| | | { |
| | | |
| | | NullIndex(TreeName name, Indexer indexer, State state, Storage storage, WriteableStorage txn, |
| | | NullIndex(TreeName name, Indexer indexer, State state, WriteableStorage txn, |
| | | EntryContainer entryContainer) throws StorageRuntimeException |
| | | { |
| | | super(name, storage, indexer, state, 0, 0, false, txn, entryContainer); |
| | | super(name, indexer, state, 0, 0, false, txn, entryContainer); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void close() throws StorageRuntimeException |
| | | { |
| | | // Do nothing. |
| | | } |
| | | |
| | | @Override |
| | | long getRecordCount(ReadableStorage txn) throws StorageRuntimeException |
| | | { |
| | | return 0; |
| | |
| | | ec.exclusiveLock.unlock(); |
| | | } |
| | | } |
| | | |
| | | compressedSchema.close(); |
| | | config.removePluggableChangeListener(this); |
| | | |
| | | if (storage != null) |
| | | { |
| | | storage.close(); |
| | |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.backends.pluggable.spi.ReadableStorage; |
| | | import org.opends.server.backends.pluggable.spi.Storage; |
| | | import org.opends.server.backends.pluggable.spi.StorageRuntimeException; |
| | | import org.opends.server.backends.pluggable.spi.TreeName; |
| | | import org.opends.server.backends.pluggable.spi.WriteableStorage; |
| | |
| | | * Create a new State object. |
| | | * |
| | | * @param name The name of the entry database. |
| | | * @param env The JE Storage. |
| | | */ |
| | | State(TreeName name, Storage env) |
| | | State(TreeName name) |
| | | { |
| | | super(name, env); |
| | | super(name); |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void truncateTree(final TreeName name) |
| | | { |
| | | txn.truncateTree(name); |
| | | logger.trace("Storage.WriteableStorage.truncateTree(%s, %s)", backendId, name); |
| | | } |
| | | |
| | | @Override |
| | | public boolean update(final TreeName name, final ByteSequence key, final UpdateFunction f) |
| | | { |
| | | final boolean isUpdated = txn.update(name, key, f); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void closeTree(final TreeName name) |
| | | { |
| | | storage.closeTree(name); |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("Storage.closeTree(%s, %s)", backendId, name); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public File getDirectory() |
| | | { |
| | | return storage.getDirectory(); |
| | |
| | | import static org.opends.messages.JebMessages.*; |
| | | import static org.opends.server.util.StaticUtils.*; |
| | | |
| | | import java.io.Closeable; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | |
| | | * to its own key. |
| | | */ |
| | | class VLVIndex extends DatabaseContainer |
| | | implements ConfigurationChangeListener<BackendVLVIndexCfg> |
| | | implements ConfigurationChangeListener<BackendVLVIndexCfg>, Closeable |
| | | { |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | |
| | | private SearchFilter filter; |
| | | private SearchScope scope; |
| | | |
| | | /** The storage associated with this index. */ |
| | | private final Storage storage; |
| | | |
| | | /** |
| | | * Create a new VLV vlvIndex object. |
| | |
| | | VLVIndex(BackendVLVIndexCfg config, State state, Storage storage, EntryContainer entryContainer, WriteableStorage txn) |
| | | throws StorageRuntimeException, ConfigException |
| | | { |
| | | super(new TreeName(entryContainer.getDatabasePrefix(), "vlv." + config.getName()), storage); |
| | | super(new TreeName(entryContainer.getDatabasePrefix(), "vlv." + config.getName())); |
| | | |
| | | this.config = config; |
| | | this.baseDN = config.getBaseDN(); |
| | | this.scope = valueOf(config.getScope()); |
| | | this.sortedSetCapacity = config.getMaxBlockSize(); |
| | | this.storage = storage; |
| | | |
| | | try |
| | | { |
| | |
| | | return bytes.toInt(); |
| | | } |
| | | |
| | | /** |
| | | * Close the VLV index. |
| | | * |
| | | * @throws StorageRuntimeException if a JE database error occurs while |
| | | * closing the index. |
| | | */ |
| | | @Override |
| | | public void close() throws StorageRuntimeException |
| | | public void close() |
| | | { |
| | | super.close(); |
| | | this.config.removeChangeListener(this); |
| | | } |
| | | |
| | |
| | | */ |
| | | void write(WriteOperation writeOperation) throws Exception; |
| | | |
| | | /** |
| | | * Closes the tree identified by the provided name. |
| | | * |
| | | * @param treeName |
| | | * the tree name |
| | | */ |
| | | void closeTree(TreeName treeName); |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | void close(); |
| | |
| | | void openTree(TreeName name); |
| | | |
| | | /** |
| | | * Truncates the tree identified by the provided name. It removes all the records in the tree. |
| | | * |
| | | * @param name |
| | | * the tree name |
| | | */ |
| | | void truncateTree(TreeName name); |
| | | |
| | | /** |
| | | * Renames the tree from the old to the new name. |
| | | * |
| | | * @param oldName |