Improved support for BytesMarshallable and Marshallable, closes https://github.com/OpenHFT/Chronicle-Map/issues/235

This commit is contained in:
Peter Lawrey
2020-10-15 18:22:28 +01:00
parent 3823ac1ee5
commit 25a2bfb4c5
9 changed files with 243 additions and 148 deletions
@@ -18,8 +18,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BytesMarshallableReaderWriter<V extends BytesMarshallable>
extends InstanceCreatingMarshaller<V>
implements SizedReader<V>, SizedWriter<V> {
extends CachingCreatingMarshaller<V> {
public BytesMarshallableReaderWriter(Class<V> vClass) {
super(vClass);
}
@@ -39,17 +38,7 @@ public class BytesMarshallableReaderWriter<V extends BytesMarshallable>
}
@Override
public long size(@NotNull V toWrite) {
Bytes<?> bytes = Wires.acquireBytes();
toWrite.writeMarshallable(bytes);
return bytes.readRemaining();
}
@Override
public void write(Bytes out, long size, @NotNull V toWrite) {
VanillaBytes vanillaBytes = VANILLA_BYTES_TL.get();
vanillaBytes.bytesStore(out, out.readPosition(), out.readRemaining());
vanillaBytes.writeLimit(out.writePosition() + size);
toWrite.writeMarshallable(vanillaBytes);
protected void writeToWire(Wire wire, @NotNull V toWrite) {
toWrite.writeMarshallable(wire.bytes());
}
}
@@ -0,0 +1,46 @@
package net.openhft.chronicle.hash.serialization.impl;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.hash.serialization.SizedReader;
import net.openhft.chronicle.hash.serialization.SizedWriter;
import net.openhft.chronicle.wire.*;
import org.jetbrains.annotations.NotNull;
public abstract class CachingCreatingMarshaller<V>
extends InstanceCreatingMarshaller<V>
implements SizedReader<V>, SizedWriter<V> {
static final ThreadLocal<Wire> WIRE_TL = ThreadLocal.withInitial(
() -> WireType.BINARY_LIGHT.apply(Bytes.allocateElasticOnHeap(128)));
static final ThreadLocal<Object> LAST_TL = new ThreadLocal<>();
public CachingCreatingMarshaller(Class<V> vClass) {
super(vClass);
}
@Override
public long size(@NotNull V toWrite) {
Wire wire = WIRE_TL.get();
wire.bytes().clear();
writeToWire(wire, toWrite);
LAST_TL.set(toWrite);
return wire.bytes().readRemaining();
}
protected abstract void writeToWire(Wire wire, @NotNull V toWrite);
@Override
public void write(Bytes out, long size, @NotNull V toWrite) {
if (LAST_TL.get() == toWrite) {
Wire wire = WIRE_TL.get();
if (wire.bytes().readRemaining() == size) {
out.write(wire.bytes());
wire.bytes().clear();
LAST_TL.set(null);
return;
}
}
BinaryWire wire = Wires.binaryWireForWrite(out, out.writePosition(), size);
writeToWire(wire, toWrite);
}
}
@@ -15,8 +15,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class MarshallableReaderWriter<V extends Marshallable>
extends InstanceCreatingMarshaller<V>
implements SizedReader<V>, SizedWriter<V> {
extends CachingCreatingMarshaller<V> {
public MarshallableReaderWriter(Class<V> vClass) {
super(vClass);
}
@@ -32,15 +31,7 @@ public class MarshallableReaderWriter<V extends Marshallable>
}
@Override
public long size(@NotNull V toWrite) {
Wire wire = Wires.acquireBinaryWire();
toWrite.writeMarshallable(wire);
return wire.bytes().readRemaining();
}
@Override
public void write(Bytes out, long size, @NotNull V toWrite) {
BinaryWire wire = Wires.binaryWireForWrite(out, out.writePosition(), size);
protected void writeToWire(Wire wire, @NotNull V toWrite) {
toWrite.writeMarshallable(wire);
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2016-2019 Chronicle Software Ltd
*/
package net.openhft.chronicle.hash.serialization.impl;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.hash.serialization.SizedReader;
import net.openhft.chronicle.hash.serialization.SizedWriter;
import net.openhft.chronicle.wire.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class TypedMarshallableReaderWriter<V extends Marshallable>
extends CachingCreatingMarshaller<V> {
public TypedMarshallableReaderWriter(Class<V> vClass) {
super(vClass);
}
@NotNull
@Override
public V read(Bytes in, long size, @Nullable V using) {
BinaryWire wire = Wires.binaryWireForRead(in, in.readPosition(), size);
return (V) wire.getValueIn().object(using, tClass());
}
protected void writeToWire(Wire wire, @NotNull V toWrite) {
wire.getValueOut().object(toWrite);
}
}
@@ -35,6 +35,7 @@ import net.openhft.chronicle.hash.serialization.*;
import net.openhft.chronicle.hash.serialization.impl.BytesMarshallableReaderWriter;
import net.openhft.chronicle.hash.serialization.impl.MarshallableReaderWriter;
import net.openhft.chronicle.hash.serialization.impl.SerializationBuilder;
import net.openhft.chronicle.hash.serialization.impl.TypedMarshallableReaderWriter;
import net.openhft.chronicle.map.replication.MapRemoteOperations;
import net.openhft.chronicle.set.ChronicleSetBuilder;
import net.openhft.chronicle.values.ValueModel;
@@ -49,6 +50,7 @@ import org.slf4j.LoggerFactory;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
@@ -136,7 +138,7 @@ import static net.openhft.chronicle.map.VanillaChronicleMap.alignAddr;
*/
public final class ChronicleMapBuilder<K, V> implements
ChronicleHashBuilder<K, ChronicleMap<K, V>,
ChronicleMapBuilder<K, V>> {
ChronicleMapBuilder<K, V>> {
private static final int UNDEFINED_ALIGNMENT_CONFIG = -1;
private static final int NO_ALIGNMENT = 1;
@@ -265,7 +267,10 @@ public final class ChronicleMapBuilder<K, V> implements
} else if (Marshallable.class.isAssignableFrom(valueClass)) {
//noinspection unchecked
builder.averageValueSize(1024)
.valueMarshaller(new MarshallableReaderWriter<>((Class) valueClass));
.valueMarshaller(
valueClass.isMemberClass() && Modifier.isFinal(valueClass.getModifiers())
? new MarshallableReaderWriter<>((Class) valueClass)
: new TypedMarshallableReaderWriter<>((Class) valueClass));
}
return builder;
}
@@ -274,14 +279,6 @@ public final class ChronicleMapBuilder<K, V> implements
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
private boolean isKeySizeKnown() {
return keyBuilder.sizeIsStaticallyKnown;
}
private boolean isValueSizeKnown() {
return valueBuilder.sizeIsStaticallyKnown;
}
private static void checkSegments(final long segments) {
if (segments <= 0) {
throw new IllegalArgumentException("segments should be positive, " + segments + " given");
@@ -359,7 +356,7 @@ public final class ChronicleMapBuilder<K, V> implements
}
private static void writeNotComplete(@NotNull final FileChannel fileChannel,
@NotNull final ByteBuffer headerBuffer,
@NotNull final ByteBuffer headerBuffer,
final int headerSize) throws IOException {
//noinspection PointlessBitwiseExpression
headerBuffer.putInt(SIZE_WORD_OFFSET, NOT_COMPLETE | DATA | headerSize);
@@ -462,11 +459,63 @@ public final class ChronicleMapBuilder<K, V> implements
return storedChecksum == checkSum;
}
private static boolean isDefined(final double config) {
return !isNaN(config);
}
private static long toLong(final double v) {
long l = round(v);
if (l != v)
throw new IllegalArgumentException("Integer argument expected, given " + v);
return l;
}
private static long roundUp(final double v) {
return round(Math.ceil(v));
}
private static long roundDown(final double v) {
return (long) v;
}
/**
* When Chronicle Maps are created using {@link #createPersistedTo(File)} or
* {@link #recoverPersistedTo(File, boolean)} or {@link
* #createOrRecoverPersistedTo(File, boolean)} methods, file lock on the Chronicle Map's file is
* acquired, that shouldn't be done from concurrent threads within the same JVM process. So
* creation of Chronicle Maps persisted to the same File should be synchronized across JVM's
* threads. Simple way would be to synchronize on some static (lock) object, but would serialize
* all Chronicle Maps creations (persisted to any files), ConcurrentHashMap#compute() gives more
* scalability. ConcurrentHashMap is used effectively for lock striping only, because the
* entries are not even landing the map, because compute() always returns null.
*/
private static void fileLockedIO(@NotNull final File file,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
FILE_LOCKING_CONTROL.compute(file, (k, v) -> {
try {
try (FileLock ignored = fileChannel.lock()) {
fileIOAction.fileIOAction();
}
return null;
} catch (IOException e) {
throw Jvm.rethrow(e);
}
});
}
private boolean isKeySizeKnown() {
return keyBuilder.sizeIsStaticallyKnown;
}
private boolean isValueSizeKnown() {
return valueBuilder.sizeIsStaticallyKnown;
}
@Override
public ChronicleMapBuilder<K, V> clone() {
try {
@SuppressWarnings("unchecked")
final ChronicleMapBuilder<K, V> result = (ChronicleMapBuilder<K, V>) super.clone();
@SuppressWarnings("unchecked") final ChronicleMapBuilder<K, V> result = (ChronicleMapBuilder<K, V>) super.clone();
result.keyBuilder = keyBuilder.clone();
result.valueBuilder = valueBuilder.clone();
result.privateAPI = new ChronicleMapBuilderPrivateAPI<>(result);
@@ -649,7 +698,7 @@ public final class ChronicleMapBuilder<K, V> implements
public ChronicleMapBuilder<K, V> averageValue(@NotNull final V averageValue) {
final Class<?> valueClass = averageValue.getClass();
if (BytesMarshallable.class.isAssignableFrom(valueClass) &&
valueBuilder.tClass.isInterface()) {
(valueBuilder.tClass.isInterface() && valueBuilder.tClass != Marshallable.class)) {
if (Serializable.class.isAssignableFrom(valueClass))
LOG.warn("BytesMarshallable " + valueClass + " will be serialized as Serializable as the value class is an interface");
else
@@ -1568,7 +1617,7 @@ public final class ChronicleMapBuilder<K, V> implements
}
@Override
public ChronicleMap<K, V> recoverPersistedTo(@NotNull final File file, final boolean sameBuilderConfigAndLibraryVersion) throws IOException {
public ChronicleMap<K, V> recoverPersistedTo(@NotNull final File file, final boolean sameBuilderConfigAndLibraryVersion) throws IOException {
return recoverPersistedTo(file, sameBuilderConfigAndLibraryVersion,
DEFAULT_CHRONICLE_MAP_CORRUPTION_LISTENER);
}
@@ -1576,7 +1625,7 @@ public final class ChronicleMapBuilder<K, V> implements
@Override
public ChronicleMap<K, V> recoverPersistedTo(@NotNull final File file,
final boolean sameBuilderConfigAndLibraryVersion,
@Nullable final ChronicleHashCorruption.Listener corruptionListener) throws IOException {
@Nullable final ChronicleHashCorruption.Listener corruptionListener) throws IOException {
return clone().createWithFile(file, true, sameBuilderConfigAndLibraryVersion, corruptionListener);
}
@@ -1791,7 +1840,7 @@ public final class ChronicleMapBuilder<K, V> implements
@NotNull final ChronicleHashResources resources,
final boolean recover,
final boolean overrideBuilderConfig,
@Nullable final ChronicleHashCorruption.Listener corruptionListener) throws IOException {
@Nullable final ChronicleHashCorruption.Listener corruptionListener) throws IOException {
final ChronicleHashCorruptionImpl corruption = recover ? new ChronicleHashCorruptionImpl() : null;
try {
int headerSize = waitUntilReady(raf, file, recover);
@@ -1967,49 +2016,4 @@ public final class ChronicleMapBuilder<K, V> implements
}
}
private static boolean isDefined(final double config) {
return !isNaN(config);
}
private static long toLong(final double v) {
long l = round(v);
if (l != v)
throw new IllegalArgumentException("Integer argument expected, given " + v);
return l;
}
private static long roundUp(final double v) {
return round(Math.ceil(v));
}
private static long roundDown(final double v) {
return (long) v;
}
/**
* When Chronicle Maps are created using {@link #createPersistedTo(File)} or
* {@link #recoverPersistedTo(File, boolean)} or {@link
* #createOrRecoverPersistedTo(File, boolean)} methods, file lock on the Chronicle Map's file is
* acquired, that shouldn't be done from concurrent threads within the same JVM process. So
* creation of Chronicle Maps persisted to the same File should be synchronized across JVM's
* threads. Simple way would be to synchronize on some static (lock) object, but would serialize
* all Chronicle Maps creations (persisted to any files), ConcurrentHashMap#compute() gives more
* scalability. ConcurrentHashMap is used effectively for lock striping only, because the
* entries are not even landing the map, because compute() always returns null.
*/
private static void fileLockedIO(@NotNull final File file,
@NotNull final FileChannel fileChannel,
@NotNull final FileIOAction fileIOAction) {
FILE_LOCKING_CONTROL.compute(file, (k, v) -> {
try {
try (FileLock ignored = fileChannel.lock()) {
fileIOAction.fileIOAction();
}
return null;
} catch (IOException e) {
throw Jvm.rethrow(e);
}
});
}
}
@@ -16,6 +16,8 @@
package net.openhft.chronicle.map;
import net.openhft.chronicle.hash.serialization.impl.TypedMarshallableReaderWriter;
import net.openhft.chronicle.wire.Marshallable;
import net.openhft.chronicle.wire.SelfDescribingMarshallable;
import org.junit.Test;
@@ -34,6 +36,19 @@ public final class AbstractMarshallableKeyValueTest {
assertThat(map.get(new Key()).number, is(new Value().number));
}
@Test
public void shouldAcceptAbstractMarshallableComponents2() throws Exception {
final ChronicleMap<Key, Marshallable> map = ChronicleMapBuilder.of(Key.class, Marshallable.class).entries(10)
.averageKey(new Key()).averageValue(new Value())
.valueMarshaller(new TypedMarshallableReaderWriter<>(Marshallable.class))
.create();
map.put(new Key(), new Value());
Value value = (Value) map.get(new Key());
assertThat(value.number, is(new Value().number));
}
private static final class Key extends SelfDescribingMarshallable {
private String k = "key";
}
@@ -468,7 +468,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.get(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -481,7 +481,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -494,7 +494,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -507,7 +507,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.put(JSR166TestCase.notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -520,7 +520,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.putIfAbsent(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -568,7 +568,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.replace(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -581,7 +581,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.replace(null, "A", "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -593,7 +593,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString(5);
c.containsValue(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}*/
@@ -606,7 +606,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString(5);
c.contains(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
*/
@@ -620,7 +620,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.putIfAbsent(JSR166TestCase.notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -633,7 +633,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.replace(JSR166TestCase.notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -646,7 +646,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.replace(JSR166TestCase.notPresent, null, "A");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -659,7 +659,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
ChronicleMap c = newShmIntString();
c.replace(JSR166TestCase.notPresent, "A", null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -673,7 +673,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
c.put("sadsdf", "asdads");
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -687,7 +687,7 @@ public class ReplicatedChronicleMapTest extends JSR166TestCase {
c.put("sadsdf", "asdads");
c.remove(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException|IllegalArgumentException success) {
}
}
@@ -1,6 +1,7 @@
package net.openhft.chronicle.map;
import net.openhft.chronicle.wire.BytesInBinaryMarshallable;
import net.openhft.chronicle.wire.Marshallable;
import net.openhft.chronicle.wire.SelfDescribingMarshallable;
import org.junit.Test;
@@ -94,6 +95,26 @@ public class SerializableTest {
assertEquals(expected, actual);
}
@Test
public void test2d() {
ChronicleMap<Integer, Marshallable> map = ChronicleMapBuilder.simpleMapOf(Integer.class, Marshallable.class)
.name("bar")
.averageValueSize(1024)
.entries(10)
.create();
String expected = IntStream.range(0, 4096)
.mapToObj(i -> i % 50 == 0 ? String.format("\n%04d", i) : "" + i % 10)
.collect(Collectors.joining(""));
Bar2 value = new Bar2(expected);
map.put(1, value);
Bar2 bar2 = (Bar2) map.get(1);
String actual = bar2.x;
assertEquals(expected, actual);
}
public static class Foo implements Serializable {
public String x;
@@ -420,7 +420,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.get(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -432,7 +432,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.containsKey(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -444,7 +444,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.put(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -457,7 +457,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.put(notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -470,7 +470,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.putIfAbsent(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -483,7 +483,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.replace(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -496,7 +496,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.replace(null, "A", "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -508,7 +508,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.putIfAbsent(notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -520,7 +520,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.replace(notPresent, null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -528,12 +528,11 @@ public class ChronicleMapTest extends JSR166TestCase {
* replace(x, null, y) throws NPE
*/
@Test(timeout = 5000)
public void testReplaceValue2_NullPointerException
() throws IOException {
public void testReplaceValue2_NullPointerException() throws IOException {
try (ChronicleMap c = newShmIntString(8076)) {
c.replace(notPresent, null, "A");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -545,7 +544,7 @@ public class ChronicleMapTest extends JSR166TestCase {
try (ChronicleMap c = newShmIntString(8076)) {
c.replace(notPresent, "A", null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -558,7 +557,7 @@ public class ChronicleMapTest extends JSR166TestCase {
c.put("sadsdf", "asdads");
c.remove(null);
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -572,7 +571,7 @@ public class ChronicleMapTest extends JSR166TestCase {
c.put("sadsdf", "asdads");
c.remove(null, "whatever");
shouldThrow();
} catch (NullPointerException success) {
} catch (NullPointerException | IllegalArgumentException success) {
}
}
@@ -588,6 +587,37 @@ public class ChronicleMapTest extends JSR166TestCase {
}
}
@Test
public void testPercentageComplete() {
try (ChronicleMap<Integer, Integer> map = ChronicleMap
.of(Integer.class, Integer.class)
.entries(1600)
.actualSegments(3)
.maxBloatFactor(2)
.create()) {
long remainingAutoResizes = 0;
short percentageFreeSpace = 0;
try {
for (int i = 0; ; i++) {
map.put(i, 0);
remainingAutoResizes = map.remainingAutoResizes();
percentageFreeSpace = map.percentageFreeSpace();
}
} catch (IllegalStateException e) {
if (e.getMessage().contains("Attempt to allocate")) {
Assert.assertEquals(0, (int) remainingAutoResizes);
Assert.assertTrue(percentageFreeSpace < 6);
return;
}
Assert.fail();
}
}
}
// classes for testing Comparable fallbacks
static class BI implements Comparable<BI> {
private final int value;
@@ -671,36 +701,5 @@ public class ChronicleMapTest extends JSR166TestCase {
}
}
@Test
public void testPercentageComplete() {
try (ChronicleMap<Integer, Integer> map = ChronicleMap
.of(Integer.class, Integer.class)
.entries(1600)
.actualSegments(3)
.maxBloatFactor(2)
.create()) {
long remainingAutoResizes = 0;
short percentageFreeSpace = 0;
try {
for (int i = 0; ; i++) {
map.put(i, 0);
remainingAutoResizes = map.remainingAutoResizes();
percentageFreeSpace = map.percentageFreeSpace();
}
} catch (IllegalStateException e) {
if (e.getMessage().contains("Attempt to allocate")) {
Assert.assertEquals(0, (int) remainingAutoResizes);
Assert.assertTrue(percentageFreeSpace < 6);
return;
}
Assert.fail();
}
}
}
}