HCOLL-155 uncompleted, checked in order that Peter can review the changes so far of - chm.acquireUsingReadLocked and chm.acquireUsingWriteLocked

This commit is contained in:
Rob Austin
2014-11-01 15:53:47 +00:00
parent 73f0778559
commit 100d839a8b
11 changed files with 495 additions and 107 deletions
@@ -843,7 +843,7 @@ public abstract class AbstractChronicleMapBuilder<K, V,
statelessBuilder,
entrySize(),
kClass,
vClass);
vClass, putReturnsNull,removeReturnsNull);
}
private VanillaChronicleMap<K, ?, ?, V, ?, ?> newMap() throws IOException {
@@ -23,6 +23,7 @@ import net.openhft.chronicle.hash.serialization.BytesReader;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshaller;
import net.openhft.lang.model.Byteable;
import org.jetbrains.annotations.NotNull;
import java.io.Closeable;
import java.util.Map;
@@ -100,7 +101,7 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
* @see #acquireUsing(Object, Object)
* @see ChronicleMapBuilder#valueMarshaller(BytesMarshaller)
*/
V getUsing(K key, V usingValue);
V getUsing(K key, V usingValue);
/**
* Acquire a value for a key, creating if absent.
@@ -137,6 +138,13 @@ public interface ChronicleMap<K, V> extends ConcurrentMap<K, V>, ChronicleHash {
* @return value to which the given key is mapping after this call, either found or created
* @see #getUsing(Object, Object)
*/
V acquireUsing(K key, V usingValue);
public V acquireUsing(K key, V usingValue) ;
// todo document
SegmentLock acquireUsingReadLocked(@NotNull K key, @NotNull V usingValue);
// todo document
SegmentLock acquireUsingWriteLocked(@NotNull K key, @NotNull V usingValue);
}
@@ -0,0 +1,13 @@
package net.openhft.chronicle.map;
/**
* @author Rob Austin.
*/
public interface SegmentLock extends AutoCloseable {
/**
* call this to unlock the segment
*/
void close();
}
@@ -28,9 +28,9 @@ import java.util.Map;
*/
interface SharedSegment<K, V> {
void readLock();
AutoCloseable readLock();
void writeLock();
AutoCloseable writeLock();
Map.Entry<K, V> getEntry(long pos);
@@ -65,6 +65,8 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
private int maxEntrySize;
private final Class<K> kClass;
private final Class<V> vClass;
private final boolean putReturnsNull;
private final boolean removeReturnsNull;
static enum EventId {
@@ -74,8 +76,11 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
IS_EMPTY,
CONTAINS_KEY,
CONTAINS_VALUE,
GET, PUT,
GET,
PUT,
PUT_WITHOUT_ACC,
REMOVE,
REMOVE_WITHOUT_ACC,
CLEAR,
KEY_SET,
VALUES,
@@ -86,6 +91,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
REMOVE_WITH_VALUE,
TO_STRING,
PUT_ALL,
PUT_ALL_WITHOUT_ACC,
HASH_CODE
}
@@ -93,12 +99,16 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
StatelessChronicleMap(final KeyValueSerializer<K, V> keyValueSerializer,
final StatelessBuilder builder,
int maxEntrySize, Class<K> kClass, Class<V> vClass) throws IOException {
int maxEntrySize, Class<K> kClass, Class<V> vClass,
boolean putReturnsNull,
boolean removeReturnsNull) throws IOException {
this.keyValueSerializer = keyValueSerializer;
this.builder = builder;
this.maxEntrySize = maxEntrySize;
this.kClass = kClass;
this.vClass = vClass;
this.putReturnsNull = putReturnsNull;
this.removeReturnsNull = removeReturnsNull;
attemptConnect(builder.remoteAddress());
buffer = allocateDirect(maxEntrySize).order(ByteOrder.nativeOrder());
@@ -242,7 +252,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
public synchronized V putIfAbsent(K key, V value) {
final long sizeLocation = writeEvent(PUT_IF_ABSENT);
final long sizeLocation = writeEventAnSkip(PUT_IF_ABSENT);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey(key, local);
writeValue(value, local);
@@ -255,7 +265,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
if (key == null)
throw new NullPointerException("key can not be null");
final long sizeLocation = writeEvent(REMOVE_WITH_VALUE);
final long sizeLocation = writeEventAnSkip(REMOVE_WITH_VALUE);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey((K) key, local);
writeValue((V) value, local);
@@ -269,7 +279,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
if (key == null)
throw new NullPointerException("key can not be null");
final long sizeLocation = writeEvent(REPLACE_WITH_OLD_AND_NEW_VALUE);
final long sizeLocation = writeEventAnSkip(REPLACE_WITH_OLD_AND_NEW_VALUE);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey(key, local);
writeValue(oldValue, local);
@@ -284,7 +294,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
if (key == null)
throw new NullPointerException("key can not be null");
final long sizeLocation = writeEvent(REPLACE);
final long sizeLocation = writeEventAnSkip(REPLACE);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey(key, local);
writeValue(value, local);
@@ -329,31 +339,23 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
}
public synchronized void putAll(Map<? extends K, ? extends V> map) {
final long sizeLocation = writeEvent(PUT_ALL);
writeEntries(map);
blockingFetch(sizeLocation);
}
@Override
public synchronized int hashCode() {
return blockingFetch(writeEvent(HASH_CODE)).readInt();
return blockingFetch(writeEventAnSkip(HASH_CODE)).readInt();
}
public synchronized String toString() {
return blockingFetch(writeEvent(TO_STRING)).readObject(String.class);
return blockingFetch(writeEventAnSkip(TO_STRING)).readObject(String.class);
}
public synchronized boolean isEmpty() {
return blockingFetch(writeEvent(IS_EMPTY)).readBoolean();
return blockingFetch(writeEventAnSkip(IS_EMPTY)).readBoolean();
}
public synchronized boolean containsKey(Object key) {
final long sizeLocation = writeEvent(CONTAINS_KEY);
final long sizeLocation = writeEventAnSkip(CONTAINS_KEY);
writeKey((K) key);
// get the data back from the server
@@ -363,7 +365,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
public synchronized boolean containsValue(Object value) {
final long sizeLocation = writeEvent(CONTAINS_VALUE);
final long sizeLocation = writeEventAnSkip(CONTAINS_VALUE);
writeValue((V) value);
// get the data back from the server
@@ -372,12 +374,12 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
public synchronized long longSize() {
return blockingFetch(writeEvent(LONG_SIZE)).readLong();
return blockingFetch(writeEventAnSkip(LONG_SIZE)).readLong();
}
public synchronized V get(Object key) {
final long sizeLocation = writeEvent(GET);
final long sizeLocation = writeEventAnSkip(GET);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey((K) key, local);
@@ -387,35 +389,102 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
}
public synchronized V getUsing(K key, V usingValue) {
throw new UnsupportedOperationException("getUsing is not supported for stateless clients");
throw new UnsupportedOperationException("getUsing() is not supported for stateless " +
"clients");
}
public synchronized V acquireUsing(K key, V usingValue) {
throw new UnsupportedOperationException("getUsing is not supported for stateless clients");
throw new UnsupportedOperationException("acquireUsing() is not supported for stateless " +
"clients");
}
public synchronized V put(K key, V value) {
final long sizeLocation = writeEvent(PUT);
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
writeKey(key, local);
writeValue(value, local);
// get the data back from the server
return readKey(sizeLocation, local);
@Override
public SegmentLock acquireUsingReadLocked(K key, V usingValue) {
throw new UnsupportedOperationException();
}
@Override
public SegmentLock acquireUsingWriteLocked(K key, V usingValue) {
throw new UnsupportedOperationException();
}
public synchronized V remove(Object key) {
if (key == null)
throw new NullPointerException("key can not be null");
final long sizeLocation = writeEvent(REMOVE);
final long sizeLocation = (removeReturnsNull) ? writeEvent(REMOVE_WITHOUT_ACC) : writeEventAnSkip(REMOVE);
writeKey((K) key);
// get the data back from the server
return readKey(sizeLocation);
if (removeReturnsNull) {
sendWithoutAcc(bytes, sizeLocation);
return null;
} else
// get the data back from the server
return readKey(sizeLocation);
}
public synchronized V put(K key, V value) {
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
final long sizeLocation = (putReturnsNull) ? writeEvent(PUT_WITHOUT_ACC) : writeEventAnSkip(PUT);
writeKey(key, local);
writeValue(value, local);
if (putReturnsNull) {
sendWithoutAcc(bytes, sizeLocation);
return null;
} else
// get the data back from the server
return readKey(sizeLocation, local);
}
public synchronized void putAll(Map<? extends K, ? extends V> map) {
final long sizeLocation = (putReturnsNull) ? writeEvent(PUT_ALL_WITHOUT_ACC) : writeEventAnSkip(PUT_ALL);
writeEntries(map);
if (putReturnsNull)
sendWithoutAcc(bytes, sizeLocation);
else
blockingFetch(sizeLocation);
}
private void sendWithoutAcc(final Bytes bytes, long sizeLocation) {
writeSizeAt(sizeLocation);
long timeoutTime = builder.timeoutMs() + System.currentTimeMillis();
try {
for (; ; ) {
if (clientChannel == null)
clientChannel = lazyConnect(builder.timeoutMs(), builder.remoteAddress());
try {
send(bytes, timeoutTime);
return;
} catch (java.nio.channels.ClosedChannelException | ClosedConnectionException e) {
checkTimeout(timeoutTime);
clientChannel = lazyConnect(builder.timeoutMs(), builder.remoteAddress());
}
}
} catch (IOException e) {
close();
throw new IORuntimeException(e);
}
}
@@ -534,13 +603,13 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
public synchronized void clear() {
// get the data back from the server
blockingFetch(writeEvent(CLEAR));
blockingFetch(writeEventAnSkip(CLEAR));
}
@NotNull
public synchronized Collection<V> values() {
final long sizeLocation = writeEvent(VALUES);
final long sizeLocation = writeEventAnSkip(VALUES);
final long startTime = System.currentTimeMillis();
final long transactionId = nextUniqueTransaction(startTime);
@@ -575,7 +644,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
@NotNull
public synchronized Set<Map.Entry<K, V>> entrySet() {
final long sizeLocation = writeEvent(ENTRY_SET);
final long sizeLocation = writeEventAnSkip(ENTRY_SET);
final long startTime = System.currentTimeMillis();
final long transactionId = nextUniqueTransaction(startTime);
@@ -623,7 +692,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
@NotNull
public synchronized Set<K> keySet() {
final long sizeLocation = writeEvent(KEY_SET);
final long sizeLocation = writeEventAnSkip(KEY_SET);
final long startTime = System.currentTimeMillis();
final long transactionId = nextUniqueTransaction(startTime);
@@ -656,9 +725,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
return result;
}
private long writeEvent(EventId event) {
buffer.clear();
bytes.clear();
@@ -666,9 +733,28 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
bytes.write((byte) event.ordinal());
long sizeLocation = markSizeLocation();
return sizeLocation;
}
/**
* skips for the transactionid
*
* @param event
* @return
*/
private long writeEventAnSkip(EventId event) {
long sizeLocation = writeEvent(event);
// skips for the transaction id
bytes.skip(SIZE_OF_TRANSACTIONID);
return sizeLocation;
}
class Entry implements Map.Entry<K, V> {
final K key;
@@ -828,7 +914,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
}
private ByteBufferBytes receive(int requiredNumberOfBytes, long timeoutTime) throws IOException {
private Bytes receive(int requiredNumberOfBytes, long timeoutTime) throws IOException {
while (bytes.buffer().position() < requiredNumberOfBytes) {
clientChannel.read(bytes.buffer());
@@ -839,7 +925,7 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
return bytes;
}
private void send(final ByteBufferBytes out, long timeoutTime) throws IOException {
private void send(final Bytes out, long timeoutTime) throws IOException {
buffer.limit((int) out.position());
buffer.position(0);
@@ -869,10 +955,16 @@ class StatelessChronicleMap<K, V> implements ChronicleMap<K, V>, Closeable {
}
private void writeSizeAt(long locationOfSize) {
final long size = bytes.position() - locationOfSize;
bytes.writeInt(locationOfSize, (int) size - SIZE_OF_SIZE);
}
private long markSizeLocation() {
final long position = bytes.position();
bytes.skip(SIZE_OF_SIZE);
bytes.skip(SIZE_OF_TRANSACTIONID);
return position;
}
@@ -1261,6 +1261,16 @@ class StatelessServerConnector<K, V> {
case ENTRY_SET:
return entrySet(reader, writer);
case PUT_WITHOUT_ACC:
return put(reader);
case PUT_ALL_WITHOUT_ACC:
return putAll(reader);
case REMOVE_WITHOUT_ACC:
return remove(reader);
}
final long sizeLocation = reflectTransactionId(reader, writer);
@@ -1484,6 +1494,20 @@ class StatelessServerConnector<K, V> {
}
private Work put(Bytes reader) {
if (MAP_SUPPORTS_BYTES) {
map.put(reader);
} else {
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
final K k = readKey(reader, local);
final V v = readValue(reader, local);
map.put(k, v);
}
return null;
}
private Work put(Bytes reader, Bytes writer, final long sizeLocation) {
if (MAP_SUPPORTS_BYTES) {
map.put(reader, writer);
@@ -1502,6 +1526,19 @@ class StatelessServerConnector<K, V> {
return null;
}
private Work remove(Bytes reader) {
if (MAP_SUPPORTS_BYTES) {
map.removeWithBytes(reader);
} else {
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
final K key = readKey(reader, local);
map.remove(key);
}
return null;
}
private Work remove(Bytes reader, Bytes writer, final long sizeLocation) {
if (MAP_SUPPORTS_BYTES) {
map.remove(reader, writer);
@@ -1540,6 +1577,18 @@ class StatelessServerConnector<K, V> {
return null;
}
private Work putAll(Bytes reader) {
if (MAP_SUPPORTS_BYTES) {
map.putAll(reader);
} else {
final ThreadLocalCopies local = keyValueSerializer.threadLocalCopies();
map.putAll(readEntries(reader, local));
}
return null;
}
private Work clear(Bytes reader, Bytes writer, final long sizeLocation) {
@@ -1788,7 +1837,9 @@ class StatelessServerConnector<K, V> {
final HashMap<K, V> result = new HashMap<K, V>();
for (long i = 0; i < numberOfEntries; i++) {
result.put(readKey(reader, local), readValue(reader, local));
K key = readKey(reader, local);
V value = readValue(reader, local);
result.put(key, value);
}
return result;
}
@@ -29,6 +29,8 @@ import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
import net.openhft.lang.threadlocal.Provider;
import net.openhft.lang.threadlocal.ThreadLocalCopies;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
@@ -48,6 +50,10 @@ import static net.openhft.lang.MemoryUnit.*;
class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
V, VW, MVW extends MetaBytesWriter<V, VW>> extends AbstractMap<K, V>
implements ChronicleMap<K, V>, Serializable {
private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class);
/**
* Because DirectBitSet implementations couldn't find more than 64 continuous clear or set
* bits.
@@ -325,11 +331,12 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
@Override
public V putIfAbsent(K key, V value) {
public V putIfAbsent( K key, V value) {
return put0(key, value, false);
}
private V put0(K key, V value, boolean replaceIfPresent) {
private V put0(@net.openhft.lang.model.constraints.NotNull K key, V value,
boolean replaceIfPresent) {
checkKey(key);
checkValue(value);
ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
@@ -354,11 +361,51 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return lookupUsing(key, usingValue, false);
}
@Override
public SegmentLock acquireUsingReadLocked(K key, V usingValue) {
return this.acquireUsing(key, usingValue, LockType.READ_LOCK);
}
@Override
public SegmentLock acquireUsingWriteLocked(K key, V usingValue) {
return this.acquireUsing(key, usingValue, LockType.WRITE_LOCK);
//todo call put() on close of a on-heap value
//todo set dirty when using replication on
}
// todo remove
@Override
public V acquireUsing(K key, V usingValue) {
return lookupUsing(key, usingValue, true);
}
private enum LockType {READ_LOCK, WRITE_LOCK}
SegmentLock acquireUsing(K key, V value, LockType lockTypeType) {
checkKey(key);
ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
KI keyInterop = keyInteropProvider.get(copies, originalKeyInterop);
copies = metaKeyInteropProvider.getCopies(copies);
MKI metaKeyInterop =
metaKeyInteropProvider.get(copies, originalMetaKeyInterop, keyInterop, key);
long hash = metaKeyInterop.hash(keyInterop, key);
int segmentNum = getSegment(hash);
long segmentHash = segmentHash(hash);
Segment segment = segments[segmentNum];
SegmentLock lock = (lockTypeType == LockType.WRITE_LOCK) ? segment.writeLock() : segment.readLock();
segment.acquireWithoutLock(copies, metaKeyInterop, keyInterop, key, value,
segmentHash, false);
return lock;
}
V lookupUsing(K key, V value, boolean create) {
checkKey(key);
ThreadLocalCopies copies = keyInteropProvider.getCopies(null);
@@ -369,8 +416,13 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
long hash = metaKeyInterop.hash(keyInterop, key);
int segmentNum = getSegment(hash);
long segmentHash = segmentHash(hash);
return segments[segmentNum].acquire(copies, metaKeyInterop, keyInterop, key, value,
segmentHash, create);
Segment segment = segments[segmentNum];
try (SegmentLock lock = create ? segment.writeLock() : segment.readLock()) {
return segment.acquireWithoutLock(copies, metaKeyInterop, keyInterop, key, value,
segmentHash, create);
}
}
@Override
@@ -400,6 +452,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return (entrySet != null) ? entrySet : (entrySet = new EntrySet());
}
/**
* @throws NullPointerException if the specified key is null
*/
@@ -418,6 +471,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return removeIfValueIs(key, (V) value) != null;
}
/**
* removes ( if there exists ) an entry from the map, if the {@param key} and {@param
* expectedValue} match that of a maps.entry. If the {@param expectedValue} equals null then (
@@ -451,6 +505,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return oldValue.equals(replaceIfValueIs(key, oldValue, newValue));
}
/**
* @throws NullPointerException if the specified key or value is null
*/
@@ -569,6 +624,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
throw new UnsupportedOperationException("todo");
}
public void putAll(Bytes reader) {
throw new UnsupportedOperationException("todo");
}
long[] segmentSizes() {
long[] sizes = new long[segments.length];
for (int i = 0; i < segments.length; i++)
@@ -576,6 +635,14 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return sizes;
}
public void put(Bytes reader) {
throw new UnsupportedOperationException("todo");
}
public void removeWithBytes(Bytes reader) {
throw new UnsupportedOperationException("todo");
}
// these methods should be package local, not public or private.
class Segment implements SharedSegment {
/*
@@ -597,6 +664,19 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
private MultiMap hashLookup;
private long nextPosToSearchFrom = 0L;
final SegmentLock readUnlock = new SegmentLock() {
@Override
public void close() {
Segment.this.readUnlock();
}
};
final SegmentLock writeUnlock = new SegmentLock() {
@Override
public void close() {
Segment.this.writeUnlock();
}
};
/**
* @param index the index of this segment held by the map
@@ -679,10 +759,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
public void readLock() throws IllegalStateException {
public SegmentLock readLock() throws IllegalStateException {
while (true) {
final boolean success = segmentHeader.tryRWReadLock(LOCK_OFFSET, lockTimeOutNS);
if (success) return;
if (success) return readUnlock;
if (currentThread().isInterrupted()) {
throw new IllegalStateException(new InterruptedException("Unable to obtain lock, interrupted"));
} else {
@@ -692,10 +772,10 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
}
public void writeLock() throws IllegalStateException {
public SegmentLock writeLock() throws IllegalStateException {
while (true) {
final boolean success = segmentHeader.tryRWWriteLock(LOCK_OFFSET, lockTimeOutNS);
if (success) return;
if (success) return writeUnlock;
if (currentThread().isInterrupted()) {
throw new IllegalStateException(new InterruptedException("Unable to obtain lock, interrupted"));
} else {
@@ -762,51 +842,44 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
return (int) (sizeInBytes / entrySize) + 1;
}
V acquire(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue,
long hash2, boolean create) {
V acquireWithoutLock(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue,
long hash2, boolean create) {
V v = acquire0(copies, metaKeyInterop, keyInterop, key, usingValue, hash2, false);
if (create && v == null)
v = acquire0(copies, metaKeyInterop, keyInterop, key, usingValue, hash2, true);
v = acquire0(copies, metaKeyInterop, keyInterop, key, usingValue, hash2, true);
return v;
}
V acquire0(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue,
long hash2, boolean create) {
if (create)
writeLock();
else
readLock();
try {
long keySize = metaKeyInterop.size(keyInterop, key);
MultiStoreBytes entry = acquireTmpBytes();
long offset = searchKey(keyInterop, metaKeyInterop, key, keySize, hash2, entry,
hashLookup);
if (offset >= 0L) {
return onKeyPresentOnAcquire(copies, key, usingValue, offset, entry);
} else {
if (!create)
return null;
if (defaultValueProvider != null) {
V defaultValue = defaultValueProvider.get(key);
copies = valueWriterProvider.getCopies(copies);
VW valueWriter = valueWriterProvider.get(copies, originalValueWriter);
copies = metaValueWriterProvider.getCopies(copies);
MetaBytesWriter<V, VW> metaValueWriter = metaValueWriterProvider.get(
copies, originalMetaValueWriter, valueWriter, defaultValue);
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
metaValueWriter, valueWriter, defaultValue);
} else {
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
prepareValueBytesAsWriter, null, key);
}
return onKeyAbsentOnAcquire(copies, key, keySize, usingValue, offset);
V acquire0(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key, V usingValue,
long hash2, boolean create) {
long keySize = metaKeyInterop.size(keyInterop, key);
MultiStoreBytes entry = acquireTmpBytes();
long offset = searchKey(keyInterop, metaKeyInterop, key, keySize, hash2, entry,
hashLookup);
if (offset >= 0L) {
return onKeyPresentOnAcquire(copies, key, usingValue, offset, entry);
} else {
if (!create)
return null;
if (defaultValueProvider != null) {
V defaultValue = defaultValueProvider.get(key);
copies = valueWriterProvider.getCopies(copies);
VW valueWriter = valueWriterProvider.get(copies, originalValueWriter);
copies = metaValueWriterProvider.getCopies(copies);
MetaBytesWriter<V, VW> metaValueWriter = metaValueWriterProvider.get(
copies, originalMetaValueWriter, valueWriter, defaultValue);
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
metaValueWriter, valueWriter, defaultValue);
} else {
offset = putEntry(metaKeyInterop, keyInterop, key, keySize,
prepareValueBytesAsWriter, null, key);
}
} finally {
if (create)
writeUnlock();
else
readUnlock();
return onKeyAbsentOnAcquire(copies, key, keySize, usingValue, offset);
}
}
long searchKey(KI keyInterop, MKI metaKeyInterop, K key, long keySize, long hash2,
@@ -1007,12 +1080,12 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
/**
* Removes a key (or key-value pair) from the Segment.
*
* <p>The entry will only be removed if {@code expectedValue} equals to {@code null} or the value previously
* corresponding to the specified key.
* <p>The entry will only be removed if {@code expectedValue} equals to {@code null} or the
* value previously corresponding to the specified key.
*
* @param hash2 a hash code related to the {@code keyBytes}
* @return the value of the entry that was removed if the entry corresponding to the {@code keyBytes} exists and
* {@link #removeReturnsNull} is {@code false}, {@code null} otherwise
* @return the value of the entry that was removed if the entry corresponding to the {@code
* keyBytes} exists and {@link #removeReturnsNull} is {@code false}, {@code null} otherwise
*/
V remove(ThreadLocalCopies copies, MKI metaKeyInterop, KI keyInterop, K key,
V expectedValue, long hash2) {
@@ -1068,8 +1141,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
/**
* Replaces the specified value for the key with the given value. {@code newValue} is set only if the existing
* value corresponding to the specified key is equal to {@code expectedValue} or {@code expectedValue == null}.
* Replaces the specified value for the key with the given value. {@code newValue} is set
* only if the existing value corresponding to the specified key is equal to {@code
* expectedValue} or {@code expectedValue == null}.
*
* @param hash2 a hash code related to the {@code keyBytes}
* @return the replaced value or {@code null} if the value was not replaced
@@ -1145,15 +1219,17 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
}
/**
* Replaces value in existing entry. May cause entry relocation, because there may be not enough space for new
* value in location already allocated for this entry.
* Replaces value in existing entry. May cause entry relocation, because there may be not
* enough space for new value in location already allocated for this entry.
*
* @param pos index of the first block occupied by the entry
* @param offset relative offset of the entry in Segment bytes (before, i. e. including metaData)
* @param offset relative offset of the entry in Segment bytes (before, i. e.
* including metaData)
* @param entry relative pointer in Segment bytes
* @param valueSizePos relative position of value size in entry
* @param entryEndAddr absolute address of the entry end
* @return relative offset of the entry in Segment bytes after putting value (that may cause entry relocation)
* @return relative offset of the entry in Segment bytes after putting value (that may cause
* entry relocation)
*/
long putValue(long pos, long offset, NativeBytes entry, long valueSizePos,
long entryEndAddr, ThreadLocalCopies copies, V value, Bytes valueBytes,