Don't use the region chunk has table until a threshold.

This commit is contained in:
sk89q 2014-08-21 22:39:32 -07:00
parent 95052546a5
commit f57afb2944

View File

@ -51,8 +51,14 @@
*/ */
public class ChunkHashTable implements ConcurrentRegionIndex { public class ChunkHashTable implements ConcurrentRegionIndex {
/**
* The number of regions required before this hash table kicks in.
*/
private static final int CACHE_THRESHOLD = 5;
private ListeningExecutorService executor = createExecutor(); private ListeningExecutorService executor = createExecutor();
private LongHashTable<ChunkState> states = new LongHashTable<ChunkState>(); @Nullable
private LongHashTable<ChunkState> states;
private final RegionIndex index; private final RegionIndex index;
private final Object lock = new Object(); private final Object lock = new Object();
@Nullable @Nullable
@ -79,35 +85,23 @@ private ListeningExecutorService createExecutor() {
} }
/** /**
* Get a state object at the given position. * Get a state object at the given position, returning an entry only
* if one exists.
* *
* @param position the position * @param position the position
* @param create true to create an entry if one does not exist * @return a chunk state object, or {@code null}
* @return a chunk state object, or {@code null} (only if {@code create} is false)
*/ */
@Nullable @Nullable
private ChunkState get(Vector2D position, boolean create) { private ChunkState get(Vector2D position) {
ChunkState state; LongHashTable<ChunkState> states = this.states;
synchronized (lock) {
state = states.get(position.getBlockX(), position.getBlockZ());
if (state == null && create) {
state = new ChunkState(position);
states.put(position.getBlockX(), position.getBlockZ(), state);
executor.submit(new EnumerateRegions(position));
}
}
return state;
}
/** if (states != null) {
* Get a state at the given position or create a new entry if one does synchronized (lock) {
* not exist. return states.get(position.getBlockX(), position.getBlockZ());
* }
* @param position the position } else {
* @return a state return null;
*/ }
private ChunkState getOrCreate(Vector2D position) {
return get(position, true);
} }
/** /**
@ -118,11 +112,15 @@ private void rebuild() {
ListeningExecutorService previousExecutor = executor; ListeningExecutorService previousExecutor = executor;
LongHashTable<ChunkState> previousStates = states; LongHashTable<ChunkState> previousStates = states;
if (index.size() > CACHE_THRESHOLD) {
previousExecutor.shutdownNow(); previousExecutor.shutdownNow();
states = new LongHashTable<ChunkState>(); states = new LongHashTable<ChunkState>();
executor = createExecutor(); executor = createExecutor();
if (previousStates != null) {
List<Vector2D> positions = new ArrayList<Vector2D>(); List<Vector2D> positions = new ArrayList<Vector2D>();
for (ChunkState state : previousStates.values()) { for (ChunkState state : previousStates.values()) {
Vector2D position = state.getPosition(); Vector2D position = state.getPosition();
positions.add(position); positions.add(position);
@ -132,8 +130,12 @@ private void rebuild() {
if (!positions.isEmpty()) { if (!positions.isEmpty()) {
executor.submit(new EnumerateRegions(positions)); executor.submit(new EnumerateRegions(positions));
} }
}
lastState = null; lastState = null;
} else {
states = null;
}
} }
} }
@ -159,7 +161,19 @@ public boolean awaitCompletion(long timeout, TimeUnit unit) throws InterruptedEx
@Override @Override
public void bias(Vector2D chunkPosition) { public void bias(Vector2D chunkPosition) {
checkNotNull(chunkPosition); checkNotNull(chunkPosition);
getOrCreate(chunkPosition);
if (states != null) {
synchronized (lock) {
if (states != null) {
ChunkState state = states.get(chunkPosition.getBlockX(), chunkPosition.getBlockZ());
if (state == null) {
state = new ChunkState(chunkPosition);
states.put(chunkPosition.getBlockX(), chunkPosition.getBlockZ(), state);
executor.submit(new EnumerateRegions(chunkPosition));
}
}
}
}
} }
@Override @Override
@ -175,6 +189,7 @@ public void biasAll(Collection<Vector2D> chunkPositions) {
public void forget(Vector2D chunkPosition) { public void forget(Vector2D chunkPosition) {
checkNotNull(chunkPosition); checkNotNull(chunkPosition);
synchronized (lock) { synchronized (lock) {
if (states != null) {
states.remove(chunkPosition.getBlockX(), chunkPosition.getBlockZ()); states.remove(chunkPosition.getBlockX(), chunkPosition.getBlockZ());
ChunkState state = lastState; ChunkState state = lastState;
if (state != null && state.getPosition().getBlockX() == chunkPosition.getBlockX() && state.getPosition().getBlockZ() == chunkPosition.getBlockZ()) { if (state != null && state.getPosition().getBlockX() == chunkPosition.getBlockX() && state.getPosition().getBlockZ() == chunkPosition.getBlockZ()) {
@ -182,6 +197,7 @@ public void forget(Vector2D chunkPosition) {
} }
} }
} }
}
@Override @Override
public void forgetAll() { public void forgetAll() {
@ -238,7 +254,7 @@ public void applyContaining(Vector position, Predicate<ProtectedRegion> consumer
int chunkZ = position.getBlockZ() >> 4; int chunkZ = position.getBlockZ() >> 4;
if (state == null || state.getPosition().getBlockX() != chunkX || state.getPosition().getBlockZ() != chunkZ) { if (state == null || state.getPosition().getBlockX() != chunkX || state.getPosition().getBlockZ() != chunkZ) {
state = get(new Vector2D(chunkX, chunkZ), false); state = get(new Vector2D(chunkX, chunkZ));
} }
if (state != null && state.isLoaded()) { if (state != null && state.isLoaded()) {
@ -301,7 +317,7 @@ private EnumerateRegions(List<Vector2D> positions) {
@Override @Override
public void run() { public void run() {
for (Vector2D position : positions) { for (Vector2D position : positions) {
ChunkState state = get(position, false); ChunkState state = get(position);
if (state != null) { if (state != null) {
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>(); List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();