From ba8227ade1ce8f39088c6a394f4edcb8d15cb1e6 Mon Sep 17 00:00:00 2001 From: leventov Date: Fri, 5 Aug 2016 23:22:51 +0700 Subject: [PATCH] Use more specific ChronicleHashClosedException instead of IllegalStateException, when methods of ChronicleHash are called after hash.close(). Actualize ChronicleHash.close() javadoc. --- .../openhft/chronicle/hash/ChronicleHash.java | 7 ++-- .../hash/ChronicleHashClosedException.java | 29 ++++++++++++++++ .../hash/impl/VanillaChronicleHash.java | 2 +- .../impl/stage/hash/ThreadLocalState.java | 3 +- .../openhft/chronicle/map/MapCloseTest.java | 33 +++++++++++++++++++ 5 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 src/main/java/net/openhft/chronicle/hash/ChronicleHashClosedException.java diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java index e46bc9892..a985866b7 100644 --- a/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHash.java @@ -165,9 +165,10 @@ public interface ChronicleHash, SC extends HashSegment * collection. This could be a problem if, for example, you target rare garbage collections, * but load and drop {@code ChronicleHash}es regularly. * - *

After this method call behaviour of all methods of {@code ChronicleMap} - * or {@code ChronicleSet} is undefined. Any method call on the map might throw - * any exception, or even JVM crash. Shortly speaking, don't call use map closing. + *

After this method call, all methods, querying the {@code ChronicleHash}'s entries, {@link + * #longSize()} and {@code size()}), throw {@link ChronicleHashClosedException}. {@link + * #isOpen()} returns {@code false}, {@code close()} itself returns immediately without effects + * (i. e. repetitive {@code close()}, even from concurrent threads, are safe). */ @Override void close(); diff --git a/src/main/java/net/openhft/chronicle/hash/ChronicleHashClosedException.java b/src/main/java/net/openhft/chronicle/hash/ChronicleHashClosedException.java new file mode 100644 index 000000000..c80e01694 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/hash/ChronicleHashClosedException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012, 2016 higherfrequencytrading.com + * 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 . + */ + +package net.openhft.chronicle.hash; + +/** + * Thrown when a {@link ChronicleHash} is accessed after {@link ChronicleHash#close()}. + */ +public final class ChronicleHashClosedException extends IllegalStateException { + private static final long serialVersionUID = 0L; + + public ChronicleHashClosedException() { + super("Access to ChronicleHash after close()"); + } +} diff --git a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java index 5e3bb0536..d5eaed471 100644 --- a/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java +++ b/src/main/java/net/openhft/chronicle/hash/impl/VanillaChronicleHash.java @@ -1002,7 +1002,7 @@ public abstract class VanillaChronicleHash map = + ChronicleMap.of(Integer.class, Integer.class).entries(1).create(); + Thread t = new Thread(() -> map.close()); + t.start(); + t.join(); + map.get(1); + } + + @Test(expected = ChronicleHashClosedException.class) + public void testIterationAfterCloseThrowsChronicleHashClosedException() + throws InterruptedException { + ChronicleMap map = + ChronicleMap.of(Integer.class, Integer.class).entries(1).create(); + Thread t = new Thread(() -> map.close()); + t.start(); + t.join(); + map.forEach((k, v) -> {}); + } + + @Test(expected = ChronicleHashClosedException.class) + public void testSizeAfterCloseThrowsChronicleHashClosedException() + throws InterruptedException { + ChronicleMap map = + ChronicleMap.of(Integer.class, Integer.class).entries(1).create(); + Thread t = new Thread(() -> map.close()); + t.start(); + t.join(); + map.size(); + } + @Test(expected = RuntimeException.class) public void closeWithContextInAnotherThreadTest() throws InterruptedException { ChronicleMap map =