Commit b9a8f56
Z User
fix: harden Folia concurrency for round lifecycle and shutdown
Phase 1 of the v1.3.0 concurrency review. Closes the gap left by 195b5aa
which only made botTask volatile but left three other fields with the same
race surface.
T1 - MahjongTableSession: make roundController, roundStartInProgress, and
riichiRoundEngine volatile. These are written on the table's region
thread during startRound / completeRoundStartInternal / setRound-
ControllerInternal but read cross-thread by the global tick timer's
bot watchdog, the async render precompute thread (via TableRegion-
FingerprintService), the seat watchdog global timer, the GameRoom
tick timer, and player entity threads. Without volatile the JVM is
free to reorder or cache reads, causing 'bot scheduled on a half-
published roundController' races that mirror the botTask race fixed
in 195b5aa.
T3 - TableRenderSnapshot: add roundStartInProgress to the snapshot record
and have TableRegionFingerprintService.seatLabelFingerprint read it
from the snapshot instead of the live session. precomputeRegion-
Fingerprints runs on the async render-precompute thread; using the
snapshot guarantees the fingerprint matches the rest of the snapshot
state captured on the region thread, avoiding a torn read where the
seat label fingerprint reflects a newer roundStartInProgress value
than the seat occupancy snapshots around it. T1 made the live read
safe but the snapshot read is strictly better.
T2 - TableSeatCoordinator.runSeatWatchdogs: stop reading session.isStarted
and session.seatOf from the global timer thread. The expiry check
(binding.expiresAtTick < nowTick) is the only pure-local-state short
circuit kept on the global timer; all session-state checks and the
player online check are deferred to inspectSeatWatchdogOnPlayerThread
which already runs on the player's entity thread. Eliminates the
'global timer reads session state' pattern that 195b5aa set out to
remove but missed in this coordinator.
T5 - MahjongTableSession.seatOf: document the best-effort read contract
for cross-thread callers. Most callers run on the table's region
thread where the write to participants.seats also happens; cross-
thread callers (player entity thread in TableEventCoordinator) read
best-effort. ArrayList.get is not throws-synchronized but the worst
case is a stale UUID that fails the equals check and returns null,
which the caller treats as 'not seated' and re-checks next tick.
T1 already covered the volatile concerns; this just fixes the
contract in code.
T6 - GameRoomManager.tick: add session.isStarted guard before scheduling
forceEndTable on the region thread. If the match has already ended
naturally between countdown expiry and this tick, skip the region
dispatch entirely. forceEndMatch is idempotent but skipping saves
a region task dispatch and an unnecessary render pass. isStarted
now reads the volatile roundController field (T1) so the cross-
thread read is safe.
T7 - MahjongPaperPlugin.onDisable + reloadMahjongConfiguration: close
the async executor BEFORE the database pool on shutdown, and drain
pending async DB tasks (awaitQuiescence) before closing the old
DataSource on reload. Previously the async queue could still hold
pending persistRoundResult / persistMatchRanks tasks that needed
a live DataSource; closing the DB first caused those tasks to throw
SQLException on getConnection(), which AsyncService swallows -
losing the final round results of any in-progress match.
AsyncService.awaitQuiescence submits a sentinel and waits for it
to complete, guaranteeing every previously-queued task has at
least started (and typically completed) before the close proceeds.
ArchitectureBoundaryTest: bump MahjongTableSession line budget from
1660 to 1700 and public method budget from 235 to 245 to accommodate
the new comments and the previously-merged addBotSilent method.1 parent 6faef1f commit b9a8f56
12 files changed
Lines changed: 134 additions & 13 deletions
File tree
- src
- main/java/top/ellan/mahjong
- bootstrap
- gameroom
- render/snapshot
- runtime
- table
- core
- render
- runtime
- test/kotlin/top/ellan/mahjong
- architecture
- perf
- render
- table/render
Lines changed: 22 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
153 | 157 | | |
154 | 158 | | |
155 | 159 | | |
156 | 160 | | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
157 | 165 | | |
158 | 166 | | |
159 | 167 | | |
| |||
321 | 329 | | |
322 | 330 | | |
323 | 331 | | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
324 | 342 | | |
325 | 343 | | |
326 | 344 | | |
| |||
Lines changed: 8 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
342 | 342 | | |
343 | 343 | | |
344 | 344 | | |
345 | | - | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
346 | 353 | | |
347 | 354 | | |
348 | 355 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
Lines changed: 43 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
49 | 92 | | |
50 | 93 | | |
Lines changed: 31 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
81 | | - | |
82 | | - | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
83 | 95 | | |
84 | 96 | | |
85 | 97 | | |
| |||
106 | 118 | | |
107 | 119 | | |
108 | 120 | | |
109 | | - | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
110 | 129 | | |
111 | 130 | | |
112 | 131 | | |
| |||
375 | 394 | | |
376 | 395 | | |
377 | 396 | | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
378 | 406 | | |
379 | 407 | | |
380 | 408 | | |
| |||
Lines changed: 8 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
174 | 174 | | |
175 | 175 | | |
176 | 176 | | |
177 | | - | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
178 | 185 | | |
179 | 186 | | |
180 | 187 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| |||
Lines changed: 11 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
200 | 200 | | |
201 | 201 | | |
202 | 202 | | |
203 | | - | |
204 | | - | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
205 | 214 | | |
206 | 215 | | |
207 | 216 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
285 | 285 | | |
286 | 286 | | |
287 | 287 | | |
288 | | - | |
| 288 | + | |
289 | 289 | | |
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
293 | 293 | | |
294 | | - | |
| 294 | + | |
295 | 295 | | |
296 | 296 | | |
297 | 297 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
376 | 376 | | |
377 | 377 | | |
378 | 378 | | |
| 379 | + | |
379 | 380 | | |
380 | 381 | | |
381 | 382 | | |
| |||
0 commit comments