package org.ethereum.datasource;

/**
 * Abstract cache implementation which tracks the cache size with
 * supplied key and value MemSizeEstimator's
 *
 * Created by Anton Nashatyrev on 01.12.2016.
 */
public abstract class AbstractCachedSource <Key, Value>
        extends AbstractChainedSource<Key, Value, Key, Value>
        implements CachedSource<Key, Value> {

    /**
     * Like the Optional interface represents either the value cached
     * or null cached (i.e. cache knows that underlying storage contain null)
     */
    public interface Entry<V> {
        V value();
    }

    static final class SimpleEntry<V> implements Entry<V> {
        private V val;
        public SimpleEntry(V val) {
            this.val = val;
        }
        public V value() {
            return val;
        }
    }

    private MemSizeEstimator<Key> keySizeEstimator;
    private MemSizeEstimator<Value> valueSizeEstimator;
    private int size = 0;

    public AbstractCachedSource(Source<Key, Value> source) {
        super(source);
    }

    /**
     * Returns the cached value if exist.
     * Method doesn't look into the underlying storage
     * @return The value Entry if it cached (Entry may has null value if null value is cached),
     *        or null if no information in the cache for this key
     */
    abstract Entry<Value> getCached(Key key);

    /**
     * Needs to be called by the implementation when cache entry is added
     * Only new entries should be accounted for accurate size tracking
     * If the value for the key is changed the {@link #cacheRemoved}
     * needs to be called first
     */
    protected synchronized void cacheAdded(Key key, Value value) {
        if (keySizeEstimator != null) {
            size += keySizeEstimator.estimateSize(key);
        }
        if (valueSizeEstimator != null) {
            size += valueSizeEstimator.estimateSize(value);
        }
    }

    /**
     * Needs to be called by the implementation when cache entry is removed
     */
    protected synchronized void cacheRemoved(Key key, Value value) {
        if (keySizeEstimator != null) {
            size -= keySizeEstimator.estimateSize(key);
        }
        if (valueSizeEstimator != null) {
            size -= valueSizeEstimator.estimateSize(value);
        }
    }

    /**
     * Needs to be called by the implementation when cache is cleared
     */
    protected synchronized void cacheCleared() {
        size = 0;
    }

    /**
     * Sets the key/value size estimators
     */
    public AbstractCachedSource <Key, Value> withSizeEstimators(MemSizeEstimator<Key> keySizeEstimator, MemSizeEstimator<Value> valueSizeEstimator) {
        this.keySizeEstimator = keySizeEstimator;
        this.valueSizeEstimator = valueSizeEstimator;
        return this;
    }

    @Override
    public long estimateCacheSize() {
        return size;
    }
}

@@ -360,16 +360,63 @@
 lue%3E %7B%0A%0A
+    private final Object lock = new Object();%0A%0A
     /**%0A
@@ -1674,37 +1674,24 @@
   protected 
-synchronized 
 void cacheAd
@@ -1710,32 +1710,66 @@
  Value value) %7B%0A
+        synchronized (lock) %7B%0A    
         if (keyS
@@ -1784,32 +1784,36 @@
 ator != null) %7B%0A
+    
             size
@@ -1856,34 +1856,41 @@
 y);%0A        
-%7D%0A
+    %7D%0A   
         
 if (valueSiz
@@ -1869,32 +1869,33 @@
    %7D%0A           
+ 
 if (valueSizeEst
@@ -1904,32 +1904,36 @@
 ator != null) %7B%0A
+    
             size
@@ -1968,32 +1968,46 @@
 ateSize(value);%0A
+            %7D%0A
         %7D%0A    %7D%0A
@@ -2109,37 +2109,24 @@
   protected 
-synchronized 
 void cacheRe
@@ -2147,32 +2147,66 @@
  Value value) %7B%0A
+        synchronized (lock) %7B%0A    
         if (keyS
@@ -2221,32 +2221,36 @@
 ator != null) %7B%0A
+    
             size
@@ -2297,26 +2297,33 @@
         
-%7D%0A
+    %7D%0A   
         
 if (valu
@@ -2306,32 +2306,33 @@
    %7D%0A           
+ 
 if (valueSizeEst
@@ -2341,32 +2341,36 @@
 ator != null) %7B%0A
+    
             size
@@ -2405,32 +2405,46 @@
 ateSize(value);%0A
+            %7D%0A
         %7D%0A    %7D%0A
@@ -2544,29 +2544,16 @@
 otected 
-synchronized 
 void cac
@@ -2575,24 +2575,68 @@
        s
-ize = 0;
+ynchronized (lock) %7B%0A            size = 0;%0A        %7D
 %0A    %7D%0A%0A

Remove inheritable object locking for AbstractCachedSource