[wp-trac] [WordPress Trac] #38931: `update_option()` race condition with non-autoloaded options

WordPress Trac noreply at wordpress.org
Thu Nov 24 13:31:56 UTC 2016


#38931: `update_option()` race condition with non-autoloaded options
--------------------------+-----------------------------
 Reporter:  dd32          |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Plugins       |    Version:  3.7
 Severity:  normal        |   Keywords:  has-patch
  Focuses:                |
--------------------------+-----------------------------
 Starting back in [25664] there's a race condition with object caches where
 `get_option()` will return a value, but `update_option()` will refuse to
 update it.
 This is kind-of-related to `alloptions`, but affects non-autoloaded
 options (which are not in `alloptions`, but in their own cache).

 Consider the following scenario:
 {{{
 Process 1: Fetch option_a. Fills local cache.
 Process 2: Update option_a.
 Process 1: Delete option_a.
 Process 2: Update DB.
 Process 1: Delete from DB. Delete from remote cache.
 Process 2: Update remote cache.
 ...
 Process 5: Fetch option_a. Fills local cache from remote cache.
 Process 5: Update option_a.  FAIL. DB doesn't have option. abort. cache
 not updated.
 ...
 (repeat process 5 above many times)
 Process 10: Get option_a (Still the value that Process 2 set in cache,
 even though it's not in the DB)
 Process 10: Update option_a (Doing the same as Process 5 now). FAIL.
 }}}

 Seems very racey and unlikely, but I've seen it happen on WordPress.org at
 least twice in the last few weeks when we update Jetpack (which makes
 heavy usage of the options table, and is loaded on most WordPress.org
 requests).

 When it happens, `get_option()` will continue to return a stale value from
 the cache that no longer exists in the DB and `update_option()` will fail
 to update the option as long as it exists in cache.
 If a plugin is performing an operation to update the stale option often,
 it can cause a huge load spike on the database server of never-ending
 failing `UPDATE` queries.
 The only way to 'fix' it is to create the DB row manually, or flush the
 object cache key.

 The patch attached attempts to perform an `add_option()` in the case of
 the `update_option()` DB query failing.
 This isn't exactly a new behaviour for options - `add_option()` will
 effectively perform an `update_option()` in the event the option you're
 trying to add already exists (through it using `INSERT .. ON DUPLICATE KEY
 UPDATE..`), doing it in reverse doesn't seem that out of the question.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/38931>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list