X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fcache%2FSoftTimedCache.java;fp=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fcache%2FSoftTimedCache.java;h=6e9ed074c6317931ab7609e91a088f62b5565e4b;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=40f47526417eb6fe592d975e3a65f271b472a1c3;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/cache/SoftTimedCache.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/cache/SoftTimedCache.java index 40f475264..6e9ed074c 100644 --- a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/cache/SoftTimedCache.java +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/cache/SoftTimedCache.java @@ -1,223 +1,223 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.utils.datastructures.cache; - -import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Timer; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.simantics.utils.threads.ThreadUtils; - -/** - * A timed (Key, Value) cache which disposes the cached entry after the - * specified amount of time if it is not removed from the cache. The hold time - * is given to the {@link #put(Object, Object, long)} method, separately for - * each value. - * - *

- * The cached values are held as soft references, which makes them collectible - * under memory pressure, even before their hold time has ran out. - * - * @author Tuukka Lehtonen - * - * @param key type, held by strong references - * @param value type, held by soft references to allow collection of the - * cached elements when under memory pressure - */ -public class SoftTimedCache implements ITimedCache { - - protected class Entry { - final K key; - final SoftReference ref; - long holdTime; - TimeUnit unit; - - ScheduledFuture future; - - Entry(K k, V v, long holdTime, TimeUnit unit) { - assert k != null; - assert v != null; - - this.key = k; - this.ref = new SoftReference(v); - this.holdTime = holdTime; - this.unit = unit; - } - } - - private final Map cache = Collections.synchronizedMap(new HashMap()); - - @SuppressWarnings("unused") - private String name; - - private Timer timer; - - public SoftTimedCache() { - this("Cache Timer"); - } - - public SoftTimedCache(String name) { - this.name = name; - } - - public int size() { - return cache.size(); - } - - @Override - protected void finalize() throws Throwable { - if (timer != null) { - timer.cancel(); - } - clear(); - super.finalize(); - } - - public synchronized void clear() { - Object[] entries; - synchronized (this) { - entries = cache.values().toArray(); - cache.clear(); - } - for (Object o : entries) { - @SuppressWarnings("unchecked") - Entry e = (Entry) o; - V v = e.ref.get(); - e.ref.clear(); - cleanup(e); - disposeValue(v); - } - } - - @Override - public void put(final K k, V v, long holdTime, TimeUnit unit) { - Entry e = new Entry(k, v, holdTime, unit); - synchronized (this) { - // First dispose of a previous entry. - dispose(k); - // Then cache the new one. - cache.put(k, e); - - if (unit != null && holdTime > 0) { - schedule(e); - } - } - } - - @Override - public V release(K k) { - Entry e; - synchronized (this) { - e = cache.remove(k); - } - if (e == null) - return null; - return cleanup(e); - } - - private V cleanup(Entry e) { - if (e.future != null) { - if (!e.future.isCancelled()) { - boolean ret = e.future.cancel(false); - if (ret == false) - // Already disposing of this cached entry, let it be. - return null; - } - } - return e.ref.get(); - } - - private void dispose(K k) { - Entry e; - synchronized (this) { - e = cache.remove(k); - } - if (e == null) - // Has been released. - return; - - V v = e.ref.get(); - if (v != null) { - if (e.future != null) - e.future.cancel(false); - e.ref.clear(); - disposeValue(v); - } - } - - void schedule(final Entry e) { - e.future = ThreadUtils.getNonBlockingWorkExecutor().schedule(new Runnable() { - @Override - public void run() { - // Disposal may block, must transfer to blocking work executor. - ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() { - @Override - public void run() { - dispose(e.key); - } - }); - } - }, e.holdTime, e.unit); - } - - - /** - * Override to customize disposal of values when their timer elapses. - * - * @param v the value to dispose of - */ - protected void disposeValue(V v) { - // Do nothing by default. - } - - public class CacheEntry { - private final Entry e; - private final V value; - public CacheEntry(Entry e) { - this.e = e; - this.value = e.ref.get(); - } - public K getKey() { - return e.key; - } - public V getValue() { - return value; - } - public boolean disposeScheduled() { - return e.future != null; - } - public void schedule(long holdTime, TimeUnit unit) { - if (e.future == null) { - e.holdTime = holdTime; - e.unit = unit; - SoftTimedCache.this.schedule(e); - } - } - } - - public Collection getEntries() { - ArrayList result = new ArrayList(); - synchronized (this) { - for (Entry e : cache.values()) { - result.add(new CacheEntry(e)); - } - } - return result; - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.utils.datastructures.cache; + +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Timer; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.simantics.utils.threads.ThreadUtils; + +/** + * A timed (Key, Value) cache which disposes the cached entry after the + * specified amount of time if it is not removed from the cache. The hold time + * is given to the {@link #put(Object, Object, long)} method, separately for + * each value. + * + *

+ * The cached values are held as soft references, which makes them collectible + * under memory pressure, even before their hold time has ran out. + * + * @author Tuukka Lehtonen + * + * @param key type, held by strong references + * @param value type, held by soft references to allow collection of the + * cached elements when under memory pressure + */ +public class SoftTimedCache implements ITimedCache { + + protected class Entry { + final K key; + final SoftReference ref; + long holdTime; + TimeUnit unit; + + ScheduledFuture future; + + Entry(K k, V v, long holdTime, TimeUnit unit) { + assert k != null; + assert v != null; + + this.key = k; + this.ref = new SoftReference(v); + this.holdTime = holdTime; + this.unit = unit; + } + } + + private final Map cache = Collections.synchronizedMap(new HashMap()); + + @SuppressWarnings("unused") + private String name; + + private Timer timer; + + public SoftTimedCache() { + this("Cache Timer"); + } + + public SoftTimedCache(String name) { + this.name = name; + } + + public int size() { + return cache.size(); + } + + @Override + protected void finalize() throws Throwable { + if (timer != null) { + timer.cancel(); + } + clear(); + super.finalize(); + } + + public synchronized void clear() { + Object[] entries; + synchronized (this) { + entries = cache.values().toArray(); + cache.clear(); + } + for (Object o : entries) { + @SuppressWarnings("unchecked") + Entry e = (Entry) o; + V v = e.ref.get(); + e.ref.clear(); + cleanup(e); + disposeValue(v); + } + } + + @Override + public void put(final K k, V v, long holdTime, TimeUnit unit) { + Entry e = new Entry(k, v, holdTime, unit); + synchronized (this) { + // First dispose of a previous entry. + dispose(k); + // Then cache the new one. + cache.put(k, e); + + if (unit != null && holdTime > 0) { + schedule(e); + } + } + } + + @Override + public V release(K k) { + Entry e; + synchronized (this) { + e = cache.remove(k); + } + if (e == null) + return null; + return cleanup(e); + } + + private V cleanup(Entry e) { + if (e.future != null) { + if (!e.future.isCancelled()) { + boolean ret = e.future.cancel(false); + if (ret == false) + // Already disposing of this cached entry, let it be. + return null; + } + } + return e.ref.get(); + } + + private void dispose(K k) { + Entry e; + synchronized (this) { + e = cache.remove(k); + } + if (e == null) + // Has been released. + return; + + V v = e.ref.get(); + if (v != null) { + if (e.future != null) + e.future.cancel(false); + e.ref.clear(); + disposeValue(v); + } + } + + void schedule(final Entry e) { + e.future = ThreadUtils.getNonBlockingWorkExecutor().schedule(new Runnable() { + @Override + public void run() { + // Disposal may block, must transfer to blocking work executor. + ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() { + @Override + public void run() { + dispose(e.key); + } + }); + } + }, e.holdTime, e.unit); + } + + + /** + * Override to customize disposal of values when their timer elapses. + * + * @param v the value to dispose of + */ + protected void disposeValue(V v) { + // Do nothing by default. + } + + public class CacheEntry { + private final Entry e; + private final V value; + public CacheEntry(Entry e) { + this.e = e; + this.value = e.ref.get(); + } + public K getKey() { + return e.key; + } + public V getValue() { + return value; + } + public boolean disposeScheduled() { + return e.future != null; + } + public void schedule(long holdTime, TimeUnit unit) { + if (e.future == null) { + e.holdTime = holdTime; + e.unit = unit; + SoftTimedCache.this.schedule(e); + } + } + } + + public Collection getEntries() { + ArrayList result = new ArrayList(); + synchronized (this) { + for (Entry e : cache.values()) { + result.add(new CacheEntry(e)); + } + } + return result; + } + +}