/** Removes all elements from this cache */ public synchronized void erase() { if (fileTable != null) { // FIXME: erase from memory too synchronized (this) { Set<Object> keys = new HashSet<Object>(); try { addAllFileTableKeys(keys); } catch (IOException e) { Debug.logError(e, module); } for (Object key : keys) { try { V value = fileTable.get(key); noteRemoval(toKey(key), value); removeHitCount.incrementAndGet(); fileTable.remove(key); jdbmMgr.commit(); } catch (IOException e) { Debug.logError(e, module); } } } memoryTable.clear(); } else { Iterator<Map.Entry<Object, CacheLine<V>>> it = memoryTable.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Object, CacheLine<V>> entry = it.next(); noteRemoval(toKey(entry.getKey()), entry.getValue().getValue()); removeHitCount.incrementAndGet(); it.remove(); } } }
/** * NOTE: this returns an unmodifiable copy of the keySet, so removing from here won't have an * effect, and calling a remove while iterating through the set will not cause a concurrent * modification exception. This behavior is necessary for now for the persisted cache feature. */ public Set<? extends K> getCacheLineKeys() { // note that this must be a HashSet and not a FastSet in order to have a null value Set<Object> keys; if (fileTable != null) { keys = new HashSet<Object>(); try { synchronized (this) { addAllFileTableKeys(keys); } } catch (IOException e) { Debug.logError(e, module); } if (keys.remove(ObjectType.NULL)) { keys.add(null); } } else { if (memoryTable.containsKey(ObjectType.NULL)) { keys = new HashSet<Object>(memoryTable.keySet()); keys.remove(ObjectType.NULL); keys.add(null); } else { keys = memoryTable.keySet(); } } return Collections.unmodifiableSet(UtilGenerics.<Set<? extends K>>cast(keys)); }
/** * Gets an element from the cache according to the specified key. * * @param key The key for the element, used to reference it in the hastables and LRU linked list * @return The value of the element specified by the key */ public V get(Object key) { boolean countGet = true; Object nulledKey = fromKey(key); CacheLine<V> line = memoryTable.get(nulledKey); if (line == null) { if (fileTable != null) { V value; try { synchronized (this) { value = fileTable.get(nulledKey); } } catch (IOException e) { Debug.logError(e, module); value = null; } if (value == null) { missCountNotFound.incrementAndGet(); return null; } else { hitCount.incrementAndGet(); } memoryTable.put( nulledKey, createCacheLine(UtilGenerics.<K>cast(key), value, expireTimeNanos)); return value; } else { missCountNotFound.incrementAndGet(); } } else { if (countGet) hitCount.incrementAndGet(); } return line != null ? line.getValue() : null; }
V putIfAbsentInternal(K key, V value, long expireTimeNanos) { Object nulledKey = fromKey(key); V oldValue; if (fileTable != null) { try { synchronized (this) { oldValue = fileTable.get(nulledKey); if (oldValue == null) { memoryTable.put(nulledKey, createCacheLine(key, value, expireTimeNanos)); fileTable.put(nulledKey, value); jdbmMgr.commit(); } } } catch (IOException e) { Debug.logError(e, module); oldValue = null; } } else { CacheLine<V> newCacheLine = createCacheLine(key, value, expireTimeNanos); CacheLine<V> oldCacheLine = memoryTable.putIfAbsent(nulledKey, newCacheLine); if (oldCacheLine == null) { oldValue = null; } else { oldValue = oldCacheLine.getValue(); cancel(newCacheLine); } } if (oldValue == null) { noteAddition(key, value); return null; } else { return oldValue; } }
public boolean isEmpty() { if (fileTable != null) { try { synchronized (this) { return fileTable.keys().next() == null; } } catch (IOException e) { Debug.logError(e, module); return false; } } else { return memoryTable.isEmpty(); } }
/** * Returns the number of elements currently in the cache * * @return The number of elements currently in the cache */ public int size() { if (fileTable != null) { int size = 0; try { synchronized (this) { FastIterator<Object> iter = fileTable.keys(); while (iter.next() != null) { size++; } } } catch (IOException e) { Debug.logError(e, module); } return size; } else { return memoryTable.size(); } }
protected synchronized void removeInternal(Object key, CacheLine<V> existingCacheLine) { Object nulledKey = fromKey(key); cancel(existingCacheLine); if (!memoryTable.remove(nulledKey, existingCacheLine)) { return; } if (fileTable != null) { try { synchronized (this) { fileTable.remove(nulledKey); jdbmMgr.commit(); } } catch (IOException e) { Debug.logError(e, module); } } noteRemoval(UtilGenerics.<K>cast(key), existingCacheLine.getValue()); }
/** This is used for internal remove calls because we only want to count external calls */ @SuppressWarnings("unchecked") protected synchronized V removeInternal(Object key, boolean countRemove) { if (key == null) { if (Debug.verboseOn()) Debug.logVerbose( "In UtilCache tried to remove with null key, using NullObject" + this.name, module); } Object nulledKey = fromKey(key); CacheLine<V> oldCacheLine; V oldValue; if (fileTable != null) { try { synchronized (this) { try { oldValue = fileTable.get(nulledKey); } catch (IOException e) { oldValue = null; throw e; } fileTable.remove(nulledKey); jdbmMgr.commit(); } } catch (IOException e) { oldValue = null; Debug.logError(e, module); } oldCacheLine = memoryTable.remove(nulledKey); } else { oldCacheLine = memoryTable.remove(nulledKey); oldValue = oldCacheLine != null ? oldCacheLine.getValue() : null; } if (oldCacheLine != null) { cancel(oldCacheLine); } if (oldValue != null) { noteRemoval((K) key, oldValue); if (countRemove) removeHitCount.incrementAndGet(); return oldValue; } else { if (countRemove) removeMissCount.incrementAndGet(); return null; } }
public Collection<? extends Map<String, Object>> getLineInfos() { List<Map<String, Object>> lineInfos = FastList.newInstance(); int keyIndex = 0; for (K key : getCacheLineKeys()) { Object nulledKey = fromKey(key); if (fileTable != null) { try { synchronized (this) { lineInfos.add(createLineInfo(keyIndex, key, fileTable.get(nulledKey))); } } catch (IOException e) { Debug.logError(e, module); } } else { CacheLine<V> line = memoryTable.get(nulledKey); if (line != null) { lineInfos.add(createLineInfo(keyIndex, key, line)); } } keyIndex++; } return lineInfos; }
public long getSizeInBytes() { long totalSize = 0; if (fileTable != null) { try { synchronized (this) { FastIterator<V> iter = fileTable.values(); V value = iter.next(); while (value != null) { totalSize += findSizeInBytes(value); value = iter.next(); } } } catch (IOException e) { Debug.logError(e, module); return 0; } } else { for (CacheLine<V> line : memoryTable.values()) { totalSize += findSizeInBytes(line.getValue()); } } return totalSize; }
/** * Returns a boolean specifying whether or not an element with the specified key is in the cache. * * @param key The key for the element, used to reference it in the hastables and LRU linked list * @return True is the cache contains an element corresponding to the specified key, otherwise * false */ public boolean containsKey(Object key) { Object nulledKey = fromKey(key); CacheLine<V> line = memoryTable.get(nulledKey); if (line == null) { if (fileTable != null) { try { synchronized (this) { FastIterator<Object> iter = fileTable.keys(); Object checkKey = null; while ((checkKey = iter.next()) != null) { if (nulledKey.equals(checkKey)) { return true; } } } } catch (IOException e) { Debug.logError(e, module); } } return false; } else { return true; } }
public Collection<V> values() { if (fileTable != null) { List<V> values = FastList.newInstance(); try { synchronized (this) { FastIterator<V> iter = fileTable.values(); V value = iter.next(); while (value != null) { values.add(value); value = iter.next(); } } } catch (IOException e) { Debug.logError(e, module); } return values; } else { List<V> valuesList = FastList.newInstance(); for (CacheLine<V> line : memoryTable.values()) { valuesList.add(line.getValue()); } return valuesList; } }
/** * Constructor which specifies the cacheName as well as the sizeLimit, expireTime and * useSoftReference. The passed sizeLimit, expireTime and useSoftReference will be overridden by * values from cache.properties if found. * * @param sizeLimit The sizeLimit member is set to this value * @param expireTime The expireTime member is set to this value * @param cacheName The name of the cache. * @param useSoftReference Specifies whether or not to use soft references for this cache. */ private UtilCache( String cacheName, int sizeLimit, int maxInMemory, long expireTimeMillis, boolean useSoftReference, boolean useFileSystemStore, String propName, String... propNames) { this.name = cacheName; this.sizeLimit = sizeLimit; this.maxInMemory = maxInMemory; this.expireTimeNanos = TimeUnit.NANOSECONDS.convert(expireTimeMillis, TimeUnit.MILLISECONDS); this.useSoftReference = useSoftReference; this.useFileSystemStore = useFileSystemStore; setPropertiesParams(propName); setPropertiesParams(propNames); int maxMemSize = this.maxInMemory; if (maxMemSize == 0) maxMemSize = sizeLimit; if (maxMemSize == 0) { memoryTable = new ConcurrentHashMap<Object, CacheLine<V>>(); } else { memoryTable = new Builder<Object, CacheLine<V>>() .maximumWeightedCapacity(maxMemSize) .listener(this) .build(); } if (this.useFileSystemStore) { // create the manager the first time it is needed jdbmMgr = fileManagers.get(fileStore); if (jdbmMgr == null) { Debug.logImportant( "Creating file system cache store for cache with name: " + cacheName, module); try { String hazeHome = System.getProperty("haze.home"); if (hazeHome == null) { Debug.logError("No haze.home property set in environment", module); } else { jdbmMgr = new JdbmRecordManager(hazeHome + "/" + fileStore); } } catch (IOException e) { Debug.logError( e, "Error creating file system cache store for cache with name: " + cacheName, module); } fileManagers.putIfAbsent(fileStore, jdbmMgr); } jdbmMgr = fileManagers.get(fileStore); if (jdbmMgr != null) { try { this.fileTable = HTree.createInstance(jdbmMgr); jdbmMgr.setNamedObject(cacheName, this.fileTable.getRecid()); jdbmMgr.commit(); } catch (IOException e) { Debug.logError(e, module); } } } }