001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.api; 018 019import java.util.HashSet; 020import java.util.List; 021import java.util.Set; 022import java.util.concurrent.atomic.AtomicLong; 023 024import org.forgerock.i18n.LocalizableMessage; 025import org.forgerock.i18n.slf4j.LocalizedLogger; 026import org.forgerock.opendj.config.server.ConfigException; 027import org.forgerock.opendj.server.config.server.EntryCacheCfg; 028import org.opends.server.monitors.EntryCacheMonitorProvider; 029import org.forgerock.opendj.ldap.DN; 030import org.opends.server.types.Entry; 031import org.opends.server.types.InitializationException; 032import org.opends.server.types.SearchFilter; 033 034/** 035 * This class defines the set of methods that must be implemented by a 036 * Directory Server entry cache. Note that components accessing the 037 * entry cache must not depend on any particular behavior. For 038 * example, if a call is made to {@code putEntry} to store an entry in 039 * the cache, there is no guarantee that immediately calling 040 * {@code getEntry} will be able to retrieve it. There are several 041 * potential reasons for this, including: 042 * <UL> 043 * <LI>The entry may have been deleted or replaced by another thread 044 * between the {@code putEntry} and {@code getEntry} calls.</LI> 045 * <LI>The entry cache may implement a purging mechanism and the 046 * entry added may have been purged between the 047 * {@code putEntry} and {@code getEntry} calls.</LI> 048 * <LI>The entry cache may implement some kind of filtering 049 * mechanism to determine which entries to store, and entries 050 * not matching the appropriate criteria may not be stored.</LI> 051 * <LI>The entry cache may not actually store any entries (this is 052 * the behavior of the default cache if no implementation 053 * specific entry cache is available).</LI> 054 * </UL> 055 * 056 * @param <T> The type of configuration handled by this entry 057 * cache. 058 */ 059@org.opends.server.types.PublicAPI( 060 stability=org.opends.server.types.StabilityLevel.VOLATILE, 061 mayInstantiate=false, 062 mayExtend=true, 063 mayInvoke=true, 064 notes="Entry cache methods may only be invoked by backends") 065public abstract class EntryCache<T extends EntryCacheCfg> 066{ 067 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 068 069 /** 070 * The set of filters that define the entries that should be 071 * excluded from the cache. 072 */ 073 private Set<SearchFilter> excludeFilters = new HashSet<>(0); 074 075 /** 076 * The set of filters that define the entries that should be 077 * included in the cache. 078 */ 079 private Set<SearchFilter> includeFilters = new HashSet<>(0); 080 081 /** 082 * Arbitrary number of cache hits for monitoring. 083 */ 084 protected AtomicLong cacheHits = new AtomicLong(0); 085 086 /** 087 * Arbitrary number of cache misses for monitoring. 088 */ 089 protected AtomicLong cacheMisses = new AtomicLong(0); 090 091 /** The monitor associated with this entry cache. */ 092 private EntryCacheMonitorProvider entryCacheMonitor; 093 094 095 /** 096 * Default constructor which is implicitly called from all entry 097 * cache implementations. 098 */ 099 public EntryCache() 100 { 101 // No implementation required. 102 } 103 104 /** 105 * Initializes this entry cache implementation so that it will be 106 * available for storing and retrieving entries. 107 * 108 * @param configuration The configuration to use to initialize 109 * the entry cache. 110 * 111 * @throws ConfigException If there is a problem with the provided 112 * configuration entry that would prevent 113 * this entry cache from being used. 114 * 115 * @throws InitializationException If a problem occurs during the 116 * initialization process that is 117 * not related to the 118 * configuration. 119 */ 120 public abstract void initializeEntryCache(T configuration) 121 throws ConfigException, InitializationException; 122 123 /** 124 * Indicates whether the provided configuration is acceptable for 125 * this entry cache. It should be possible to call this method on 126 * an uninitialized entry cache instance in order to determine 127 * whether the entry cache would be able to use the provided 128 * configuration. 129 * <BR><BR> 130 * Note that implementations which use a subclass of the provided 131 * configuration class will likely need to cast the configuration 132 * to the appropriate subclass type. 133 * 134 * @param configuration The entry cache configuration for 135 * which to make the determination. 136 * @param unacceptableReasons A list that may be used to hold the 137 * reasons that the provided 138 * configuration is not acceptable. 139 * 140 * @return {@code true} if the provided configuration is acceptable 141 * for this entry cache, or {@code false} if not. 142 */ 143 public boolean isConfigurationAcceptable( 144 EntryCacheCfg configuration, 145 List<LocalizableMessage> unacceptableReasons) 146 { 147 // This default implementation does not perform any special 148 // validation. It should be overridden by entry cache 149 // implementations that wish to perform more detailed validation. 150 return true; 151 } 152 153 /** 154 * Performs any necessary cleanup work (e.g., flushing all cached 155 * entries and releasing any other held resources) that should be 156 * performed when the server is to be shut down or the entry cache 157 * destroyed or replaced. 158 */ 159 public abstract void finalizeEntryCache(); 160 161 /** 162 * Indicates whether the entry cache currently contains the entry 163 * with the specified DN. This method may be called without holding 164 * any locks if a point-in-time check is all that is required. 165 * Note that this method is called from @see #getEntry(DN entryDN, 166 * LockType lockType, List lockList) 167 * 168 * @param entryDN The DN for which to make the determination. 169 * 170 * @return {@code true} if the entry cache currently contains the 171 * entry with the specified DN, or {@code false} if not. 172 */ 173 public abstract boolean containsEntry(DN entryDN); 174 175 /** 176 * Retrieves the entry with the specified DN from the cache. 177 * 178 * @param entryDN The DN of the entry to retrieve. 179 * 180 * @return The requested entry if it is present in the cache, or 181 * {@code null} if it is not present. 182 */ 183 public abstract Entry getEntry(DN entryDN); 184 185 /** 186 * Retrieves the requested entry if it is present in the cache. 187 * 188 * @param backendID ID of the backend associated with the entry 189 * to retrieve. 190 * @param entryID The entry ID within the provided backend for 191 * the specified entry. 192 * 193 * @return The requested entry if it is present in the cache, or 194 * {@code null} if it is not present. 195 */ 196 public Entry getEntry(String backendID, long entryID) 197 { 198 // Translate given backend/entryID pair to entryDN. 199 DN entryDN = getEntryDN(backendID, entryID); 200 if (entryDN == null) 201 { 202 // Indicate cache miss. 203 cacheMisses.getAndIncrement(); 204 return null; 205 } 206 // Delegate to by DN lock and load method. 207 return getEntry(entryDN); 208 } 209 210 /** 211 * Retrieves the entry ID for the entry with the specified DN from 212 * the cache. The caller should have already acquired a read or 213 * write lock for the entry if such protection is needed. 214 * 215 * @param entryDN The DN of the entry for which to retrieve the 216 * entry ID. 217 * 218 * @return The entry ID for the requested entry, or -1 if it is 219 * not present in the cache. 220 */ 221 public abstract long getEntryID(DN entryDN); 222 223 /** 224 * Retrieves the entry DN for the entry with the specified ID on 225 * the specific backend from the cache. The caller should have 226 * already acquired a read or write lock for the entry if such 227 * protection is needed. 228 * Note that this method is called from @see #getEntry(Backend 229 * backend, long entryID, LockType lockType, List lockList) 230 * 231 * @param backendID ID of the backend associated with the 232 * entry for which to retrieve the entry DN. 233 * @param entryID The entry ID within the provided backend 234 * for which to retrieve the entry DN. 235 * 236 * @return The entry DN for the requested entry, or 237 * {@code null} if it is not present in the cache. 238 */ 239 public abstract DN getEntryDN(String backendID, long entryID); 240 241 /** 242 * Stores the provided entry in the cache. Note that the mechanism 243 * that it uses to achieve this is implementation-dependent, and it 244 * is acceptable for the entry to not actually be stored in any 245 * cache. 246 * 247 * @param entry The entry to store in the cache. 248 * @param backendID ID of the backend with which the entry is 249 * associated. 250 * @param entryID The entry ID within the provided backend that 251 * uniquely identifies the specified entry. 252 */ 253 public abstract void putEntry(Entry entry, String backendID, long entryID); 254 255 /** 256 * Stores the provided entry in the cache only if it does not 257 * conflict with an entry that already exists. Note that the 258 * mechanism that it uses to achieve this is 259 * implementation-dependent, and it is acceptable for the entry to 260 * not actually be stored in any cache. However, this method must 261 * not overwrite an existing version of the entry. 262 * 263 * @param entry The entry to store in the cache. 264 * @param backendID ID of the backend with which the entry is 265 * associated. 266 * @param entryID The entry ID within the provided backend that 267 * uniquely identifies the specified entry. 268 * 269 * @return {@code false} if an existing entry or some other problem 270 * prevented the method from completing successfully, or 271 * {@code true} if there was no conflict and the entry was 272 * either stored or the cache determined that this entry 273 * should never be cached for some reason. 274 */ 275 public abstract boolean putEntryIfAbsent(Entry entry, 276 String backendID, 277 long entryID); 278 279 /** 280 * Removes the specified entry from the cache. 281 * 282 * @param entryDN The DN of the entry to remove from the cache. 283 */ 284 public abstract void removeEntry(DN entryDN); 285 286 /** 287 * Removes all entries from the cache. The cache should still be 288 * available for future use. 289 */ 290 public abstract void clear(); 291 292 /** 293 * Removes all entries from the cache that are associated with the 294 * provided backend. 295 * 296 * @param backendID ID of the backend for which to flush the 297 * associated entries. 298 */ 299 public abstract void clearBackend(String backendID); 300 301 /** 302 * Removes all entries from the cache that are below the provided 303 * DN. 304 * 305 * @param baseDN The base DN below which all entries should be 306 * flushed. 307 */ 308 public abstract void clearSubtree(DN baseDN); 309 310 /** 311 * Attempts to react to a scenario in which it is determined that 312 * the system is running low on available memory. In this case, the 313 * entry cache should attempt to free some memory if possible to try 314 * to avoid out of memory errors. 315 */ 316 public abstract void handleLowMemory(); 317 318 /** 319 * Retrieves the monitor that is associated with this entry 320 * cache. 321 * 322 * @return The monitor that is associated with this entry 323 * cache, or {@code null} if none has been assigned. 324 */ 325 public final EntryCacheMonitorProvider getEntryCacheMonitor() 326 { 327 return entryCacheMonitor; 328 } 329 330 /** 331 * Sets the monitor for this entry cache. 332 * 333 * @param entryCacheMonitor The monitor for this entry cache. 334 */ 335 public final void setEntryCacheMonitor( 336 EntryCacheMonitorProvider entryCacheMonitor) 337 { 338 this.entryCacheMonitor = entryCacheMonitor; 339 } 340 341 /** 342 * Retrieves a set of attributes containing monitor data that should 343 * be returned to the client if the corresponding monitor entry is 344 * requested. 345 * 346 * @return A list of attributes containing monitor data that should 347 * be returned to the client if the corresponding monitor 348 * entry is requested. 349 */ 350 public abstract MonitorData getMonitorData(); 351 352 /** 353 * Retrieves the current number of entries stored within the cache. 354 * 355 * @return The current number of entries stored within the cache. 356 */ 357 public abstract Long getCacheCount(); 358 359 /** 360 * Retrieves the current number of cache hits for this cache. 361 * 362 * @return The current number of cache hits for this cache. 363 */ 364 public long getCacheHits() 365 { 366 return cacheHits.longValue(); 367 } 368 369 /** 370 * Retrieves the current number of cache misses for this cache. 371 * 372 * @return The current number of cache misses for this cache. 373 */ 374 public long getCacheMisses() 375 { 376 return cacheMisses.longValue(); 377 } 378 379 /** 380 * Retrieves the set of search filters that may be used to determine 381 * whether an entry should be excluded from the cache. 382 * 383 * @return The set of search filters that may be used to determine 384 * whether an entry should be excluded from the cache. 385 */ 386 public Set<SearchFilter> getExcludeFilters() 387 { 388 return excludeFilters; 389 } 390 391 /** 392 * Specifies the set of search filters that may be used to determine 393 * whether an entry should be excluded from the cache. 394 * 395 * @param excludeFilters The set of search filters that may be 396 * used to determine whether an entry should 397 * be excluded from the cache. 398 */ 399 public void setExcludeFilters(Set<SearchFilter> excludeFilters) 400 { 401 if (excludeFilters == null) 402 { 403 this.excludeFilters = new HashSet<>(0); 404 } 405 else 406 { 407 this.excludeFilters = excludeFilters; 408 } 409 } 410 411 /** 412 * Retrieves the set of search filters that may be used to determine 413 * whether an entry should be included in the cache. 414 * 415 * @return The set of search filters that may be used to determine 416 * whether an entry should be included in the cache. 417 */ 418 public Set<SearchFilter> getIncludeFilters() 419 { 420 return includeFilters; 421 } 422 423 /** 424 * Specifies the set of search filters that may be used to determine 425 * whether an entry should be included in the cache. 426 * 427 * @param includeFilters The set of search filters that may be 428 * used to determine whether an entry should 429 * be included in the cache. 430 */ 431 public void setIncludeFilters(Set<SearchFilter> includeFilters) 432 { 433 if (includeFilters == null) 434 { 435 this.includeFilters = new HashSet<>(0); 436 } 437 else 438 { 439 this.includeFilters = includeFilters; 440 } 441 } 442 443 /** 444 * Indicates whether the current set of exclude and include filters 445 * allow caching of the specified entry. 446 * 447 * @param entry The entry to evaluate against exclude and include 448 * filter sets. 449 * 450 * @return {@code true} if current set of filters allow caching the 451 * entry and {@code false} otherwise. 452 */ 453 public boolean filtersAllowCaching(Entry entry) 454 { 455 // If there is a set of exclude filters, then make sure that the 456 // provided entry doesn't match any of them. 457 if (! excludeFilters.isEmpty()) 458 { 459 for (SearchFilter f : excludeFilters) 460 { 461 try 462 { 463 if (f.matchesEntry(entry)) 464 { 465 return false; 466 } 467 } 468 catch (Exception e) 469 { 470 logger.traceException(e); 471 472 // This shouldn't happen, but if it does then we can't be 473 // sure whether the entry should be excluded, so we will 474 // by default. 475 return false; 476 } 477 } 478 } 479 480 // If there is a set of include filters, then make sure that the 481 // provided entry matches at least one of them. 482 if (! includeFilters.isEmpty()) 483 { 484 boolean matchFound = false; 485 for (SearchFilter f : includeFilters) 486 { 487 try 488 { 489 if (f.matchesEntry(entry)) 490 { 491 matchFound = true; 492 break; 493 } 494 } 495 catch (Exception e) 496 { 497 logger.traceException(e); 498 499 // This shouldn't happen, but if it does, then 500 // just ignore it. 501 } 502 } 503 504 if (! matchFound) 505 { 506 return false; 507 } 508 } 509 510 return true; 511 } 512 513 /** 514 * Return a verbose string representation of the current cache maps. This is 515 * useful primary for debugging and diagnostic purposes such as in the entry 516 * cache unit tests. 517 * <p> 518 * This method is invoked by unit tests for debugging. 519 * 520 * @return String verbose string representation of the current cache maps in 521 * the following format: dn:id:backend one cache entry map 522 * representation per line or <CODE>null</CODE> if all maps are empty. 523 */ 524 public abstract String toVerboseString(); 525}