Changes by Marius Dumitru Florea on 14/Oct/26 11:43
Fix Version:
18.9.0-rc-1
Fix Version:
18.8.0
Documentation in Release Notes:
N/A
Documentation:
N/A
Resolution:
Solved By
Status:
OpenClosed
1 comment
Marius Dumitru Florea on 14/Oct/26 11:43
Closing as solved by XWIKI-24997, released in 18.8.0. That change made the store default to READ COMMITTED when hibernate.cfg.xml doesn't set an isolation level. The deadlock came from the gap lock that the DELETE in saveLock takes under REPEATABLE READ when the document has no lock yet, and InnoDB doesn't take that gap lock under READ COMMITTED. XWIKI-22421, which introduced the DELETE + INSERT, was not backported, so 18.8.0-rc-1 is the only released version affected in a default configuration.
Evidence
CI, ConfigurableClassIT#testLockingAndUnlocking in the MySQL environment: 0 failures in 209 runs from 2026-01-01 to 2026-08-28; 7 failures and 1 flaky run in 69 runs from 2026-08-28 to 2026-09-17; 0 failures in 93 runs since XWIKI-24997 was merged.
Local stress test on stable-18.9.x (MySQL latest, Tomcat, default isolation): 300 rounds, each replaying concurrently the requests sent when switching between two administration sections (unlock the previous section's page and XWiki.XWikiPreferences, lock the next section's page and XWiki.XWikiPreferences). No lock was lost, and there was no deadlock and no duplicate key.
The deadlock at READ COMMITTED reported in the previous comment was most likely measured at REPEATABLE READ. That run used the oldcore snapshot built on 2026-09-17 at 10:05 UTC, before XWIKI-24997 was merged, and that jar doesn't set a default isolation level. No deadlock has been observed at READ COMMITTED since: none in about 1.2M stress transactions and 40 IT runs reported on the PR, none in the stress test above, and none on CI.
What remains
An installation whose hibernate.cfg.xml explicitly sets REPEATABLE READ can still hit the deadlock. Since XWIKI-24997 the store expects READ COMMITTED, so this is not handled here.
The stress test did reproduce a different lock failure: XWikiHibernateStore#loadLock selects the lock id and then loads the lock in a second statement. If a concurrent unlock commits between the two, the load fails with ObjectNotFoundException, LockAction answers with an error that the browser ignores, and the lock is not taken. This happened 3 times in the 300 rounds, always on XWiki.XWikiPreferences, the page that is unlocked and locked at the same time. It affects any database running at READ COMMITTED (always the case for PostgreSQL), so it predates XWIKI-24997. It will be handled in a separate issue.