stamps and notes

This commit is contained in:
mcrcortex
2025-05-02 23:44:49 +10:00
parent 917e308ece
commit fce99fbde3
4 changed files with 84 additions and 33 deletions

View File

@@ -4,18 +4,21 @@ import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
import me.cortex.voxy.common.world.WorldEngine;
import me.cortex.voxy.common.world.WorldSection;
import java.util.concurrent.locks.StampedLock;
import java.util.function.LongConsumer;
import static me.cortex.voxy.common.world.WorldEngine.UPDATE_TYPE_BLOCK_BIT;
public class SectionUpdateRouter implements ISectionWatcher {
private static final int SLICES = 1<<8;
private static final int SLICES = 1<<4;
public interface IChildUpdate {void accept(WorldSection section);}
private final Long2ByteOpenHashMap[] slices = new Long2ByteOpenHashMap[SLICES];
private final StampedLock[] locks = new StampedLock[SLICES];
{
for (int i = 0; i < this.slices.length; i++) {
this.slices[i] = new Long2ByteOpenHashMap();
this.locks[i] = new StampedLock();
}
}
@@ -35,17 +38,34 @@ public class SectionUpdateRouter implements ISectionWatcher {
}
public boolean watch(long position, int types) {
var set = this.slices[getSliceIndex(position)];
int idx = getSliceIndex(position);
var set = this.slices[idx];
var lock = this.locks[idx];
byte delta = 0;
synchronized (set) {
byte current = 0;
if (set.containsKey(position)) {
current = set.get(position);
}
{
long stamp = lock.readLock();
byte current = set.getOrDefault(position, (byte) 0);
delta = (byte) (current&types);
current |= (byte) types;
delta ^= (byte) (current&types);
if (delta != 0) {//Was change
long ws = lock.tryConvertToWriteLock(stamp);
if (ws == 0) {
lock.unlockRead(stamp);
stamp = lock.writeLock();
//We need to recompute as we failed to acquire an immediate write lock
current = set.getOrDefault(position, (byte) 0);
delta = (byte) (current&types);
current |= (byte) types;
delta ^= (byte) (current&types);
if (delta != 0)
set.put(position, current);
} else {
stamp = ws;
set.put(position, current);
}
}
lock.unlock(stamp);
}
if ((delta&UPDATE_TYPE_BLOCK_BIT)!=0) {
//If we added it, immediately invoke for an update
@@ -58,38 +78,67 @@ public class SectionUpdateRouter implements ISectionWatcher {
return this.unwatch(WorldEngine.getWorldSectionId(lvl, x, y, z), types);
}
public boolean unwatch(long position, int types) {
var set = this.slices[getSliceIndex(position)];
synchronized (set) {
if (!set.containsKey(position)) {
throw new IllegalStateException("Section pos not in map!! " + WorldEngine.pprintPos(position));
public boolean unwatch(long position, int types) {//Types is types to unwatch
int idx = getSliceIndex(position);
var set = this.slices[idx];
var lock = this.locks[idx];
long stamp = lock.readLock();
byte current = set.getOrDefault(position, (byte)0);
if (current == 0) {
throw new IllegalStateException("Section pos not in map " + WorldEngine.pprintPos(position));
}
byte current = set.get(position);
byte delta = (byte) (current&types);
boolean removed = false;
if ((current&types) != 0) {//Was change
long ws = lock.tryConvertToWriteLock(stamp);
if (ws == 0) {//failed to get write lock, need to unlock, get write, then redo
lock.unlockRead(stamp);
stamp = lock.writeLock();
current = set.getOrDefault(position, (byte)0);
if (current == 0) {
throw new IllegalStateException("Section pos not in map " + WorldEngine.pprintPos(position));
}
} else {
stamp = ws;
}
if ((current&types) != 0) {
current &= (byte) ~types;
if (current == 0) {
set.remove(position);
return true;
}
removed = true;
} else {
set.put(position, current);
return false;
}
}
}
lock.unlock(stamp);
return removed;
}
public int get(long position) {
var set = this.slices[getSliceIndex(position)];
synchronized (set) {
return set.getOrDefault(position, (byte) 0);
}
int idx = getSliceIndex(position);
var set = this.slices[idx];
var lock = this.locks[idx];
long stamp = lock.readLock();
int ret = set.getOrDefault(position, (byte) 0);
lock.unlockRead(stamp);
return ret;
}
public void forwardEvent(WorldSection section, int type) {
final long position = section.key;
var set = this.slices[getSliceIndex(position)];
byte types = 0;
synchronized (set) {
types = set.getOrDefault(position, (byte)0);
}
int idx = getSliceIndex(position);
var set = this.slices[idx];
var lock = this.locks[idx];
long stamp = lock.readLock();
byte types = set.getOrDefault(position, (byte) 0);
lock.unlockRead(stamp);
if (types!=0) {
if ((type&WorldEngine.UPDATE_TYPE_CHILD_EXISTENCE_BIT)!=0) {
this.childUpdateCallback.accept(section);

View File

@@ -331,6 +331,7 @@ public class RenderDataFactory45 {
}
}
//TODO: add neighbor face culling
private void generateYZOpaqueInnerGeometry(int axis) {
for (int layer = 0; layer < 31; layer++) {
this.blockMesher.auxiliaryPosition = layer;

View File

@@ -16,6 +16,7 @@ import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer;
import java.util.function.LongConsumer;
//TODO: replace synchronize with StampedLock
public class MemoryStorageBackend extends StorageBackend {
private final Long2ObjectMap<MemoryBuffer>[] maps;
private final Int2ObjectMap<ByteBuffer> idMappings = new Int2ObjectOpenHashMap<>();

View File

@@ -18,7 +18,7 @@ public class ActiveSectionTracker {
//Loaded section world cache, TODO: get rid of VolatileHolder and use something more sane
private final Long2ObjectOpenHashMap<VolatileHolder<WorldSection>>[] loadedSectionCache;
private final ReentrantLock[] locks;
private final ReentrantLock[] locks;//TODO: replace with StampedLocks
private final SectionLoader loader;
private final int lruSize;