@@ -75,7 +75,10 @@ public class UserDataManager {
7575 private final Set <UUID > completedSharedCachePopulations = ConcurrentHashMap .newKeySet ();
7676 private final ConcurrentHashMap <UUID , SharedCachePopulationState > sharedCachePopulationStates = new ConcurrentHashMap <>();
7777 /** Live storage identities, maintained from platform join/quit events. */
78- private final Set <UUID > onlineUserSessions = ConcurrentHashMap .newKeySet ();
78+ // TRUE/FALSE records the latest player-event state. Offline tombstones keep a
79+ // concurrent Folia snapshot from re-adding a player whose quit event won the
80+ // race; a later snapshot removes tombstones once Bukkit no longer lists them.
81+ private final ConcurrentHashMap <UUID , Boolean > onlineUserSessions = new ConcurrentHashMap <>();
7982
8083 private static final class SharedCachePopulationState {
8184 private long generation ;
@@ -1170,14 +1173,19 @@ public void clearCacheBasic() {
11701173 */
11711174 public void clearNonNeededCachedUsers () {
11721175 Runnable capture = () -> {
1173- java .util .HashSet <UUID > online = new java .util .HashSet <>();
1176+ java .util .HashSet <UUID > platformOnline = new java .util .HashSet <>();
11741177 for (Player player : Bukkit .getOnlinePlayers ()) {
11751178 UUID storageUuid = onlineStorageUuid (player );
1176- if (storageUuid != null ) {
1177- online .add (storageUuid );
1178- onlineUserSessions .add (storageUuid );
1179- }
1179+ if (storageUuid != null ) platformOnline .add (storageUuid );
1180+ }
1181+ java .util .HashSet <UUID > online = new java .util .HashSet <>();
1182+ for (UUID uuid : platformOnline ) {
1183+ Boolean state = onlineUserSessions .compute (uuid ,
1184+ (ignored , current ) -> Boolean .FALSE .equals (current ) ? Boolean .FALSE : Boolean .TRUE );
1185+ if (Boolean .TRUE .equals (state )) online .add (uuid );
11801186 }
1187+ onlineUserSessions .entrySet ().removeIf (entry -> Boolean .FALSE .equals (entry .getValue ())
1188+ && !platformOnline .contains (entry .getKey ()));
11811189 try {
11821190 timer .execute (() -> {
11831191 try { clearNonNeededCachedUsers (online ); }
@@ -1212,7 +1220,7 @@ private UUID onlineStorageUuid(Player player) {
12121220 }
12131221
12141222 public void markUserOnline (UUID uuid ) {
1215- if (uuid != null ) onlineUserSessions .add (uuid );
1223+ if (uuid != null ) onlineUserSessions .put (uuid , Boolean . TRUE );
12161224 }
12171225
12181226 /** Capture an online session from a Bukkit/Folia-owned player event. */
@@ -1221,7 +1229,7 @@ public void markUserOnline(Player player) {
12211229 }
12221230
12231231 public void markUserOffline (UUID uuid ) {
1224- if (uuid != null ) onlineUserSessions .remove (uuid );
1232+ if (uuid != null ) onlineUserSessions .put (uuid , Boolean . FALSE );
12251233 }
12261234
12271235 /** Remove an online session from a Bukkit/Folia-owned player event. */
@@ -1233,17 +1241,17 @@ private void clearNonNeededCachedUsers(Set<UUID> onlineSnapshot) {
12331241 plugin .devDebug ("Clearing cache for non online players (if any)" );
12341242 int removed = 0 ;
12351243 for (UUID uuid : Set .copyOf (userDataCache .keySet ())) {
1236- if (onlineSnapshot .contains (uuid ) || onlineUserSessions .contains (uuid )) continue ;
1244+ if (onlineSnapshot .contains (uuid ) || Boolean . TRUE . equals ( onlineUserSessions .get (uuid ) )) continue ;
12371245 UserDataCache expected = userDataCache .get (uuid );
12381246 if (expected == null ) continue ;
12391247 long expectedVersion = expected .getSharedSnapshotVersion ();
12401248 java .util .concurrent .atomic .AtomicBoolean retired = new java .util .concurrent .atomic .AtomicBoolean ();
12411249 withSharedSqlBackendExclusive (uuid , () -> {
1242- if (onlineUserSessions .contains (uuid )) return ;
1250+ if (Boolean . TRUE . equals ( onlineUserSessions .get (uuid ) )) return ;
12431251 UserDataCache current = userDataCache .get (uuid );
12441252 if (current != expected || current .getSharedSnapshotVersion () != expectedVersion ) return ;
12451253 current .beginRemoval ();
1246- if (onlineUserSessions .contains (uuid )) {
1254+ if (Boolean . TRUE . equals ( onlineUserSessions .get (uuid ) )) {
12471255 current .cancelRemoval ();
12481256 return ;
12491257 }
0 commit comments