Skip to content

Commit

Permalink
GH-3572 allow concurrent reads and writes against the WeakObjectRegistry
Browse files Browse the repository at this point in the history
Signed-off-by: Håvard Ottestad <hmottestad@gmail.com>
  • Loading branch information
hmottestad committed Jan 5, 2022
1 parent 986fe34 commit f3deb06
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public MemResource getMemResource(Resource resource) {
/**
* See getMemValue() for description.
*/
public synchronized MemIRI getMemURI(IRI uri) {
public MemIRI getMemURI(IRI uri) {
if (isOwnMemValue(uri)) {
return (MemIRI) uri;
} else {
Expand All @@ -129,7 +129,7 @@ public synchronized MemIRI getMemURI(IRI uri) {
/**
* See getMemValue() for description.
*/
public synchronized MemBNode getMemBNode(BNode bnode) {
public MemBNode getMemBNode(BNode bnode) {
if (isOwnMemValue(bnode)) {
return (MemBNode) bnode;
} else {
Expand All @@ -140,7 +140,7 @@ public synchronized MemBNode getMemBNode(BNode bnode) {
/**
* See getMemValue() for description.
*/
public synchronized MemLiteral getMemLiteral(Literal literal) {
public MemLiteral getMemLiteral(Literal literal) {
if (isOwnMemValue(literal)) {
return (MemLiteral) literal;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

import java.lang.ref.WeakReference;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.locks.StampedLock;

/**
* An object registry that uses weak references to keep track of the stored objects. The registry can be used to
Expand All @@ -29,7 +31,8 @@ public class WeakObjectRegistry<E> extends AbstractSet<E> {
/**
* The hash map that is used to store the objects.
*/
private final Map<E, WeakReference<E>> objectMap = new WeakHashMap<>();
private final Map<E, WeakReference<E>>[] objectMap;
private final StampedLock[] locks;

/*--------------*
* Constructors *
Expand All @@ -40,6 +43,17 @@ public class WeakObjectRegistry<E> extends AbstractSet<E> {
*/
public WeakObjectRegistry() {
super();
int concurrency = Runtime.getRuntime().availableProcessors() * 2;

objectMap = new WeakHashMap[concurrency];
for (int i = 0; i < objectMap.length; i++) {
objectMap[i] = new WeakHashMap<>();
}

locks = new StampedLock[objectMap.length];
for (int i = 0; i < locks.length; i++) {
locks[i] = new StampedLock();
}
}

/**
Expand All @@ -64,54 +78,131 @@ public WeakObjectRegistry(Collection<? extends E> c) {
* @return A stored object that is equal to the supplied key, or <var>null</var> if no such object was found.
*/
public E get(Object key) {
WeakReference<E> weakRef = objectMap.get(key);
if (key == null) {
return null;
}

if (weakRef != null) {
return weakRef.get();
int index = getIndex(key);
long readLock = locks[index].readLock();
try {
Map<E, WeakReference<E>> weakReferenceMap = objectMap[index];

WeakReference<E> weakRef = weakReferenceMap.get(key);
if (weakRef != null) {
return weakRef.get();
} else {
return null;
}

} finally {
locks[index].unlockRead(readLock);
}

return null;
}

private int getIndex(Object key) {
int i = Math.abs(key.hashCode());
return i % objectMap.length;
}

@Override
public Iterator<E> iterator() {
return objectMap.keySet().iterator();
return new Iterator<>() {

final Iterator<Map<E, WeakReference<E>>> iterator = Arrays.asList(objectMap).iterator();
Iterator<E> currentIterator = iterator.next().keySet().iterator();

@Override
public boolean hasNext() {
if (currentIterator == null) {
return false;
}
while (currentIterator != null) {
if (currentIterator.hasNext()) {
return true;
} else {
currentIterator = null;
if (iterator.hasNext()) {
currentIterator = iterator.next().keySet().iterator();
}
}
}

return false;
}

@Override
public E next() {
return currentIterator.next();
}
};

}

@Override
public int size() {
return objectMap.size();
int size = 0;
for (Map<E, WeakReference<E>> weakReferenceMap : objectMap) {
size += weakReferenceMap.size();
}
return size;
}

@Override
public boolean contains(Object o) {
return get(o) != null;
public boolean contains(Object key) {
return get(key) != null;
}

@Override
public boolean add(E object) {
WeakReference<E> ref = new WeakReference<>(object);
int index = getIndex(object);
long writeLock = locks[index].writeLock();
try {
Map<E, WeakReference<E>> weakReferenceMap = objectMap[index];
WeakReference<E> ref = new WeakReference<>(object);

ref = weakReferenceMap.put(object, ref);

if (ref != null && ref.get() != null) {
// A duplicate was added which replaced the existing object. Undo this
// operation.
weakReferenceMap.put(ref.get(), ref);
return false;
}

ref = objectMap.put(object, ref);
return true;

if (ref != null && ref.get() != null) {
// A duplicate was added which replaced the existing object. Undo this
// operation.
objectMap.put(ref.get(), ref);
return false;
} finally {
locks[index].unlockWrite(writeLock);
}

return true;
}

@Override
public boolean remove(Object o) {
WeakReference<E> ref = objectMap.remove(o);
return ref != null && ref.get() != null;
public boolean remove(Object object) {
int index = getIndex(object);
long writeLock = locks[index].writeLock();
try {
Map<E, WeakReference<E>> weakReferenceMap = objectMap[index];
WeakReference<E> ref = weakReferenceMap.remove(object);
return ref != null && ref.get() != null;

} finally {
locks[index].unlockWrite(writeLock);
}
}

@Override
public void clear() {
objectMap.clear();

for (int i = 0; i < objectMap.length; i++) {
long writeLock = locks[i].writeLock();
try {
objectMap[i].clear();
} finally {
locks[i].unlockWrite(writeLock);
}
}

}
}

0 comments on commit f3deb06

Please sign in to comment.