Extend HashMapLOW interface. Put PlayerData FCFS under lock.
HashMapLOW * Add a constructor for using an external lock. * Add putIfAbsent. DataManager * Use playerDataMap.putIfAbsent, return the PlayerData instance that has been there first.
This commit is contained in:
parent
c53d3f1521
commit
8077b4a0dc
|
@ -66,14 +66,17 @@ public class HashMapLOW <K, V> {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public K getKey() {
|
public K getKey() {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public V getValue() {
|
public V getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public V setValue(V value) {
|
public V setValue(V value) {
|
||||||
final V oldValue = this.value;
|
final V oldValue = this.value;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -140,11 +143,15 @@ public class HashMapLOW <K, V> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called under lock.
|
* Called under lock.
|
||||||
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
|
* @param ifAbsent
|
||||||
|
* If true, an existing non-null (!) value will not be
|
||||||
|
* overridden.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
V put(final int hashCode, final K key, final V value) {
|
V put(final int hashCode, final K key, final V value, final boolean ifAbsent) {
|
||||||
int emptyIndex;
|
int emptyIndex;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
emptyIndex = 0;
|
emptyIndex = 0;
|
||||||
|
@ -173,7 +180,9 @@ public class HashMapLOW <K, V> {
|
||||||
}
|
}
|
||||||
if (oldEntry != null) {
|
if (oldEntry != null) {
|
||||||
final V oldValue = oldEntry.getValue();
|
final V oldValue = oldEntry.getValue();
|
||||||
oldEntry.setValue(value);
|
if (oldValue == null || !ifAbsent) {
|
||||||
|
oldEntry.setValue(value);
|
||||||
|
}
|
||||||
return oldValue;
|
return oldValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,7 +414,7 @@ public class HashMapLOW <K, V> {
|
||||||
// Instance members
|
// Instance members
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
private final Lock lock = new ReentrantLock();
|
private final Lock lock;
|
||||||
|
|
||||||
/** Intended/expected size. */
|
/** Intended/expected size. */
|
||||||
private final int targetSize;
|
private final int targetSize;
|
||||||
|
@ -420,11 +429,21 @@ public class HashMapLOW <K, V> {
|
||||||
// TODO: Configurable: allow shrink.
|
// TODO: Configurable: allow shrink.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Initialize with a ReentrantLock.
|
||||||
* @param targetSize
|
* @param targetSize
|
||||||
* Expected (average) number of elements in the map.
|
* Expected (average) number of elements in the map.
|
||||||
*/
|
*/
|
||||||
public HashMapLOW(int targetSize) {
|
public HashMapLOW(int targetSize) {
|
||||||
|
this(new ReentrantLock(), targetSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize with a certain lock.
|
||||||
|
* @param lock
|
||||||
|
* @param targetSize
|
||||||
|
*/
|
||||||
|
public HashMapLOW(Lock lock, int targetSize) {
|
||||||
|
this.lock = lock;
|
||||||
this.targetSize = targetSize;
|
this.targetSize = targetSize;
|
||||||
buckets = newBuckets(targetSize);
|
buckets = newBuckets(targetSize);
|
||||||
}
|
}
|
||||||
|
@ -502,6 +521,31 @@ public class HashMapLOW <K, V> {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public V put(final K key, final V value) {
|
public V put(final K key, final V value) {
|
||||||
|
return put(key, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediate put, only if there is no value or a null value set for the key,
|
||||||
|
* under lock.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public V putIfAbsent(final K key, final V value) {
|
||||||
|
return put(key, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param ifAbsent
|
||||||
|
* If true, an existing non-null (!) value will not be
|
||||||
|
* overridden.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private final V put(final K key, final V value, final boolean ifAbsent) {
|
||||||
final int hashCode = getHashCode(key);
|
final int hashCode = getHashCode(key);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
final int index = getBucketIndex(hashCode, buckets.length);
|
final int index = getBucketIndex(hashCode, buckets.length);
|
||||||
|
@ -510,7 +554,7 @@ public class HashMapLOW <K, V> {
|
||||||
bucket = new LHMBucket<K, V>();
|
bucket = new LHMBucket<K, V>();
|
||||||
buckets[index] = bucket;
|
buckets[index] = bucket;
|
||||||
}
|
}
|
||||||
final V oldValue = bucket.put(hashCode, key, value);
|
V oldValue = bucket.put(hashCode, key, value, ifAbsent);
|
||||||
if (oldValue == null) {
|
if (oldValue == null) {
|
||||||
size ++;
|
size ++;
|
||||||
if (size > (int) (loadFactor * (float) buckets.length)) {
|
if (size > (int) (loadFactor * (float) buckets.length)) {
|
||||||
|
|
|
@ -694,9 +694,10 @@ public class DataManager implements Listener, INeedConfig, ComponentRegistry<IRe
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Creating this should be mostly harmless.
|
||||||
final PlayerData newData = new PlayerData(playerId, playerName);
|
final PlayerData newData = new PlayerData(playerId, playerName);
|
||||||
instance.playerData.put(playerId, newData);
|
final PlayerData oldData = instance.playerData.putIfAbsent(playerId, newData);
|
||||||
return newData;
|
return oldData == null ? newData : oldData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,18 @@ import fr.neatmonster.nocheatplus.components.data.IData;
|
||||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Central player data object.
|
* Central player-specific data object.
|
||||||
|
* <ul>
|
||||||
|
* <li>Access to on-tick request functionality.</li>
|
||||||
|
* <li>TBD: Permission cache.</li>
|
||||||
|
* <li>TBD: Check data.</li>
|
||||||
|
* <li>TBD: Exemptions</li>
|
||||||
|
* <li>...</li>
|
||||||
|
* </ul>
|
||||||
* <hr>
|
* <hr>
|
||||||
|
* Creating PlayerData must always be thread-safe and fail-safe.
|
||||||
|
* <hr>
|
||||||
|
* OLD javadocs to be cleaned up (...):<br>
|
||||||
* On the medium run this is intended to carry all data for the player...
|
* On the medium run this is intended to carry all data for the player...
|
||||||
* <li>Checks data objects.</li>
|
* <li>Checks data objects.</li>
|
||||||
* <li>Time stamps for logged out players</li>
|
* <li>Time stamps for logged out players</li>
|
||||||
|
|
Loading…
Reference in New Issue