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 2008-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import java.util.List; 020import java.util.SortedMap; 021 022import org.forgerock.i18n.LocalizableMessage; 023import org.forgerock.i18n.slf4j.LocalizedLogger; 024import org.forgerock.opendj.config.server.ConfigChangeResult; 025import org.forgerock.opendj.config.server.ConfigException; 026import org.forgerock.opendj.config.server.ConfigurationChangeListener; 027import org.forgerock.opendj.server.config.server.EntryCacheCfg; 028import org.opends.server.api.Backend; 029import org.opends.server.api.BackendInitializationListener; 030import org.opends.server.api.EntryCache; 031import org.opends.server.api.MonitorData; 032import org.opends.server.core.DirectoryServer; 033import org.forgerock.opendj.ldap.DN; 034import org.opends.server.types.Entry; 035import org.opends.server.types.InitializationException; 036 037/** 038 * This class defines the default entry cache which acts as an arbiter for 039 * every entry cache implementation configured and installed within the 040 * Directory Server or acts an an empty cache if no implementation specific 041 * entry cache is configured. It does not actually store any entries, so 042 * all calls to the entry cache public API are routed to underlying entry 043 * cache according to the current configuration order and preferences. 044 */ 045public class DefaultEntryCache 046 extends EntryCache<EntryCacheCfg> 047 implements ConfigurationChangeListener<EntryCacheCfg>, 048 BackendInitializationListener 049{ 050 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 051 052 /** 053 * The entry cache order array reflects all currently configured and 054 * active entry cache implementations in cache level specific order. 055 */ 056 private static EntryCache<? extends EntryCacheCfg>[] cacheOrder = 057 new EntryCache<?>[0]; 058 059 /** Creates a new instance of this default entry cache. */ 060 public DefaultEntryCache() 061 { 062 super(); 063 064 // Register with backend initialization listener to clear cache 065 // entries belonging to given backend that about to go offline. 066 DirectoryServer.registerBackendInitializationListener(this); 067 } 068 069 @Override 070 public void initializeEntryCache(EntryCacheCfg configEntry) 071 throws ConfigException, InitializationException 072 { 073 // No implementation required. 074 } 075 076 @Override 077 public void finalizeEntryCache() 078 { 079 for (EntryCache<?> entryCache : cacheOrder) { 080 entryCache.finalizeEntryCache(); 081 } 082 // ReInitialize cache order array. 083 cacheOrder = new EntryCache<?>[0]; 084 } 085 086 @Override 087 public boolean containsEntry(DN entryDN) 088 { 089 if (entryDN == null) { 090 return false; 091 } 092 093 for (EntryCache<?> entryCache : cacheOrder) { 094 if (entryCache.containsEntry(entryDN)) { 095 return true; 096 } 097 } 098 099 return false; 100 } 101 102 @Override 103 public Entry getEntry(String backendID, long entryID) 104 { 105 for (EntryCache<? extends EntryCacheCfg> entryCache : cacheOrder) 106 { 107 Entry entry = entryCache.getEntry(backendID, entryID); 108 if (entry != null) 109 { 110 return entry.duplicate(true); 111 } 112 } 113 114 // Indicate global cache miss. 115 if (cacheOrder.length != 0) 116 { 117 cacheMisses.getAndIncrement(); 118 } 119 return null; 120 } 121 122 @Override 123 public Entry getEntry(DN entryDN) 124 { 125 for (EntryCache<? extends EntryCacheCfg> entryCache : cacheOrder) 126 { 127 Entry entry = entryCache.getEntry(entryDN); 128 if (entry != null) 129 { 130 return entry.duplicate(true); 131 } 132 } 133 134 // Indicate global cache miss. 135 if (cacheOrder.length != 0) 136 { 137 cacheMisses.getAndIncrement(); 138 } 139 return null; 140 } 141 142 @Override 143 public long getEntryID(DN entryDN) 144 { 145 for (EntryCache<?> entryCache : cacheOrder) 146 { 147 long entryID = entryCache.getEntryID(entryDN); 148 if (entryID != -1) 149 { 150 return entryID; 151 } 152 } 153 return -1; 154 } 155 156 @Override 157 public DN getEntryDN(String backendID, long entryID) 158 { 159 for (EntryCache<?> entryCache : cacheOrder) 160 { 161 DN entryDN = entryCache.getEntryDN(backendID, entryID); 162 if (entryDN != null) 163 { 164 return entryDN; 165 } 166 } 167 return null; 168 } 169 170 @Override 171 public void putEntry(Entry entry, String backendID, long entryID) 172 { 173 for (EntryCache<?> entryCache : cacheOrder) { 174 // The first cache in the order which can take this entry 175 // gets it. 176 if (entryCache.filtersAllowCaching(entry)) { 177 entryCache.putEntry(entry.duplicate(false), backendID, entryID); 178 break; 179 } 180 } 181 } 182 183 @Override 184 public boolean putEntryIfAbsent(Entry entry, String backendID, long entryID) 185 { 186 for (EntryCache<?> entryCache : cacheOrder) { 187 // The first cache in the order which can take this entry 188 // gets it. 189 if (entryCache.filtersAllowCaching(entry)) { 190 return entryCache.putEntryIfAbsent(entry.duplicate(false), 191 backendID, entryID); 192 } 193 } 194 195 return false; 196 } 197 198 @Override 199 public void removeEntry(DN entryDN) 200 { 201 for (EntryCache<?> entryCache : cacheOrder) { 202 if (entryCache.containsEntry(entryDN)) { 203 entryCache.removeEntry(entryDN); 204 break; 205 } 206 } 207 } 208 209 @Override 210 public void clear() 211 { 212 for (EntryCache<?> entryCache : cacheOrder) { 213 entryCache.clear(); 214 } 215 } 216 217 @Override 218 public void clearBackend(String backendID) 219 { 220 for (EntryCache<?> entryCache : cacheOrder) { 221 entryCache.clearBackend(backendID); 222 } 223 } 224 225 @Override 226 public void clearSubtree(DN baseDN) 227 { 228 for (EntryCache<?> entryCache : cacheOrder) { 229 entryCache.clearSubtree(baseDN); 230 } 231 } 232 233 @Override 234 public void handleLowMemory() 235 { 236 for (EntryCache<?> entryCache : cacheOrder) { 237 entryCache.handleLowMemory(); 238 } 239 } 240 241 @Override 242 public boolean isConfigurationChangeAcceptable( 243 EntryCacheCfg configuration, 244 List<LocalizableMessage> unacceptableReasons 245 ) 246 { 247 // No implementation required. 248 return true; 249 } 250 251 @Override 252 public ConfigChangeResult applyConfigurationChange(EntryCacheCfg configuration) 253 { 254 // No implementation required. 255 return new ConfigChangeResult(); 256 } 257 258 @Override 259 public MonitorData getMonitorData() 260 { 261 // The sum of cache hits of all active entry cache implementations. 262 long entryCacheHits = 0; 263 // Common for all active entry cache implementations. 264 long entryCacheMisses = cacheMisses.longValue(); 265 // The sum of cache counts of all active entry cache implementations. 266 long currentEntryCacheCount = 0; 267 268 for (EntryCache<?> entryCache : cacheOrder) { 269 // Get cache hits and counts from every active cache. 270 entryCacheHits += entryCache.getCacheHits(); 271 currentEntryCacheCount += entryCache.getCacheCount(); 272 } 273 274 try { 275 return EntryCacheCommon.getGenericMonitorData( 276 entryCacheHits, 277 entryCacheMisses, 278 null, 279 null, 280 currentEntryCacheCount, 281 null 282 ); 283 } catch (Exception e) { 284 logger.traceException(e); 285 return new MonitorData(0); 286 } 287 } 288 289 @Override 290 public Long getCacheCount() 291 { 292 long cacheCount = 0; 293 for (EntryCache<?> entryCache : cacheOrder) { 294 cacheCount += entryCache.getCacheCount(); 295 } 296 return cacheCount; 297 } 298 299 @Override 300 public String toVerboseString() 301 { 302 StringBuilder sb = new StringBuilder(); 303 for (EntryCache<?> entryCache : cacheOrder) 304 { 305 String s = entryCache.toVerboseString(); 306 if (s != null) 307 { 308 sb.append(s); 309 } 310 } 311 String verboseString = sb.toString(); 312 return verboseString.length() > 0 ? verboseString : null; 313 } 314 315 /** 316 * Retrieves the current cache order array. 317 * 318 * @return The current cache order array. 319 */ 320 public final static EntryCache<? extends EntryCacheCfg>[] getCacheOrder() 321 { 322 return DefaultEntryCache.cacheOrder; 323 } 324 325 /** 326 * Sets the current cache order array. 327 * 328 * @param cacheOrderMap The current cache order array. 329 */ 330 public final static void setCacheOrder( 331 SortedMap<Integer, 332 EntryCache<? extends EntryCacheCfg>> cacheOrderMap) 333 { 334 DefaultEntryCache.cacheOrder = 335 cacheOrderMap.values().toArray(new EntryCache<?>[0]); 336 } 337 338 /** 339 * Performs any processing that may be required whenever a backend 340 * is initialized for use in the Directory Server. This method will 341 * be invoked after the backend has been initialized but before it 342 * has been put into service. 343 * 344 * @param backend The backend that has been initialized and is 345 * about to be put into service. 346 */ 347 @Override 348 public void performBackendPreInitializationProcessing(Backend<?> backend) 349 { 350 // Do nothing. 351 } 352 353 /** 354 * Performs any processing that may be required whenever a backend 355 * is finalized. This method will be invoked after the backend has 356 * been taken out of service but before it has been finalized. 357 * 358 * @param backend The backend that has been taken out of service 359 * and is about to be finalized. 360 */ 361 @Override 362 public void performBackendPostFinalizationProcessing(Backend<?> backend) 363 { 364 // Do not clear any backends if the server is shutting down. 365 if (!DirectoryServer.getInstance().isShuttingDown()) 366 { 367 clearBackend(backend.getBackendID()); 368 } 369 } 370 371 @Override 372 public void performBackendPostInitializationProcessing(Backend<?> backend) { 373 // Nothing to do. 374 } 375 376 @Override 377 public void performBackendPreFinalizationProcessing(Backend<?> backend) { 378 // Nothing to do. 379 } 380}