diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index 4dd29ab8..9a5c08c7 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -145,8 +145,7 @@ public class Settings extends Config { public static int CHUNK_WAIT_MS = 1000; @Comment("Delete history on disk after a number of days") public static int DELETE_AFTER_DAYS = 7; - @Comment("Delete history in memory on logout (does not effect disk) (BROKEN, USE DISK INSTEAD)") - @Final // Deprecated + @Comment("Delete history in memory on logout (does not effect disk)") public static boolean DELETE_ON_LOGOUT = true; @Comment({ "If history should be enabled by default for plugins using WorldEdit:", diff --git a/core/src/main/java/com/boydti/fawe/object/collection/SoftHashMap.java b/core/src/main/java/com/boydti/fawe/object/collection/SoftHashMap.java new file mode 100644 index 00000000..c1056c26 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/collection/SoftHashMap.java @@ -0,0 +1,99 @@ +package com.boydti.fawe.object.collection; + +import java.lang.ref.*; +import java.util.*; +import java.io.Serializable; + +public class SoftHashMap extends AbstractMap + implements Serializable { + /** The internal HashMap that will hold the SoftReference. */ + private final Map> hash = + new HashMap>(); + + private final Map, K> reverseLookup = + new HashMap, K>(); + + /** Reference queue for cleared SoftReference objects. */ + private final ReferenceQueue queue = new ReferenceQueue(); + + public V get(Object key) { + expungeStaleEntries(); + V result = null; + // We get the SoftReference represented by that key + SoftReference soft_ref = hash.get(key); + if (soft_ref != null) { + // From the SoftReference we get the value, which can be + // null if it has been garbage collected + result = soft_ref.get(); + if (result == null) { + // If the value has been garbage collected, remove the + // entry from the HashMap. + hash.remove(key); + reverseLookup.remove(soft_ref); + } + } + return result; + } + + private void expungeStaleEntries() { + Reference sv; + while ((sv = queue.poll()) != null) { + hash.remove(reverseLookup.remove(sv)); + } + } + + public V put(K key, V value) { + expungeStaleEntries(); + SoftReference soft_ref = new SoftReference(value, queue); + reverseLookup.put(soft_ref, key); + SoftReference result = hash.put(key, soft_ref); + if (result == null) return null; + reverseLookup.remove(result); + return result.get(); + } + + public V remove(Object key) { + expungeStaleEntries(); + SoftReference result = hash.remove(key); + if (result == null) return null; + return result.get(); + } + + public void clear() { + hash.clear(); + reverseLookup.clear(); + } + + public int size() { + expungeStaleEntries(); + return hash.size(); + } + + /** + * Returns a copy of the key/values in the map at the point of + * calling. However, setValue still sets the value in the + * actual SoftHashMap. + */ + public Set> entrySet() { + expungeStaleEntries(); + Set> result = new LinkedHashSet>(); + for (final Entry> entry : hash.entrySet()) { + final V value = entry.getValue().get(); + if (value != null) { + result.add(new Entry() { + public K getKey() { + return entry.getKey(); + } + public V getValue() { + return value; + } + public V setValue(V v) { + entry.setValue(new SoftReference(v, queue)); + return value; + } + }); + } + } + return result; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java index a66174b7..be4a2320 100644 --- a/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java +++ b/core/src/main/java/com/sk89q/worldedit/session/SessionManager.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.session; +import com.boydti.fawe.object.collection.SoftHashMap; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.sk89q.worldedit.LocalConfiguration; @@ -33,6 +34,7 @@ import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors; import com.sk89q.worldedit.util.eventbus.Subscribe; import java.io.File; import java.io.IOException; +import java.util.Iterator; import java.util.Map; import java.util.Timer; import java.util.UUID; @@ -60,7 +62,9 @@ public class SessionManager { private static final Logger log = Logger.getLogger(SessionManager.class.getCanonicalName()); private final Timer timer = new Timer(); private final WorldEdit worldEdit; - private final Map sessions = new ConcurrentHashMap(8, 0.9f, 1); + private final Map sessions = new ConcurrentHashMap<>(8, 0.9f, 1); + private final Map softSessions = new SoftHashMap<>(); + private SessionStore store = new VoidStore(); private File path; @@ -90,7 +94,7 @@ public class SessionManager { */ public synchronized boolean contains(SessionOwner owner) { checkNotNull(owner); - return sessions.containsKey(getKey(owner)); + return sessions.containsKey(getKey(owner)) || softSessions.containsKey(owner); } /** @@ -108,7 +112,20 @@ public class SessionManager { return holder.session; } } - + Iterator> iter = softSessions.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + UUID key = entry.getKey(); + SessionHolder holder = entry.getValue(); + String test = holder.key.getName(); + if (test != null && name.equals(test)) { +// if (holder.key.isActive()) { + iter.remove(); + sessions.put(key, holder); +// } + return holder.session; + } + } return null; } @@ -122,11 +139,21 @@ public class SessionManager { @Nullable public synchronized LocalSession getIfPresent(SessionOwner owner) { checkNotNull(owner); - SessionHolder stored = sessions.get(getKey(owner)); + UUID key = getKey(owner); + SessionHolder stored = sessions.get(key); if (stored != null) { return stored.session; } else { - return null; + stored = softSessions.get(key); + if (stored != null) { +// if (stored.key.isActive()) { + softSessions.remove(key); + sessions.put(key, stored); +// } + return stored.session; + } else { + return null; + } } } @@ -156,10 +183,7 @@ public class SessionManager { session.setConfiguration(config); session.setBlockChangeLimit(config.defaultChangeLimit); - // Remember the session if the session is still active -// if (sessionKey.isActive()) { - sessions.put(getKey(owner), new SessionHolder(sessionKey, session)); -// } + sessions.put(getKey(owner), new SessionHolder(sessionKey, session)); } // Set the limit on the number of blocks that an operation can @@ -251,6 +275,14 @@ public class SessionManager { save(sessions.remove(getKey(owner))); } + public synchronized void forget(SessionOwner owner) { + checkNotNull(owner); + UUID key = getKey(owner); + SessionHolder holder = sessions.remove(key); + softSessions.put(key, holder); + save(holder); + } + /** * Remove all sessions. */