mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
HCOLL-192 onPut now returns the replacedValue ( previous value )
This commit is contained in:
@@ -20,30 +20,28 @@ package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.ChronicleHashBuilder;
|
||||
import net.openhft.lang.io.Bytes;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Contains methods which are called when {@link ChronicleMap} key events occur. Typical use cases:
|
||||
* <ul>
|
||||
* <li>Map data backup / replication.</li>
|
||||
* <li>Logging, monitoring, debugging.</li>
|
||||
* </ul>
|
||||
* Contains methods which are called when {@link ChronicleMap} key events occur. Typical use cases: <ul>
|
||||
* <li>Map data backup / replication.</li> <li>Logging, monitoring, debugging.</li> </ul>
|
||||
*
|
||||
* <p>This is an adapter class - all methods have default implementations as no-ops. Extend this
|
||||
* class and override only methods corresponding the events you are interested in.
|
||||
* <p>This is an adapter class - all methods have default implementations as no-ops. Extend this class and
|
||||
* override only methods corresponding the events you are interested in.
|
||||
*
|
||||
* <p>To configure {@code MapEventListener} for {@code ChronicleMap}, use
|
||||
* {@link AbstractChronicleMapBuilder#eventListener(MapEventListener)} method.
|
||||
* <p>To configure {@code MapEventListener} for {@code ChronicleMap}, use {@link
|
||||
* AbstractChronicleMapBuilder#eventListener(MapEventListener)} method.
|
||||
*
|
||||
* <p>{@link MapEventListeners} uninstantiable class contains several logging implementations and
|
||||
* the default {@linkplain MapEventListeners#nop() no-op implementation}.
|
||||
* <p>{@link MapEventListeners} uninstantiable class contains several logging implementations and the default
|
||||
* {@linkplain MapEventListeners#nop() no-op implementation}.
|
||||
*
|
||||
* <p>All these calls are synchronous while a {@code ChronicleMap} lock is held so make them
|
||||
* as quick as possible.
|
||||
* <p>All these calls are synchronous while a {@code ChronicleMap} lock is held so make them as quick as
|
||||
* possible.
|
||||
*
|
||||
* <p>The {@code entry} passed to the methods is {@code Bytes} instance positioned at meta data
|
||||
* area. See {@link ChronicleHashBuilder#metaDataBytes(int)} for more information.
|
||||
* <p>The {@code entry} passed to the methods is {@code Bytes} instance positioned at meta data area. See
|
||||
* {@link ChronicleHashBuilder#metaDataBytes(int)} for more information.
|
||||
*
|
||||
* @param <K> key type of the maps, trackable by this event listener
|
||||
* @param <V> value type of the maps, trackable by this event listener
|
||||
@@ -56,14 +54,12 @@ public abstract class MapEventListener<K, V, M extends ChronicleMap<K, V>>
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* This method is called if the key is found in the map during {@link ChronicleMap#get get},
|
||||
* {@link ChronicleMap#getUsing getUsing} or {@link ChronicleMap#acquireUsing acquireUsing}
|
||||
* method call.
|
||||
* This method is called if the key is found in the map during {@link ChronicleMap#get get}, {@link
|
||||
* ChronicleMap#getUsing getUsing} or {@link ChronicleMap#acquireUsing acquireUsing} method call.
|
||||
*
|
||||
* @param map the accessed map
|
||||
* @param entry bytes of the entry
|
||||
* @param metaDataBytes length of {@link ChronicleHashBuilder#metaDataBytes(int) meta data}
|
||||
* for this map
|
||||
* @param metaDataBytes length of {@link ChronicleHashBuilder#metaDataBytes(int) meta data} for this map
|
||||
* @param key the key looked up
|
||||
* @param value the value found for the key
|
||||
*/
|
||||
@@ -71,32 +67,32 @@ public abstract class MapEventListener<K, V, M extends ChronicleMap<K, V>>
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void onPut(M map, Bytes entry, int metaDataBytes, boolean added, K key, V value,
|
||||
void onPut(M map, Bytes entry, int metaDataBytes, boolean added, K key, V replacedValue, V value,
|
||||
long pos, SharedSegment segment) {
|
||||
onPut(map, entry, metaDataBytes, added, key, value);
|
||||
onPut(map, entry, metaDataBytes, added, key, value, replacedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called whenever a new value is put for the key in the map during calls of such
|
||||
* methods as {@link ChronicleMap#put put}, {@link ChronicleMap#putIfAbsent putIfAbsent},
|
||||
* {@link ChronicleMap#replace(Object, Object, Object) replace}, etc. When a new value is
|
||||
* {@linkplain AbstractChronicleMapBuilder#defaultValue(Object) default} for the map or obtained
|
||||
* during {@link ChronicleMap#acquireUsing acquireUsing} call is put for the key, this method
|
||||
* is called as well.
|
||||
* This method is called whenever a new value is put for the key in the map during calls of such methods
|
||||
* as {@link ChronicleMap#put put}, {@link ChronicleMap#putIfAbsent putIfAbsent}, {@link
|
||||
* ChronicleMap#replace(Object, Object, Object) replace}, etc. When a new value is {@linkplain
|
||||
* AbstractChronicleMapBuilder#defaultValue(Object) default} for the map or obtained during {@link
|
||||
* ChronicleMap#acquireUsing acquireUsing} call is put for the key, this method is called as well.
|
||||
*
|
||||
* <p>This method is called when put is already happened.
|
||||
*
|
||||
* @param map the accessed map
|
||||
* @param entry bytes of the entry (with the value already written to)
|
||||
* @param metaDataBytes length of {@link ChronicleHashBuilder#metaDataBytes(int) meta data}
|
||||
* for this map
|
||||
* @param added {@code true} is the key was absent in the map before current
|
||||
* {@code ChronicleMap} method call, led to putting a value and inherently
|
||||
* calling this listener method
|
||||
* @param metaDataBytes length of {@link net.openhft.chronicle.hash.ChronicleHashBuilder#metaDataBytes(int)
|
||||
* meta data} for this map
|
||||
* @param added {@code true} is the key was absent in the map before current {@code ChronicleMap}
|
||||
* method call, led to putting a value and inherently calling this listener method
|
||||
* @param key the key the given value is put for
|
||||
* @param value the value which is now associated with the given key
|
||||
* @param replacedValue the value which was replaced by {@code value}, is NULL if {@code added} is true
|
||||
*/
|
||||
public void onPut(M map, Bytes entry, int metaDataBytes, boolean added, K key, V value) {
|
||||
public void onPut(M map, Bytes entry, int metaDataBytes, boolean added, K key, V value,
|
||||
@Nullable V replacedValue) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@@ -106,13 +102,12 @@ public abstract class MapEventListener<K, V, M extends ChronicleMap<K, V>>
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when an entry is removed. Misses, i. e. when {@code map.remove(key)}
|
||||
* is called, but key is already absent in the map, are not notified.
|
||||
* This is called when an entry is removed. Misses, i. e. when {@code map.remove(key)} is called, but key
|
||||
* is already absent in the map, are not notified.
|
||||
*
|
||||
* @param map accessed
|
||||
* @param entry bytes of the entry just removed, but any data is not yet erased
|
||||
* @param metaDataBytes length of {@link ChronicleHashBuilder#metaDataBytes(int) meta data}
|
||||
* for this map
|
||||
* @param metaDataBytes length of {@link ChronicleHashBuilder#metaDataBytes(int) meta data} for this map
|
||||
* @param key the key removed from the map
|
||||
* @param value the value which was associated with the given key
|
||||
*/
|
||||
|
||||
@@ -68,7 +68,7 @@ public final class MapEventListeners {
|
||||
|
||||
@Override
|
||||
public void onPut(ChronicleMap map, Bytes entry, int metaDataBytes, boolean added,
|
||||
Object key, Object value, long pos, SharedSegment segment) {
|
||||
Object key, Object replacedValue, Object value, long pos, SharedSegment segment) {
|
||||
logOperation(map, entry, metaDataBytes, added ? " +put " : " put ");
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public final class MapEventListeners {
|
||||
|
||||
@Override
|
||||
public void onPut(ChronicleMap map, Bytes entry, int metaDataBytes, boolean added,
|
||||
Object key, Object value, long pos, SharedSegment segment) {
|
||||
Object key, Object replacedValue, Object value, long pos, SharedSegment segment) {
|
||||
LOGGER.info("{} put {} => {}", map.file(), key, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,13 +199,20 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
* as this will trigger the modification iterators to send out another replication event. So instead with
|
||||
* call this method iterators
|
||||
*
|
||||
* @return
|
||||
* @return the event listener added by the user
|
||||
*/
|
||||
MapEventListener<K, V, ChronicleMap<K, V>> eventListenerWithoutModIterators() {
|
||||
MapEventListener<K, V, ChronicleMap<K, V>> attachedEventListener() {
|
||||
return eventListener;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the user has added an event listerner
|
||||
*/
|
||||
boolean hasAttachedEventListener() {
|
||||
return eventListener != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return put0(key, value, true, localIdentifier, timeProvider.currentTimeMillis());
|
||||
@@ -635,7 +642,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
throw new IllegalStateException("ENTRY WRITE_BUFFER_SIZE TOO LARGE : Replicated " +
|
||||
"ChronicleMap's" +
|
||||
" are restricted to an " +
|
||||
"entry size of " + Integer.MAX_VALUE + ", " +
|
||||
"entry size of " + Integer.MAX_VALUE + ", " +
|
||||
"your entry size=" + result);
|
||||
|
||||
return result;
|
||||
@@ -728,7 +735,8 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
|
||||
void notifyRemotePut(long offset, boolean added, final long pos, long keySize, final Bytes inBytes,
|
||||
final long valueSize, final long valuePosition, final long keyPosition) {
|
||||
final long valueSize, final long valuePosition,
|
||||
final long keyPosition, final V replacedValue) {
|
||||
if (eventListener() != MapEventListeners.NOP) {
|
||||
final MultiStoreBytes b = acquireTmpBytes();
|
||||
b.storePositionAndSize(bytes, offset, entrySize);
|
||||
@@ -747,8 +755,8 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
inBytes.position(valuePosition);
|
||||
final V value = valueReaderProvider.get(copiesV, originalValueReader).read(inBytes, valueSize);
|
||||
|
||||
eventListener().onPut(ReplicatedChronicleMap.this, b, metaDataBytes,
|
||||
added, key, value, pos, this);
|
||||
attachedEventListener().onPut(ReplicatedChronicleMap.this, b, metaDataBytes,
|
||||
added, key, replacedValue, value, pos, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -759,10 +767,19 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
private void remotePut(@NotNull final Bytes inBytes, long hash2,
|
||||
final byte identifier, final long timestamp,
|
||||
long valuePos, long valueLimit) {
|
||||
|
||||
|
||||
writeLock();
|
||||
try {
|
||||
// inBytes position and limit correspond to the key
|
||||
final long keySize = inBytes.remaining();
|
||||
V replacedValue = null;
|
||||
|
||||
ThreadLocalCopies keyCopies = keyInteropProvider.getCopies(null);
|
||||
BytesReader<K> keyReader = keyReaderProvider.get(keyCopies, originalKeyReader);
|
||||
|
||||
ThreadLocalCopies valueCopies = valueReaderProvider.getCopies(keyCopies);
|
||||
BytesReader<V> valueReader = valueReaderProvider.get(valueCopies, originalValueReader);
|
||||
|
||||
hashLookupLiveAndDeleted.startSearch(hash2);
|
||||
for (long pos; (pos = hashLookupLiveAndDeleted.nextPos()) >= 0L; ) {
|
||||
@@ -775,6 +792,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
// key is found
|
||||
|
||||
|
||||
entry.skip(keySize);
|
||||
|
||||
final long timeStampPos = entry.positionAddr();
|
||||
@@ -793,13 +811,17 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
entry.writeBoolean(false);
|
||||
|
||||
long valueSizePos = entry.position();
|
||||
long valueSize = readValueSize(entry);
|
||||
long entryEndAddr = entry.positionAddr() + valueSize;
|
||||
long replacedValueSize = readValueSize(entry);
|
||||
long entryEndAddr = entry.positionAddr() + replacedValueSize;
|
||||
|
||||
// write the value
|
||||
inBytes.limit(valueLimit);
|
||||
inBytes.position(valuePos);
|
||||
|
||||
// if we have event listeners attached we have to read back the old value
|
||||
if (hasAttachedEventListener())
|
||||
replacedValue = valueReader.read(entry, replacedValueSize, null);
|
||||
|
||||
putValue(pos, offset, entry, valueSizePos, entryEndAddr, null, null, inBytes,
|
||||
hashLookupLiveAndDeleted);
|
||||
|
||||
@@ -809,10 +831,21 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
incrementSize();
|
||||
}
|
||||
|
||||
// this is just like notifyPut, but it won't trigger the modification iterators
|
||||
notifyRemotePut(offset, false, posFromOffset(offset), keySize, inBytes, valueLimit
|
||||
-valuePos,
|
||||
valuePos, keyPosition);
|
||||
if (hasAttachedEventListener()) {
|
||||
|
||||
// this is just like notifyPut, but it won't trigger the modification iterators
|
||||
notifyRemotePut(offset,
|
||||
false,
|
||||
posFromOffset(offset),
|
||||
keySize,
|
||||
inBytes,
|
||||
valueLimit - valuePos,
|
||||
valuePos,
|
||||
keyPosition,
|
||||
replacedValue
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -848,7 +881,8 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
incrementSize();
|
||||
|
||||
// this is just like notifyPut, but it won't trigger the modification iterators
|
||||
notifyRemotePut(offset, true, posFromOffset(offset), keySize, inBytes, valueSize, valuePos, kPosition);
|
||||
notifyRemotePut(offset, true, posFromOffset(offset), keySize, inBytes, valueSize, valuePos,
|
||||
kPosition, null);
|
||||
|
||||
} finally {
|
||||
writeUnlock();
|
||||
@@ -913,13 +947,14 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
long offset = putEntry(copies, metaKeyWriter, keyWriter, key, keySize, hash2, value,
|
||||
identifier, timestamp, hashLookup);
|
||||
incrementSize();
|
||||
notifyPut(offset, true, key, value, posFromOffset(offset));
|
||||
notifyPut(offset, true, key, value, null, posFromOffset(offset));
|
||||
return null;
|
||||
} finally {
|
||||
writeUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used only with replication, its sometimes possible to receive an old ( or stale update ) from a
|
||||
* remote map. This method is used to determine if we should ignore such updates. <p>We can reject
|
||||
@@ -1309,12 +1344,12 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
@Override
|
||||
public void onPut(ChronicleMap<K, V> map, Bytes entry, int metaDataBytes,
|
||||
boolean added, K key, V value, long pos, SharedSegment segment) {
|
||||
boolean added, K key, V replacedValue, V value, long pos, SharedSegment segment) {
|
||||
|
||||
assert ReplicatedChronicleMap.this == map :
|
||||
"ModificationIterator.onPut() is called from outside of the parent map";
|
||||
try {
|
||||
nextListener.onPut(map, entry, metaDataBytes, added, key, value, pos, segment);
|
||||
nextListener.onPut(map, entry, metaDataBytes, added, key, replacedValue, value, pos, segment);
|
||||
} catch (Exception e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
@@ -1323,7 +1358,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
try {
|
||||
final ModificationIterator modificationIterator = modificationIterators.get((int) next);
|
||||
modificationIterator.onPut(map, entry, metaDataBytes,
|
||||
added, key, value, pos, segment);
|
||||
added, key, replacedValue, value, pos, segment);
|
||||
} catch (Exception e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
@@ -1445,7 +1480,7 @@ final class ReplicatedChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
@Override
|
||||
public void onPut(ChronicleMap<K, V> map, Bytes entry, int metaDataBytes,
|
||||
boolean added, K key, V value, long pos, SharedSegment segment) {
|
||||
boolean added, K key, V replacedValue, V value, long pos, SharedSegment segment) {
|
||||
|
||||
assert ReplicatedChronicleMap.this == map :
|
||||
"ModificationIterator.onPut() is called from outside of the parent map";
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
package net.openhft.chronicle.map;
|
||||
|
||||
import net.openhft.chronicle.hash.ChronicleHashErrorListener;
|
||||
import net.openhft.chronicle.hash.serialization.*;
|
||||
import net.openhft.chronicle.hash.serialization.BytesReader;
|
||||
import net.openhft.chronicle.hash.serialization.Hasher;
|
||||
import net.openhft.chronicle.hash.serialization.SizeMarshaller;
|
||||
import net.openhft.chronicle.hash.serialization.internal.MetaBytesInterop;
|
||||
import net.openhft.chronicle.hash.serialization.internal.MetaBytesWriter;
|
||||
import net.openhft.chronicle.hash.serialization.internal.MetaProvider;
|
||||
@@ -32,6 +34,7 @@ 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.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -58,8 +61,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VanillaChronicleMap.class);
|
||||
|
||||
/**
|
||||
* Because DirectBitSet implementations couldn't find more than 64 continuous clear or set
|
||||
* bits.
|
||||
* Because DirectBitSet implementations couldn't find more than 64 continuous clear or set bits.
|
||||
*/
|
||||
static final int MAX_ENTRY_OVERSIZE_FACTOR = 64;
|
||||
static final ThreadLocal<MultiStoreBytes> tmpBytes = new ThreadLocal<>();
|
||||
@@ -484,9 +486,9 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
|
||||
/**
|
||||
* 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 (
|
||||
* if there exists ) an entry whose key equals {@param key} this is removed.
|
||||
* 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 ( if there exists ) an entry whose
|
||||
* key equals {@param key} this is removed.
|
||||
*
|
||||
* @param k the key of the entry to remove
|
||||
* @param expectedValue null if not required
|
||||
@@ -546,8 +548,8 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
* replace the value in a map, only if the existing entry equals {@param existingValue}
|
||||
*
|
||||
* @param key the key into the map
|
||||
* @param existingValue the expected existing value in the map ( could be null when we don't
|
||||
* wish to do this check )
|
||||
* @param existingValue the expected existing value in the map ( could be null when we don't wish to do
|
||||
* this check )
|
||||
* @param newValue the new value you wish to store in the map
|
||||
* @return the value that was replaced
|
||||
*/
|
||||
@@ -680,7 +682,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
/**
|
||||
* close for native values does not call put on close
|
||||
*/
|
||||
final MutableLockedEntry<K, V, MKI, KI> writeUnlock = isNativeValueClass
|
||||
final WriteLocked<K, V, MKI, KI> writeUnlock = isNativeValueClass
|
||||
? new NativeWriteLocked()
|
||||
: new HeapWriteLocked();
|
||||
|
||||
@@ -766,7 +768,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
}
|
||||
|
||||
|
||||
public MutableLockedEntry<K, V, MKI, KI> readLock() throws IllegalStateException {
|
||||
public ReadLocked<K, V, MKI, KI> readLock() throws IllegalStateException {
|
||||
while (true) {
|
||||
final boolean success = segmentHeader.tryRWReadLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
if (success) {
|
||||
@@ -784,7 +786,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
}
|
||||
}
|
||||
|
||||
public MutableLockedEntry<K, V, MKI, KI> writeLock() throws IllegalStateException {
|
||||
public WriteLocked<K, V, MKI, KI> writeLock() throws IllegalStateException {
|
||||
while (true) {
|
||||
final boolean success = segmentHeader.tryRWWriteLock(LOCK_OFFSET, lockTimeOutNS);
|
||||
if (success) return writeUnlock;
|
||||
@@ -926,7 +928,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
entry.skip(keySizeMarshaller.sizeEncodingSize(keySize) + keySize);
|
||||
skipReplicationBytes(entry);
|
||||
V v = readValue(copies, entry, usingValue);
|
||||
notifyPut(offset, true, key, v, posFromOffset(offset));
|
||||
notifyPut(offset, true, key, v, null, posFromOffset(offset));
|
||||
notifyGet(offset, key, v);
|
||||
return v;
|
||||
}
|
||||
@@ -965,7 +967,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
// key is not found
|
||||
long offset = putEntry(copies, metaKeyInterop, keyInterop, key, keySize, value);
|
||||
incrementSize();
|
||||
notifyPut(offset, true, key, value, posFromOffset(offset));
|
||||
notifyPut(offset, true, key, value, null, posFromOffset(offset));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -981,7 +983,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
// putValue may relocate entry and change offset
|
||||
offset = putValue(pos, offset, entry, valueSizePos, entryEndAddr, copies, value, null,
|
||||
searchedHashLookup);
|
||||
notifyPut(offset, false, key, value, posFromOffset(offset));
|
||||
notifyPut(offset, false, key, value, prevValue, posFromOffset(offset));
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
@@ -1082,7 +1084,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
return readValue(copies, entry, value, readValueSize(entry));
|
||||
}
|
||||
|
||||
V readValue(ThreadLocalCopies copies, MultiStoreBytes entry, V value, long valueSize) {
|
||||
V readValue(ThreadLocalCopies copies, NativeBytes entry, V value, long valueSize) {
|
||||
copies = valueReaderProvider.getCopies(copies);
|
||||
BytesReader<V> valueReader = valueReaderProvider.get(copies, originalValueReader);
|
||||
return valueReader.read(entry, valueSize, value);
|
||||
@@ -1097,12 +1099,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) {
|
||||
@@ -1162,9 +1164,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
|
||||
@@ -1205,19 +1207,20 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
// putValue may relocate entry and change offset
|
||||
offset = putValue(pos, offset, entry, valueSizePos, entryEndAddr, copies, newValue,
|
||||
null, searchedHashLookup);
|
||||
notifyPut(offset, false, key, newValue, posFromOffset(offset));
|
||||
notifyPut(offset, false, key, newValue, valueRead, posFromOffset(offset));
|
||||
return valueRead;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
void notifyPut(long offset, boolean added, K key, V value, final long pos) {
|
||||
void notifyPut(long offset, boolean added, K key, V value, @Nullable final V replacedValue,
|
||||
final long pos) {
|
||||
if (eventListener() != MapEventListeners.NOP) {
|
||||
MultiStoreBytes b = acquireTmpBytes();
|
||||
b.storePositionAndSize(bytes, offset, entrySize);
|
||||
eventListener().onPut(VanillaChronicleMap.this, b, metaDataBytes,
|
||||
added, key, value, pos, this);
|
||||
added, key, replacedValue, value, pos, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1240,17 +1243,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,
|
||||
@@ -1661,7 +1664,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
|
||||
}
|
||||
|
||||
private static abstract class ReadLocked<K, V, MKI, KI> extends MutableLockedEntry<K, V, MKI,
|
||||
static abstract class ReadLocked<K, V, MKI, KI> extends MutableLockedEntry<K, V, MKI,
|
||||
KI> implements ReadContext<K, V> {
|
||||
|
||||
boolean present;
|
||||
@@ -1680,7 +1683,7 @@ class VanillaChronicleMap<K, KI, MKI extends MetaBytesInterop<K, KI>,
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class WriteLocked<K, V, MKI, KI> extends MutableLockedEntry<K, V, MKI,
|
||||
static abstract class WriteLocked<K, V, MKI, KI> extends MutableLockedEntry<K, V, MKI,
|
||||
KI> implements WriteContext<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user