Skip to content

Commit e05b0cd

Browse files
committed
Ensure single-threaded chunk access
1 parent 7fb811d commit e05b0cd

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

src/main/java/org/yatopiamc/barium/common/threading/chunkio/BariumCachedRegionStorage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ public BariumCachedRegionStorage(File file, boolean bl, String string) {
5959
this.storage = new RegionBasedStorage(file, bl);
6060
this.chunkCache = CacheBuilder.newBuilder()
6161
.concurrencyLevel(Runtime.getRuntime().availableProcessors() * 2)
62-
.expireAfterAccess(16, TimeUnit.SECONDS)
63-
.maximumSize(16384)
62+
.expireAfterAccess(3, TimeUnit.SECONDS)
63+
.maximumSize(8192)
6464
.removalListener((RemovalNotification<ChunkPos, CompoundTag> notification) -> {
6565
if (notification.getValue() != EMPTY_VALUE)
6666
scheduleWrite(notification.getKey(), notification.getValue());

src/main/java/org/yatopiamc/barium/common/threading/worldgen/ChunkStatusUtils.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
package org.yatopiamc.barium.common.threading.worldgen;
22

3+
import com.ibm.asyncutil.locks.AsyncLock;
4+
import com.ibm.asyncutil.locks.AsyncNamedLock;
5+
import net.minecraft.util.math.ChunkPos;
36
import net.minecraft.world.chunk.ChunkStatus;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
import java.util.concurrent.CompletableFuture;
12+
import java.util.function.Supplier;
413

514
public class ChunkStatusUtils {
615

@@ -23,4 +32,25 @@ public static ChunkStatusThreadingType getThreadingType(final ChunkStatus status
2332
}
2433
}
2534

35+
private static <T> CompletableFuture<T> buildChain0(@NotNull List<CompletableFuture<AsyncLock.LockToken>> list, int index, Supplier<CompletableFuture<T>> code) {
36+
if (index < list.size()) {
37+
return list.get(index).thenCompose(lockToken -> {
38+
final CompletableFuture<T> future = buildChain0(list, index + 1, code);
39+
future.thenRun(lockToken::releaseLock);
40+
return future;
41+
});
42+
} else {
43+
return code.get();
44+
}
45+
}
46+
47+
public static <T> CompletableFuture<T> runChunkGenWithLock(ChunkPos target, int radius, AsyncNamedLock<ChunkPos> chunkLock, Supplier<CompletableFuture<T>> action) {
48+
List<CompletableFuture<AsyncLock.LockToken>> acquiredLocks = new ArrayList<>((radius + 1) * (radius + 1));
49+
for (int x = target.x - radius; x <= target.x + radius; x++)
50+
for (int z = target.z - radius; z <= target.z + radius; z++)
51+
acquiredLocks.add(chunkLock.acquireLock(new ChunkPos(x, z)).toCompletableFuture());
52+
53+
return buildChain0(acquiredLocks, 0, action);
54+
}
55+
2656
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package org.yatopiamc.barium.common.threading.worldgen;
22

33
import com.ibm.asyncutil.locks.AsyncLock;
4+
import com.ibm.asyncutil.locks.AsyncNamedLock;
5+
import net.minecraft.util.math.ChunkPos;
46

57
public interface IWorldGenLockable {
68

79
AsyncLock getWorldGenSingleThreadedLock();
810

11+
AsyncNamedLock<ChunkPos> getWorldGenChunkLock();
12+
913
}

src/main/java/org/yatopiamc/barium/mixin/threading/worldgen/MixinChunkStatus.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,21 @@ public class MixinChunkStatus {
2626
@Final
2727
private ChunkStatus.GenerationTask generationTask;
2828

29+
@Shadow @Final public static ChunkStatus FEATURES;
30+
2931
/**
3032
* @author ishland
3133
* @reason take over generation
3234
*/
3335
@Overwrite
3436
public CompletableFuture<Either<Chunk, ChunkHolder.Unloaded>> runGenerationTask(ServerWorld world, ChunkGenerator chunkGenerator, StructureManager structureManager, ServerLightingProvider lightingProvider, Function<Chunk, CompletableFuture<Either<Chunk, ChunkHolder.Unloaded>>> function, List<Chunk> chunks) {
35-
return ChunkStatusUtils.getThreadingType((ChunkStatus) (Object) this).runTask(((IWorldGenLockable) world).getWorldGenSingleThreadedLock(), () -> this.generationTask.doWork((ChunkStatus) (Object) this, world, chunkGenerator, structureManager, lightingProvider, function, chunks, chunks.get(chunks.size() / 2)));
37+
final Chunk targetChunk = chunks.get(chunks.size() / 2);
38+
//noinspection ConstantConditions
39+
return ChunkStatusUtils.runChunkGenWithLock(targetChunk.getPos(), (Object) this == FEATURES ? 1 : 0, ((IWorldGenLockable) world).getWorldGenChunkLock(), () ->
40+
ChunkStatusUtils.getThreadingType((ChunkStatus) (Object) this).runTask(((IWorldGenLockable) world).getWorldGenSingleThreadedLock(), () ->
41+
this.generationTask.doWork((ChunkStatus) (Object) this, world, chunkGenerator, structureManager, lightingProvider, function, chunks, targetChunk)
42+
)
43+
);
3644
}
3745

3846
}

src/main/java/org/yatopiamc/barium/mixin/threading/worldgen/MixinServerWorld.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.yatopiamc.barium.mixin.threading.worldgen;
22

33
import com.ibm.asyncutil.locks.AsyncLock;
4+
import com.ibm.asyncutil.locks.AsyncNamedLock;
45
import net.minecraft.server.world.ServerWorld;
6+
import net.minecraft.util.math.ChunkPos;
57
import org.spongepowered.asm.mixin.Mixin;
68
import org.spongepowered.asm.mixin.injection.At;
79
import org.spongepowered.asm.mixin.injection.Inject;
@@ -12,14 +14,21 @@
1214
public class MixinServerWorld implements IWorldGenLockable {
1315

1416
private volatile AsyncLock worldGenSingleThreadedLock = null;
17+
private volatile AsyncNamedLock<ChunkPos> worldGenChunkLock = null;
1518

1619
@Inject(method = "<init>", at = @At("RETURN"))
1720
private void initWorldGenSingleThreadedLock(CallbackInfo ci) {
1821
worldGenSingleThreadedLock = AsyncLock.createFair();
22+
worldGenChunkLock = AsyncNamedLock.createFair();
1923
}
2024

2125
@Override
2226
public AsyncLock getWorldGenSingleThreadedLock() {
2327
return worldGenSingleThreadedLock;
2428
}
29+
30+
@Override
31+
public AsyncNamedLock<ChunkPos> getWorldGenChunkLock() {
32+
return worldGenChunkLock;
33+
}
2534
}

0 commit comments

Comments
 (0)