world gen queue refactoring

This commit is contained in:
James Seibel
2025-12-13 08:49:31 -06:00
parent 4ed7941288
commit a74a37a0e8
3 changed files with 26 additions and 39 deletions
@@ -227,7 +227,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
parentDataSource.applyToParent = true;
}
this.dataUpdater.updateDataSource(parentDataSource, false);
this.dataUpdater.updateDataSource(parentDataSource);
}
}
}
@@ -328,7 +328,7 @@ public class FullDataUpdatePropagatorV2 implements IDebugRenderable, AutoCloseab
childDataSource.applyToChildren = true;
}
this.dataUpdater.updateDataSource(childDataSource, false);
this.dataUpdater.updateDataSource(childDataSource);
}
}
}
@@ -63,7 +63,7 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
/**
* Can be used if you don't want to lock the current thread
* Otherwise the sync version {@link FullDataUpdaterV2#updateDataSource(FullDataSourceV2, boolean)} may be a better choice.
* Otherwise the sync version {@link FullDataUpdaterV2#updateDataSource(FullDataSourceV2)} may be a better choice.
*/
public CompletableFuture<Void> updateDataSourceAsync(@NotNull FullDataSourceV2 inputDataSource)
{
@@ -86,7 +86,7 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
{
try
{
this.updateDataSource(inputDataSource, true);
this.updateDataSource(inputDataSource);
}
catch (Exception e)
{
@@ -107,7 +107,7 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
}
/** After this method returns the inputData will be written to file. */
public void updateDataSource(@NotNull FullDataSourceV2 inputData, boolean lockOnUpdatePos)
public void updateDataSource(@NotNull FullDataSourceV2 inputData)
{
if (this.isShutdownRef.get())
{
@@ -117,25 +117,20 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
long updatePos = inputData.getPos();
boolean methodLocked = false;
// a lock is necessary to prevent two threads from writing to the same position at once,
// if that happens only the second update will apply and the LOD will end up with hole(s)
ReentrantLock updateLock = this.updateLockProvider.getLock(updatePos);
try
{
if (lockOnUpdatePos)
{
methodLocked = true;
updateLock.lock();
this.lockedPosSet.add(updatePos);
}
updateLock.lock();
this.lockedPosSet.add(updatePos);
// get or create the data source
try (FullDataSourceV2 recipientDataSource = this.provider.get(updatePos))
{
if (recipientDataSource != null)
if (recipientDataSource != null) // will be null if the repo was shut down
{
boolean dataModified = recipientDataSource.updateFromDataSource(inputData);
if (dataModified)
@@ -170,11 +165,8 @@ public class FullDataUpdaterV2 implements IDebugRenderable, AutoCloseable
}
finally
{
if (methodLocked)
{
updateLock.unlock();
this.lockedPosSet.remove(updatePos);
}
updateLock.unlock();
this.lockedPosSet.remove(updatePos);
}
}
@@ -210,7 +210,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
while (!this.isGeneratorBusy()
&& taskStarted)
{
taskStarted = this.startNextWorldGenTask(this.generationTargetPos);
taskStarted = this.tryStartNextWorldGenTask(this.generationTargetPos);
}
}
catch (Exception e)
@@ -240,7 +240,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
* @param targetPos the position to center the generation around
* @return false if no tasks were found to generate
*/
private boolean startNextWorldGenTask(DhBlockPos2D targetPos)
private boolean tryStartNextWorldGenTask(DhBlockPos2D targetPos)
{
if (this.waitingTasks.isEmpty())
{
@@ -249,23 +249,23 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
Mapper closestTaskMap = this.waitingTasks.reduceEntries(1024,
entry -> new Mapper(entry.getValue(), DhSectionPos.getSectionBBoxPos(entry.getValue().pos).getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D())),
(aMapper, bMapper) -> aMapper.dist < bMapper.dist ? aMapper : bMapper);
TaskDistancePair closestTaskPair = this.waitingTasks.reduceEntries(1024,
entry -> new TaskDistancePair(entry.getValue(), DhSectionPos.getSectionBBoxPos(entry.getValue().pos).getCenterBlockPos().toPos2D().chebyshevDist(targetPos.toPos2D())),
(TaskDistancePair aTaskPair, TaskDistancePair bTaskPair) -> (aTaskPair.dist < bTaskPair.dist) ? aTaskPair : bTaskPair);
if (closestTaskMap == null)
if (closestTaskPair == null)
{
// FIXME concurrency issue
return false;
}
WorldGenTask closestTask = closestTaskMap.task;
WorldGenTask closestTask = closestTaskPair.task;
// remove the task we found, we are going to start it and don't want to run it multiple times
this.waitingTasks.remove(closestTask.pos, closestTask);
// do we need to modify this task to generate it?
if (this.canGeneratePos(closestTask.pos))
if (this.canGenerateDetailLevel(DhSectionPos.getDetailLevel(closestTask.pos)))
{
// detail level is correct for generation, start generation
@@ -276,11 +276,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
{
// no task exists for this position, start one
InProgressWorldGenTaskGroup newTaskGroup = new InProgressWorldGenTaskGroup(closestTaskGroup);
boolean taskStarted = this.tryStartingWorldGenTaskGroup(newTaskGroup);
if (!taskStarted)
{
//LOGGER.trace("Unable to start task: "+closestTask.pos+", skipping. Task position may have already been generated.");
}
this.startWorldGenTaskGroup(newTaskGroup);
}
else
{
@@ -289,7 +285,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
// the newly selected task, we cannot use it,
// as some chunks may have already been written into.
//LOGGER.trace("A task already exists for this position, todo: "+closestTask.pos);
//LOGGER.warn("A task already exists for this position, todo: "+DhSectionPos.toString(closestTask.pos));
}
// a task has been started
@@ -321,8 +317,7 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
return true;
}
}
/** @return true if the task was started, false otherwise */
private boolean tryStartingWorldGenTaskGroup(InProgressWorldGenTaskGroup newTaskGroup)
private void startWorldGenTaskGroup(InProgressWorldGenTaskGroup newTaskGroup)
{
byte taskDetailLevel = newTaskGroup.group.dataDetail;
long taskPos = newTaskGroup.group.pos;
@@ -375,7 +370,6 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
});
this.inProgressGenTasksByLodPos.put(taskPos, newTaskGroup);
return true;
}
private CompletableFuture<Void> startGenerationEvent(
long requestPos,
@@ -689,9 +683,9 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
// helper methods //
//================//
private boolean canGeneratePos(long taskPos)
private boolean canGenerateDetailLevel(byte taskDetailLevel)
{
byte requestedDetailLevel = (byte) (DhSectionPos.getDetailLevel(taskPos) - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
byte requestedDetailLevel = (byte) (taskDetailLevel - DhSectionPos.SECTION_MINIMUM_DETAIL_LEVEL);
return (this.highestDataDetail <= requestedDetailLevel && requestedDetailLevel <= this.lowestDataDetail);
}
@@ -701,11 +695,12 @@ public class WorldGenerationQueue implements IFullDataSourceRetrievalQueue, IDeb
// helper classes //
//================//
private static class Mapper
private static class TaskDistancePair
{
public final WorldGenTask task;
public final int dist;
public Mapper(WorldGenTask task, int dist)
public TaskDistancePair(WorldGenTask task, int dist)
{
this.task = task;
this.dist = dist;