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());
+ }
+}