Fixed a bug in MapEntryStages.putValueDeletedEntry() -- the slot in hashLookup is empty, should be filled, not just the value updated

This commit is contained in:
leventov
2015-07-30 03:38:00 +03:00
parent cf583d4510
commit a0eb9a2f98
5 changed files with 122 additions and 54 deletions
@@ -36,7 +36,6 @@ import net.openhft.chronicle.map.impl.stage.data.bytes.InputFirstValueBytesData;
import net.openhft.chronicle.map.impl.stage.data.bytes.InputSecondValueBytesData;
import net.openhft.chronicle.map.impl.stage.data.instance.InputValueInstanceData;
import net.openhft.chronicle.map.impl.stage.data.instance.WrappedValueInstanceData;
import net.openhft.chronicle.map.impl.stage.entry.MapEntryStages;
import net.openhft.chronicle.map.impl.stage.input.MapInputBytesValues;
import net.openhft.chronicle.map.impl.stage.map.MapEntryOperationsDelegation;
import net.openhft.chronicle.map.impl.stage.map.ValueBytesInterop;
@@ -66,7 +65,7 @@ import net.openhft.sg.Staged;
QueryCheckOnEachPublicOperation.class,
SearchAllocatedChunks.class,
MapEntryStages.class,
QueryMapEntryStages.class,
MapEntryOperationsDelegation.class,
WrappedValueInstanceValueHolder.class,
MapQuery.class,
@@ -33,10 +33,11 @@ import org.jetbrains.annotations.NotNull;
public abstract class MapEntryStages<K, V> extends HashEntryStages<K>
implements MapEntry<K, V> {
@StageRef VanillaChronicleMapHolder<?, ?, ?, ?, ?, ?, ?> mh;
@StageRef AllocatedChunks allocatedChunks;
@StageRef public VanillaChronicleMapHolder<?, ?, ?, ?, ?, ?, ?> mh;
@StageRef public AllocatedChunks allocatedChunks;
@StageRef HashLookup hashLookup;
long countValueSizeOffset() {
return keyEnd();
}
@@ -106,51 +107,8 @@ public abstract class MapEntryStages<K, V> extends HashEntryStages<K>
}
public void putValueDeletedEntry(Data<V> newValue) {
assert s.innerUpdateLock.isHeldByCurrentThread();
int newSizeInChunks;
long entryStartOffset = keySizeOffset;
long newSizeOfEverythingBeforeValue = -1;
boolean newValueSizeIsDifferent = newValue.size() != valueSize;
if (newValueSizeIsDifferent) {
newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue);
long newValueOffset = mh.m().alignment.alignAddr(
entryStartOffset + newSizeOfEverythingBeforeValue);
long newEntrySize = newValueOffset + newValue.size() - entryStartOffset;
newSizeInChunks = mh.m().inChunks(newEntrySize);
} else {
newSizeInChunks = entrySizeInChunks;
}
if (pos + newSizeInChunks < s.freeList.size() &&
s.freeList.allClear(pos, pos + newSizeInChunks)) {
s.freeList.set(pos, pos + newSizeInChunks);
s.innerWriteLock.lock();
allocatedChunks.incrementSegmentEntriesIfNeeded();
if (newValueSizeIsDifferent) {
initValue(newValue);
} else {
writeValue(newValue);
}
} else {
if (newValueSizeIsDifferent) {
assert newSizeOfEverythingBeforeValue >= 0;
} else {
newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue);
}
long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size());
if (newValueSizeIsDifferent) {
allocatedChunks.initEntryAndKeyCopying(entrySize, valueSizeOffset - entryStartOffset);
initValue(newValue);
} else {
long oldValueSizeOffset = valueSizeOffset;
long oldValueSize = valueSize;
long oldValueOffset = valueOffset;
allocatedChunks.initEntryAndKeyCopying(entrySize, valueOffset - entryStartOffset);
initValueWithoutSize(newValue, oldValueSizeOffset, oldValueSize, oldValueOffset);
}
freeExtraAllocatedChunks();
}
hashLookup.putValueVolatile(hlp.hashLookupPos, pos);
throw new AssertionError("putValueDeletedEntry() might be called only from " +
"non-Replicated Map query context");
}
public void writeValueAndPutPos(Data<V> value) {
@@ -158,9 +158,4 @@ public abstract class ReplicatedMapEntryStages<K, V, T> extends MapEntryStages<K
long sizeOfEverythingBeforeValue(long keySize, long valueSize) {
return super.sizeOfEverythingBeforeValue(keySize, valueSize) + ADDITIONAL_ENTRY_BYTES;
}
@Override
public void putValueDeletedEntry(Data<V> newValue) {
throw new AssertionError("Replicated Map doesn't remove entries truly, yet");
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 higherfrequencytrading.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.chronicle.map.impl.stage.query;
import net.openhft.chronicle.hash.Data;
import net.openhft.chronicle.hash.impl.stage.query.HashLookupSearch;
import net.openhft.chronicle.map.impl.stage.entry.MapEntryStages;
import net.openhft.sg.StageRef;
import net.openhft.sg.Staged;
@Staged
public abstract class QueryMapEntryStages<K, V> extends MapEntryStages<K, V> {
@StageRef HashLookupSearch hls;
@Override
public void putValueDeletedEntry(Data<V> newValue) {
assert s.innerUpdateLock.isHeldByCurrentThread();
int newSizeInChunks;
long entryStartOffset = keySizeOffset;
long newSizeOfEverythingBeforeValue = -1;
boolean newValueSizeIsDifferent = newValue.size() != valueSize;
if (newValueSizeIsDifferent) {
newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue);
long newValueOffset = mh.m().alignment.alignAddr(
entryStartOffset + newSizeOfEverythingBeforeValue);
long newEntrySize = newValueOffset + newValue.size() - entryStartOffset;
newSizeInChunks = mh.m().inChunks(newEntrySize);
} else {
newSizeInChunks = entrySizeInChunks;
}
if (pos + newSizeInChunks < s.freeList.size() &&
s.freeList.allClear(pos, pos + newSizeInChunks)) {
s.freeList.set(pos, pos + newSizeInChunks);
s.innerWriteLock.lock();
allocatedChunks.incrementSegmentEntriesIfNeeded();
if (newValueSizeIsDifferent) {
initValue(newValue);
} else {
writeValue(newValue);
}
} else {
if (newValueSizeIsDifferent) {
assert newSizeOfEverythingBeforeValue >= 0;
} else {
newSizeOfEverythingBeforeValue = newSizeOfEverythingBeforeValue(newValue);
}
long entrySize = innerEntrySize(newSizeOfEverythingBeforeValue, newValue.size());
if (newValueSizeIsDifferent) {
allocatedChunks.initEntryAndKeyCopying(entrySize, valueSizeOffset - entryStartOffset);
initValue(newValue);
} else {
long oldValueSizeOffset = valueSizeOffset;
long oldValueSize = valueSize;
long oldValueOffset = valueOffset;
allocatedChunks.initEntryAndKeyCopying(entrySize, valueOffset - entryStartOffset);
initValueWithoutSize(newValue, oldValueSizeOffset, oldValueSize, oldValueOffset);
}
freeExtraAllocatedChunks();
}
hls.putNewVolatile(pos);
}
}