mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Tag prefetched copies with the controller's run token
If the controller crashes after sending generation N but before saving it, the destination keeps that prefetch while the controller restarts at N-1, and another instance can then upload different data as generation N. The controller now picks a random token per run, sends it with every prefetch and acquire reply, and the scenario applies a held copy only when its generation and token both match, and lets a new run's copy replace one with another token. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ca7caedfbe
commit
5e4dcada50
6 files changed
+84
-18
No files matched your search
@@ -358,6 +358,7 @@ function player_sync.sync_player(acquire_response)
|
||||
local record = downloads[acquire_response.player_name]
|
||||
if record and record.prefetch and not (
|
||||
acquire_response.status == "acquired" and record.generation == acquire_response.generation
|
||||
and record.token == acquire_response.token
|
||||
and serialize.same_components(record.components, script_data.components)
|
||||
) then
|
||||
downloads[acquire_response.player_name] = nil
|
||||
@@ -698,12 +699,14 @@ function player_sync.check_active_uploads()
|
||||
end
|
||||
end
|
||||
|
||||
-- Called by instance.ts as /sc player_sync.prefetch_inventory('name', generation, 'chunk', number, total) with a copy
|
||||
-- of a player's stored data that the controller sent ahead (PrefetchEvent) while they switch to this server. It holds
|
||||
-- Called by instance.ts as /sc player_sync.prefetch_inventory('name', generation, 'chunk', number, total, components,
|
||||
-- token) with a copy of a player's stored data that the controller sent ahead (PrefetchEvent) while they switch to this
|
||||
-- server. It holds
|
||||
-- the copy for a player who is offline here or doesn't exist yet. It prints only when it refuses or ignores a chunk,
|
||||
-- which stops the host sending the rest.
|
||||
--- @param components string? JSON of the components the instance stripped the copy by, given with the first chunk
|
||||
function player_sync.prefetch_inventory(player_name, generation, data, number, total, components)
|
||||
--- @param token string? The controller run that sent the copy, given with the first chunk
|
||||
function player_sync.prefetch_inventory(player_name, generation, data, number, total, components, token)
|
||||
local script_data = get_script_data()
|
||||
if number == 1 then
|
||||
local player = game.get_player(player_name)
|
||||
@@ -719,9 +722,12 @@ function player_sync.prefetch_inventory(player_name, generation, data, number, t
|
||||
return
|
||||
end
|
||||
-- Two copies can reach here out of order (applyRecipeNotificationDelta awaits zlib). A held finished copy of the
|
||||
-- same generation is replaced: it can be one the controller lost (a crash before its save), and the newer copy
|
||||
-- of the same number is what the controller holds now
|
||||
if (active and active.generation >= generation) or (finished and finished.generation > generation) then
|
||||
-- same generation is replaced: the newer copy of the same number is what the controller holds now. A copy
|
||||
-- with another token came from an earlier controller run, which may have crashed before saving that
|
||||
-- generation, so this run's copy replaces it whatever the generation
|
||||
local active_newer = active and active.token == token and active.generation >= generation
|
||||
local finished_newer = finished and finished.token == token and finished.generation > generation
|
||||
if active_newer or finished_newer then
|
||||
rcon.print("Refused prefetch for " .. player_name .. ": generation " .. generation .. " is not newer")
|
||||
return
|
||||
end
|
||||
@@ -732,6 +738,7 @@ function player_sync.prefetch_inventory(player_name, generation, data, number, t
|
||||
generation = generation,
|
||||
data = "",
|
||||
prefetch = true,
|
||||
token = token,
|
||||
components = components and compat.json_to_table(components),
|
||||
}
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user