[wp-trac] [WordPress Trac] #34304: get_and_update_post_meta for atomic post meta operations

WordPress Trac noreply at wordpress.org
Wed Oct 14 19:49:54 UTC 2015


#34304: get_and_update_post_meta for atomic post meta operations
-----------------------------+-----------------------------
 Reporter:  lpghatguy        |      Owner:
     Type:  feature request  |     Status:  new
 Priority:  normal           |  Milestone:  Awaiting Review
Component:  Database         |    Version:  trunk
 Severity:  normal           |   Keywords:
  Focuses:                   |
-----------------------------+-----------------------------
 Assuming I have a function on the server that pulls post meta using
 `get_post_meta` and then writes it back, there's a relatively wide window
 for another request to compete with database resources and write an
 incorrect value.

 I'm going to call this function F, separated into two parts, read (R) and
 write (W). The result of F depends on the current value of the meta.

 As an example, say that I have two requests, R1 and R2, both competing to
 perform operation F. Ideally, this would happen like so:
 R1: R
 R1: W
 R2: R
 R2: W

 In the wild, sometimes an awful race happens:
 R1: R
 R2: R
 R1: W
 R2: W

 This can result in a catastrophically wrong value written to the database
 (usually as if request R1 never happened). What I'm proposing is a way to
 lock a specific row (or piece of post meta) for a defined period of time.

 The model of flow would then change to the following:
 R1: R & lock
 R1: W & release lock
 R2: R & lock
 R2: W & release lock

 In this case, '&' denotes that the operation should be totally atomic (one
 database query).

 A possible API for this might be:

 {{{
 get_and_update_post_meta($postID, $metaName, $callback);
 }}}

 Then, assuming PHP 5.4 or newer, it could be used to create an atomic
 increment operation like so:

 {{{
 get_and_update_post_meta($ID, "some_meta_field", function($value) {
         return parseInt($value) + 1;
 });
 }}}

 In older PHP releases, this could be done with a predefined function and a
 string-based function name.

 As far as implementation goes, MySQL 5.0+ supports GET_LOCK, RELEASE_LOCK,
 and IS_FREE_LOCK (http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-
 functions.html#function_get-lock) that would be perfect for this purpose.

 `get_and_update_post_meta` would be functionally equivalent to the
 following two:
 1. IS_FREE_LOCK & GET_LOCK & `get_post_meta`
 2. RELEASE_LOCK & `update_post_meta`

 The reasoning for the callback is to prevent accidental locks without
 corresponding unlocks. Other systems totally unrelated to WordPress use a
 similar model, like LOVE: https://love2d.org/wiki/Channel:performAtomic

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


More information about the wp-trac mailing list