improvement to map (#266) and (#265)

* added AbstractClosable

* added Jvm.init()

* added disable.thread.safety

* ignore thread safety check

* disabled threadSafetyCheck for chronicle map

* removed init()

* changed isOpen() to be !isClosed()

* throwExceptionIfClosed() now creates a new ChronicleHashClosedException()

* added  test testRemainingAutoResizesAfterClose

Co-authored-by: Rob Austin <rob.austin@boundedbuffer.co.uk>
This commit is contained in:
Rob Austin
2021-01-27 18:23:07 +00:00
committed by GitHub
co-authored by Rob Austin
parent f921c40819
commit addfc1481f
4 changed files with 49 additions and 14 deletions
@@ -16,10 +16,12 @@
package net.openhft.chronicle.hash;
import net.openhft.chronicle.core.io.ClosedIllegalStateException;
/**
* Thrown when a {@link ChronicleHash} is accessed after {@link ChronicleHash#close()}.
*/
public final class ChronicleHashClosedException extends IllegalStateException {
public final class ChronicleHashClosedException extends ClosedIllegalStateException {
private static final long serialVersionUID = 0L;
public ChronicleHashClosedException(ChronicleHash hash) {
@@ -29,4 +31,8 @@ public final class ChronicleHashClosedException extends IllegalStateException {
public ChronicleHashClosedException(String chronicleHashIdentityString) {
super("Access to " + chronicleHashIdentityString + " after close()");
}
public ChronicleHashClosedException(String s, Throwable t) {
super(s, t);
}
}
@@ -20,8 +20,10 @@ import net.openhft.chronicle.algo.locks.*;
import net.openhft.chronicle.bytes.BytesStore;
import net.openhft.chronicle.bytes.MappedBytesStoreFactory;
import net.openhft.chronicle.bytes.NativeBytesStore;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.Maths;
import net.openhft.chronicle.core.OS;
import net.openhft.chronicle.core.io.AbstractCloseable;
import net.openhft.chronicle.core.io.ReferenceOwner;
import net.openhft.chronicle.hash.*;
import net.openhft.chronicle.hash.impl.util.BuildVersion;
@@ -69,7 +71,7 @@ import static net.openhft.chronicle.map.ChronicleHashCorruptionImpl.report;
public abstract class VanillaChronicleHash<K,
C extends HashEntry<K>, SC extends HashSegmentContext<K, ?>,
ECQ extends ExternalHashQueryContext<K>>
ECQ extends ExternalHashQueryContext<K>> extends AbstractCloseable
implements ChronicleHash<K, C, SC, ECQ>, Marshallable {
public static final long TIER_COUNTERS_AREA_SIZE = 64;
@@ -680,7 +682,13 @@ public abstract class VanillaChronicleHash<K,
}
@Override
public final void close() {
protected boolean threadSafetyCheck(boolean isUsed) {
// disabled for chronicle map
return true;
}
@Override
protected void performClose() {
if (resources != null && resources.releaseManually()) {
cleanupOnClose();
}
@@ -698,11 +706,14 @@ public abstract class VanillaChronicleHash<K,
keyDataAccess = null;
}
/**
* @return !isClosed()
* @Deprecated use !isClosed() instead
*/
@Deprecated(/*remove in x.23*/)
@Override
public boolean isOpen() {
throwExceptionIfClosed();
return !resources.closed();
return !isClosed();
}
public final void checkKey(final Object key) {
@@ -715,6 +726,12 @@ public abstract class VanillaChronicleHash<K,
}
}
@Override
public void throwExceptionIfClosed() throws IllegalStateException {
if (this.isClosed())
throw new ChronicleHashClosedException(this.getClass().getName() + " closed", Jvm.getValue(this, "closedHere"));
}
public final long segmentHeaderAddress(final int segmentIndex) {
return bsAddress() + segmentHeadersOffset + ((long) segmentIndex) * segmentHeaderSize;
}
@@ -16,8 +16,10 @@
package net.openhft.chronicle.map;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.hash.Data;
import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import java.util.Map;
@@ -27,6 +29,7 @@ import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.BiFunction;
import static net.openhft.chronicle.core.Jvm.*;
import static net.openhft.chronicle.hash.Data.bytesEquivalent;
import static net.openhft.chronicle.map.BiMapTest.DualLockSuccess.FAIL;
import static net.openhft.chronicle.map.BiMapTest.DualLockSuccess.SUCCESS;
@@ -25,13 +25,14 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import static net.openhft.chronicle.hash.impl.BigSegmentHeader.LOCK_TIMEOUT_SECONDS;
import static net.openhft.chronicle.map.ChronicleMap.of;
public class MapCloseTest {
@Test(expected = IllegalStateException.class)
@Test
public void closeInContextTest() {
ChronicleMap<Integer, Integer> map =
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
ExternalMapQueryContext<Integer, Integer, ?> cxt = map.queryContext(1);
map.close();
}
@@ -39,7 +40,7 @@ public class MapCloseTest {
@Test(expected = ChronicleHashClosedException.class)
public void testGetAfterCloseThrowsChronicleHashClosedException() throws InterruptedException {
ChronicleMap<Integer, Integer> map =
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
Thread t = new Thread(() -> map.close());
t.start();
t.join();
@@ -50,7 +51,7 @@ public class MapCloseTest {
public void testIterationAfterCloseThrowsChronicleHashClosedException()
throws InterruptedException {
ChronicleMap<Integer, Integer> map =
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
Thread t = new Thread(() -> map.close());
t.start();
t.join();
@@ -62,18 +63,18 @@ public class MapCloseTest {
public void testSizeAfterCloseThrowsChronicleHashClosedException()
throws InterruptedException {
ChronicleMap<Integer, Integer> map =
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
Thread t = new Thread(() -> map.close());
t.start();
t.join();
map.size();
}
@Test(expected = RuntimeException.class)
@Test
public void closeWithContextInAnotherThreadTest() throws InterruptedException {
LOCK_TIMEOUT_SECONDS = 2;
ChronicleMap<Integer, Integer> map =
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
Object lock = new Object();
CountDownLatch latch = new CountDownLatch(1);
synchronized (lock) {
@@ -93,11 +94,19 @@ public class MapCloseTest {
LOCK_TIMEOUT_SECONDS = 60;
}
@Test(expected = ChronicleHashClosedException.class)
public void testRemainingAutoResizesAfterClose() {
ChronicleMap<Integer, Integer> map = of(Integer.class, Integer.class).entries(1).create();
map.close();
map.remainingAutoResizes();
}
@Test
public void vanillaChronicleHashAllContextsExpungeTest() throws InterruptedException {
VanillaChronicleMap<Integer, Integer, Void> map =
(VanillaChronicleMap<Integer, Integer, Void>)
ChronicleMap.of(Integer.class, Integer.class).entries(1).create();
of(Integer.class, Integer.class).entries(1).create();
Semaphore semaphore = new Semaphore(0);
CountDownLatch latch = new CountDownLatch(2);
class MapAccessThread extends Thread {