Use backendID for entry cache rather than backend instance.
RootContainer is now directly constructed with the Storage rather than getting it from the Backend.
| | |
| | | /** |
| | | * Retrieves the requested entry if it is present in the cache. |
| | | * |
| | | * @param backend The backend associated with the entry to |
| | | * retrieve. |
| | | * @param backendID ID of the backend associated with the entry |
| | | * to retrieve. |
| | | * @param entryID The entry ID within the provided backend for |
| | | * the specified entry. |
| | | * |
| | | * @return The requested entry if it is present in the cache, or |
| | | * {@code null} if it is not present. |
| | | */ |
| | | public Entry getEntry(Backend backend, long entryID) |
| | | public Entry getEntry(String backendID, long entryID) |
| | | { |
| | | // Translate given backend/entryID pair to entryDN. |
| | | DN entryDN = getEntryDN(backend, entryID); |
| | | DN entryDN = getEntryDN(backendID, entryID); |
| | | if (entryDN == null) |
| | | { |
| | | // Indicate cache miss. |
| | |
| | | * Note that this method is called from @see #getEntry(Backend |
| | | * backend, long entryID, LockType lockType, List lockList) |
| | | * |
| | | * @param backend The backend associated with the entry for |
| | | * which to retrieve the entry DN. |
| | | * @param entryID The entry ID within the provided backend |
| | | * for which to retrieve the entry DN. |
| | | * @param backendID ID of the backend associated with the |
| | | * entry for which to retrieve the entry DN. |
| | | * @param entryID The entry ID within the provided backend |
| | | * for which to retrieve the entry DN. |
| | | * |
| | | * @return The entry DN for the requested entry, or |
| | | * {@code null} if it is not present in the cache. |
| | | */ |
| | | public abstract DN getEntryDN(Backend backend, long entryID); |
| | | public abstract DN getEntryDN(String backendID, long entryID); |
| | | |
| | | /** |
| | | * Stores the provided entry in the cache. Note that the mechanism |
| | |
| | | * is acceptable for the entry to not actually be stored in any |
| | | * cache. |
| | | * |
| | | * @param entry The entry to store in the cache. |
| | | * @param backend The backend with which the entry is associated. |
| | | * @param entryID The entry ID within the provided backend that |
| | | * uniquely identifies the specified entry. |
| | | * @param entry The entry to store in the cache. |
| | | * @param backendID ID of the backend with which the entry is |
| | | * associated. |
| | | * @param entryID The entry ID within the provided backend that |
| | | * uniquely identifies the specified entry. |
| | | */ |
| | | public abstract void putEntry(Entry entry, Backend backend, |
| | | long entryID); |
| | | public abstract void putEntry(Entry entry, String backendID, long entryID); |
| | | |
| | | /** |
| | | * Stores the provided entry in the cache only if it does not |
| | |
| | | * not actually be stored in any cache. However, this method must |
| | | * not overwrite an existing version of the entry. |
| | | * |
| | | * @param entry The entry to store in the cache. |
| | | * @param backend The backend with which the entry is associated. |
| | | * @param entryID The entry ID within the provided backend that |
| | | * uniquely identifies the specified entry. |
| | | * @param entry The entry to store in the cache. |
| | | * @param backendID ID of the backend with which the entry is |
| | | * associated. |
| | | * @param entryID The entry ID within the provided backend that |
| | | * uniquely identifies the specified entry. |
| | | * |
| | | * @return {@code false} if an existing entry or some other problem |
| | | * prevented the method from completing successfully, or |
| | |
| | | * should never be cached for some reason. |
| | | */ |
| | | public abstract boolean putEntryIfAbsent(Entry entry, |
| | | Backend backend, |
| | | String backendID, |
| | | long entryID); |
| | | |
| | | /** |
| | |
| | | * Removes all entries from the cache that are associated with the |
| | | * provided backend. |
| | | * |
| | | * @param backend The backend for which to flush the associated |
| | | * entries. |
| | | * @param backendID ID of the backend for which to flush the |
| | | * associated entries. |
| | | */ |
| | | public abstract void clearBackend(Backend backend); |
| | | public abstract void clearBackend(String backendID); |
| | | |
| | | /** |
| | | * Removes all entries from the cache that are below the provided |
| | |
| | | import org.opends.server.admin.std.server.LocalDBBackendCfg; |
| | | import org.opends.server.admin.std.server.LocalDBIndexCfg; |
| | | import org.opends.server.admin.std.server.LocalDBVLVIndexCfg; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.api.EntryCache; |
| | | import org.opends.server.api.plugin.PluginResult.SubordinateDelete; |
| | |
| | | /** The vlv index configuration manager. */ |
| | | private final VLVJEIndexCfgManager vlvJEIndexCfgManager; |
| | | |
| | | /** The backend to which this entry container belongs. */ |
| | | private final Backend<?> backend; |
| | | /** ID of the backend to which this entry container belongs. */ |
| | | private final String backendID; |
| | | |
| | | /** The root container in which this entryContainer belongs. */ |
| | | private final RootContainer rootContainer; |
| | |
| | | * storing on disk. |
| | | * @param databasePrefix The prefix to use in the database names used by |
| | | * this entry container. |
| | | * @param backend A reference to the JE backend that is creating this entry |
| | | * container. It is needed by the Directory Server entry cache |
| | | * methods. |
| | | * @param backendID ID of the JE backend that is creating this entry |
| | | * container. It is needed by the Directory Server |
| | | * entry cache methods. |
| | | * @param config The configuration of the JE backend. |
| | | * @param env The JE environment to create this entryContainer in. |
| | | * @param rootContainer The root container this entry container is in. |
| | | * @throws ConfigException if a configuration related error occurs. |
| | | */ |
| | | EntryContainer(DN baseDN, String databasePrefix, Backend<?> backend, |
| | | EntryContainer(DN baseDN, String databasePrefix, String backendID, |
| | | LocalDBBackendCfg config, Environment env, RootContainer rootContainer) |
| | | throws ConfigException |
| | | { |
| | | this.backend = backend; |
| | | this.backendID = backendID; |
| | | this.baseDN = baseDN; |
| | | this.config = config; |
| | | this.env = env; |
| | |
| | | } |
| | | id2subtree.open(); // No-op |
| | | |
| | | logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backend.getBackendID()); |
| | | logger.info(NOTE_JEB_SUBORDINATE_INDEXES_DISABLED, backendID); |
| | | } |
| | | |
| | | dn2uri = new DN2URI(databasePrefix + "_" + REFERRAL_DATABASE_NAME, env, this); |
| | |
| | | { |
| | | // Try the entry cache first. |
| | | final EntryCache<?> entryCache = getEntryCache(); |
| | | final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue()); |
| | | final Entry cacheEntry = entryCache.getEntry(backendID, entryID.longValue()); |
| | | if (cacheEntry != null) |
| | | { |
| | | return cacheEntry; |
| | |
| | | { |
| | | // Put the entry in the cache making sure not to overwrite a newer copy |
| | | // that may have been inserted since the time we read the cache. |
| | | entryCache.putEntryIfAbsent(entry, backend, entryID.longValue()); |
| | | entryCache.putEntryIfAbsent(entry, backendID, entryID.longValue()); |
| | | } |
| | | return entry; |
| | | } |
| | |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | if (entryCache != null) |
| | | { |
| | | entryCache.putEntry(entry, backend, entryID.longValue()); |
| | | entryCache.putEntry(entry, backendID, entryID.longValue()); |
| | | } |
| | | } |
| | | catch (DatabaseException | DirectoryException | CanceledOperationException e) |
| | |
| | | * Put the entry in the cache making sure not to overwrite a newer copy that may have been |
| | | * inserted since the time we read the cache. |
| | | */ |
| | | entryCache.putEntryIfAbsent(entry, backend, entryID.longValue()); |
| | | entryCache.putEntryIfAbsent(entry, backendID, entryID.longValue()); |
| | | } |
| | | return entry; |
| | | } |
| | |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | if (entryCache != null) |
| | | { |
| | | entryCache.putEntry(newEntry, backend, entryID.longValue()); |
| | | entryCache.putEntry(newEntry, backendID, entryID.longValue()); |
| | | } |
| | | } |
| | | catch (DatabaseException | DirectoryException | CanceledOperationException e) |
| | |
| | | databasePrefix = name; |
| | | } |
| | | |
| | | EntryContainer ec = new EntryContainer(baseDN, databasePrefix, |
| | | backend, config, env, this); |
| | | EntryContainer ec = new EntryContainer(baseDN, databasePrefix, backend.getBackendID(), config, env, this); |
| | | ec.open(); |
| | | return ec; |
| | | } |
| | |
| | | private Storage storage; |
| | | |
| | | /** The controls supported by this backend. */ |
| | | private static final Set<String> supportedControls = new HashSet<String>(Arrays.asList( |
| | | private static final Set<String> supportedControls = new HashSet<>(Arrays.asList( |
| | | OID_SUBTREE_DELETE_CONTROL, |
| | | OID_PAGED_RESULTS_CONTROL, |
| | | OID_MANAGE_DSAIT_CONTROL, |
| | |
| | | @Override |
| | | public void configureBackend(C cfg, ServerContext serverContext) throws ConfigException |
| | | { |
| | | Reject.ifNull(cfg); |
| | | Reject.ifNull(cfg, "cfg must not be null"); |
| | | |
| | | this.cfg = cfg; |
| | | baseDNs = this.cfg.getBaseDN().toArray(new DN[0]); |
| | |
| | | throws ConfigException, InitializationException { |
| | | // Open the storage |
| | | try { |
| | | RootContainer rc = new RootContainer(this, cfg); |
| | | final RootContainer rc = new RootContainer(getBackendID(), storage, cfg); |
| | | rc.open(); |
| | | return rc; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | Storage getStorage() |
| | | { |
| | | return storage; |
| | | } |
| | | } |
| | |
| | | import org.opends.server.admin.std.server.BackendIndexCfg; |
| | | import org.opends.server.admin.std.server.BackendVLVIndexCfg; |
| | | import org.opends.server.admin.std.server.PluggableBackendCfg; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.api.EntryCache; |
| | | import org.opends.server.api.VirtualAttributeProvider; |
| | |
| | | /** The vlv index configuration manager. */ |
| | | private final VLVIndexCfgManager vlvIndexCfgManager; |
| | | |
| | | /** The backend to which this entry container belongs. */ |
| | | private final Backend<?> backend; |
| | | /** ID of the backend to which this entry container belongs. */ |
| | | private final String backendID; |
| | | |
| | | /** The root container in which this entryContainer belongs. */ |
| | | private final RootContainer rootContainer; |
| | |
| | | * |
| | | * @param baseDN The baseDN this entry container will be responsible for |
| | | * storing on disk. |
| | | * @param backend A reference to the backend that is creating this entry |
| | | * container. It is needed by the Directory Server entry cache |
| | | * methods. |
| | | * @param backendID ID of the backend that is creating this entry container. |
| | | * It is needed by the Directory Server entry cache methods. |
| | | * @param config The configuration of the backend. |
| | | * @param storage The storage for this entryContainer. |
| | | * @param rootContainer The root container this entry container is in. |
| | | * @throws ConfigException if a configuration related error occurs. |
| | | */ |
| | | EntryContainer(DN baseDN, Backend<?> backend, PluggableBackendCfg config, Storage storage, |
| | | EntryContainer(DN baseDN, String backendID, PluggableBackendCfg config, Storage storage, |
| | | RootContainer rootContainer) throws ConfigException |
| | | { |
| | | this.backend = backend; |
| | | this.backendID = backendID; |
| | | this.baseDN = baseDN; |
| | | this.config = config; |
| | | this.storage = storage; |
| | |
| | | { |
| | | // Try the entry cache first. |
| | | final EntryCache<?> entryCache = getEntryCache(); |
| | | final Entry cacheEntry = entryCache.getEntry(backend, entryID.longValue()); |
| | | final Entry cacheEntry = entryCache.getEntry(backendID, entryID.longValue()); |
| | | if (cacheEntry != null) |
| | | { |
| | | return cacheEntry; |
| | |
| | | { |
| | | // Put the entry in the cache making sure not to overwrite a newer copy |
| | | // that may have been inserted since the time we read the cache. |
| | | entryCache.putEntryIfAbsent(entry, backend, entryID.longValue()); |
| | | entryCache.putEntryIfAbsent(entry, backendID, entryID.longValue()); |
| | | } |
| | | return entry; |
| | | } |
| | |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | if (entryCache != null) |
| | | { |
| | | entryCache.putEntry(entry, backend, entryID.longValue()); |
| | | entryCache.putEntry(entry, backendID, entryID.longValue()); |
| | | } |
| | | } |
| | | catch (StorageRuntimeException | DirectoryException | CanceledOperationException e) |
| | |
| | | * Put the entry in the cache making sure not to overwrite a newer copy that may have been |
| | | * inserted since the time we read the cache. |
| | | */ |
| | | entryCache.putEntryIfAbsent(entry, backend, entryID.longValue()); |
| | | entryCache.putEntryIfAbsent(entry, backendID, entryID.longValue()); |
| | | } |
| | | return entry; |
| | | } |
| | |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | if (entryCache != null) |
| | | { |
| | | entryCache.putEntry(newEntry, backend, entryID.longValue()); |
| | | entryCache.putEntry(newEntry, backendID, entryID.longValue()); |
| | | } |
| | | } |
| | | catch (StorageRuntimeException | DirectoryException | CanceledOperationException e) |
| | |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | /** The tree storage. */ |
| | | private Storage storage; |
| | | private final Storage storage; |
| | | |
| | | /** The backend to which this entry root container belongs. */ |
| | | private final BackendImpl<?> backend; |
| | | /** The ID of the backend to which this entry root container belongs. */ |
| | | private final String backendId; |
| | | /** The backend configuration. */ |
| | | private final PluggableBackendCfg config; |
| | | /** The monitor for this backend. */ |
| | |
| | | * |
| | | * @param config |
| | | * The configuration of the backend. |
| | | * @param backend |
| | | * @param backendID |
| | | * A reference to the backend that is creating this root |
| | | * container. |
| | | */ |
| | | RootContainer(BackendImpl<?> backend, PluggableBackendCfg config) |
| | | RootContainer(String backendID, Storage storage, PluggableBackendCfg config) |
| | | { |
| | | this.backend = backend; |
| | | this.backendId = backendID; |
| | | this.storage = storage; |
| | | this.config = config; |
| | | |
| | | getMonitorProvider().enableFilterUseStats(config.isIndexFilterAnalyzerEnabled()); |
| | |
| | | { |
| | | try |
| | | { |
| | | storage = backend.getStorage(); |
| | | storage.open(); |
| | | storage.write(new WriteOperation() |
| | | { |
| | |
| | | EntryContainer openEntryContainer(DN baseDN, WriteableTransaction txn) |
| | | throws StorageRuntimeException, ConfigException |
| | | { |
| | | EntryContainer ec = new EntryContainer(baseDN, backend, config, storage, this); |
| | | EntryContainer ec = new EntryContainer(baseDN, backendId, config, storage, this); |
| | | ec.open(txn); |
| | | return ec; |
| | | } |
| | |
| | | { |
| | | if (monitor == null) |
| | | { |
| | | String monitorName = backend.getBackendID() + " Storage"; |
| | | monitor = new BackendMonitor(monitorName, this); |
| | | monitor = new BackendMonitor(backendId + " Storage", this); |
| | | } |
| | | return monitor; |
| | | } |
| | |
| | | } |
| | | catch (StorageRuntimeException e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | logger.error(ERR_CACHE_PRELOAD, backend.getBackendID(), |
| | | logger.error(ERR_CACHE_PRELOAD, backendId, |
| | | stackTraceToSingleLineString(e.getCause() != null ? e.getCause() : e)); |
| | | } |
| | | } |
| | |
| | | if (storage != null) |
| | | { |
| | | storage.close(); |
| | | storage = null; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Entry getEntry(Backend backend, long entryID) |
| | | public Entry getEntry(String backendID, long entryID) |
| | | { |
| | | for (EntryCache<? extends EntryCacheCfg> entryCache : cacheOrder) |
| | | { |
| | | Entry entry = entryCache.getEntry(backend, entryID); |
| | | Entry entry = entryCache.getEntry(backendID, entryID); |
| | | if (entry != null) |
| | | { |
| | | return entry.duplicate(true); |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getEntryDN(Backend backend, long entryID) |
| | | public DN getEntryDN(String backendID, long entryID) |
| | | { |
| | | for (EntryCache<?> entryCache : cacheOrder) |
| | | { |
| | | DN entryDN = entryCache.getEntryDN(backend, entryID); |
| | | DN entryDN = entryCache.getEntryDN(backendID, entryID); |
| | | if (entryDN != null) |
| | | { |
| | | return entryDN; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void putEntry(Entry entry, Backend backend, long entryID) |
| | | public void putEntry(Entry entry, String backendID, long entryID) |
| | | { |
| | | for (EntryCache<?> entryCache : cacheOrder) { |
| | | // The first cache in the order which can take this entry |
| | | // gets it. |
| | | if (entryCache.filtersAllowCaching(entry)) { |
| | | entryCache.putEntry(entry.duplicate(false), |
| | | backend, entryID); |
| | | entryCache.putEntry(entry.duplicate(false), backendID, entryID); |
| | | break; |
| | | } |
| | | } |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) |
| | | public boolean putEntryIfAbsent(Entry entry, String backendID, long entryID) |
| | | { |
| | | for (EntryCache<?> entryCache : cacheOrder) { |
| | | // The first cache in the order which can take this entry |
| | | // gets it. |
| | | if (entryCache.filtersAllowCaching(entry)) { |
| | | return entryCache.putEntryIfAbsent(entry.duplicate(false), |
| | | backend, entryID); |
| | | backendID, entryID); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clearBackend(Backend backend) |
| | | public void clearBackend(String backendID) |
| | | { |
| | | for (EntryCache<?> entryCache : cacheOrder) { |
| | | entryCache.clearBackend(backend); |
| | | entryCache.clearBackend(backendID); |
| | | } |
| | | } |
| | | |
| | |
| | | // Do not clear any backends if the server is shutting down. |
| | | if (!DirectoryServer.getInstance().isShuttingDown()) |
| | | { |
| | | clearBackend(backend); |
| | | clearBackend(backend.getBackendID()); |
| | | } |
| | | } |
| | | } |
| | |
| | | private static final Runtime runtime = Runtime.getRuntime(); |
| | | |
| | | /** The mapping between entry backends/IDs and entries. */ |
| | | private Map<Backend<?>, Map<Long, CacheEntry>> idMap; |
| | | private Map<String, Map<Long, CacheEntry>> idMap; |
| | | |
| | | /** The mapping between DNs and entries. */ |
| | | private LinkedHashMap<DN,CacheEntry> dnMap; |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getEntryDN(Backend backend, long entryID) |
| | | public DN getEntryDN(String backendID, long entryID) |
| | | { |
| | | // Locate specific backend map and return the entry DN by ID. |
| | | cacheReadLock.lock(); |
| | | try { |
| | | Map<Long, CacheEntry> backendMap = idMap.get(backend); |
| | | Map<Long, CacheEntry> backendMap = idMap.get(backendID); |
| | | if (backendMap != null) { |
| | | CacheEntry e = backendMap.get(entryID); |
| | | if (e != null) { |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void putEntry(Entry entry, Backend backend, long entryID) |
| | | public void putEntry(Entry entry, String backendID, long entryID) |
| | | { |
| | | // Create the cache entry based on the provided information. |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backendID, entryID); |
| | | |
| | | |
| | | // Obtain a lock on the cache. If this fails, then don't do anything. |
| | |
| | | CacheEntry ce = iterator.next(); |
| | | iterator.remove(); |
| | | |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackend()); |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackendID()); |
| | | if (m != null) |
| | | { |
| | | m.remove(ce.getEntryID()); |
| | |
| | | else |
| | | { |
| | | // Try to remove the entry from the ID list as well. |
| | | Map<Long,CacheEntry> map = idMap.get(backend); |
| | | Map<Long,CacheEntry> map = idMap.get(backendID); |
| | | if (map != null) |
| | | { |
| | | map.remove(cacheEntry.getEntryID()); |
| | | // If this backend becomes empty now remove it from the idMap map. |
| | | if (map.isEmpty()) |
| | | { |
| | | idMap.remove(backend); |
| | | idMap.remove(backendID); |
| | | } |
| | | } |
| | | } |
| | |
| | | // present and add it if it isn't. |
| | | dnMap.put(entry.getName(), cacheEntry); |
| | | |
| | | Map<Long,CacheEntry> map = idMap.get(backend); |
| | | Map<Long,CacheEntry> map = idMap.get(backendID); |
| | | if (map == null) |
| | | { |
| | | map = new HashMap<>(); |
| | | map.put(entryID, cacheEntry); |
| | | idMap.put(backend, map); |
| | | idMap.put(backendID, map); |
| | | } |
| | | else |
| | | { |
| | |
| | | CacheEntry ce = iterator.next(); |
| | | iterator.remove(); |
| | | |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackend()); |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackendID()); |
| | | if (m != null) |
| | | { |
| | | m.remove(ce.getEntryID()); |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean putEntryIfAbsent(Entry entry, Backend backend, long entryID) |
| | | public boolean putEntryIfAbsent(Entry entry, String backendID, long entryID) |
| | | { |
| | | // Create the cache entry based on the provided information. |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backendID, entryID); |
| | | |
| | | |
| | | // Obtain a lock on the cache. If this fails, then don't do anything. |
| | |
| | | CacheEntry ce = iterator.next(); |
| | | iterator.remove(); |
| | | |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackend()); |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackendID()); |
| | | if (m != null) |
| | | { |
| | | m.remove(ce.getEntryID()); |
| | |
| | | // present and add it if it isn't. |
| | | dnMap.put(entry.getName(), cacheEntry); |
| | | |
| | | Map<Long,CacheEntry> map = idMap.get(backend); |
| | | Map<Long,CacheEntry> map = idMap.get(backendID); |
| | | if (map == null) |
| | | { |
| | | map = new HashMap<>(); |
| | | map.put(entryID, cacheEntry); |
| | | idMap.put(backend, map); |
| | | idMap.put(backendID, map); |
| | | } |
| | | else |
| | | { |
| | |
| | | CacheEntry ce = iterator.next(); |
| | | iterator.remove(); |
| | | |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackend()); |
| | | Map<Long,CacheEntry> m = idMap.get(ce.getBackendID()); |
| | | if (m != null) |
| | | { |
| | | m.remove(ce.getEntryID()); |
| | |
| | | return; |
| | | } |
| | | |
| | | Backend backend = entry.getBackend(); |
| | | final String backendID = entry.getBackendID(); |
| | | |
| | | // Try to remove the entry from the ID list as well. |
| | | Map<Long,CacheEntry> map = idMap.get(backend); |
| | | Map<Long,CacheEntry> map = idMap.get(backendID); |
| | | if (map == null) |
| | | { |
| | | // This should't happen, but the entry isn't cached in the ID map so |
| | |
| | | // If this backend becomes empty now remove it from the idMap map. |
| | | if (map.isEmpty()) |
| | | { |
| | | idMap.remove(backend); |
| | | idMap.remove(backendID); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clearBackend(Backend backend) |
| | | public void clearBackend(String backendID) |
| | | { |
| | | // Acquire a lock on the cache. We should not return until the cache has |
| | | // been cleared, so we will block until we can obtain the lock. |
| | |
| | | try |
| | | { |
| | | // Remove all references to entries for this backend from the ID cache. |
| | | Map<Long,CacheEntry> map = idMap.remove(backend); |
| | | Map<Long,CacheEntry> map = idMap.remove(backendID); |
| | | if (map == null) |
| | | { |
| | | // No entries were in the cache for this backend, so we can return |
| | |
| | | { |
| | | // Determine which backend should be used for the provided base DN. If |
| | | // there is none, then we don't need to do anything. |
| | | Backend backend = DirectoryServer.getBackend(baseDN); |
| | | Backend<?> backend = DirectoryServer.getBackend(baseDN); |
| | | if (backend == null) |
| | | { |
| | | return; |
| | |
| | | * @param baseDN The base DN below which all entries should be flushed. |
| | | * @param backend The backend for which to remove the appropriate entries. |
| | | */ |
| | | private void clearSubtree(DN baseDN, Backend backend) |
| | | private void clearSubtree(DN baseDN, Backend<?> backend) |
| | | { |
| | | // See if there are any entries for the provided backend in the cache. If |
| | | // not, then return. |
| | | Map<Long,CacheEntry> map = idMap.get(backend); |
| | | Map<Long,CacheEntry> map = idMap.get(backend.getBackendID()); |
| | | if (map == null) |
| | | { |
| | | // No entries were in the cache for this backend, so we can return without |
| | |
| | | |
| | | // See if the backend has any subordinate backends. If so, then process |
| | | // them recursively. |
| | | for (Backend subBackend : backend.getSubordinateBackends()) |
| | | for (Backend<?> subBackend : backend.getSubordinateBackends()) |
| | | { |
| | | boolean isAppropriate = false; |
| | | for (DN subBase : subBackend.getBaseDNs()) |
| | |
| | | CacheEntry entry = iterator.next(); |
| | | iterator.remove(); |
| | | |
| | | Map<Long,CacheEntry> m = idMap.get(entry.getBackend()); |
| | | Map<Long,CacheEntry> m = idMap.get(entry.getBackendID()); |
| | | if (m != null) |
| | | { |
| | | m.remove(entry.getEntryID()); |
| | |
| | | StringBuilder sb = new StringBuilder(); |
| | | |
| | | Map<DN,CacheEntry> dnMapCopy; |
| | | Map<Backend<?>, Map<Long, CacheEntry>> idMapCopy; |
| | | Map<String, Map<Long, CacheEntry>> idMapCopy; |
| | | |
| | | // Grab cache lock to prevent any modifications |
| | | // to the cache maps until a snapshot is taken. |
| | |
| | | final CacheEntry cacheEntry = dnMapCopy.get(dn); |
| | | sb.append(dn); |
| | | sb.append(":"); |
| | | sb.append(cacheEntry != null ? |
| | | Long.toString(cacheEntry.getEntryID()) : null); |
| | | sb.append(cacheEntry != null ? Long.toString(cacheEntry.getEntryID()) : null); |
| | | sb.append(":"); |
| | | sb.append(cacheEntry != null ? |
| | | cacheEntry.getBackend().getBackendID() : null); |
| | | sb.append(cacheEntry != null ? cacheEntry.getBackendID() : null); |
| | | sb.append(ServerConstants.EOL); |
| | | } |
| | | |
| | | // See if there is anything on idMap that is not reflected on |
| | | // dnMap in case maps went out of sync. |
| | | for (Backend<?> backend : idMapCopy.keySet()) { |
| | | for (Long id : idMapCopy.get(backend).keySet()) { |
| | | final CacheEntry cacheEntry = idMapCopy.get(backend).get(id); |
| | | for (String backendID : idMapCopy.keySet()) { |
| | | for (Map.Entry<Long, CacheEntry> entry : idMapCopy.get(backendID).entrySet()) { |
| | | final CacheEntry cacheEntry = entry.getValue(); |
| | | if (cacheEntry == null || !dnMapCopy.containsKey(cacheEntry.getDN())) { |
| | | sb.append(cacheEntry != null ? cacheEntry.getDN() : null); |
| | | sb.append(":"); |
| | | sb.append(id); |
| | | sb.append(entry.getKey()); |
| | | sb.append(":"); |
| | | sb.append(backend.getBackendID()); |
| | | sb.append(backendID); |
| | | sb.append(ServerConstants.EOL); |
| | | } |
| | | } |
| | |
| | | private ConcurrentMap<DN, Reference<CacheEntry>> dnMap; |
| | | |
| | | /** The mapping between backend+ID and their corresponding entries. */ |
| | | private ConcurrentMap<Backend, ConcurrentMap<Long, Reference<CacheEntry>>> idMap; |
| | | private ConcurrentMap<String, ConcurrentMap<Long, Reference<CacheEntry>>> idMap; |
| | | |
| | | /** |
| | | * The reference queue that will be used to notify us whenever a soft |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public DN getEntryDN(Backend backend, long entryID) |
| | | public DN getEntryDN(String backendID, long entryID) |
| | | { |
| | | // Locate specific backend map and return the entry DN by ID. |
| | | ConcurrentMap<Long, Reference<CacheEntry>> backendMap = idMap.get(backend); |
| | | ConcurrentMap<Long, Reference<CacheEntry>> backendMap = idMap.get(backendID); |
| | | if (backendMap != null) { |
| | | Reference<CacheEntry> ref = backendMap.get(entryID); |
| | | if (ref != null) { |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void putEntry(Entry entry, Backend backend, long entryID) |
| | | public void putEntry(Entry entry, String backendID, long entryID) |
| | | { |
| | | // Create the cache entry based on the provided information. |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backendID, entryID); |
| | | Reference<CacheEntry> ref = new SoftReference<>(cacheEntry, referenceQueue); |
| | | |
| | | Reference<CacheEntry> oldRef = dnMap.put(entry.getName(), ref); |
| | |
| | | oldRef.clear(); |
| | | } |
| | | |
| | | ConcurrentMap<Long,Reference<CacheEntry>> map = idMap.get(backend); |
| | | ConcurrentMap<Long,Reference<CacheEntry>> map = idMap.get(backendID); |
| | | if (map == null) |
| | | { |
| | | map = new ConcurrentHashMap<>(); |
| | | map.put(entryID, ref); |
| | | idMap.put(backend, map); |
| | | idMap.put(backendID, map); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean putEntryIfAbsent(Entry entry, Backend backend, |
| | | long entryID) |
| | | public boolean putEntryIfAbsent(Entry entry, String backendID, long entryID) |
| | | { |
| | | // See if the entry already exists. If so, then return false. |
| | | if (dnMap.containsKey(entry.getName())) |
| | |
| | | |
| | | |
| | | // Create the cache entry based on the provided information. |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backend, entryID); |
| | | CacheEntry cacheEntry = new CacheEntry(entry, backendID, entryID); |
| | | Reference<CacheEntry> ref = new SoftReference<>(cacheEntry, referenceQueue); |
| | | |
| | | dnMap.put(entry.getName(), ref); |
| | | |
| | | ConcurrentMap<Long,Reference<CacheEntry>> map = idMap.get(backend); |
| | | ConcurrentMap<Long,Reference<CacheEntry>> map = idMap.get(backendID); |
| | | if (map == null) |
| | | { |
| | | map = new ConcurrentHashMap<>(); |
| | | map.put(entryID, ref); |
| | | idMap.put(backend, map); |
| | | idMap.put(backendID, map); |
| | | } |
| | | else |
| | | { |
| | |
| | | CacheEntry cacheEntry = ref.get(); |
| | | if (cacheEntry != null) |
| | | { |
| | | Backend<?> backend = cacheEntry.getBackend(); |
| | | final String backendID = cacheEntry.getBackendID(); |
| | | |
| | | ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.get(backend); |
| | | ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.get(backendID); |
| | | if (map != null) |
| | | { |
| | | ref = map.remove(cacheEntry.getEntryID()); |
| | |
| | | // it from the idMap map. |
| | | if (map.isEmpty()) |
| | | { |
| | | idMap.remove(backend); |
| | | idMap.remove(backendID); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void clearBackend(Backend backend) |
| | | public void clearBackend(String backendID) |
| | | { |
| | | // FIXME -- Would it be better just to dump everything? |
| | | ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.remove(backend); |
| | | final ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.remove(backendID); |
| | | if (map != null) |
| | | { |
| | | for (Reference<CacheEntry> ref : map.values()) |
| | | { |
| | | CacheEntry cacheEntry = ref.get(); |
| | | final CacheEntry cacheEntry = ref.get(); |
| | | if (cacheEntry != null) |
| | | { |
| | | dnMap.remove(cacheEntry.getDN()); |
| | |
| | | } |
| | | else |
| | | { |
| | | clearBackend(backend); |
| | | clearBackend(backend.getBackendID()); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | ref.clear(); |
| | | |
| | | Backend<?> backend = freedEntry.getBackend(); |
| | | ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.get(backend); |
| | | final String backendID = freedEntry.getBackendID(); |
| | | final ConcurrentMap<Long, Reference<CacheEntry>> map = idMap.get(backendID); |
| | | if (map != null) |
| | | { |
| | | ref = map.remove(freedEntry.getEntryID()); |
| | |
| | | // If this backend becomes empty now remove |
| | | // it from the idMap map. |
| | | if (map.isEmpty()) { |
| | | idMap.remove(backend); |
| | | idMap.remove(backendID); |
| | | } |
| | | } |
| | | } |
| | |
| | | sb.append(":"); |
| | | sb.append(ce.get().getEntryID()); |
| | | sb.append(":"); |
| | | sb.append(ce.get().getBackend().getBackendID()); |
| | | sb.append(ce.get().getBackendID()); |
| | | sb.append(ServerConstants.EOL); |
| | | } |
| | | |
| | |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | | import org.opends.server.api.Backend; |
| | | |
| | | /** |
| | | * This class defines a Directory Server cache entry, which is simply |
| | | * used to store an entry with its associated backend and entry ID. |
| | |
| | | public final class CacheEntry |
| | | { |
| | | /** The backend with which this cache entry is associated. */ |
| | | private final Backend<?> backend; |
| | | private final String backendID; |
| | | |
| | | /** The entry itself. */ |
| | | private final Entry entry; |
| | |
| | | * Creates a new cache entry with the provided information. |
| | | * |
| | | * @param entry The entry for this cache entry. |
| | | * @param backend The backend for this cache entry. |
| | | * @param backendID ID of the backend for this cache entry. |
| | | * @param entryID The entry ID for this cache entry. |
| | | */ |
| | | public CacheEntry(Entry entry, Backend<?> backend, long entryID) |
| | | public CacheEntry(Entry entry, String backendID, long entryID) |
| | | { |
| | | this.entry = entry; |
| | | this.backend = backend; |
| | | this.backendID = backendID; |
| | | this.entryID = entryID; |
| | | } |
| | | |
| | |
| | | * |
| | | * @return The backend for this cache entry. |
| | | */ |
| | | public Backend<?> getBackend() |
| | | public String getBackendID() |
| | | { |
| | | return backend; |
| | | return backendID; |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.std.server.EntryCacheCfg; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.EntryCache; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.DN; |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertFalse(cache.containsEntry(testEntriesList.get(0).getName()), |
| | | "Not expected to find " + testEntriesList.get(0).getName() + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertNull(cache.getEntry(testEntriesList.get(0).getName()), |
| | | "Not expected to find " + testEntriesList.get(0).getName() + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertNull(cache.getEntry(testEntriesList.get(0).getName()), |
| | | "Not expected to find " + testEntriesList.get(0).getName() + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertNull(cache.getEntry(b, -1), |
| | | "Not expected to find entry id " + -1 + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertEquals(cache.getEntryID(testEntriesList.get(0).getName()), -1, |
| | | "Not expected to find " + testEntriesList.get(0).getName() + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | cache.putEntry(testEntriesList.get(0), b, 1); |
| | | |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | assertTrue(cache.putEntryIfAbsent(testEntriesList.get(0), b, 1), |
| | | "Not expected to find " + testEntriesList.get(0).getName() + |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | cache.removeEntry(testEntriesList.get(0).getName()); |
| | | cache.putEntry(testEntriesList.get(0), b, 1); |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | cache.clear(); |
| | | cache.putEntry(testEntriesList.get(0), b, 1); |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | Backend<?> c = DirectoryServer.getBackend(DN.valueOf("cn=config")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | String c = DirectoryServer.getBackend(DN.valueOf("cn=config")).getBackendID(); |
| | | |
| | | cache.clearBackend(b); |
| | | cache.putEntry(testEntriesList.get(0), b, 1); |
| | |
| | | |
| | | assertNull(cache.getEntry(b, 1), |
| | | "Not expected to find entry id " + 1 + " on backend " + |
| | | b.getBackendID() + " in the cache. Cache contents:" + |
| | | b + " in the cache. Cache contents:" + |
| | | ServerConstants.EOL + cache.toVerboseString()); |
| | | |
| | | assertNull(cache.getEntry(testEntriesList.get(0).getName()), |
| | |
| | | |
| | | assertNotNull(cache.getEntry(c, 1), |
| | | "Expected to find entry id " + 1 + " on backend " + |
| | | c.getBackendID() + " in the cache. Cache contents:" + |
| | | c + " in the cache. Cache contents:" + |
| | | ServerConstants.EOL + cache.toVerboseString()); |
| | | |
| | | // Clear the cache so that other tests can start from scratch. |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | Backend<?> c = DirectoryServer.getBackend(DN.valueOf("cn=config")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | String c = DirectoryServer.getBackend(DN.valueOf("cn=config")).getBackendID(); |
| | | |
| | | cache.putEntry(testEntriesList.get(0), b, 1); |
| | | Entry testEntry = testEntriesList.get(1); |
| | |
| | | public void testCacheConcurrency() |
| | | throws Exception |
| | | { |
| | | Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | for(int loops = 0; loops < CONCURRENCYLOOPS; loops++) { |
| | | for(int i = 0; i < NUMTESTENTRIES; i++) { |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.SortedMap; |
| | | import java.util.TreeMap; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.opends.server.admin.std.meta.*; |
| | | import org.opends.server.admin.std.server.EntryCacheCfg; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.EntryCache; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.DN; |
| | |
| | | import org.testng.annotations.AfterGroups; |
| | | import org.testng.annotations.BeforeGroups; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | |
| | | cache.toVerboseString()); |
| | | |
| | | TestCaseUtils.initializeTestBackend(false); |
| | | Backend b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | // Spread test entries among all cache levels via default cache. |
| | | for (int i = 0; i < NUMTESTENTRIES; i++) { |
| | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.opends.server.admin.std.meta.*; |
| | | import org.opends.server.admin.std.server.FIFOEntryCacheCfg; |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | |
| | | import org.testng.annotations.AfterGroups; |
| | | import org.testng.annotations.BeforeGroups; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | |
| | | "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL + |
| | | cache.toVerboseString()); |
| | | |
| | | Backend b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { |
| | | super.cache.putEntry(super.testEntriesList.get(i), b, i); |
| | |
| | | "Expected empty cache. " + "Cache contents:" + ServerConstants.EOL + |
| | | cache.toVerboseString()); |
| | | |
| | | Backend b = DirectoryServer.getBackend(DN.valueOf("o=test")); |
| | | String b = DirectoryServer.getBackend(DN.valueOf("o=test")).getBackendID(); |
| | | |
| | | for(int i = 0; i < super.NUMTESTENTRIES; i++ ) { |
| | | super.cache.putEntry(super.testEntriesList.get(i), b, i); |