diff --git a/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndex.java b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndex.java new file mode 100644 index 000000000..1ab521e3a --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndex.java @@ -0,0 +1,21 @@ +package com.googlecode.cqengine.pk; + +import com.googlecode.cqengine.attribute.Attribute; +import com.googlecode.cqengine.index.support.Factory; +import com.googlecode.cqengine.index.unique.UniqueIndex; + +import java.util.concurrent.ConcurrentMap; + +/** + * An index that reuses map supplied in constructor + */ +public class PrimaryKeyIndex extends UniqueIndex { + public PrimaryKeyIndex(final ConcurrentMap indexMap, Attribute attribute) { + super(new Factory>() { + @Override + public ConcurrentMap create() { + return indexMap; + } + }, attribute); + } +} diff --git a/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndexedCollection.java b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndexedCollection.java new file mode 100644 index 000000000..c94837e8f --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyIndexedCollection.java @@ -0,0 +1,39 @@ +package com.googlecode.cqengine.pk; + +import com.googlecode.cqengine.ConcurrentIndexedCollection; +import com.googlecode.cqengine.attribute.SimpleAttribute; +import com.googlecode.cqengine.index.unique.UniqueIndex; + +import java.util.concurrent.ConcurrentMap; + +/** + * Indexed collection backed by primary key to object map + */ +public class PrimaryKeyIndexedCollection> extends ConcurrentIndexedCollection { + + private ConcurrentMap pkMap; + private SimpleAttribute primaryKeyAttribute; + + public PrimaryKeyIndexedCollection(SimpleAttribute attribute) { + this(new PrimaryKeyOnHeapPersistence(attribute)); + } + + public PrimaryKeyIndexedCollection(PrimaryKeyOnHeapPersistence persistence) { + super(persistence); + pkMap = ((PrimaryKeyOnHeapObjectStore) objectStore).getPkMap(); + primaryKeyAttribute = persistence.getPrimaryKeyAttribute(); + UniqueIndex pkIndex = new PrimaryKeyIndex(pkMap, primaryKeyAttribute); + addIndex(pkIndex); + } + + /** + * Fast access to entry by Key + * + * @param key + * @return + */ + public O get(A key) { + return pkMap.get(key); + } + +} diff --git a/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapObjectStore.java b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapObjectStore.java new file mode 100644 index 000000000..c5b46cbdc --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapObjectStore.java @@ -0,0 +1,131 @@ +package com.googlecode.cqengine.pk; + +import com.googlecode.cqengine.attribute.SimpleAttribute; +import com.googlecode.cqengine.persistence.support.CollectionWrappingObjectStore; + +import java.io.IOException; +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * ObjectStore backed by index + */ +public class PrimaryKeyOnHeapObjectStore> extends CollectionWrappingObjectStore { + private final ConcurrentMap pkMap; + + public PrimaryKeyOnHeapObjectStore(SimpleAttribute pkAttr) { + super(new SetFromMap(new ConcurrentHashMap(), pkAttr)); + pkMap = ((SetFromMap) getBackingCollection()).getMap(); + } + + public PrimaryKeyOnHeapObjectStore(int initialCapacity, float loadFactor, int concurrencyLevel, SimpleAttribute pkAttr) { + super(new SetFromMap(new ConcurrentHashMap(initialCapacity, loadFactor, concurrencyLevel), pkAttr)); + pkMap = ((SetFromMap) getBackingCollection()).getMap(); + } + + public ConcurrentMap getPkMap() { + return pkMap; + } + + private static class SetFromMap> extends AbstractSet + implements Set, Serializable { + // The backing map + private final ConcurrentMap map; + // Its values view + private transient Collection values; + // Attribute to read a key + private final SimpleAttribute attr; + + SetFromMap(ConcurrentMap map, SimpleAttribute attr) { + if (!map.isEmpty()) + throw new IllegalArgumentException("Map must be empty"); + this.map = map; + // ValuesView in ConcurrentHashMap is unique and final! + // store the reference for faster access + values = map.values(); + this.attr = attr; + } + + public void clear() { + map.clear(); + } + + public int size() { + return map.size(); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public boolean contains(Object o) { + return map.containsKey(attr.getValue((O)o, null)); + } + + public boolean remove(Object o) { + return map.remove(attr.getValue((O)o, null)) != null; + } + + public boolean add(O o) { + return map.put(attr.getValue((O)o, null), o) == null; + } + + public Iterator iterator() { + return values.iterator(); + } + + public Object[] toArray() { + return values.toArray(); + } + + public T[] toArray(T[] a) { + return values.toArray(a); + } + + public String toString() { + return values.toString(); + } + + public int hashCode() { + return map.keySet().hashCode(); + } + + public boolean equals(Object o) { + return o == this; + } + + public boolean containsAll(Collection c) { + for (Object o : c) { + A value = attr.getValue((O) o, null); + if(map.get(value) == null) return false; + } + return true; + } + + public boolean removeAll(Collection c) { + boolean changed = false; + for (Object o : c) { + A value = attr.getValue((O) o, null); + if(map.remove(value) != null) changed = true; + } + return changed; + } + + // retainAll and addAll is are inherited implementation + + ConcurrentMap getMap(){ + return map; + } + + private static final long serialVersionUID = 2454657854757543879L; + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + values = map.values(); + } + + } +} diff --git a/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapPersistence.java b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapPersistence.java new file mode 100644 index 000000000..d6fe928d9 --- /dev/null +++ b/code/src/main/java/com/googlecode/cqengine/pk/PrimaryKeyOnHeapPersistence.java @@ -0,0 +1,35 @@ +package com.googlecode.cqengine.pk; + +import com.googlecode.cqengine.attribute.SimpleAttribute; +import com.googlecode.cqengine.persistence.onheap.OnHeapPersistence; +import com.googlecode.cqengine.persistence.support.ObjectStore; + +/** + * ObjectStore with direct access to pk map + */ +public class PrimaryKeyOnHeapPersistence> extends OnHeapPersistence { + + private final int initialCapacity; + private final float loadFactor; + private final int concurrencyLevel; + + public PrimaryKeyOnHeapPersistence() { + this(null, 16, 0.75F, 16); + } + + public PrimaryKeyOnHeapPersistence(SimpleAttribute primaryKeyAttribute) { + this(primaryKeyAttribute, 16, 0.75F, 16); + } + + public PrimaryKeyOnHeapPersistence(SimpleAttribute primaryKeyAttribute, int initialCapacity, float loadFactor, int concurrencyLevel) { + super(primaryKeyAttribute, initialCapacity, loadFactor, concurrencyLevel); + this.initialCapacity = initialCapacity; + this.loadFactor = loadFactor; + this.concurrencyLevel = concurrencyLevel; + } + + @Override + public ObjectStore createObjectStore() { + return new PrimaryKeyOnHeapObjectStore(initialCapacity, loadFactor, concurrencyLevel, getPrimaryKeyAttribute()); + } +}