mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Maintenance after evacuation
- Mantle-bypass maintenance starts only after players leave the world - This covers studio close, studio disable, world remove, world unload and create rollback - Maintenance ends only when it was entered - Folia no longer treats a refused chunk requested during evacuation as a chunk system crash
This commit is contained in:
1 parent
f55fde17d4
commit
b1fbede364
7 files changed
+102
-23
No files matched your search
@@ -1098,12 +1098,14 @@ public class StudioSVC implements IrisService {
|
||||
}
|
||||
|
||||
private void destroyStudioWorld(World world, PlatformChunkGenerator generator) {
|
||||
IrisToolbelt.beginWorldMaintenance(world, "studio-disable", true);
|
||||
try {
|
||||
IrisToolbelt.evacuate(world);
|
||||
} catch (Throwable e) {
|
||||
IrisLogging.reportError("Failed to evacuate studio world \"" + world.getName() + "\" during shutdown cleanup.", e);
|
||||
}
|
||||
// Entered after the evacuation: maintenance that forbids mantle stages refuses every chunk, and Folia
|
||||
// treats a refused chunk as a chunk system failure.
|
||||
IrisToolbelt.beginWorldMaintenance(world, "studio-disable", true);
|
||||
try {
|
||||
WorldLifecycleService.get().unloadAsync(world, false)
|
||||
.thenCompose(unloaded -> {
|
||||
|
||||
@@ -459,12 +459,14 @@ public final class StudioOpenCoordinator {
|
||||
) {
|
||||
AtomicBoolean unloadConfirmed = new AtomicBoolean(false);
|
||||
AtomicBoolean folderDeleted = new AtomicBoolean(!deleteFolder);
|
||||
if (world != null) {
|
||||
IrisToolbelt.beginWorldMaintenance(world, "studio-close", true);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> sequence = sequenceStudioClose(
|
||||
() -> evacuateWorldFamily(worldName, world),
|
||||
() -> {
|
||||
if (world != null) {
|
||||
IrisToolbelt.beginWorldMaintenance(world, "studio-close", true);
|
||||
}
|
||||
},
|
||||
() -> unloadWorldFamily(worldName, world).thenRun(() -> unloadConfirmed.set(true)),
|
||||
() -> provider == null ? CompletableFuture.completedFuture(null) : provider.closeAsync(),
|
||||
() -> deleteFolder
|
||||
@@ -491,14 +493,22 @@ public final class StudioOpenCoordinator {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintenance that forbids mantle stages refuses every chunk, and Folia treats a refused chunk as a chunk
|
||||
* system failure, so it is entered only once no player is left to request one.
|
||||
*/
|
||||
static CompletableFuture<Void> sequenceStudioClose(
|
||||
Supplier<CompletableFuture<Void>> evacuate,
|
||||
Runnable enterMaintenance,
|
||||
Supplier<CompletableFuture<Void>> unload,
|
||||
Supplier<CompletableFuture<Void>> closeGenerator,
|
||||
Supplier<CompletableFuture<Void>> deleteFolders
|
||||
) {
|
||||
return invokePhase(evacuate)
|
||||
.thenCompose(ignored -> invokePhase(unload))
|
||||
.thenCompose(ignored -> {
|
||||
enterMaintenance.run();
|
||||
return invokePhase(unload);
|
||||
})
|
||||
.thenCompose(ignored -> invokePhase(closeGenerator))
|
||||
.thenCompose(ignored -> invokePhase(deleteFolders));
|
||||
}
|
||||
|
||||
@@ -756,12 +756,17 @@ public class IrisCreator {
|
||||
}
|
||||
}
|
||||
if (activeWorld != null) {
|
||||
IrisToolbelt.beginWorldMaintenance(activeWorld, "world-create-rollback", true);
|
||||
boolean maintenanceEntered = false;
|
||||
try {
|
||||
PlatformChunkGenerator generator = IrisToolbelt.access(activeWorld);
|
||||
boolean evacuated = Boolean.TRUE.equals(IrisToolbelt.evacuateAsync(activeWorld)
|
||||
.get(ROLLBACK_PHASE_TIMEOUT_SECONDS, TimeUnit.SECONDS));
|
||||
if (!evacuated) {
|
||||
if (evacuated) {
|
||||
// Maintenance that forbids mantle stages refuses every chunk, and Folia treats a refused chunk
|
||||
// as a chunk system failure, so it starts only once no player is left to request one.
|
||||
IrisToolbelt.beginWorldMaintenance(activeWorld, "world-create-rollback", true);
|
||||
maintenanceEntered = true;
|
||||
} else {
|
||||
safeToDelete = false;
|
||||
failure.addSuppressed(new IllegalStateException(
|
||||
"Rollback could not evacuate world \"" + name + "\"."));
|
||||
@@ -789,7 +794,9 @@ public class IrisCreator {
|
||||
ServerConfigurator.restart("World creation rollback timed out for \"" + name + "\".");
|
||||
}
|
||||
} finally {
|
||||
IrisToolbelt.endWorldMaintenance(activeWorld, "world-create-rollback", true);
|
||||
if (maintenanceEntered) {
|
||||
IrisToolbelt.endWorldMaintenance(activeWorld, "world-create-rollback", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -152,15 +152,21 @@ public final class IrisWorldRemovalService {
|
||||
boolean deleteFiles,
|
||||
AtomicBoolean terminal
|
||||
) {
|
||||
// Maintenance that forbids mantle stages refuses every chunk, and Folia treats a refused chunk as a chunk
|
||||
// system failure, so it starts only once no player is left to request one.
|
||||
AtomicBoolean maintenanceEntered = new AtomicBoolean(false);
|
||||
CompletableFuture<RemovalResult> operation = phase(
|
||||
RemovalStatus.RESOLUTION_FAILED,
|
||||
() -> backend.beginMaintenance(resolved).thenApply(ignored -> resolved),
|
||||
RemovalStatus.TELEPORT_FAILED,
|
||||
() -> backend.evacuatePlayers(resolved).thenApply(ignored -> resolved),
|
||||
terminal
|
||||
)
|
||||
.thenCompose(activeWorld -> phase(
|
||||
RemovalStatus.TELEPORT_FAILED,
|
||||
() -> backend.evacuatePlayers(activeWorld)
|
||||
.thenApply(ignored -> activeWorld),
|
||||
RemovalStatus.RESOLUTION_FAILED,
|
||||
() -> {
|
||||
CompletableFuture<Void> begun = backend.beginMaintenance(activeWorld);
|
||||
maintenanceEntered.set(true);
|
||||
return begun.thenApply(ignored -> activeWorld);
|
||||
},
|
||||
terminal
|
||||
))
|
||||
.thenCompose(activeWorld -> phase(
|
||||
@@ -198,7 +204,7 @@ public final class IrisWorldRemovalService {
|
||||
);
|
||||
}));
|
||||
|
||||
return operation.handle((result, throwable) -> backend.endMaintenance(resolved)
|
||||
return operation.handle((result, throwable) -> endMaintenance(resolved, maintenanceEntered.get())
|
||||
.handle((ignored, cleanupFailure) -> {
|
||||
if (cleanupFailure != null) {
|
||||
Throwable unwrappedCleanup = unwrap(cleanupFailure);
|
||||
@@ -216,6 +222,10 @@ public final class IrisWorldRemovalService {
|
||||
})).thenCompose(result -> result);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> endMaintenance(ResolvedWorld resolved, boolean entered) {
|
||||
return entered ? backend.endMaintenance(resolved) : CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
private CompletableFuture<ResolvedWorld> validateResolvedWorld(ResolvedWorld resolvedWorld) {
|
||||
if (!resolvedWorld.managed()) {
|
||||
return CompletableFuture.failedFuture(new RemovalFailure(
|
||||
|
||||
Reference in new issue
Block a user