From 2e0795bb83761933c5616dae8800243104acbec6 Mon Sep 17 00:00:00 2001 From: Narek Karapetian Date: Thu, 27 Jul 2017 17:27:08 +0300 Subject: [PATCH 1/2] Done --- .../part2/cache/CachingDataStorageImpl.java | 59 +++++++++++++++--- .../cache/CachingDataStorageImplTest.java | 62 ++++++++++++++++++- 2 files changed, 112 insertions(+), 9 deletions(-) diff --git a/src/main/java/part2/cache/CachingDataStorageImpl.java b/src/main/java/part2/cache/CachingDataStorageImpl.java index a2ae460..2bca3e2 100755 --- a/src/main/java/part2/cache/CachingDataStorageImpl.java +++ b/src/main/java/part2/cache/CachingDataStorageImpl.java @@ -32,12 +32,55 @@ public CachingDataStorageImpl(DataStorage db, int timeout, TimeUnit t @Override public OutdatableResult getOutdatable(String key) { - // TODO implement - // TODO use ScheduledExecutorService to remove outdated result from cache - see SlowCompletableFutureDb implementation - // TODO complete OutdatableResult::outdated after removing outdated result from cache - // TODO don't use obtrudeException on result - just don't - // TODO use remove(Object key, Object value) to remove target value - // TODO Start timeout after receiving result in CompletableFuture, not after receiving CompletableFuture itself - throw new UnsupportedOperationException(); + final OutdatableResult result = + new OutdatableResult<>(new CompletableFuture<>(), new CompletableFuture<>()); + final OutdatableResult previous = cache.putIfAbsent(key, result); + + if (previous != null) { + return previous; + } + + db.get(key).whenComplete((value, throwable) -> { + + if (throwable != null) { + result.getResult().completeExceptionally(throwable); + } else { + result.getResult().complete(value); + } + + scheduledExecutorService.schedule( + () -> { + cache.remove(key, result); + result.getOutdated().complete(null); + }, + timeout, + timeoutUnits + ); + + }); + + return result; + } + + + + + + + + + + + + public static void main(String[] args) { + + ConcurrentMap cache = new ConcurrentHashMap<>(); + + Integer integer = cache.putIfAbsent(1, 11); + Integer integer2 = cache.putIfAbsent(1, 11); + + System.out.println(integer); // null + System.out.println(integer2); + } -} +} \ No newline at end of file diff --git a/src/test/java/part2/cache/CachingDataStorageImplTest.java b/src/test/java/part2/cache/CachingDataStorageImplTest.java index 041370d..4a44e09 100755 --- a/src/test/java/part2/cache/CachingDataStorageImplTest.java +++ b/src/test/java/part2/cache/CachingDataStorageImplTest.java @@ -55,7 +55,7 @@ public static void after() { } @Test - public void expiration() throws InterruptedException, ExecutionException, TimeoutException { + public void expirationEmployee() throws InterruptedException, ExecutionException, TimeoutException { final CachingDataStorageImpl employeeCache = new CachingDataStorageImpl<>(employeeDb, 100, TimeUnit.MILLISECONDS); @@ -84,4 +84,64 @@ public void expiration() throws InterruptedException, ExecutionException, Timeou assertEquals(person2, result3.getResult().get().getPerson()); } + @Test + public void expirationEmployer() throws InterruptedException, ExecutionException, TimeoutException { + final CachingDataStorageImpl employerCache = + new CachingDataStorageImpl<>(employerDb, 100, TimeUnit.MILLISECONDS); + + Map values = new HashMap<>(); + Employer google = Employer.Google; + values.put("a", google); + employerDb.setValues(values); + + final OutdatableResult result1 = employerCache.getOutdatable("a"); + + values = new HashMap<>(); + Employer yandex = Employer.Yandex; + values.put("a", yandex); + employerDb.setValues(values); + + Thread.sleep(10); + final OutdatableResult result2 = employerCache.getOutdatable("a"); + + assertEquals(google, result1.getResult().get()); + assertEquals(result1.getResult().get(), result2.getResult().get()); + + result1.getOutdated().get(100, TimeUnit.MILLISECONDS); + + OutdatableResult result3 = employerCache.getOutdatable("a"); + + assertEquals(yandex, result3.getResult().get()); + } + + @Test + public void expirationPosition() throws InterruptedException, ExecutionException, TimeoutException { + final CachingDataStorageImpl employerCache = + new CachingDataStorageImpl<>(positionDb, 100, TimeUnit.MILLISECONDS); + + Map values = new HashMap<>(); + Position dev = Position.DEV; + values.put("a", dev); + positionDb.setValues(values); + + final OutdatableResult result1 = employerCache.getOutdatable("a"); + + values = new HashMap<>(); + Position devOps = Position.DevOps; + values.put("a", devOps); + positionDb.setValues(values); + + Thread.sleep(10); + final OutdatableResult result2 = employerCache.getOutdatable("a"); + + assertEquals(dev, result1.getResult().get()); + assertEquals(result1.getResult().get(), result2.getResult().get()); + + result1.getOutdated().get(100, TimeUnit.MILLISECONDS); + + OutdatableResult result3 = employerCache.getOutdatable("a"); + + assertEquals(devOps, result3.getResult().get()); + } + } From 55b31cd2cf960a208d44909136f076a847a9e46a Mon Sep 17 00:00:00 2001 From: Narek Karapetian Date: Thu, 27 Jul 2017 17:29:47 +0300 Subject: [PATCH 2/2] Little fixes --- .../part2/cache/CachingDataStorageImpl.java | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/main/java/part2/cache/CachingDataStorageImpl.java b/src/main/java/part2/cache/CachingDataStorageImpl.java index 2bca3e2..8abac84 100755 --- a/src/main/java/part2/cache/CachingDataStorageImpl.java +++ b/src/main/java/part2/cache/CachingDataStorageImpl.java @@ -1,7 +1,6 @@ package part2.cache; import db.DataStorage; -import db.SlowCompletableFutureDb; import java.util.concurrent.*; @@ -10,7 +9,7 @@ public class CachingDataStorageImpl implements CachingDataStorage private final DataStorage db; private final int timeout; private final TimeUnit timeoutUnits; - // TODO can we use Map here? Why? + // TODO can we use Map here? Why? - cause we write for a multithreading app private final ConcurrentMap> cache = new ConcurrentHashMap<>(); private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { @@ -62,25 +61,4 @@ public OutdatableResult getOutdatable(String key) { return result; } - - - - - - - - - - - public static void main(String[] args) { - - ConcurrentMap cache = new ConcurrentHashMap<>(); - - Integer integer = cache.putIfAbsent(1, 11); - Integer integer2 = cache.putIfAbsent(1, 11); - - System.out.println(integer); // null - System.out.println(integer2); - - } } \ No newline at end of file