
com.bigdata.util.concurrent.CanonicalFactory Maven / Gradle / Ivy
Show all versions of bigdata-core Show documentation
/*
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.util.concurrent;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.Map;
import com.bigdata.cache.ConcurrentWeakValueCache;
/**
* A pattern for a canonicalizing factory based on a map with weak values.
*
* @param
* @param
* @param
*
* @author thompsonbry
*/
abstract public class CanonicalFactory {
/**
* Canonicalizing mapping.
*/
// private WeakValueCache cache;
private ConcurrentWeakValueCache cache;
/**
*
* @param queueCapacity
* The capacity of the backing hard reference queue. This places
* a lower bound on the #of instances which will be retained by
* the factory.
*/
public CanonicalFactory(final int queueCapacity) {
// cache = new WeakValueCache(new LRUCache(queueCapacity));
cache = new ConcurrentWeakValueCache(queueCapacity);
}
/**
* Canonical factory pattern.
*
* @param key
* The key.
* @param state
* Additional state from the caller which will be passed through
* to {@link #newInstance(Object, Object)} when creating a new
* instance (optional).
*
* @return The instance paired with that key.
*
* @throws IllegalArgumentException
* if the key is null
.
*/
public VAL getInstance(final KEY key, final STATE state) {
if (key == null)
throw new IllegalArgumentException();
// check first w/o lock.
VAL val = cache.get(key);
if (val != null) {
/*
* Fast code path if entry exists for that key. This amortizes the
* lock costs by relying on the striped locks of the CHM to provide
* less lock contention.
*/
return val;
}
// obtain lock
synchronized (cache) {
// check with lock held
val = cache.get(key);
if (val == null) {
// create an instance
val = newInstance(key,state);
// pair that instance with the key in the map.
// cache.put(key, val, true/* dirty */);
cache.put(key, val);
}
return val;
}
}
/**
* Remove an entry from the cache.
*
* Note: It is sometimes necessary to clear a cache entry. For example, if a
* persistent resource is destroyed it may be necessary to discard the cache
* entry to avoid inappropriate carry over via the cache if the resource is
* then recreated.
*
* @param key
* The key for the entry.
*
* @throws IllegalArgumentException
* if the key is null
.
*/
public void remove(KEY key) {
if (key == null)
throw new IllegalArgumentException();
cache.remove(key);
}
/**
* Create an instance which will be associated with the key in the
* {@link CanonicalFactory}.
*
* @param key
* The key.
* @param state
* Additional state used to initialize the new instance
* (optional).
*
* @return The new instance to be paired with that key.
*/
abstract protected VAL newInstance(KEY key,STATE state);
/**
* Clear all entries from the cache.
*/
public void clear() {
cache.clear();
}
/**
* An iterator that visits the entries in the map. You must test the weak
* reference for each entry in order to determine whether its value has been
* cleared as of the moment that you request that value. The entries visited
* by the iterator are not "touched" so the use of the iterator will not
* cause them to be retained any longer than they otherwise would have been
* retained.
*/
public Iterator>> entryIterator() {
return cache.entryIterator();
}
}