Improve TriStateintCache with Unsafe

This commit is contained in:
Zoe Gidiere
2025-12-10 22:33:49 -07:00
parent 8b933b0d5c
commit d6285a5901
4 changed files with 32 additions and 24 deletions

View File

@@ -33,8 +33,7 @@ public class ReplaceExtrusion implements Extrusion {
this.range = range;
this.biomes = biomes;
this.hasTag = BiomeQueries.has(tag);
this.cache = new TriStateIntCache(65536);
this.cache = new TriStateIntCache(Math.max(512, Biome.INT_ID_COUNTER.get()));
}
@Override

View File

@@ -19,7 +19,6 @@ import com.dfsek.terra.api.world.biome.PlatformBiome;
* Class representing a config-defined biome
*/
public class UserDefinedBiome implements Biome {
private final static AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
private final PlatformBiome vanilla;
private final String id;
private final BiomeTemplate config;

View File

@@ -1,7 +1,11 @@
package com.dfsek.terra.api.util.collection;
import java.util.concurrent.atomic.AtomicLongArray;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import com.dfsek.seismic.util.UnsafeUtils;
import sun.misc.Unsafe;
public class TriStateIntCache {
public static final long STATE_UNSET = 0L;
@@ -9,10 +13,19 @@ public class TriStateIntCache {
public static final long STATE_TRUE = 2L;
private static final long BIT_MASK = 3L;
private final AtomicLongArray data;
private final long[] data;
private static final VarHandle ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(long[].class);
private static final long ARRAY_BASE_OFFSET;
static {
assert UnsafeUtils.UNSAFE != null;
ARRAY_BASE_OFFSET = UnsafeUtils.UNSAFE.arrayBaseOffset(long[].class);
}
public TriStateIntCache(int maxKeySize) {
this.data = new AtomicLongArray((maxKeySize + 31) >>> 5);
this.data = new long[(maxKeySize + 31) >>> 5];
}
/**
@@ -21,33 +34,28 @@ public class TriStateIntCache {
* @return STATE_UNSET (0), STATE_FALSE (1), or STATE_TRUE (2)
*/
public long get(int key) {
int arrayIndex = key >>> 5;
int bitShift = (key & 31) << 1;
long currentWord = data.get(arrayIndex);
return (currentWord >>> bitShift) & BIT_MASK;
long offset = ARRAY_BASE_OFFSET + ((long)(key >>> 5) << 3);
long currentWord = UnsafeUtils.UNSAFE.getLong(data, offset);
return (currentWord >>> ((key << 1) & 63)) & BIT_MASK;
}
/**
* Sets the value safely. Handles race conditions internally.
*/
public void set(int key, boolean value) {
int arrayIndex = key >>> 5;
int bitShift = (key & 31) << 1;
long targetState = value ? STATE_TRUE : STATE_FALSE;
int index = key >>> 5;
int shift = (key << 1) & 63;
long currentWord, newWord;
long targetWord = (value ? STATE_TRUE : STATE_FALSE) << shift;
long current;
do {
currentWord = data.get(arrayIndex);
current = (long) ARRAY_HANDLE.getVolatile(data, index);
// Race condition check:
long existingState = (currentWord >>> bitShift) & BIT_MASK;
if(existingState != STATE_UNSET) {
return; // Already set, abort our update
if (((current >>> shift) & BIT_MASK) != STATE_UNSET) {
return;
}
// Create new word with our bit set
newWord = (currentWord & ~(BIT_MASK << bitShift)) | (targetState << bitShift);
} while(!data.compareAndSet(arrayIndex, currentWord, newWord));
} while (!ARRAY_HANDLE.compareAndSet(data, index, current, current | targetWord));
}
}

View File

@@ -9,6 +9,7 @@ package com.dfsek.terra.api.world.biome;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.StringIdentifiable;
@@ -18,6 +19,7 @@ import com.dfsek.terra.api.registry.key.StringIdentifiable;
* Represents a Terra biome
*/
public interface Biome extends PropertyHolder, StringIdentifiable {
AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
/**
* Gets the platform biome this custom biome delegates to.