Skip to content

Commit 636b18b

Browse files
chriszarateadamsilverstein
authored andcommitted
RTC: Use prepared queries instead of *_post_meta functions (#76779)
## What? Use prepared queries instead of `*_post_meta` functions. ## Why? Backport of WordPress/wordpress-develop#11325. Prevents post and post meta cache invalidation when RTC requests are handled. - See: https://core.trac.wordpress.org/ticket/64696 - See: https://core.trac.wordpress.org/ticket/64916
1 parent 0471862 commit 636b18b

3 files changed

Lines changed: 802 additions & 10 deletions

File tree

‎backport-changelog/7.0/11325.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
https://github.com/WordPress/wordpress-develop/pull/11325
2+
3+
* https://github.com/WordPress/gutenberg/pull/76779

‎lib/compat/wordpress-7.0/class-wp-sync-post-meta-storage.php‎

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ class WP_Sync_Post_Meta_Storage implements WP_Sync_Storage {
3232
* @since 7.0.0
3333
* @var string
3434
*/
35-
const AWARENESS_META_KEY = 'wp_sync_awareness';
35+
const AWARENESS_META_KEY = 'wp_sync_awareness_state';
3636

3737
/**
3838
* Meta key for sync updates.
3939
*
4040
* @since 7.0.0
4141
* @var string
4242
*/
43-
const SYNC_UPDATE_META_KEY = 'wp_sync_update';
43+
const SYNC_UPDATE_META_KEY = 'wp_sync_update_data';
4444

4545
/**
4646
* Cache of cursors by room.
@@ -71,36 +71,68 @@ class WP_Sync_Post_Meta_Storage implements WP_Sync_Storage {
7171
*
7272
* @since 7.0.0
7373
*
74+
* @global wpdb $wpdb WordPress database abstraction object.
75+
*
7476
* @param string $room Room identifier.
7577
* @param mixed $update Sync update.
7678
* @return bool True on success, false on failure.
7779
*/
7880
public function add_update( string $room, $update ): bool {
81+
global $wpdb;
82+
7983
$post_id = $this->get_storage_post_id( $room );
8084
if ( null === $post_id ) {
8185
return false;
8286
}
8387

84-
$meta_id = add_post_meta( $post_id, self::SYNC_UPDATE_META_KEY, $update, false );
85-
86-
return (bool) $meta_id;
88+
// Use direct database operation to avoid cache invalidation performed by
89+
// post meta functions (`wp_cache_set_posts_last_changed()` and direct
90+
// `wp_cache_delete()` calls).
91+
return (bool) $wpdb->insert(
92+
$wpdb->postmeta,
93+
array(
94+
'post_id' => $post_id,
95+
'meta_key' => self::SYNC_UPDATE_META_KEY,
96+
'meta_value' => wp_json_encode( $update ),
97+
),
98+
array( '%d', '%s', '%s' )
99+
);
87100
}
88101

89102
/**
90103
* Gets awareness state for a given room.
91104
*
92105
* @since 7.0.0
93106
*
107+
* @global wpdb $wpdb WordPress database abstraction object.
108+
*
94109
* @param string $room Room identifier.
95110
* @return array<int, mixed> Awareness state.
96111
*/
97112
public function get_awareness_state( string $room ): array {
113+
global $wpdb;
114+
98115
$post_id = $this->get_storage_post_id( $room );
99116
if ( null === $post_id ) {
100117
return array();
101118
}
102119

103-
$awareness = get_post_meta( $post_id, self::AWARENESS_META_KEY, true );
120+
// Use direct database operation to avoid updating the post meta cache.
121+
// ORDER BY meta_id DESC ensures the latest row wins if duplicates exist
122+
// from a past race condition in set_awareness_state().
123+
$meta_value = $wpdb->get_var(
124+
$wpdb->prepare(
125+
"SELECT meta_value FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s ORDER BY meta_id DESC LIMIT 1",
126+
$post_id,
127+
self::AWARENESS_META_KEY
128+
)
129+
);
130+
131+
if ( null === $meta_value ) {
132+
return array();
133+
}
134+
135+
$awareness = json_decode( $meta_value, true );
104136

105137
if ( ! is_array( $awareness ) ) {
106138
return array();
@@ -114,19 +146,54 @@ public function get_awareness_state( string $room ): array {
114146
*
115147
* @since 7.0.0
116148
*
149+
* @global wpdb $wpdb WordPress database abstraction object.
150+
*
117151
* @param string $room Room identifier.
118152
* @param array<int, mixed> $awareness Serializable awareness state.
119153
* @return bool True on success, false on failure.
120154
*/
121155
public function set_awareness_state( string $room, array $awareness ): bool {
156+
global $wpdb;
157+
122158
$post_id = $this->get_storage_post_id( $room );
123159
if ( null === $post_id ) {
124160
return false;
125161
}
126162

127-
// update_post_meta returns false if the value is the same as the existing value.
128-
update_post_meta( $post_id, self::AWARENESS_META_KEY, $awareness );
129-
return true;
163+
// Use direct database operation to avoid cache invalidation performed by
164+
// post meta functions (`wp_cache_set_posts_last_changed()` and direct
165+
// `wp_cache_delete()` calls).
166+
//
167+
// If two concurrent requests both see no row and both INSERT, the
168+
// duplicate is harmless: get_awareness_state() reads the latest row
169+
// (ORDER BY meta_id DESC).
170+
$meta_id = $wpdb->get_var(
171+
$wpdb->prepare(
172+
"SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s ORDER BY meta_id DESC LIMIT 1",
173+
$post_id,
174+
self::AWARENESS_META_KEY
175+
)
176+
);
177+
178+
if ( $meta_id ) {
179+
return (bool) $wpdb->update(
180+
$wpdb->postmeta,
181+
array( 'meta_value' => wp_json_encode( $awareness ) ),
182+
array( 'meta_id' => $meta_id ),
183+
array( '%s' ),
184+
array( '%d' )
185+
);
186+
}
187+
188+
return (bool) $wpdb->insert(
189+
$wpdb->postmeta,
190+
array(
191+
'post_id' => $post_id,
192+
'meta_key' => self::AWARENESS_META_KEY,
193+
'meta_value' => wp_json_encode( $awareness ),
194+
),
195+
array( '%d', '%s', '%s' )
196+
);
130197
}
131198

132199
/**
@@ -170,6 +237,8 @@ private function get_storage_post_id( string $room ): ?int {
170237
'post_status' => 'publish',
171238
'name' => $room_hash,
172239
'fields' => 'ids',
240+
'orderby' => 'ID',
241+
'order' => 'ASC',
173242
)
174243
);
175244

@@ -220,6 +289,8 @@ public function get_update_count( string $room ): int {
220289
*
221290
* @since 7.0.0
222291
*
292+
* @global wpdb $wpdb WordPress database abstraction object.
293+
*
223294
* @param string $room Room identifier.
224295
* @param int $cursor Return updates after this cursor (meta_id).
225296
* @return array<int, mixed> Sync updates.
@@ -269,7 +340,10 @@ public function get_updates_after_cursor( string $room, int $cursor ): array {
269340

270341
$updates = array();
271342
foreach ( $rows as $row ) {
272-
$updates[] = maybe_unserialize( $row->meta_value );
343+
$decoded = json_decode( $row->meta_value, true );
344+
if ( null !== $decoded ) {
345+
$updates[] = $decoded;
346+
}
273347
}
274348

275349
return $updates;
@@ -280,6 +354,8 @@ public function get_updates_after_cursor( string $room, int $cursor ): array {
280354
*
281355
* @since 7.0.0
282356
*
357+
* @global wpdb $wpdb WordPress database abstraction object.
358+
*
283359
* @param string $room Room identifier.
284360
* @param int $cursor Remove updates with meta_id < this cursor.
285361
* @return bool True on success, false on failure.

0 commit comments

Comments
 (0)