Do not perform chunk existance check for I/O scheduling

In order to check if a chunk exists, the RegionFile lock
(if the RegionFile is opened) will be acquired. However,
the RegionFile may be performing I/O operations, in which
case will stall the acquire operation.

To ensure that threads scheduling loads do not incur a stall,
we can avoid this check entirely - the RegionFile I/O
thread(s) will eventually perform the exist check itself.
This commit is contained in:
Spottedleaf 2024-06-03 13:28:31 -07:00
parent ca07564e47
commit 3df0d9a457

View file

@ -4337,34 +4337,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return thread.loadDataAsyncInternal(world, chunkX, chunkZ, type, onComplete, intendingToBlock, priority);
+ }
+
+ private static Boolean doesRegionFileExist(final int chunkX, final int chunkZ, final boolean intendingToBlock,
+ final ChunkDataController taskController) {
+ final ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ);
+ if (intendingToBlock) {
+ return taskController.computeForRegionFile(chunkX, chunkZ, true, (final RegionFile file) -> {
+ if (file == null) { // null if no regionfile exists
+ return Boolean.FALSE;
+ }
+
+ return file.hasChunk(chunkPos) ? Boolean.TRUE : Boolean.FALSE;
+ });
+ } else {
+ // first check if the region file for sure does not exist
+ if (taskController.doesRegionFileNotExist(chunkX, chunkZ)) {
+ return Boolean.FALSE;
+ } // else: it either exists or is not known, fall back to checking the loaded region file
+
+ return taskController.computeForRegionFileIfLoaded(chunkX, chunkZ, (final RegionFile file) -> {
+ if (file == null) { // null if not loaded
+ // not sure at this point, let the I/O thread figure it out
+ return Boolean.TRUE;
+ }
+
+ return file.hasChunk(chunkPos) ? Boolean.TRUE : Boolean.FALSE;
+ });
+ }
+ }
+
+ Cancellable loadDataAsyncInternal(final ServerLevel world, final int chunkX, final int chunkZ,
+ final RegionFileType type, final BiConsumer<CompoundTag, Throwable> onComplete,
+ final boolean intendingToBlock, final PrioritisedExecutor.Priority priority) {
@ -4377,20 +4349,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (running == null) {
+ // not scheduled
+
+ if (callbackInfo.regionFileCalculation == null) {
+ // caller will compute this outside of compute(), to avoid holding the bin lock
+ callbackInfo.needsRegionFileTest = true;
+ return null;
+ }
+
+ if (callbackInfo.regionFileCalculation == Boolean.FALSE) {
+ // not on disk
+ callbackInfo.data = null;
+ callbackInfo.throwable = null;
+ callbackInfo.completeNow = true;
+ return null;
+ }
+
+ // set up task
+ final ChunkDataTask newTask = new ChunkDataTask(
+ world, chunkX, chunkZ, taskController, RegionFileIOThread.this, priority
@ -4422,17 +4380,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return running;
+ };
+
+ ChunkDataTask curr = taskController.tasks.get(key);
+ if (curr == null) {
+ callbackInfo.regionFileCalculation = doesRegionFileExist(chunkX, chunkZ, intendingToBlock, taskController);
+ }
+ ChunkDataTask ret = taskController.tasks.compute(key, compute);
+ if (callbackInfo.needsRegionFileTest) {
+ // curr isn't null but when we went into compute() it was
+ callbackInfo.regionFileCalculation = doesRegionFileExist(chunkX, chunkZ, intendingToBlock, taskController);
+ // now it should be fine
+ ret = taskController.tasks.compute(key, compute);
+ }
+ final ChunkDataTask ret = taskController.tasks.compute(key, compute);
+
+ // needs to be scheduled
+ if (callbackInfo.tasksNeedsScheduling) {
@ -4491,8 +4439,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ public Throwable throwable;
+ public boolean completeNow;
+ public boolean tasksNeedsScheduling;
+ public boolean needsRegionFileTest;
+ public Boolean regionFileCalculation;
+
+ }
+