Class MigrationService

java.lang.Object
com.enhancedechest.migration.MigrationService

public final class MigrationService extends Object
Orchestrates migration of vanilla enderchest data into the plugin's storage.

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

    Constructors
    Constructor
    Description
    MigrationService(EnderChestStorage storage, ContainerCodec codec, org.slf4j.Logger logger, ChestSessionManager sessions, Scheduler scheduler, Telemetry telemetry, long tempExpiryMillis)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    migrateOnline(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.
    void
    setTempExpiry(long tempExpiryMillis)
    Re-applies the runtime-tunable temp-chest lifetime after a /ee reload.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

  • 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

      public CompletableFuture<Boolean> migrateOnline(org.bukkit.entity.Player player)
      Migrates a live online player's vanilla enderchest into their chest #1, in three phases:
      1. Entity thread — snapshot the vanilla contents (cloned, so the stacks can safely cross threads);
      2. 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;
      3. 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 true if migration ran to completion; false if the player was already migrated, went offline before the snapshot, or encoding failed