Fix race condition in player search index synchronization

players array and index are now updated atomically under write lock.
Index is rebuilt every time since it stores array indices into players.
License status propagation also moved inside write lock.
This commit is contained in:
Claude Brisson
2025-11-29 12:02:36 +01:00
parent 67d8428b85
commit cbadb4d6bb

View File

@@ -56,7 +56,7 @@ object RatingsManager: Runnable {
object Task: TimerTask() { object Task: TimerTask() {
override fun run() { override fun run() {
try { try {
players = ratingsHandlers.values.filter { it.active }.flatMapTo(Json.MutableArray()) { ratings -> val newPlayers = ratingsHandlers.values.filter { it.active }.flatMapTo(Json.MutableArray()) { ratings ->
val ratingsFile = WebappManager.properties.getProperty("ratings.${ratings.origin.name.lowercase()}") as String? val ratingsFile = WebappManager.properties.getProperty("ratings.${ratings.origin.name.lowercase()}") as String?
if (ratingsFile == null) { if (ratingsFile == null) {
ratings.fetchPlayers() ratings.fetchPlayers()
@@ -64,17 +64,12 @@ object RatingsManager: Runnable {
ratings.fetchPlayers(Paths.get("").resolve(ratingsFile).toFile()) ratings.fetchPlayers(Paths.get("").resolve(ratingsFile).toFile())
} }
} }
val updated = ratingsHandlers.values.filter { it.active }.map { it.updated() }.reduce { u1, u2 -> // Always update players and index together under the write lock
u1 or u2 // Index must be rebuilt every time since it stores array indices
}
if (updated) {
try { try {
updateLock.writeLock().lock() updateLock.writeLock().lock()
players = newPlayers
index.build(players) index.build(players)
} finally {
updateLock.writeLock().unlock()
}
}
// propagate French players license status from ffg to egf // propagate French players license status from ffg to egf
val licenseStatus = players.map { it -> it as Json.MutableObject }.filter { val licenseStatus = players.map { it -> it as Json.MutableObject }.filter {
@@ -93,7 +88,9 @@ object RatingsManager: Runnable {
} }
} }
} }
} finally {
updateLock.writeLock().unlock()
}
} catch (e: Exception) { } catch (e: Exception) {
logger.error("could not build or refresh index: ${e.javaClass.name} ${e.message}") logger.error("could not build or refresh index: ${e.javaClass.name} ${e.message}")
logger.debug("could not build or refresh index", e) logger.debug("could not build or refresh index", e)