opendj3-server-dev/src/server/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -29,7 +29,6 @@ import java.io.Closeable; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; @@ -38,7 +37,6 @@ import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.schema.MatchingRule; import org.forgerock.opendj.ldap.spi.IndexQueryFactory; import org.forgerock.opendj.ldap.spi.IndexingOptions; @@ -48,6 +46,8 @@ import org.opends.server.admin.std.server.LocalDBIndexCfg; import org.opends.server.backends.pluggable.BackendImpl.StorageRuntimeException; import org.opends.server.backends.pluggable.BackendImpl.TreeName; import org.opends.server.backends.pluggable.BackendImpl.WriteOperation; import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage; import org.opends.server.core.DirectoryServer; import org.opends.server.monitors.DatabaseEnvironmentMonitor; import org.opends.server.types.*; @@ -133,42 +133,42 @@ * @param entryContainer The entryContainer of this attribute index. * @throws ConfigException if a configuration related error occurs. */ public AttributeIndex(LocalDBIndexCfg indexConfig, EntryContainer entryContainer) throws ConfigException public AttributeIndex(LocalDBIndexCfg indexConfig, EntryContainer entryContainer, WriteableStorage txn) throws ConfigException { this.entryContainer = entryContainer; this.indexConfig = indexConfig; buildPresenceIndex(); buildIndexes(IndexType.EQUALITY); buildIndexes(IndexType.SUBSTRING); buildIndexes(IndexType.ORDERING); buildIndexes(IndexType.APPROXIMATE); buildExtensibleIndexes(); buildPresenceIndex(txn); buildIndexes(txn, IndexType.EQUALITY); buildIndexes(txn, IndexType.SUBSTRING); buildIndexes(txn, IndexType.ORDERING); buildIndexes(txn, IndexType.APPROXIMATE); buildExtensibleIndexes(txn); final JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength()); indexQueryFactory = new IndexQueryFactoryImpl(nameToIndexes, config); extensibleIndexesMapping = computeExtensibleIndexesMapping(); } private void buildPresenceIndex() private void buildPresenceIndex(WriteableStorage txn) { final IndexType indexType = IndexType.PRESENCE; if (indexConfig.getIndexType().contains(indexType)) { String indexID = indexType.toString(); nameToIndexes.put(indexID, newPresenceIndex(indexConfig)); nameToIndexes.put(indexID, newPresenceIndex(txn, indexConfig)); } } private Index newPresenceIndex(LocalDBIndexCfg cfg) private Index newPresenceIndex(WriteableStorage txn, LocalDBIndexCfg cfg) { final AttributeType attrType = cfg.getAttribute(); final TreeName indexName = getIndexName(attrType, IndexType.PRESENCE.toString()); final PresenceIndexer indexer = new PresenceIndexer(attrType); return entryContainer.newIndexForAttribute(indexName, indexer, cfg.getIndexEntryLimit()); return entryContainer.newIndexForAttribute(txn, indexName, indexer, cfg.getIndexEntryLimit()); } private void buildExtensibleIndexes() throws ConfigException private void buildExtensibleIndexes(WriteableStorage txn) throws ConfigException { final IndexType indexType = IndexType.EXTENSIBLE; if (indexConfig.getIndexType().contains(indexType)) @@ -198,14 +198,14 @@ if (!nameToIndexes.containsKey(indexId)) { // There is no index available for this index id. Create a new index nameToIndexes.put(indexId, newAttributeIndex(indexConfig, indexer)); nameToIndexes.put(indexId, newAttributeIndex(txn, indexConfig, indexer)); } } } } } private void buildIndexes(IndexType indexType) throws ConfigException private void buildIndexes(WriteableStorage txn, IndexType indexType) throws ConfigException { if (indexConfig.getIndexType().contains(indexType)) { @@ -219,7 +219,7 @@ for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers()) { nameToIndexes.put(indexID, newAttributeIndex(indexConfig, indexer)); nameToIndexes.put(indexID, newAttributeIndex(txn, indexConfig, indexer)); } } } @@ -241,12 +241,13 @@ } } private Index newAttributeIndex(LocalDBIndexCfg indexConfig, org.forgerock.opendj.ldap.spi.Indexer indexer) private Index newAttributeIndex(WriteableStorage txn, LocalDBIndexCfg indexConfig, org.forgerock.opendj.ldap.spi.Indexer indexer) { final AttributeType attrType = indexConfig.getAttribute(); final TreeName indexName = getIndexName(attrType, indexer.getIndexID()); final AttributeIndexer attrIndexer = new AttributeIndexer(attrType, indexer); return entryContainer.newIndexForAttribute(indexName, attrIndexer, indexConfig.getIndexEntryLimit()); return entryContainer.newIndexForAttribute(txn, indexName, attrIndexer, indexConfig.getIndexEntryLimit()); } private TreeName getIndexName(AttributeType attrType, String indexID) @@ -260,11 +261,11 @@ * @throws StorageRuntimeException if a JE database error occurs while * opening the index. */ public void open() throws StorageRuntimeException public void open(WriteableStorage txn) throws StorageRuntimeException { for (Index index : nameToIndexes.values()) { index.open(); index.open(txn); } indexConfig.addChangeListener(this); } @@ -635,35 +636,37 @@ /** {@inheritDoc} */ @Override public synchronized ConfigChangeResult applyConfigurationChange(LocalDBIndexCfg cfg) public synchronized ConfigChangeResult applyConfigurationChange(final LocalDBIndexCfg cfg) { // this method is not perf sensitive, using an AtomicBoolean will not hurt AtomicBoolean adminActionRequired = new AtomicBoolean(false); ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>(); final ConfigChangeResult ccr = new ConfigChangeResult(); try { applyChangeToPresenceIndex(cfg, adminActionRequired, messages); applyChangeToIndex(IndexType.EQUALITY, cfg, adminActionRequired, messages); applyChangeToIndex(IndexType.SUBSTRING, cfg, adminActionRequired, messages); applyChangeToIndex(IndexType.ORDERING, cfg, adminActionRequired, messages); applyChangeToIndex(IndexType.APPROXIMATE, cfg, adminActionRequired, messages); applyChangeToExtensibleIndexes(cfg, adminActionRequired, messages); entryContainer.getStorage().write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { applyChangeToPresenceIndex(txn, cfg, ccr); applyChangeToIndex(txn, IndexType.EQUALITY, cfg, ccr); applyChangeToIndex(txn, IndexType.SUBSTRING, cfg, ccr); applyChangeToIndex(txn, IndexType.ORDERING, cfg, ccr); applyChangeToIndex(txn, IndexType.APPROXIMATE, cfg, ccr); applyChangeToExtensibleIndexes(txn, cfg, ccr); } }); extensibleIndexesMapping = computeExtensibleIndexesMapping(); indexConfig = cfg; return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired.get(), messages); } catch(Exception e) { messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); return new ConfigChangeResult( DirectoryServer.getServerErrorResultCode(), adminActionRequired.get(), messages); ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); } return ccr; } private void applyChangeToExtensibleIndexes(LocalDBIndexCfg cfg, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages) private void applyChangeToExtensibleIndexes(WriteableStorage txn, LocalDBIndexCfg cfg, ConfigChangeResult ccr) { final AttributeType attrType = cfg.getAttribute(); if (!cfg.getIndexType().contains(IndexType.EXTENSIBLE)) @@ -694,8 +697,8 @@ validIndexIds.add(indexId); if (!nameToIndexes.containsKey(indexId)) { Index index = newAttributeIndex(cfg, indexer); openIndex(index, adminActionRequired, messages); Index index = newAttributeIndex(txn, cfg, indexer); openIndex(txn, index, ccr); nameToIndexes.put(indexId, index); } else @@ -703,8 +706,8 @@ Index index = nameToIndexes.get(indexId); if (index.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); } if (indexConfig.getSubstringLength() != cfg.getSubstringLength()) { @@ -770,8 +773,7 @@ return rules; } private void applyChangeToIndex(IndexType indexType, LocalDBIndexCfg cfg, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages) private void applyChangeToIndex(WriteableStorage txn, IndexType indexType, LocalDBIndexCfg cfg, ConfigChangeResult ccr) { String indexId = indexType.toString(); Index index = nameToIndexes.get(indexId); @@ -786,8 +788,8 @@ final MatchingRule matchingRule = getMatchingRule(indexType, cfg.getAttribute()); for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.getIndexers()) { index = newAttributeIndex(cfg, indexer); openIndex(index, adminActionRequired, messages); index = newAttributeIndex(txn, cfg, indexer); openIndex(txn, index, ccr); nameToIndexes.put(indexId, index); } } @@ -796,14 +798,13 @@ // already exists. Just update index entry limit. if (index.setIndexEntryLimit(cfg.getIndexEntryLimit())) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); } } } private void applyChangeToPresenceIndex(LocalDBIndexCfg cfg, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages) private void applyChangeToPresenceIndex(WriteableStorage txn, LocalDBIndexCfg cfg, ConfigChangeResult ccr) { final IndexType indexType = IndexType.PRESENCE; final String indexID = indexType.toString(); @@ -816,8 +817,8 @@ if (index == null) { index = newPresenceIndex(cfg); openIndex(index, adminActionRequired, messages); index = newPresenceIndex(txn, cfg); openIndex(txn, index, ccr); nameToIndexes.put(indexID, index); } else @@ -825,8 +826,8 @@ // already exists. Just update index entry limit. if (index.setIndexEntryLimit(cfg.getIndexEntryLimit())) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName())); } } } @@ -848,14 +849,14 @@ } } private void openIndex(Index index, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages) private void openIndex(WriteableStorage txn, Index index, ConfigChangeResult ccr) { index.open(); index.open(txn); if (!index.isTrusted()) { adminActionRequired.set(true); messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(index.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(index.getName())); } } opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DN2URI.java
@@ -497,7 +497,7 @@ * DN. The referral URLs will be set appropriately for the references found * in the referral entry. */ public void targetEntryReferrals(DN targetDN, SearchScope searchScope) public void targetEntryReferrals(ReadableStorage txn, DN targetDN, SearchScope searchScope) throws DirectoryException { if (containsReferrals == ConditionResult.UNDEFINED) @@ -512,7 +512,7 @@ try { Cursor cursor = storage.openCursor(treeName); final Cursor cursor = txn.openCursor(treeName); try { // Go up through the DIT hierarchy until we find a referral. @@ -550,7 +550,7 @@ * has been reached or the search has been abandoned). * @throws DirectoryException If a Directory Server error occurs. */ public boolean returnSearchReferences(SearchOperation searchOp) public boolean returnSearchReferences(ReadableStorage txn, SearchOperation searchOp) throws DirectoryException { if (containsReferrals == ConditionResult.UNDEFINED) @@ -584,7 +584,7 @@ ByteSequence startKey = suffix; try { Cursor cursor = storage.openCursor(treeName); final Cursor cursor = txn.openCursor(treeName); try { // Initialize the cursor very close to the starting value then opendj3-server-dev/src/server/org/opends/server/backends/pluggable/DatabaseContainer.java
@@ -78,35 +78,13 @@ * @throws StorageRuntimeException if a JE database error occurs while * opening the index. */ public void open() throws StorageRuntimeException public void open(WriteableStorage txn) throws StorageRuntimeException { if (dbConfig.getTransactional()) { // Open the database under a transaction. Transaction txn = entryContainer.beginTransaction(); try { treeName = storage.openDatabase(txn, treeName, dbConfig); storage.openTree(treeName); if (logger.isTraceEnabled()) { logger.trace("JE database %s opened. txnid=%d", treeName, txn.getId()); } EntryContainer.transactionCommit(txn); } catch (StorageRuntimeException e) { EntryContainer.transactionAbort(txn); throw e; } } else { treeName = storage.openDatabase(null, treeName, dbConfig); if (logger.isTraceEnabled()) { logger.trace("JE database %s opened. txnid=none", treeName); } } } /** @@ -131,7 +109,6 @@ { treeName.sync(); } storage.openTree(treeName) treeName.close(); treeName = null; opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
@@ -152,14 +152,19 @@ { /** {@inheritDoc} */ @Override public boolean isConfigurationAddAcceptable( LocalDBIndexCfg cfg, List<LocalizableMessage> unacceptableReasons) public boolean isConfigurationAddAcceptable(final LocalDBIndexCfg cfg, List<LocalizableMessage> unacceptableReasons) { try { storage.write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { //Try creating all the indexes before confirming they are valid ones. new AttributeIndex(cfg, EntryContainer.this); new AttributeIndex(cfg, EntryContainer.this, txn); } }); return true; } catch(Exception e) @@ -171,31 +176,33 @@ /** {@inheritDoc} */ @Override public ConfigChangeResult applyConfigurationAdd(LocalDBIndexCfg cfg) public ConfigChangeResult applyConfigurationAdd(final LocalDBIndexCfg cfg) { boolean adminActionRequired = false; List<LocalizableMessage> messages = new ArrayList<LocalizableMessage>(); final ConfigChangeResult ccr = new ConfigChangeResult(); try { AttributeIndex index = new AttributeIndex(cfg, EntryContainer.this); index.open(); storage.write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { final AttributeIndex index = new AttributeIndex(cfg, EntryContainer.this, txn); index.open(txn); if(!index.isTrusted()) { adminActionRequired = true; messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get( cfg.getAttribute().getNameOrOID())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getAttribute().getNameOrOID())); } attrIndexMap.put(cfg.getAttribute(), index); } }); } catch(Exception e) { messages.add(LocalizableMessage.raw(e.getLocalizedMessage())); return new ConfigChangeResult( DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages); ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(LocalizableMessage.raw(e.getLocalizedMessage())); } return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages); return ccr; } /** {@inheritDoc} */ @@ -308,38 +315,38 @@ /** {@inheritDoc} */ @Override public ConfigChangeResult applyConfigurationAdd(LocalDBVLVIndexCfg cfg) public ConfigChangeResult applyConfigurationAdd(final LocalDBVLVIndexCfg cfg) { boolean adminActionRequired = false; ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>(); final ConfigChangeResult ccr = new ConfigChangeResult(); try { VLVIndex vlvIndex = new VLVIndex(cfg, state, storage, EntryContainer.this); vlvIndex.open(); storage.write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { VLVIndex vlvIndex = new VLVIndex(cfg, state, storage, EntryContainer.this, txn); vlvIndex.open(txn); if(!vlvIndex.isTrusted()) { adminActionRequired = true; messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get( cfg.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(cfg.getName())); } vlvIndexMap.put(cfg.getName().toLowerCase(), vlvIndex); } }); } catch(Exception e) { messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); return new ConfigChangeResult( DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages); ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); } return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages); return ccr; } /** {@inheritDoc} */ @Override public boolean isConfigurationDeleteAcceptable( LocalDBVLVIndexCfg cfg, List<LocalizableMessage> unacceptableReasons) public boolean isConfigurationDeleteAcceptable(LocalDBVLVIndexCfg cfg, List<LocalizableMessage> unacceptableReasons) { // TODO: validate more before returning true? return true; @@ -425,8 +432,7 @@ * @throws StorageRuntimeException If an error occurs in the JE database. * @throws ConfigException if a configuration related error occurs. */ public void open() throws StorageRuntimeException, ConfigException public void open(WriteableStorage txn) throws StorageRuntimeException, ConfigException { try { @@ -437,17 +443,17 @@ id2entry = new ID2Entry(databasePrefix.child(ID2ENTRY_DATABASE_NAME), entryDataConfig, storage, this); id2entry.open(); id2entry.open(txn); dn2id = new DN2ID(databasePrefix.child(DN2ID_DATABASE_NAME), storage, this); dn2id.open(); dn2id.open(txn); state = new State(databasePrefix.child(STATE_DATABASE_NAME), storage, this); state.open(); state.open(txn); if (config.isSubordinateIndexesEnabled()) { openSubordinateIndexes(); openSubordinateIndexes(txn); } else { @@ -459,7 +465,7 @@ { state.putIndexTrustState(null, id2children, false); } id2children.open(); // No-op id2children.open(txn); // No-op id2subtree = new NullIndex(databasePrefix.child(ID2SUBTREE_DATABASE_NAME), new ID2SIndexer(), state, storage, this); @@ -467,20 +473,20 @@ { state.putIndexTrustState(null, id2subtree, false); } id2subtree.open(); // No-op id2subtree.open(txn); // No-op logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backend.getBackendID()); } dn2uri = new DN2URI(databasePrefix.child(REFERRAL_DATABASE_NAME), storage, this); dn2uri.open(); dn2uri.open(txn); for (String idx : config.listLocalDBIndexes()) { LocalDBIndexCfg indexCfg = config.getLocalDBIndex(idx); AttributeIndex index = new AttributeIndex(indexCfg, this); index.open(); AttributeIndex index = new AttributeIndex(indexCfg, this, txn); index.open(txn); if(!index.isTrusted()) { logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, index.getName()); @@ -492,8 +498,8 @@ { LocalDBVLVIndexCfg vlvIndexCfg = config.getLocalDBVLVIndex(idx); VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this); vlvIndex.open(); VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this, txn); vlvIndex.open(txn); if(!vlvIndex.isTrusted()) { @@ -683,9 +689,9 @@ * @return The highest entry ID. * @throws StorageRuntimeException If an error occurs in the JE database. */ public EntryID getHighestEntryID() throws StorageRuntimeException public EntryID getHighestEntryID(ReadableStorage txn) throws StorageRuntimeException { Cursor cursor = storage.openCursor(id2entry.getName()); Cursor cursor = txn.openCursor(id2entry.getName()); try { // Position a cursor on the last data item, and the key should give the highest ID. @@ -821,9 +827,7 @@ // Handle base-object search first. if (searchScope == SearchScope.BASE_OBJECT) { // Fetch the base entry. Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope); final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope); if (!isManageDsaITOperation(searchOperation)) { dn2uri.checkTargetForReferral(baseEntry, searchOperation.getScope()); @@ -1002,7 +1006,7 @@ { rootContainer.getMonitorProvider().updateIndexedSearchCount(); } searchIndexed(entryIDList, candidatesAreInScope, searchOperation, pageRequest); searchIndexed(txn, entryIDList, candidatesAreInScope, searchOperation, pageRequest); } else { @@ -1045,7 +1049,7 @@ } } searchNotIndexed(searchOperation, pageRequest); searchNotIndexed(txn, searchOperation, pageRequest); } return null; } @@ -1075,7 +1079,7 @@ * @throws DirectoryException If an error prevented the search from being * processed. */ private void searchNotIndexed(SearchOperation searchOperation, PagedResultsControl pageRequest) private void searchNotIndexed(ReadableStorage txn, SearchOperation searchOperation, PagedResultsControl pageRequest) throws DirectoryException, CanceledOperationException { DN aBaseDN = searchOperation.getBaseDN(); @@ -1087,9 +1091,7 @@ // the base entry processing if the cookie is set. if (pageRequest == null || pageRequest.getCookie().length() == 0) { // Fetch the base entry. Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope); final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope); if (!manageDsaIT) { dn2uri.checkTargetForReferral(baseEntry, searchScope); @@ -1105,7 +1107,7 @@ } if (!manageDsaIT && !dn2uri.returnSearchReferences(searchOperation) && !dn2uri.returnSearchReferences(txn, searchOperation) && pageRequest != null) { // Indicate no more pages. @@ -1165,7 +1167,7 @@ try { Cursor cursor = storage.openCursor(dn2id.getName()); final Cursor cursor = txn.openCursor(dn2id.getName()); try { // Initialize the cursor very close to the starting value. @@ -1305,11 +1307,9 @@ * @throws DirectoryException If an error prevented the search from being * processed. */ private void searchIndexed(EntryIDSet entryIDList, boolean candidatesAreInScope, SearchOperation searchOperation, PagedResultsControl pageRequest) throws DirectoryException, CanceledOperationException private void searchIndexed(ReadableStorage txn, EntryIDSet entryIDList, boolean candidatesAreInScope, SearchOperation searchOperation, PagedResultsControl pageRequest) throws DirectoryException, CanceledOperationException { SearchScope searchScope = searchOperation.getScope(); DN aBaseDN = searchOperation.getBaseDN(); @@ -1336,8 +1336,7 @@ } else if (!manageDsaIT) { // Return any search result references. continueSearch = dn2uri.returnSearchReferences(searchOperation); continueSearch = dn2uri.returnSearchReferences(txn, searchOperation); } // Make sure the candidate list is smaller than the lookthrough limit @@ -1408,9 +1407,7 @@ if (searchOperation.getEntriesSent() == 0 && searchOperation.getReferencesSent() == 0) { // Fetch the base entry if it exists. Entry baseEntry = fetchBaseEntry(aBaseDN, searchScope); final Entry baseEntry = fetchBaseEntry(txn, aBaseDN, searchScope); if (!manageDsaIT) { dn2uri.checkTargetForReferral(baseEntry, searchScope); @@ -1499,7 +1496,7 @@ if (parentDN != null) { // Check for referral entries above the target. dn2uri.targetEntryReferrals(entry.getName(), null); dn2uri.targetEntryReferrals(txn, entry.getName(), null); // Read the parent ID from dn2id. parentID = dn2id.get(txn, parentDN, false); @@ -1651,7 +1648,7 @@ try { // Check for referral entries above the target entry. dn2uri.targetEntryReferrals(entryDN, null); dn2uri.targetEntryReferrals(txn, entryDN, null); // Determine whether this is a subtree delete. boolean isSubtreeDelete = @@ -1677,8 +1674,6 @@ ByteSequence startKey = suffix; CursorConfig cursorConfig = new CursorConfig(); cursorConfig.setReadCommitted(true); Cursor cursor = dn2id.openCursor(txn); try { @@ -1989,7 +1984,7 @@ { // The entryDN does not exist. // Check for referral entries above the target entry. dn2uri.targetEntryReferrals(entryDN, null); dn2uri.targetEntryReferrals(txn, entryDN, null); return null; } @@ -2212,7 +2207,7 @@ if (oldApexID == null) { // Check for referral entries above the target entry. dn2uri.targetEntryReferrals(currentDN, null); dn2uri.targetEntryReferrals(txn, currentDN, null); LocalizableMessage message = ERR_JEB_MODIFYDN_NO_SUCH_OBJECT.get(currentDN); DN matchedDN = getMatchedDN(baseDN); @@ -3109,7 +3104,7 @@ { TreeName oldName = db.getName(); String newName = oldName.replace(databasePrefix, newDbPrefix); storage.renameDatabase(null, oldName, newName); storage.renameDatabase(txn, oldName, newName); db.setName(newName); } @@ -3122,7 +3117,7 @@ // Open the containers backup. for(DatabaseContainer db : databases) { db.open(); db.open(txn); } } } @@ -3161,20 +3156,24 @@ /** {@inheritDoc} */ @Override public ConfigChangeResult applyConfigurationChange(LocalDBBackendCfg cfg) public ConfigChangeResult applyConfigurationChange(final LocalDBBackendCfg cfg) { boolean adminActionRequired = false; ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>(); final ConfigChangeResult ccr = new ConfigChangeResult(); exclusiveLock.lock(); try { storage.write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { if (config.isSubordinateIndexesEnabled() != cfg.isSubordinateIndexesEnabled()) { if (cfg.isSubordinateIndexesEnabled()) { // Re-enabling subordinate indexes. openSubordinateIndexes(); openSubordinateIndexes(txn); } else { @@ -3182,15 +3181,15 @@ // future attempts to use the real indexes will fail. id2children.close(); id2children = new NullIndex(databasePrefix.child(ID2CHILDREN_DATABASE_NAME), new ID2CIndexer(), state, storage, this); new ID2CIndexer(), state, storage, EntryContainer.this); state.putIndexTrustState(null, id2children, false); id2children.open(); // No-op id2children.open(txn); // No-op id2subtree.close(); id2subtree = new NullIndex(databasePrefix.child(ID2SUBTREE_DATABASE_NAME), new ID2SIndexer(), state, storage, this); new ID2SIndexer(), state, storage, EntryContainer.this); state.putIndexTrustState(null, id2subtree, false); id2subtree.open(); // No-op id2subtree.open(txn); // No-op logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, cfg.getBackendId()); } @@ -3200,14 +3199,14 @@ { if (id2children.setIndexEntryLimit(cfg.getIndexEntryLimit())) { adminActionRequired = true; messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2children.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2children.getName())); } if (id2subtree.setIndexEntryLimit(cfg.getIndexEntryLimit())) { adminActionRequired = true; messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2subtree.getName())); ccr.setAdminActionRequired(true); ccr.addMessage(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(id2subtree.getName())); } } @@ -3215,20 +3214,21 @@ cfg.isCompactEncoding(), rootContainer.getCompressedSchema()); id2entry.setDataConfig(entryDataConfig); this.config = cfg; EntryContainer.this.config = cfg; } catch (StorageRuntimeException e) }); } catch (Exception e) { messages.add(LocalizableMessage.raw(stackTraceToSingleLineString(e))); return new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(), false, messages); ccr.setResultCode(DirectoryServer.getServerErrorResultCode()); ccr.addMessage(LocalizableMessage.raw(stackTraceToSingleLineString(e))); } finally { exclusiveLock.unlock(); } return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages); return ccr; } /** @@ -3294,7 +3294,7 @@ { for(DatabaseContainer db : databases) { db.open(); db.open(txn); } Transaction txn = null; @@ -3370,7 +3370,7 @@ } finally { database.open(); database.open(txn); } if(logger.isTraceEnabled()) { @@ -3401,20 +3401,18 @@ return null; } /** * Opens the id2children and id2subtree indexes. */ private void openSubordinateIndexes() /** Opens the id2children and id2subtree indexes. */ private void openSubordinateIndexes(WriteableStorage txn) { id2children = newIndex(ID2CHILDREN_DATABASE_NAME, new ID2CIndexer()); id2subtree = newIndex(ID2SUBTREE_DATABASE_NAME, new ID2SIndexer()); id2children = newIndex(txn, ID2CHILDREN_DATABASE_NAME, new ID2CIndexer()); id2subtree = newIndex(txn, ID2SUBTREE_DATABASE_NAME, new ID2SIndexer()); } private Index newIndex(String name, Indexer indexer) private Index newIndex(WriteableStorage txn, String name, Indexer indexer) { final Index index = new Index(databasePrefix.child(name), indexer, state, config.getIndexEntryLimit(), 0, true, storage, this); index.open(); indexer, state, config.getIndexEntryLimit(), 0, true, storage, txn, this); index.open(txn); if (!index.isTrusted()) { logger.info(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD, index.getName()); @@ -3430,10 +3428,10 @@ * @param indexEntryLimit the index entry limit * @return a new index */ Index newIndexForAttribute(TreeName indexName, Indexer indexer, int indexEntryLimit) Index newIndexForAttribute(WriteableStorage txn, TreeName indexName, Indexer indexer, int indexEntryLimit) { final int cursorEntryLimit = 100000; return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, storage, this); return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, storage, txn, this); } @@ -3481,10 +3479,9 @@ * @return the Entry matching the baseDN. * @throws DirectoryException if the baseDN doesn't exist. */ private Entry fetchBaseEntry(DN baseDN, SearchScope searchScope) private Entry fetchBaseEntry(ReadableStorage txn, DN baseDN, SearchScope searchScope) throws DirectoryException { // Fetch the base entry. Entry baseEntry = null; try { @@ -3499,7 +3496,7 @@ if (baseEntry == null) { // Check for referral entries above the base entry. dn2uri.targetEntryReferrals(baseDN, searchScope); dn2uri.targetEntryReferrals(txn, baseDN, searchScope); LocalizableMessage message = ERR_JEB_SEARCH_NO_SUCH_OBJECT.get(baseDN); DN matchedDN = getMatchedDN(baseDN); opendj3-server-dev/src/server/org/opends/server/backends/pluggable/Index.java
@@ -37,13 +37,13 @@ import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ConditionResult; import org.forgerock.opendj.ldap.spi.IndexingOptions; import org.opends.server.backends.pluggable.IndexBuffer.BufferedIndexValues; import org.opends.server.backends.pluggable.BackendImpl.Cursor; import org.opends.server.backends.pluggable.BackendImpl.ReadableStorage; import org.opends.server.backends.pluggable.BackendImpl.Storage; import org.opends.server.backends.pluggable.BackendImpl.StorageRuntimeException; import org.opends.server.backends.pluggable.BackendImpl.TreeName; import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage; import org.opends.server.backends.pluggable.IndexBuffer.BufferedIndexValues; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.Modification; @@ -77,9 +77,6 @@ */ private int entryLimitExceededCount; /** The max number of tries to rewrite phantom records. */ private final int phantomWriteRetries = 3; /** * Whether to maintain a count of IDs for a key once the entry limit * has exceeded. @@ -129,7 +126,7 @@ */ public Index(TreeName name, Indexer indexer, State state, int indexEntryLimit, int cursorEntryLimit, boolean maintainCount, Storage storage, EntryContainer entryContainer) Storage storage, WriteableStorage txn, EntryContainer entryContainer) throws StorageRuntimeException { super(name, storage, entryContainer); @@ -140,11 +137,11 @@ this.state = state; this.trusted = state.getIndexTrustState(null, this); if (!trusted && entryContainer.getHighestEntryID().longValue() == 0) if (!trusted && entryContainer.getHighestEntryID(txn).longValue() == 0) { // If there are no entries in the entry container then there // is no reason why this index can't be upgraded to trusted. setTrusted(null, true); setTrusted(txn, true); } } opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NullIndex.java
@@ -208,7 +208,7 @@ /** {@inheritDoc} */ @Override public void open() throws StorageRuntimeException public void open(WriteableStorage txn) throws StorageRuntimeException { // Do nothing. } opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
@@ -40,6 +40,8 @@ import org.opends.server.api.Backend; import org.opends.server.backends.pluggable.BackendImpl.Storage; import org.opends.server.backends.pluggable.BackendImpl.StorageRuntimeException; import org.opends.server.backends.pluggable.BackendImpl.WriteOperation; import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage; import org.opends.server.core.DirectoryServer; import org.opends.server.monitors.DatabaseEnvironmentMonitor; import org.opends.server.types.ConfigChangeResult; @@ -47,10 +49,6 @@ import org.opends.server.types.FilePermission; import org.opends.server.types.InitializationException; import static org.opends.messages.ConfigMessages.*; import static org.opends.messages.JebMessages.*; import static org.opends.server.util.StaticUtils.*; @@ -209,7 +207,15 @@ } compressedSchema = new JECompressedSchema(storage); openAndRegisterEntryContainers(config.getBaseDN()); storage.write(new WriteOperation() { @Override public void run(WriteableStorage txn) throws Exception { openAndRegisterEntryContainers(txn, config.getBaseDN()); } }); } /** @@ -229,7 +235,7 @@ * @throws ConfigException If an configuration error occurs while opening * the entry container. */ public EntryContainer openEntryContainer(DN baseDN, String name) public EntryContainer openEntryContainer(DN baseDN, String name, WriteableStorage txn) throws StorageRuntimeException, ConfigException { String databasePrefix; @@ -244,7 +250,7 @@ EntryContainer ec = new EntryContainer(baseDN, databasePrefix, backend, config, storage, this); ec.open(); ec.open(txn); return ec; } @@ -283,15 +289,15 @@ * @throws ConfigException If a configuration error occurs while * opening the entry container. */ private void openAndRegisterEntryContainers(Set<DN> baseDNs) private void openAndRegisterEntryContainers(WriteableStorage txn, Set<DN> baseDNs) throws StorageRuntimeException, InitializationException, ConfigException { EntryID id; EntryID highestID = null; for(DN baseDN : baseDNs) { EntryContainer ec = openEntryContainer(baseDN, null); id = ec.getHighestEntryID(); EntryContainer ec = openEntryContainer(baseDN, null, txn); id = ec.getHighestEntryID(txn); registerEntryContainer(baseDN, ec); if(highestID == null || id.compareTo(highestID) > 0) { opendj3-server-dev/src/server/org/opends/server/backends/pluggable/VLVIndex.java
@@ -51,6 +51,7 @@ import org.opends.server.backends.pluggable.BackendImpl.ReadableStorage; import org.opends.server.backends.pluggable.BackendImpl.Storage; import org.opends.server.backends.pluggable.BackendImpl.StorageRuntimeException; import org.opends.server.backends.pluggable.BackendImpl.WriteOperation; import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage; import org.opends.server.controls.ServerSideSortRequestControl; import org.opends.server.controls.VLVRequestControl; @@ -131,7 +132,7 @@ * configuration */ public VLVIndex(LocalDBVLVIndexCfg config, State state, Storage env, EntryContainer entryContainer) EntryContainer entryContainer, ReadableStorage txn) throws StorageRuntimeException, ConfigException { super(entryContainer.getDatabasePrefix().child("vlv."+config.getName()), @@ -197,7 +198,7 @@ this.state = state; this.trusted = state.getIndexTrustState(null, this); if (!trusted && entryContainer.getHighestEntryID().longValue() == 0) if (!trusted && entryContainer.getHighestEntryID(txn).longValue() == 0) { // If there are no entries in the entry container then there // is no reason why this vlvIndex can't be upgraded to trusted. @@ -223,11 +224,11 @@ /** {@inheritDoc} */ @Override public void open() throws StorageRuntimeException public void open(WriteableStorage txn) throws StorageRuntimeException { super.open(); super.open(txn); Cursor cursor = storage.openCursor(treeName); final Cursor cursor = txn.openCursor(treeName); try { while (cursor.next()) @@ -1304,8 +1305,8 @@ { this.sortedSetCapacity = cfg.getMaxBlockSize(); // Require admin action only if the new capacity is larger. Otherwise, // we will lazyly update the sorted sets. // Require admin action only if the new capacity is larger. // Otherwise, we will lazily update the sorted sets. if (config.getMaxBlockSize() < cfg.getMaxBlockSize()) { adminActionRequired = true; @@ -1391,12 +1392,19 @@ entryContainer.exclusiveLock.lock(); try { close(); open(); } catch(StorageRuntimeException de) storage.write(new WriteOperation() { messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de))); @Override public void run(WriteableStorage txn) throws Exception { close(); open(txn); } }); } catch (Exception e) { messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e))); if(resultCode == ResultCode.SUCCESS) { resultCode = DirectoryServer.getServerErrorResultCode(); opendj3-server-dev/src/server/org/opends/server/types/ConfigChangeResult.java
@@ -44,27 +44,31 @@ mayInvoke=true) public final class ConfigChangeResult { // A set of messages describing the changes that were made, any // action that may be required, or any problems that were // encountered. private List<LocalizableMessage> messages; // Indicates whether one or more of the changes requires // administrative action in order to take effect. private boolean adminActionRequired; // The result code to return to the client from this configuration // change. private ResultCode resultCode; /** * A set of messages describing the changes that were made, any action that * may be required, or any problems that were encountered. */ private final List<LocalizableMessage> messages; /** * Creates a new config change result object with the provided * information. * Indicates whether one or more of the changes requires administrative action * in order to take effect. */ private boolean adminActionRequired; /** The result code to return to the client from this configuration change. */ private ResultCode resultCode; /** Creates a new mutable config change result object. */ public ConfigChangeResult() { this(ResultCode.SUCCESS, false, new ArrayList<LocalizableMessage>()); } /** * Creates a new config change result object with the provided information. * * @param resultCode The result code for this config * change result. * @param resultCode The result code for this config change result. * @param adminActionRequired Indicates whether administrative * action is required for one or more * of the changes to take effect. @@ -72,13 +76,9 @@ public ConfigChangeResult(ResultCode resultCode, boolean adminActionRequired) { this.resultCode = resultCode; this.adminActionRequired = adminActionRequired; this.messages = new ArrayList<LocalizableMessage>(); this(resultCode, adminActionRequired, new ArrayList<LocalizableMessage>()); } /** * Creates a new config change result object with the provided * information. @@ -101,8 +101,6 @@ this.messages = messages; } /** * Retrieves the result code for this config change result. * @@ -126,8 +124,6 @@ this.resultCode = resultCode; } /** * Indicates whether administrative action is required before one or * more of the changes will take effect. @@ -141,8 +137,6 @@ return adminActionRequired; } /** * Specifies whether administrative action is required before one or * more of the changes will take effect. @@ -157,8 +151,6 @@ this.adminActionRequired = adminActionRequired; } /** * Retrieves the set of messages that provide explanation for the * processing of the configuration changes. This list may be @@ -172,8 +164,6 @@ return messages; } /** * Adds the provided message to the set of messages for this config * change result. @@ -186,8 +176,6 @@ messages.add(message); } /** * Retrieves a string representation of this config change result. * @@ -201,8 +189,6 @@ return buffer.toString(); } /** * Appends a string representation of this config change result to * the provided buffer. @@ -213,18 +199,15 @@ public void toString(StringBuilder buffer) { buffer.append("ConfigChangeResult(result="); buffer.append(resultCode.toString()); buffer.append(resultCode); buffer.append(", adminActionRequired="); buffer.append(adminActionRequired); buffer.append(", messages={"); if (! messages.isEmpty()) { Iterator<LocalizableMessage> iterator = messages.iterator(); LocalizableMessage firstMessage = iterator.next(); buffer.append(firstMessage); final Iterator<LocalizableMessage> iterator = messages.iterator(); buffer.append(iterator.next()); while (iterator.hasNext()) { buffer.append(","); @@ -232,8 +215,6 @@ } } buffer.append("})"); } }