3
0
Mirror von https://github.com/PaperMC/Paper.git synchronisiert 2024-11-16 21:10:17 +01:00

Updated SoftMap to be concurrent.

Dieser Commit ist enthalten in:
Raphfrk 2011-03-10 22:13:47 +00:00 committet von Erik Broes
Ursprung 9464602720
Commit 0b05cbb998
2 geänderte Dateien mit 97 neuen und 28 gelöschten Zeilen

Datei anzeigen

@ -13,11 +13,11 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.craftbukkit.util.SoftMap; import org.bukkit.craftbukkit.util.ConcurrentSoftMap;
public class CraftChunk implements Chunk { public class CraftChunk implements Chunk {
private WeakReference<net.minecraft.server.Chunk> weakChunk; private WeakReference<net.minecraft.server.Chunk> weakChunk;
private final SoftMap<Integer, Block> cache = new SoftMap<Integer, Block>(); private final ConcurrentSoftMap<Integer, Block> cache = new ConcurrentSoftMap<Integer, Block>();
private WorldServer worldServer; private WorldServer worldServer;
private int x; private int x;
private int z; private int z;
@ -63,8 +63,13 @@ public class CraftChunk implements Chunk {
int pos = (x & 0xF) << 11 | (z & 0xF) << 7 | (y & 0x7F); int pos = (x & 0xF) << 11 | (z & 0xF) << 7 | (y & 0x7F);
Block block = this.cache.get( pos ); Block block = this.cache.get( pos );
if (block == null) { if (block == null) {
block = new CraftBlock( this, (getX() << 4) | (x & 0xF), y & 0x7F, (getZ() << 4) | (z & 0xF) ); Block newBlock = new CraftBlock( this, (getX() << 4) | (x & 0xF), y & 0x7F, (getZ() << 4) | (z & 0xF) );
this.cache.put( pos, block ); Block oldBlock = this.cache.put( pos, newBlock );
if(oldBlock == null) {
block = newBlock;
} else {
block = oldBlock;
}
} }
return block; return block;
} }

Datei anzeigen

@ -3,7 +3,7 @@ package org.bukkit.craftbukkit.util;
import java.util.Map; import java.util.Map;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.Set; import java.util.Set;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@ -13,52 +13,54 @@ import java.lang.ref.SoftReference;
/** /**
* Creates a map that uses soft reference. This indicates to the garbage collector * Creates a map that uses soft reference. This indicates to the garbage collector
* that they can be removed if necessary * that they can be removed if necessary
* *
* A minimum number of strong references can be set. These most recent N objects added * A minimum number of strong references can be set. These most recent N objects added
* to the map will not be removed by the garbage collector. * to the map will not be removed by the garbage collector.
* *
* Objects will never be removed if they are referenced strongly from somewhere else * Objects will never be removed if they are referenced strongly from somewhere else
* Note: While data corruption won't happen, the garbage collector is potentially async * Note: While data corruption won't happen, the garbage collector is potentially async
* This could lead to the return values from containsKey() and similar methods being * This could lead to the return values from containsKey() and similar methods being
* out of date by the time they are used. The class could return null when the object * out of date by the time they are used. The class could return null when the object
* is retrieved by a .get() call directly after a .containsKey() call returned true * is retrieved by a .get() call directly after a .containsKey() call returned true
* *
* @author raphfrk * @author raphfrk
*/ */
public class SoftMap<K,V> { public class ConcurrentSoftMap<K,V> {
private final HashMap<K,SoftMapReference<K,V>> map = new HashMap<K,SoftMapReference<K,V>>(); private final ConcurrentHashMap<K,SoftMapReference<K,V>> map = new ConcurrentHashMap<K,SoftMapReference<K,V>>();
private final ReferenceQueue<SoftMapReference> queue = new ReferenceQueue<SoftMapReference>(); private final ReferenceQueue<SoftMapReference> queue = new ReferenceQueue<SoftMapReference>();
private final LinkedList<V> strongReferenceQueue = new LinkedList<V>(); private final LinkedList<V> strongReferenceQueue = new LinkedList<V>();
private final int strongReferenceSize; private final int strongReferenceSize;
public SoftMap() { public ConcurrentSoftMap() {
this(20); this(20);
} }
public SoftMap(int size) { public ConcurrentSoftMap(int size) {
strongReferenceSize = size; strongReferenceSize = size;
} }
// When a soft reference is deleted by the garbage collector, it is set to reference null // When a soft reference is deleted by the garbage collector, it is set to reference null
// and added to the queue // and added to the queue
// //
// However, these null references still exist in the HashMap as keys. This method removes these keys. // However, these null references still exist in the ConcurrentHashMap as keys. This method removes these keys.
// //
// It is called whenever there is a method call of the map. // It is called whenever there is a method call of the map.
private void emptyQueue() { private void emptyQueue() {
SoftMapReference ref; SoftMapReference ref;
while((ref=(SoftMapReference)queue.poll()) != null) { while ((ref=(SoftMapReference) queue.poll()) != null) {
map.remove(ref.key); map.remove(ref.key);
} }
} }
public void clear() { public void clear() {
strongReferenceQueue.clear(); synchronized(strongReferenceQueue) {
strongReferenceQueue.clear();
}
map.clear(); map.clear();
emptyQueue(); emptyQueue();
} }
@ -105,9 +107,11 @@ public class SoftMap<K,V> {
} }
V value = ref.get(); V value = ref.get();
if (value!=null) { if (value!=null) {
strongReferenceQueue.addFirst(value); synchronized(strongReferenceQueue) {
if (strongReferenceQueue.size() > strongReferenceSize) { strongReferenceQueue.addFirst(value);
strongReferenceQueue.removeLast(); if (strongReferenceQueue.size() > strongReferenceSize) {
strongReferenceQueue.removeLast();
}
} }
} }
return value; return value;
@ -125,7 +129,7 @@ public class SoftMap<K,V> {
public boolean isEmpty() { public boolean isEmpty() {
emptyQueue(); emptyQueue();
return map.isEmpty(); return map.isEmpty();
} }
// Return all the keys, again could go out of date // Return all the keys, again could go out of date
@ -138,27 +142,76 @@ public class SoftMap<K,V> {
public V put(K key, V value) { public V put(K key, V value) {
emptyQueue(); emptyQueue();
V old = fastGet(key); V old = fastGet(key);
fastPut(key, value); fastPut(key, value);
return old; return old;
} }
private void fastPut(K key, V value) { private void fastPut(K key, V value) {
map.put(key, new SoftMapReference<K,V>(key, value, queue)); map.put(key, new SoftMapReference<K,V>(key, value, queue));
strongReferenceQueue.addFirst(value); synchronized(strongReferenceQueue) {
if (strongReferenceQueue.size() > strongReferenceSize) { strongReferenceQueue.addFirst(value);
strongReferenceQueue.removeLast(); if (strongReferenceQueue.size() > strongReferenceSize) {
strongReferenceQueue.removeLast();
}
} }
} }
public V putIfAbsent(K key, V value) {
emptyQueue();
return fastPutIfAbsent(key, value);
}
private V fastPutIfAbsent(K key, V value) {
V ret = null;
if (map.containsKey(key)) {
SoftMapReference<K,V> current = map.get(key);
if (current != null) {
ret = current.get();
}
}
if (ret == null) {
SoftMapReference<K,V> newValue = new SoftMapReference<K,V>(key, value, queue);
boolean success = false;
while (!success) {
SoftMapReference<K,V> oldValue = map.putIfAbsent(key, newValue);
if (oldValue == null) { // put was successful (key didn't exist)
ret = null;
success = true;
} else {
ret = oldValue.get();
if (ret == null) { // key existed, but referenced null
success = map.replace(key, oldValue, newValue); // try to swap old for new
} else { // key existed, and referenced a valid object
success = true;
}
}
}
}
if (ret == null) {
synchronized(strongReferenceQueue) {
strongReferenceQueue.addFirst(value);
if (strongReferenceQueue.size() > strongReferenceSize) {
strongReferenceQueue.removeLast();
}
}
}
return ret;
}
// Adds the mappings to the map // Adds the mappings to the map
public void putAll(Map other) { public void putAll(Map other) {
emptyQueue(); emptyQueue();
Iterator<K> itr = other.keySet().iterator(); Iterator<K> itr = other.keySet().iterator();
while(itr.hasNext()) { while (itr.hasNext()) {
K key = itr.next(); K key = itr.next();
fastPut(key, (V)other.get(key)); fastPut(key, (V) other.get(key));
} }
} }
@ -178,7 +231,7 @@ public class SoftMap<K,V> {
public int size() { public int size() {
emptyQueue(); emptyQueue();
return map.size(); return map.size();
} }
// Shouldn't support this since it would create strong references to all the entries // Shouldn't support this since it would create strong references to all the entries
@ -195,6 +248,17 @@ public class SoftMap<K,V> {
super(value, queue); super(value, queue);
this.key = key; this.key = key;
} }
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof SoftMapReference)) {
return false;
}
SoftMapReference other = (SoftMapReference) o;
return other.get() == get();
}
}
} }