Repository navigation
Fix deadlocks when concurrent requests write tracked options - #81
Merged
Merged
Conversation
Every request writes the options it read to wp_option_optimizer_tracked
on shutdown with INSERT ... ON DUPLICATE KEY UPDATE. InnoDB locks rows in
VALUES order, which followed per-request access order, so concurrent
requests locked the same rows in different orders and deadlocked
("Deadlock found when trying to get lock"), losing that request's counts.
Sort the options before writing so all writers lock in one order. On a
failed insert, ROLLBACK instead of sending COMMIT (which also hid the
error by clearing $wpdb->last_error), and retry once on a deadlock; the
deadlock rolls back the whole transaction, so the retry can't double count.
Reproduced locally with 20 parallel writers x 50 batch_insert() calls of
200 shuffled options: ~920/1000 deadlocks before, 0/1000 after with all
200000 increments landed. Retry path verified with a forced deadlock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Test on Playground |
jdevalk
approved these changes
Oct 5, 2026
ilicfilip
marked this pull request as ready for review
October 5, 2026 07:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A user reported
Deadlock found when trying to get lockerrors in their logs, attributed to Option Optimizer.Every request writes the options it read to
wp_option_optimizer_trackedonshutdown, viaDatabase::batch_insert()(INSERT … ON DUPLICATE KEY UPDATEinside a transaction). InnoDB locks rows inVALUESorder, which followed each request's option access order. Concurrent requests (front end, admin, REST, cron) therefore locked the same hot rows (siteurl,active_plugins, …) in different orders and deadlocked. MySQL rolled back the victim and that request's counts were lost. TheCOMMITsent afterwards also cleared$wpdb->last_error, so the failure was silent in code.Fix
ksort( $options, SORT_STRING )before writing, so all writers lock rows in one order.SORT_STRINGbecause numeric option names become int keys.ROLLBACK(instead of falling through toCOMMIT), preserving the error.Covers both callers: the per-request shutdown write and the legacy-data migration.
Verification (local, MySQL 8.0.33)
Load test: 20 parallel processes × 50
batch_insert()calls of 200 shuffled real option names. Deadlocks counted withinformation_schema.INNODB_METRICS.lock_deadlocks.node_modules).Not tested: MariaDB. A deadlock that the retry recovers from is still logged once by wpdb, but these should now be rare.
🤖 Generated with Claude Code