diff --git a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java index 0706395e4..616b53ad5 100755 --- a/src/main/java/net/openhft/chronicle/map/ChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/ChronicleMap.java @@ -204,17 +204,33 @@ public interface ChronicleMap extends ConcurrentMap, ChronicleHash { */ R updateForKey(K key, @NotNull Mutator mutator); - /** * Returns a {@link java.util.concurrent.Future} containing the value to which the specified key is * mapped, or {@code null} if this map contains no mapping for the key. This method behaves the same as * {@link java.util.Map#get(java.lang.Object)} yet wraps result in a future a {@link * java.util.concurrent.Future}. * + * @return a future containing the value to which the specified key is mapped after this method call, or + * {@code null} if no value is mapped * @see java.util.Map#get(java.lang.Object) * @see java.util.concurrent.Future */ - Future getLater(K key); + Future getLater(@NotNull K key); + + + /** + * Associates the specified value with the specified key in this map (optional operation). If the map + * previously contained a mapping for the key, the old value is replaced by the specified value. (A map + * m is said to contain a mapping for a key k if and only if {@link #containsKey(Object) + * m.containsKey(k)} would return true.) + * + * @return a future containing the previous value associated with key, or null if there + * was no mapping for key. (A null return can also indicate that the map previously + * associated null with key, if the implementation supports null values.) + * @see java.util.Map#get(java.lang.Object) + * @see java.util.concurrent.Future + */ + Future putLater(@NotNull K key,@NotNull V value); } diff --git a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java index 19e5f0425..e53e32216 100644 --- a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMap.java @@ -40,8 +40,10 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon private final AbstractChronicleMapBuilder chronicleMapBuilder; private final StatelessMapConfig builder; - ChronicleMap statelessClient; + private final ChronicleMap statelessClient; + private ChronicleMap asyncStatelessClient; + private ExecutorService executorService; public StatelessChronicleMap(final StatelessMapConfig builder, final AbstractChronicleMapBuilder chronicleMapBuilder) throws IOException { @@ -53,7 +55,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon @Override - public synchronized Future getLater(final K key) { + public Future getLater(@NotNull final K key) { return lazyExecutorService().submit(new Callable() { @Override public V call() throws Exception { @@ -62,7 +64,16 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon }); } - private ExecutorService executorService = null; + @Override + public Future putLater(@NotNull final K key, @NotNull final V value) { + return lazyExecutorService().submit(new Callable() { + @Override + public V call() throws Exception { + return lazyAsyncStatelessClient().put(key, value); + } + }); + } + private ExecutorService lazyExecutorService() { @@ -79,8 +90,6 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon } - private ChronicleMap asyncStatelessClient; - /** * @return a lazily created instance of the StatelessClient used for the async calls. */ @@ -90,7 +99,7 @@ class StatelessChronicleMap implements ChronicleMap, Closeable, Clon synchronized (this) { if (asyncStatelessClient == null) try { - asyncStatelessClient = new StatelessChronicleMapUnsynchronized(builder, + asyncStatelessClient = new StatelessChronicleMapUnsynchronized(builder, chronicleMapBuilder); } catch (IOException e) { throw new RuntimeException(e); diff --git a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMapUnsynchronized.java b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMapUnsynchronized.java index ec777eaab..a6da4ee41 100644 --- a/src/main/java/net/openhft/chronicle/map/StatelessChronicleMapUnsynchronized.java +++ b/src/main/java/net/openhft/chronicle/map/StatelessChronicleMapUnsynchronized.java @@ -497,7 +497,12 @@ class StatelessChronicleMapUnsynchronized implements ChronicleMap, C } @Override - public Future getLater(K key) { + public Future getLater(@NotNull K key) { + throw new UnsupportedOperationException(); + } + + @Override + public Future putLater(@NotNull K key, @NotNull V value) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java index 8e3430210..aff8d7053 100755 --- a/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java +++ b/src/main/java/net/openhft/chronicle/map/VanillaChronicleMap.java @@ -385,7 +385,7 @@ class VanillaChronicleMap, } @Override - public Future getLater(K key) { + public Future getLater(@NotNull K key) { final V v = get(key); return new Future() { @@ -416,6 +416,38 @@ class VanillaChronicleMap, }; } + @Override + public Future putLater(@NotNull K key, @NotNull V value) { + final V v = put(key, value); + return new Future() { + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public V get() throws InterruptedException, ExecutionException { + return v; + } + + @Override + public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return v; + } + }; + } + @NotNull @Override public WriteContext acquireUsingLocked(@NotNull K key, @NotNull V usingValue) { diff --git a/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java b/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java index 4dee5e4d8..3e267c142 100644 --- a/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java +++ b/src/test/java/net/openhft/chronicle/map/ReplicationCheckingMap.java @@ -256,7 +256,12 @@ public class ReplicationCheckingMap implements ChronicleMap { } @Override - public Future getLater(K key) { + public Future getLater(@NotNull K key) { + throw new UnsupportedOperationException(); + } + + @Override + public Future putLater(@NotNull K key, @NotNull V value) { throw new UnsupportedOperationException(); } diff --git a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java index b0e40e03b..249fb3c3b 100644 --- a/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java +++ b/src/test/java/net/openhft/chronicle/map/StatelessClientTest.java @@ -418,10 +418,7 @@ public class StatelessClientTest { statelessMap.remove(1); - Assert.assertEquals(null, statelessMap.getLater(1).get()); - - Assert.assertEquals(0, statelessMap.size()); } @@ -430,6 +427,27 @@ public class StatelessClientTest { } + @Test + public void testPutLater() throws IOException, + InterruptedException, ExecutionException { + + try (ChronicleMap serverMap = ChronicleMapBuilder.of(Integer.class, CharSequence.class) + .replication((byte) 2, TcpTransportAndNetworkConfig.of(8056)).create()) { + + try (ChronicleMap statelessMap = ChronicleMapBuilder.of(Integer + .class, CharSequence.class) + .statelessClient(new InetSocketAddress("localhost", 8056)).create()) { + + CharSequence oldValue = statelessMap.putLater(1, "some value").get(); + Assert.assertEquals("some value", statelessMap.get(1)); + Assert.assertEquals(1, statelessMap.size()); + + } + } + + } + + @Test public void testEquals() throws IOException, InterruptedException { diff --git a/src/test/java/net/openhft/chronicle/map/jrs166/map/StatelessChronicleMapTest.java b/src/test/java/net/openhft/chronicle/map/jrs166/map/StatelessChronicleMapTest.java index 4219bf767..5c181ec4b 100755 --- a/src/test/java/net/openhft/chronicle/map/jrs166/map/StatelessChronicleMapTest.java +++ b/src/test/java/net/openhft/chronicle/map/jrs166/map/StatelessChronicleMapTest.java @@ -178,10 +178,15 @@ public class StatelessChronicleMapTest extends JSR166TestCase { } @Override - public Future getLater(K key) { + public Future getLater(@NotNull K key) { return d.getLater(key); } + @Override + public Future putLater(@NotNull K key, @NotNull V value) { + return d.putLater(key, value); + } + @Override public V putIfAbsent(K key, V value) { return d.putIfAbsent(key, value);