From c6f2f71f6c9d375c597efef0cdd0879eedc228d7 Mon Sep 17 00:00:00 2001 From: Speiger Date: Wed, 13 Apr 2022 02:00:52 +0200 Subject: [PATCH] Switching to a new lock to make read operations actually concurrent. --- .../concurrent/ConcurrentOpenHashMap.template | 712 ++++++++++++------ 1 file changed, 484 insertions(+), 228 deletions(-) diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template index ec69e61..2d85655 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template @@ -4,7 +4,7 @@ import java.util.Arrays; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.StampedLock; import java.util.function.Consumer; import java.util.function.BiFunction; @@ -78,6 +78,8 @@ import speiger.src.collections.utils.HashUtil; * A TypeSpecific ConcurrentHashMap implementation that is based on Guavas approach and backing array implementations. * Like Guavas implementation this solution can be accessed by multiple threads, but it is not as flexible as Javas implementation. * The concurrencyLevel decides how many pools exist, and each pool can be accessed by 1 thread for writing and as many threads for reading. + * Though it is ill adviced to iterate over the collection using the Iterator if the Map is written to. Keep that in mind. + * * * @Type(T) * @ValueType(V) @@ -607,10 +609,16 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY public void forEach(Consumer action) { for(int i = 0,m=segments.length;i= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), seg.values[index]); + long stamp = seg.readLock(); + try { + int index = seg.findIndex(hash, key); + if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), seg.values[index]); + } + finally { + seg.unlockRead(stamp); + } } else { Map.Entry entry = (Map.Entry)o; int hash = getHashCode(entry.getKey()); Segment KEY_VALUE_GENERIC_TYPE seg = getSegment(hash); - int index = seg.findIndex(hash, entry.getKey()); - if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(seg.values[index])); + long stamp = seg.readLock(); + try { + int index = seg.findIndex(hash, entry.getKey()); + if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(seg.values[index])); + } + finally { + seg.unlockRead(stamp); + } } } return false; @@ -865,10 +938,16 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY Objects.requireNonNull(action); for(int i = 0,m=segments.length;i= 0; + long stamp = readLock(); + try { + return findIndex(hash, key) >= 0; + } + finally { + unlockRead(stamp); + } } #endif @Deprecated protected boolean containsKey(int hash, Object key) { - return findIndex(hash, key) >= 0; + long stamp = readLock(); + try { + return findIndex(hash, key) >= 0; + } + finally { + unlockRead(stamp); + } } #if !VALUE_OBJECT protected boolean containsValue(VALUE_TYPE value) { - int index = firstIndex; - while(index != -1) { - if(VALUE_EQUALS(values[index], value)) return true; - index = (int)links[index]; + long stamp = readLock(); + try { + int index = firstIndex; + while(index != -1) { + if(VALUE_EQUALS(values[index], value)) return true; + index = (int)links[index]; + } + return false; + } + finally { + unlockRead(stamp); } - return false; } #endif @Deprecated protected boolean containsValue(Object value) { - int index = firstIndex; - while(index != -1) { + long stamp = readLock(); + try { + int index = firstIndex; + while(index != -1) { #if VALUE_OBJECT - if(VALUE_EQUALS(values[index], value)) return true; + if(VALUE_EQUALS(values[index], value)) return true; #else - if((value == null && values[index] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[index], value)) return true; + if((value == null && values[index] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[index], value)) return true; #endif - index = (int)links[index]; + index = (int)links[index]; + } + return false; + } + finally { + unlockRead(stamp); } - return false; } #if !TYPE_OBJECT protected VALUE_TYPE get(int hash, KEY_TYPE key) { - int slot = findIndex(hash, key); - return slot < 0 ? getDefaultReturnValue() : values[slot]; + long stamp = readLock(); + try { + int slot = findIndex(hash, key); + return slot < 0 ? getDefaultReturnValue() : values[slot]; + } + finally { + unlockRead(stamp); + } } #endif protected VALUE_TYPE get(int hash, Object key) { - int slot = findIndex(hash, key); - return slot < 0 ? getDefaultReturnValue() : values[slot]; + long stamp = readLock(); + try { + int slot = findIndex(hash, key); + return slot < 0 ? getDefaultReturnValue() : values[slot]; + } + finally { + unlockRead(stamp); + } } #if TYPE_OBJECT && VALUE_OBJECT protected VALUE_TYPE getOrDefault(int hash, Object key, VALUE_TYPE defaultValue) { - int slot = findIndex(hash, key); - return slot < 0 ? defaultValue : values[slot]; + long stamp = readLock(); + try { + int slot = findIndex(hash, key); + return slot < 0 ? defaultValue : values[slot]; + } + finally { + unlockRead(stamp); + } } #else protected VALUE_TYPE getOrDefault(int hash, KEY_TYPE key, VALUE_TYPE defaultValue) { - int slot = findIndex(hash, key); - return slot < 0 ? defaultValue : values[slot]; + long stamp = readLock(); + try { + int slot = findIndex(hash, key); + return slot < 0 ? defaultValue : values[slot]; + } + finally { + unlockRead(stamp); + } } #endif protected void forEach(BI_CONSUMER KEY_VALUE_GENERIC_TYPE action) { - int index = firstIndex; - while(index != -1) { - action.accept(keys[index], values[index]); - index = (int)links[index]; + long stamp = readLock(); + try { + int index = firstIndex; + while(index != -1) { + action.accept(keys[index], values[index]); + index = (int)links[index]; + } + } + finally { + unlockRead(stamp); } } #if !TYPE_OBJECT protected VALUE_TYPE remove(int hash, KEY_TYPE key) { - lock(); + long stamp = writeLock(); try { int slot = findIndex(hash, key); if(slot < 0) return getDefaultReturnValue(); return removeIndex(slot); } finally { - unlock(); + unlockWrite(stamp); } } #endif protected VALUE_TYPE removeOrDefault(int hash, KEY_TYPE key, VALUE_TYPE defaultValue) { - lock(); + long stamp = writeLock(); try { int slot = findIndex(hash, key); if(slot < 0) return defaultValue; return removeIndex(slot); } finally { - unlock(); + unlockWrite(stamp); } } protected CLASS_VALUE_TYPE remove(int hash, Object key) { - lock(); + long stamp = writeLock(); try { int slot = findIndex(hash, key); if(slot < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); return VALUE_TO_OBJ(removeIndex(slot)); } finally { - unlock(); + unlockWrite(stamp); } } #if !TYPE_OBJECT || !VALUE_OBJECT protected boolean remove(int hash, KEY_TYPE key, VALUE_TYPE value) { - lock(); + long stamp = writeLock(); try { if(KEY_EQUALS_NULL(key)) { if(containsNull && VALUE_EQUALS(value, values[nullIndex])) { @@ -1767,37 +2016,44 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY } } finally { - unlock(); + unlockWrite(stamp); } } #endif protected boolean remove(int hash, Object key, Object value) { - if(key == null) { - if(containsNull && EQUALS_VALUE_TYPE(values[nullIndex], value)) { - removeNullIndex(); - return true; + long stamp = writeLock(); + try + { + if(key == null) { + if(containsNull && EQUALS_VALUE_TYPE(values[nullIndex], value)) { + removeNullIndex(); + return true; + } + return false; } - return false; - } - int pos = hash & mask; - KEY_TYPE current = keys[pos]; - if(KEY_EQUALS_NULL(current)) return false; - if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)) { - removeIndex(pos); - return true; - } - while(true) { - if(KEY_EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; - else if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)){ + int pos = hash & mask; + KEY_TYPE current = keys[pos]; + if(KEY_EQUALS_NULL(current)) return false; + if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)) { removeIndex(pos); return true; } + while(true) { + if(KEY_EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; + else if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)){ + removeIndex(pos); + return true; + } + } + } + finally { + unlockWrite(stamp); } } protected boolean replace(int hash, KEY_TYPE key, VALUE_TYPE oldValue, VALUE_TYPE newValue) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0 || values[index] != oldValue) return false; @@ -1805,12 +2061,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return true; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE replace(int hash, KEY_TYPE key, VALUE_TYPE value) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0) return getDefaultReturnValue(); @@ -1819,12 +2075,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return oldValue; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE compute(int hash, KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0) { @@ -1842,12 +2098,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return newValue; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE computeIfAbsent(int hash, KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0) { @@ -1865,12 +2121,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return newValue; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE supplyIfAbsent(int hash, KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0) { @@ -1888,12 +2144,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return newValue; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE computeIfPresent(int hash, KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); if(index < 0 || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue(); @@ -1906,12 +2162,12 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return newValue; } finally { - unlock(); + unlockWrite(stamp); } } protected VALUE_TYPE merge(int hash, KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { - lock(); + long stamp = writeLock(); try { int index = findIndex(hash, key); VALUE_TYPE newValue = index < 0 || VALUE_EQUALS(values[index], getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(values[index], value); @@ -1924,13 +2180,13 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return newValue; } finally { - unlock(); + unlockWrite(stamp); } } protected void clear() { if(size == 0) return; - lock(); + long stamp = writeLock(); try { size = 0; containsNull = false; @@ -1940,14 +2196,14 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY lastIndex = -1; } finally { - unlock(); + unlockWrite(stamp); } } protected boolean trim(int size) { int request = Math.max(minCapacity, HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor))); if(request >= size || this.size > Math.min((int)Math.ceil(request * loadFactor), request - 1)) return false; - lock(); + long stamp = writeLock(); try { try { rehash(request); @@ -1956,7 +2212,7 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY return true; } finally { - unlock(); + unlockWrite(stamp); } } @@ -1966,7 +2222,7 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY clear(); return; } - lock(); + long stamp = writeLock(); try { if(nullIndex != -1) { nullIndex = request; @@ -1983,7 +2239,7 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY containsNull = false; } finally { - unlock(); + unlockWrite(stamp); } }