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
@@ -33,8 +33,7 @@ public class ReplaceExtrusion implements Extrusion {
this.range = range; this.range = range;
this.biomes = biomes; this.biomes = biomes;
this.hasTag = BiomeQueries.has(tag); this.hasTag = BiomeQueries.has(tag);
this.cache = new TriStateIntCache(Math.max(512, Biome.INT_ID_COUNTER.get()));
this.cache = new TriStateIntCache(65536);
} }
@Override @Override
@@ -19,7 +19,6 @@ import com.dfsek.terra.api.world.biome.PlatformBiome;
* Class representing a config-defined biome * Class representing a config-defined biome
*/ */
public class UserDefinedBiome implements Biome { public class UserDefinedBiome implements Biome {
private final static AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
private final PlatformBiome vanilla; private final PlatformBiome vanilla;
private final String id; private final String id;
private final BiomeTemplate config; private final BiomeTemplate config;
@@ -1,7 +1,11 @@
package com.dfsek.terra.api.util.collection; 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 class TriStateIntCache {
public static final long STATE_UNSET = 0L; public static final long STATE_UNSET = 0L;
@@ -9,10 +13,19 @@ public class TriStateIntCache {
public static final long STATE_TRUE = 2L; public static final long STATE_TRUE = 2L;
private static final long BIT_MASK = 3L; 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) { 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) * @return STATE_UNSET (0), STATE_FALSE (1), or STATE_TRUE (2)
*/ */
public long get(int key) { public long get(int key) {
int arrayIndex = key >>> 5; long offset = ARRAY_BASE_OFFSET + ((long)(key >>> 5) << 3);
int bitShift = (key & 31) << 1; long currentWord = UnsafeUtils.UNSAFE.getLong(data, offset);
long currentWord = data.get(arrayIndex); return (currentWord >>> ((key << 1) & 63)) & BIT_MASK;
return (currentWord >>> bitShift) & BIT_MASK;
} }
/** /**
* Sets the value safely. Handles race conditions internally. * Sets the value safely. Handles race conditions internally.
*/ */
public void set(int key, boolean value) { public void set(int key, boolean value) {
int arrayIndex = key >>> 5; int index = key >>> 5;
int bitShift = (key & 31) << 1; int shift = (key << 1) & 63;
long targetState = value ? STATE_TRUE : STATE_FALSE;
long currentWord, newWord; long targetWord = (value ? STATE_TRUE : STATE_FALSE) << shift;
long current;
do { do {
currentWord = data.get(arrayIndex); current = (long) ARRAY_HANDLE.getVolatile(data, index);
// Race condition check: if (((current >>> shift) & BIT_MASK) != STATE_UNSET) {
long existingState = (currentWord >>> bitShift) & BIT_MASK; return;
if(existingState != STATE_UNSET) {
return; // Already set, abort our update
} }
// Create new word with our bit set } while (!ARRAY_HANDLE.compareAndSet(data, index, current, current | targetWord));
newWord = (currentWord & ~(BIT_MASK << bitShift)) | (targetState << bitShift);
} while(!data.compareAndSet(arrayIndex, currentWord, newWord));
} }
} }
@@ -9,6 +9,7 @@ package com.dfsek.terra.api.world.biome;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import com.dfsek.terra.api.properties.PropertyHolder; import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.StringIdentifiable; import com.dfsek.terra.api.registry.key.StringIdentifiable;
@@ -18,6 +19,7 @@ import com.dfsek.terra.api.registry.key.StringIdentifiable;
* Represents a Terra biome * Represents a Terra biome
*/ */
public interface Biome extends PropertyHolder, StringIdentifiable { public interface Biome extends PropertyHolder, StringIdentifiable {
AtomicInteger INT_ID_COUNTER = new AtomicInteger(0);
/** /**
* Gets the platform biome this custom biome delegates to. * Gets the platform biome this custom biome delegates to.