Mirror von
https://github.com/PaperMC/Paper.git
synchronisiert 2024-11-17 05:20:05 +01:00
Updated SoftMap to be concurrent.
Dieser Commit ist enthalten in:
Ursprung
9464602720
Commit
0b05cbb998
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
@ -28,37 +28,39 @@ import java.lang.ref.SoftReference;
|
|||||||
* @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() {
|
||||||
|
synchronized(strongReferenceQueue) {
|
||||||
strongReferenceQueue.clear();
|
strongReferenceQueue.clear();
|
||||||
|
}
|
||||||
map.clear();
|
map.clear();
|
||||||
emptyQueue();
|
emptyQueue();
|
||||||
}
|
}
|
||||||
@ -105,11 +107,13 @@ public class SoftMap<K,V> {
|
|||||||
}
|
}
|
||||||
V value = ref.get();
|
V value = ref.get();
|
||||||
if (value!=null) {
|
if (value!=null) {
|
||||||
|
synchronized(strongReferenceQueue) {
|
||||||
strongReferenceQueue.addFirst(value);
|
strongReferenceQueue.addFirst(value);
|
||||||
if (strongReferenceQueue.size() > strongReferenceSize) {
|
if (strongReferenceQueue.size() > strongReferenceSize) {
|
||||||
strongReferenceQueue.removeLast();
|
strongReferenceQueue.removeLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,20 +149,69 @@ public class SoftMap<K,V> {
|
|||||||
|
|
||||||
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));
|
||||||
|
synchronized(strongReferenceQueue) {
|
||||||
strongReferenceQueue.addFirst(value);
|
strongReferenceQueue.addFirst(value);
|
||||||
if (strongReferenceQueue.size() > strongReferenceSize) {
|
if (strongReferenceQueue.size() > strongReferenceSize) {
|
||||||
strongReferenceQueue.removeLast();
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren