cache

added population monitoring. replaced invalidation analysis

10/17/2020 10:05:47 PM

Details

diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/CachePerformance.java b/src/main/java/br/ufrgs/inf/prosoft/cache/CachePerformance.java
index cf0e9ed..887c7af 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/CachePerformance.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/CachePerformance.java
@@ -69,8 +69,6 @@ public class CachePerformance {
                 this.invalidations++;
                 this.bytesInvalidated += size;
                 break;
-            default:
-                throw new AssertionError(type.name());
         }
         CacheEvent cacheEvent = new CacheEvent(type, this.name, identifier, size);
         logCacheEvent(cacheEvent);
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/Caffeine.java b/src/main/java/br/ufrgs/inf/prosoft/cache/Caffeine.java
index 9f2c229..279ae7b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/Caffeine.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/Caffeine.java
@@ -6,11 +6,15 @@
 package br.ufrgs.inf.prosoft.cache;
 
 import com.github.benmanes.caffeine.cache.Expiry;
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
 
@@ -20,13 +24,14 @@ import java.util.stream.Collectors;
  * @param <K>
  * @param <V>
  */
-public class Caffeine<K, V> implements Cache<K, V> {
+public class Caffeine<K, V> implements Cache<K, V>, AutoCloseable {
 
     private static final boolean CACHE_EVALUATE_PERFORMANCE = System.getenv("CACHE_EVENTS") == null || !System.getenv("CACHE_EVENTS").equals("false");
     private static final boolean CACHE_REGISTER_SIZE = System.getenv("CACHE_REGISTER_SIZE") != null && System.getenv("CACHE_REGISTER_SIZE").equals("true");
     private final com.github.benmanes.caffeine.cache.Cache<Optional<K>, Optional<V>> cache;
     private final ConcurrentHashMap<Optional<K>, Long> keyHasTTL;
     private final CachePerformance cachePerformance;
+    private final ScheduledExecutorService sizeMonitor;
 
     public Caffeine() {
         this(new CachePerformance());
@@ -94,6 +99,22 @@ public class Caffeine<K, V> implements Cache<K, V> {
             registerEvent(EventType.INVALIDATION, v.orElse(null));
         });
         this.cache = builder.build();
+
+        this.sizeMonitor = Executors.newScheduledThreadPool(0);
+        if (Caffeine.CACHE_EVALUATE_PERFORMANCE) {
+            this.sizeMonitor.scheduleAtFixedRate(() -> {
+                this.cachePerformance.registerEvent(EventType.POPULATION, String.valueOf(size()));
+            }, 0, 1, TimeUnit.SECONDS);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException ex) {
+        }
+        this.sizeMonitor.shutdown();
     }
 
     public CachePerformance getCachePerformance() {
@@ -153,18 +174,18 @@ public class Caffeine<K, V> implements Cache<K, V> {
     }
 
     public int size() {
-        return values().size();
+        return this.cache.asMap().size();
     }
 
     public boolean isEmpty() {
-        return values().isEmpty();
+        return this.cache.asMap().isEmpty();
     }
 
     private String getIdentifier(Object object) {
         return object != null ? String.valueOf(object.hashCode()) : "null";
     }
 
-    protected void registerEvent(EventType eventType, Object object) {
+    private void registerEvent(EventType eventType, Object object) {
         if (!CACHE_EVALUATE_PERFORMANCE) {
             return;
         }
@@ -175,7 +196,7 @@ public class Caffeine<K, V> implements Cache<K, V> {
             this.cachePerformance.registerEvent(eventType, identifier);
         }
         if (eventType.equals(EventType.ADDITION)) {
-            this.cachePerformance.registerSize((int) this.cache.stats().loadCount());
+            this.cachePerformance.registerSize(size());
         }
     }
 
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/CaffeineSingleCache.java b/src/main/java/br/ufrgs/inf/prosoft/cache/CaffeineSingleCache.java
index ae312d8..6e32697 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/CaffeineSingleCache.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/CaffeineSingleCache.java
@@ -29,10 +29,4 @@ public class CaffeineSingleCache<K, V> extends Caffeine<K, V> {
         super(cachingPerformance, ttl, 1L);
     }
 
-    @Override
-    public void put(K key, V value) {
-        registerEvent(EventType.INVALIDATION, null);
-        super.put(key, value);
-    }
-
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/EventType.java b/src/main/java/br/ufrgs/inf/prosoft/cache/EventType.java
index 4507fb5..f80036b 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/EventType.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/EventType.java
@@ -10,5 +10,5 @@ package br.ufrgs.inf.prosoft.cache;
  * @author romulo
  */
 public enum EventType {
-    HIT, MISS, ADDITION, INVALIDATION;
+    HIT, MISS, ADDITION, INVALIDATION, POPULATION;
 }
diff --git a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
index 9044da2..549e7da 100644
--- a/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
+++ b/src/main/java/br/ufrgs/inf/prosoft/cache/tools/Reducer.java
@@ -13,9 +13,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.TreeMap;
+import java.util.function.Consumer;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Stream;
@@ -61,65 +60,25 @@ public class Reducer {
     public static void size(String eventsPath, String reducePath, String prefix) {
         try (Stream<String> lines = Files.lines(Paths.get(eventsPath))) {
             Gson gson = new Gson();
-            Map<String, TreeMap<Long, Integer>> cacheHasSizeAlongTime = new HashMap<>();
-            lines.forEach(line -> {
-                CacheEvent event = gson.fromJson(line, CacheEvent.class);
-                if (!(event.getType().equals(EventType.ADDITION) || event.getType().equals(EventType.INVALIDATION))) {
-                    return;
-                }
-                cacheHasSizeAlongTime.compute(event.getName(), (key, previous) -> {
-                    if (previous == null) {
-                        previous = new TreeMap<>();
-                    }
-                    previous.compute(event.getTime() / 1000, (innerKey, innerPrevious) -> {
-                        if (innerPrevious == null) {
-                            innerPrevious = 0;
-                        }
-                        if (event.getType().equals(EventType.ADDITION)) {
-                            return innerPrevious + 1;
-                        }
-                        return innerPrevious - 1;
-                    });
-                    return previous;
-                });
-            });
+            lines.forEach(new Consumer<String>() {
+                int second = 0;
 
-            cacheHasSizeAlongTime.forEach((name, sizeAlongTime) -> {
-                Iterator<Map.Entry<Long, Integer>> iterator = sizeAlongTime.entrySet().iterator();
-                int accumulated = iterator.next().getValue();
-                while (iterator.hasNext()) {
-                    Map.Entry<Long, Integer> entry = iterator.next();
-                    accumulated += entry.getValue();
-                    if (accumulated < 0) {
-                        accumulated = 0;
+                @Override
+                public void accept(String line) {
+                    CacheEvent event = gson.fromJson(line, CacheEvent.class);
+                    if (!event.getType().equals(EventType.POPULATION)) {
+                        return;
                     }
-                    entry.setValue(accumulated);
-                }
-            });
-
-            final Long baseTime = cacheHasSizeAlongTime.values().stream().map(map -> map.firstKey()).min(Long::compare).orElse(0L);
-            final Long adjustedMaxTime = cacheHasSizeAlongTime.values().stream().map(map -> map.lastKey()).max(Long::compare).orElse(0L) - baseTime;
-
-            try (FileWriter fileWriter = new FileWriter(reducePath, true)) {
-                cacheHasSizeAlongTime.forEach((name, sizeAlongTime) -> {
-                    try {
-                        Map.Entry<Long, Integer> pollFirstEntry = sizeAlongTime.pollFirstEntry();
-                        for (long i = 0; i < pollFirstEntry.getKey() - baseTime; i++) {
-                            fileWriter.write(prefix + name + "," + i + "," + 0 + "\n");
-                        }
-                        for (long i = pollFirstEntry.getKey() - baseTime; i <= adjustedMaxTime; i++) {
-                            if (sizeAlongTime.size() > 1 && i > pollFirstEntry.getKey() - baseTime) {
-                                pollFirstEntry = sizeAlongTime.pollFirstEntry();
-                            }
-                            fileWriter.write(prefix + name + "," + i + "," + pollFirstEntry.getValue() + "\n");
-                        }
+                    try (FileWriter fileWriter = new FileWriter(reducePath, true)) {
+                        fileWriter.write(prefix + event.getName() + "," + this.second + "," + event.getIdentifier() + "\n");
                     } catch (IOException ex) {
-                        LOGGER.log(Level.SEVERE, "file not found {0}", reducePath);
+                        LOGGER.log(Level.SEVERE, "output error {0}", eventsPath);
                     }
-                });
-            }
+                    this.second++;
+                }
+            });
         } catch (IOException ex) {
-            LOGGER.log(Level.SEVERE, "file not found {0}", eventsPath);
+            LOGGER.log(Level.SEVERE, "input not found {0}", eventsPath);
         }
     }