mirror of
https://github.com/OpenHFT/Chronicle-Map.git
synced 2021-09-13 01:26:12 +00:00
Ensure compatibility with 3.12 and Chronicle Maps created with Integer key, add ChronicleMap3_12IntegerKeyCompatibilityTest
This commit is contained in:
+17
-1
@@ -17,20 +17,25 @@
|
||||
|
||||
package net.openhft.chronicle.hash.impl.stage.data.bytes;
|
||||
|
||||
import net.openhft.chronicle.algo.hashing.LongHashFunction;
|
||||
import net.openhft.chronicle.bytes.Bytes;
|
||||
import net.openhft.chronicle.bytes.RandomDataInput;
|
||||
import net.openhft.chronicle.hash.AbstractData;
|
||||
import net.openhft.chronicle.hash.impl.VanillaChronicleHashHolder;
|
||||
import net.openhft.chronicle.hash.impl.stage.entry.HashEntryStages;
|
||||
import net.openhft.chronicle.hash.impl.stage.entry.SegmentStages;
|
||||
import net.openhft.chronicle.hash.impl.stage.hash.CheckOnEachPublicOperation;
|
||||
import net.openhft.chronicle.hash.impl.stage.hash.KeyBytesInterop;
|
||||
import net.openhft.chronicle.hash.serialization.impl.IntegerDataAccess;
|
||||
import net.openhft.chronicle.hash.serialization.impl.WrongXxHash;
|
||||
import net.openhft.sg.Stage;
|
||||
import net.openhft.sg.StageRef;
|
||||
import net.openhft.sg.Staged;
|
||||
|
||||
@Staged
|
||||
public class EntryKeyBytesData<K> extends AbstractData<K> {
|
||||
|
||||
|
||||
@StageRef VanillaChronicleHashHolder<K> hh;
|
||||
@StageRef KeyBytesInterop<K> ki;
|
||||
@StageRef SegmentStages s;
|
||||
@StageRef HashEntryStages<K> entry;
|
||||
@@ -62,6 +67,17 @@ public class EntryKeyBytesData<K> extends AbstractData<K> {
|
||||
return entry.keySize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long hash(LongHashFunction f) {
|
||||
checkOnEachPublicOperation.checkOnEachPublicOperation();
|
||||
if (f == LongHashFunction.xx_r39() && entry.keySize == 4 &&
|
||||
hh.h().keyDataAccess instanceof IntegerDataAccess) {
|
||||
return WrongXxHash.hashInt(s.segmentBS.readInt(entry.keyOffset));
|
||||
} else {
|
||||
return super.hash(f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get() {
|
||||
checkOnEachPublicOperation.checkOnEachPublicOperation();
|
||||
|
||||
@@ -18,15 +18,20 @@
|
||||
package net.openhft.chronicle.hash.impl.stage.iter;
|
||||
|
||||
import net.openhft.chronicle.algo.hashing.LongHashFunction;
|
||||
import net.openhft.chronicle.core.OS;
|
||||
import net.openhft.chronicle.hash.impl.VanillaChronicleHashHolder;
|
||||
import net.openhft.chronicle.hash.impl.stage.entry.HashEntryStages;
|
||||
import net.openhft.chronicle.hash.impl.stage.entry.KeyHashCode;
|
||||
import net.openhft.chronicle.hash.impl.stage.entry.SegmentStages;
|
||||
import net.openhft.chronicle.hash.serialization.impl.IntegerDataAccess;
|
||||
import net.openhft.chronicle.hash.serialization.impl.WrongXxHash;
|
||||
import net.openhft.sg.StageRef;
|
||||
import net.openhft.sg.Staged;
|
||||
|
||||
@Staged
|
||||
public class IterationKeyHashCode implements KeyHashCode {
|
||||
|
||||
@StageRef VanillaChronicleHashHolder<?> hh;
|
||||
@StageRef SegmentStages s;
|
||||
@StageRef HashEntryStages<?> e;
|
||||
|
||||
@@ -35,7 +40,11 @@ public class IterationKeyHashCode implements KeyHashCode {
|
||||
void initKeyHash() {
|
||||
long addr = s.tierBaseAddr + e.keyOffset;
|
||||
long len = e.keySize;
|
||||
keyHash = LongHashFunction.xx_r39().hashMemory(addr, len);
|
||||
if (len == 4 && hh.h().keyDataAccess instanceof IntegerDataAccess) {
|
||||
keyHash = WrongXxHash.hashInt(OS.memory().readInt(addr));
|
||||
} else {
|
||||
keyHash = LongHashFunction.xx_r39().hashMemory(addr, len);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -181,11 +181,13 @@ public class TierRecovery {
|
||||
long entry = hashLookup.readEntry(currentTierBaseAddr, hlPos);
|
||||
if (!hashLookup.empty(entry)) {
|
||||
e.readExistingEntry(hashLookup.value(entry));
|
||||
Data key = (Data) e.key();
|
||||
Data key = e.key();
|
||||
try (ExternalMapQueryContext<?, ?, ?> c = m.queryContext(key)) {
|
||||
MapEntry<?, ?> entry2 = c.entry();
|
||||
Data<?> key2 = ((MapEntry) c).key();
|
||||
if (key2.bytes().address(key2.offset()) != key.bytes().address(key.offset())) {
|
||||
long keyAddress = key.bytes().address(key.offset());
|
||||
long key2Address = key2.bytes().address(key2.offset());
|
||||
if (key2Address != keyAddress) {
|
||||
lh.LOG.error("entries with duplicate key {} in segment {}: " +
|
||||
"with values {} and {}, removing the latter",
|
||||
key, c.segmentIndex(),
|
||||
|
||||
@@ -29,6 +29,14 @@ import net.openhft.chronicle.wire.WireOut;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link IntegerDataAccess_3_13} instead. This class is not removed only because
|
||||
* users who created a Chronicle Map with older version of the library with this class as the key or
|
||||
* value data access should be able to read and access the map with the present version of the
|
||||
* Chronicle Map library.
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
public final class IntegerDataAccess extends AbstractData<Integer>
|
||||
implements DataAccess<Integer>, Data<Integer> {
|
||||
|
||||
@@ -78,7 +86,11 @@ public final class IntegerDataAccess extends AbstractData<Integer>
|
||||
|
||||
@Override
|
||||
public long hash(LongHashFunction f) {
|
||||
return f.hashInt(instance);
|
||||
if (f == LongHashFunction.xx_r39()) {
|
||||
return WrongXxHash.hashInt(instance);
|
||||
} else {
|
||||
return f.hashInt(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,6 +127,7 @@ public final class IntegerDataAccess extends AbstractData<Integer>
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public DataAccess<Integer> copy() {
|
||||
return new IntegerDataAccess();
|
||||
}
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Roman Leventov
|
||||
*
|
||||
* 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.hash.serialization.impl;
|
||||
|
||||
import net.openhft.chronicle.algo.hashing.LongHashFunction;
|
||||
import net.openhft.chronicle.bytes.BytesStore;
|
||||
import net.openhft.chronicle.bytes.RandomDataInput;
|
||||
import net.openhft.chronicle.bytes.RandomDataOutput;
|
||||
import net.openhft.chronicle.hash.AbstractData;
|
||||
import net.openhft.chronicle.hash.Data;
|
||||
import net.openhft.chronicle.hash.serialization.DataAccess;
|
||||
import net.openhft.chronicle.wire.WireIn;
|
||||
import net.openhft.chronicle.wire.WireOut;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class IntegerDataAccess_3_13 extends AbstractData<Integer>
|
||||
implements DataAccess<Integer>, Data<Integer> {
|
||||
|
||||
// Cache fields
|
||||
private transient boolean bsInit;
|
||||
private transient BytesStore bs;
|
||||
|
||||
/** State field */
|
||||
private transient Integer instance;
|
||||
|
||||
public IntegerDataAccess_3_13() {
|
||||
initTransients();
|
||||
}
|
||||
|
||||
private void initTransients() {
|
||||
bs = BytesStore.wrap(new byte[4]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RandomDataInput bytes() {
|
||||
if (!bsInit) {
|
||||
bs.writeInt(0, instance);
|
||||
bsInit = true;
|
||||
}
|
||||
return bs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long offset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getUsing(@Nullable Integer using) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long hash(LongHashFunction f) {
|
||||
return f.hashInt(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equivalent(RandomDataInput source, long sourceOffset) {
|
||||
return source.readInt(sourceOffset) == instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(RandomDataOutput target, long targetOffset) {
|
||||
target.writeInt(targetOffset, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Data<Integer> getData(@NotNull Integer instance) {
|
||||
this.instance = instance;
|
||||
bsInit = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninit() {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMarshallable(@NotNull WireIn wireIn) {
|
||||
// no config fields to read
|
||||
initTransients();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeMarshallable(@NotNull WireOut wireOut) {
|
||||
// no config fields to write
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataAccess<Integer> copy() {
|
||||
return new IntegerDataAccess_3_13();
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* As a writer for top-level Chronicle Map's key or value type (Integer), {@code IntegerMarshaller}
|
||||
* is deprecated in favor of {@link IntegerDataAccess}. As reader and element writer for {@link
|
||||
* is deprecated in favor of {@link IntegerDataAccess_3_13}. As reader and element writer for {@link
|
||||
* ListMarshaller} and similar composite marshallers, {@code IntegerMarshaller} is not deprecated.
|
||||
*/
|
||||
public final class IntegerMarshaller
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ public final class SerializationBuilder<T> implements Cloneable {
|
||||
sizeMarshaller(constant(8));
|
||||
} else if (tClass == Integer.class) {
|
||||
reader((SizedReader<T>) IntegerMarshaller.INSTANCE);
|
||||
dataAccess((DataAccess<T>) new IntegerDataAccess());
|
||||
dataAccess((DataAccess<T>) new IntegerDataAccess_3_13());
|
||||
sizeMarshaller(constant(4));
|
||||
} else if (tClass == byte[].class) {
|
||||
reader((SizedReader<T>) ByteArraySizedReader.INSTANCE);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Roman Leventov
|
||||
*
|
||||
* 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.hash.serialization.impl;
|
||||
|
||||
/**
|
||||
* @deprecated this class exists for compatibility with old versions of Chronicle Map, which used
|
||||
* wrong version of xxHash.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class WrongXxHash {
|
||||
|
||||
// xxHash constants
|
||||
private static final long P1 = -7046029288634856825L;
|
||||
private static final long P2 = -4417276706812531889L;
|
||||
private static final long P3 = 1609587929392839161L;
|
||||
private static final long P5 = 2870177450012600261L;
|
||||
|
||||
public static long hashInt(int input) {
|
||||
long hash = P5 + 4;
|
||||
// Preserve old, wrong behaviour. In the correct version, input is widened to long as
|
||||
// unsigned here.
|
||||
hash ^= input * P1;
|
||||
hash = Long.rotateLeft(hash, 23) * P2 + P3;
|
||||
return finalize(hash);
|
||||
}
|
||||
|
||||
private static long finalize(long hash) {
|
||||
hash ^= hash >>> 33;
|
||||
hash *= P2;
|
||||
hash ^= hash >>> 29;
|
||||
hash *= P3;
|
||||
hash ^= hash >>> 32;
|
||||
return hash;
|
||||
}
|
||||
|
||||
private WrongXxHash() {}
|
||||
}
|
||||
Reference in New Issue
Block a user