diff --git a/src/main/java/bdv/cache/iotiming/IoTimeBudget.java b/src/main/java/bdv/cache/iotiming/IoTimeBudget.java index 63bf4cf9c0cdf3aa246effbd306cd3beaf5f0f2f..9374570f677304a4116ecdbcecdb6c68dc3b9828 100644 --- a/src/main/java/bdv/cache/iotiming/IoTimeBudget.java +++ b/src/main/java/bdv/cache/iotiming/IoTimeBudget.java @@ -87,4 +87,18 @@ public class IoTimeBudget for ( ; l < budget.length && budget[ l ] > budget[ l - 1 ]; ++l ) budget[ l ] = budget[ l - 1 ]; } + + /** + * Returns how much time is left for the specified priority level. + * + * @param level + * priority level. must be greater ≥ 0. + * @return time left for the specified priority level. + */ + public long estimateTimeLeft( final int level ) + { + final long[] b = budget; + final int blevel = Math.min( level, b.length - 1 ); + return b[ blevel ]; + } } diff --git a/src/main/java/bdv/cache/revised/SoftRefCache.java b/src/main/java/bdv/cache/revised/SoftRefCache.java index 4bd3eecf10a219e0d6d444d77fa322c5fc4af769..a9a392db9e98e9c68e6d47872a1335d6ba5305e4 100644 --- a/src/main/java/bdv/cache/revised/SoftRefCache.java +++ b/src/main/java/bdv/cache/revised/SoftRefCache.java @@ -25,17 +25,17 @@ public class SoftRefCache< K, V > implements Cache< K, V > public void clean() { - map.remove( entry.getKey(), entry ); + map.remove( entry.key, entry ); } } final class Entry { - private final K key; + final K key; private SoftReference< V > ref; - private boolean loaded; + boolean loaded; public Entry( final K key ) { @@ -44,11 +44,6 @@ public class SoftRefCache< K, V > implements Cache< K, V > this.loaded = false; } - public K getKey() - { - return key; - } - public V getValue() { return ref.get(); @@ -59,11 +54,6 @@ public class SoftRefCache< K, V > implements Cache< K, V > this.loaded = true; this.ref = new CacheSoftReference( value, this ); } - - public boolean wasLoaded() - { - return loaded; - } } @Override @@ -82,7 +72,7 @@ public class SoftRefCache< K, V > implements Cache< K, V > { synchronized ( entry ) { - if ( entry.wasLoaded() ) + if ( entry.loaded ) { value = entry.getValue(); if ( value == null ) diff --git a/src/main/java/bdv/cache/revised/WeakRefVolatileCache.java b/src/main/java/bdv/cache/revised/WeakRefVolatileCache.java index 1ebae175ccab5ed5e62459c22794047fb8bd594a..383ed99191a3eb710163f696680ea22edc506c2f 100644 --- a/src/main/java/bdv/cache/revised/WeakRefVolatileCache.java +++ b/src/main/java/bdv/cache/revised/WeakRefVolatileCache.java @@ -48,6 +48,9 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements } } + /* + * Possible states of Entry.loaded + */ static final int NOTLOADED = 0; static final int INVALID = 1; static final int VALID = 2; @@ -112,16 +115,13 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements if ( v != null && v.isValid() ) return v; + cleanUp( 50 ); switch ( hints.getLoadingStrategy() ) { case BLOCKING: return getBlocking( entry ); case BUDGETED: - final int priority = hints.getQueuePriority(); - final IoStatistics stats = CacheIoTiming.getIoStatistics(); - final IoTimeBudget budget = stats.getIoTimeBudget(); - final long timeLeft = budget.timeLeft( priority ); - if ( timeLeft > 0 ) + if ( estimatedBugdetTimeLeft( hints ) > 0 ) return getBudgeted( entry, hints ); case VOLATILE: enqueue( entry, hints ); @@ -131,18 +131,27 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements } } + private long estimatedBugdetTimeLeft( final CacheHints hints ) + { + final int priority = hints.getQueuePriority(); + final IoStatistics stats = CacheIoTiming.getIoStatistics(); + final IoTimeBudget budget = stats.getIoTimeBudget(); + return budget.estimateTimeLeft( priority ); + } + @Override public V get( final K key, final VolatileLoader< ? extends V > loader, final CacheHints hints ) throws ExecutionException { /* * Get existing entry for key or create it. */ - final Entry entry = map.computeIfAbsent( key, k -> new Entry( key, loader ) ); + final Entry entry = map.computeIfAbsent( key, k -> new Entry( k, loader ) ); V v = entry.getValue(); if ( v != null && v.isValid() ) return v; + cleanUp( 50 ); switch ( hints.getLoadingStrategy() ) { case BLOCKING: @@ -159,8 +168,6 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements break; } - cleanUp( 10 ); - if ( v == null ) return get( key, loader, hints ); else @@ -298,6 +305,7 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements V v = entry.getValue(); if ( v == null && entry.loaded != NOTLOADED ) { +// printEntryCollected( "map.remove getBudgeted 1", entry ); map.remove( entry.key, entry ); return null; } @@ -338,6 +346,7 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements } else { +// printEntryCollected( "map.remove getBudgeted 2", entry ); map.remove( entry.key, entry ); return null; } @@ -354,6 +363,7 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements final V v = entry.getValue(); if ( v == null && entry.loaded != NOTLOADED ) { +// printEntryCollected( "map.remove getBlocking 1", entry ); map.remove( entry.key, entry ); return null; } @@ -369,6 +379,7 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements final V v = entry.getValue(); if ( v == null && entry.loaded != NOTLOADED ) { +// printEntryCollected( "map.remove getBlocking 2", entry ); map.remove( entry.key, entry ); return null; } @@ -395,4 +406,24 @@ public class WeakRefVolatileCache< K, V extends VolatileCacheValue > implements fetchQueue.put( new FetchEntry( entry.key ), hints.getQueuePriority(), hints.isEnqueuToFront() ); } } + + /** + * For debugging. Print stack trace when an Entry's value has been collected while we want + * to load it. + * + * @param title + * @param entry + */ + private synchronized void printEntryCollected( final String title, final Entry entry ) + { + final String state = entry.loaded == 0 + ? "NOTLOADED" + : ( entry.loaded == 1 + ? "INVALID" + : ( entry.loaded == 2 + ? "VALID" + : "UNDEFINED" ) ); + System.out.println( title + " entry.loaded = " + state ); +// new Throwable().printStackTrace( System.out ); + } }