Class MigrationService
Single-location invariant: items are moved from the vanilla EC to the plugin DB with no window where a player can reach them in both places.
Why the migration runs under the session manager's exclusivity primitives: the DB write
targets chest #1, which may have a live shared session at that moment (the player raced a
/ec open against the join pre-check, or an admin ran /ee migrate while the chest was
open). Writing underneath a live session would be silently undone by that session's save on close —
with the vanilla EC already cleared, the migrated items would be lost. So the write phase first
force-closes any session of chest #1 (flushing its
contents, so the merge below reads the freshest state) and then runs inside
ChestSessionManager.runExclusive(java.util.UUID, int, java.util.function.Supplier<T>), which makes any concurrent open of chest #1 wait
behind the migration and then load the migrated contents. This reuses the same per-(owner, index)
serialization every other chest mutation uses — no separate lock.
Why merge-spill-and-flag is one atomic transaction: chest #1 may already hold items when
the migration write runs (the player deposited during the pre-check window, or the row pre-existed
un-flagged), so the write merges the vanilla snapshot into the chest's current contents
instead of replacing them — and chest #1's size is never changed (its size is the admin /
permission domain): vanilla items that do not fit spill into a recoverable temp chest, exactly like
every other overflow in the plugin. A merge is not idempotent — running it twice would
duplicate the vanilla items — so the migrated flag, the merged contents and the overflow temp chest
must all become visible together: EnderChestStorage.completeMigration(java.util.UUID, byte[], byte[], int, long) commits the three in
one transaction. No crash or concurrently-queued second migration can ever observe "merged but not
flagged" and merge again.
-
Constructor Summary
ConstructorsConstructorDescriptionMigrationService(EnderChestStorage storage, ContainerCodec codec, org.slf4j.Logger logger, ChestSessionManager sessions, Scheduler scheduler, Telemetry telemetry, long tempExpiryMillis) -
Method Summary
Modifier and TypeMethodDescriptionmigrateOnline(org.bukkit.entity.Player player) Migrates a live online player's vanilla enderchest into their chest #1, in three phases: Entity thread — snapshot the vanilla contents (cloned, so the stacks can safely cross threads); Exclusive DB phase — force-close any live session of chest #1, then (behind its save) re-check the migrated flag, ensure chest #1 exists, merge the snapshot into the chest's current contents (never resizing it — overflow spills to a temp chest), and commit contents + overflow + migrated flag in one atomic transaction.voidsetTempExpiry(long tempExpiryMillis) Re-applies the runtime-tunable temp-chest lifetime after a/ee reload.
-
Constructor Details
-
MigrationService
public MigrationService(EnderChestStorage storage, ContainerCodec codec, org.slf4j.Logger logger, ChestSessionManager sessions, Scheduler scheduler, Telemetry telemetry, long tempExpiryMillis)
-
-
Method Details
-
setTempExpiry
public void setTempExpiry(long tempExpiryMillis) Re-applies the runtime-tunable temp-chest lifetime after a/ee reload. Only affects temp chests stamped after this call. -
migrateOnline
Migrates a live online player's vanilla enderchest into their chest #1, in three phases:- Entity thread — snapshot the vanilla contents (cloned, so the stacks can safely cross threads);
- Exclusive DB phase — force-close any live session of chest #1, then (behind its
save) re-check the migrated flag, ensure chest #1 exists, merge the snapshot into the
chest's current contents (never resizing it — overflow spills to a temp chest), and
commit contents + overflow + migrated flag in one atomic transaction. The flag re-check
inside the exclusive section plus the atomic flag write make any racing double-run
(join + concurrent
/ee migrate, or two admin runs) a no-op; - Entity thread again — clear the vanilla EC. The DB copy is already authoritative and flagged; if the player logged out in the meantime the stale vanilla copy simply stays behind un-cleared, unreachable in-game (the plugin intercepts every ender chest open).
- Returns:
- a future completing with
trueif migration ran to completion;falseif the player was already migrated, went offline before the snapshot, or encoding failed
-