- Timestamp:
- 03/19/2026 01:13:06 PM (4 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/collaboration/class-wp-sync-post-meta-storage.php
r61788 r62064 80 80 } 81 81 82 // Create an envelope and stamp each update to enable cursor-based filtering. 83 $envelope = array( 84 'timestamp' => $this->get_time_marker(), 85 'value' => $update, 86 ); 87 88 return (bool) add_post_meta( $post_id, wp_slash( self::SYNC_UPDATE_META_KEY ), wp_slash( $envelope ), false ); 89 } 90 91 /** 92 * Retrieves all sync updates for a given room. 93 * 94 * @since 7.0.0 95 * 96 * @param string $room Room identifier. 97 * @return array<int, array{ timestamp: int, value: mixed }> Sync updates. 98 */ 99 private function get_all_updates( string $room ): array { 100 $this->room_cursors[ $room ] = $this->get_time_marker() - 100; // Small buffer to ensure consistency. 101 102 $post_id = $this->get_storage_post_id( $room ); 103 if ( null === $post_id ) { 104 return array(); 105 } 106 107 $updates = get_post_meta( $post_id, self::SYNC_UPDATE_META_KEY, false ); 108 109 if ( ! is_array( $updates ) ) { 110 $updates = array(); 111 } 112 113 // Filter out any updates that don't have the expected structure. 114 $updates = array_filter( 115 $updates, 116 static function ( $update ): bool { 117 return is_array( $update ) && isset( $update['timestamp'], $update['value'] ) && is_int( $update['timestamp'] ); 118 } 119 ); 120 121 $this->room_update_counts[ $room ] = count( $updates ); 122 123 return $updates; 82 $meta_id = add_post_meta( $post_id, self::SYNC_UPDATE_META_KEY, $update, false ); 83 84 return (bool) $meta_id; 124 85 } 125 86 … … 171 132 * 172 133 * The cursor is set during get_updates_after_cursor() and represents the 173 * point in time just before the updates were retrieved, with a small buffer 174 * to ensure consistency. 134 * highest meta_id seen for the room's sync updates. 175 135 * 176 136 * @since 7.0.0 … … 237 197 238 198 /** 239 * Gets the current time in milliseconds as a comparable time marker.240 *241 * @since 7.0.0242 *243 * @return int Current time in milliseconds.244 */245 private function get_time_marker(): int {246 return (int) floor( microtime( true ) * 1000 );247 }248 249 /**250 199 * Gets the number of updates stored for a given room. 251 200 * … … 260 209 261 210 /** 262 * Retrieves sync updates from a room for a given client and cursor. Updates 263 * from the specified client should be excluded. 211 * Retrieves sync updates from a room after the given cursor. 264 212 * 265 213 * @since 7.0.0 266 214 * 267 215 * @param string $room Room identifier. 268 * @param int $cursor Return updates after this cursor .216 * @param int $cursor Return updates after this cursor (meta_id). 269 217 * @return array<int, mixed> Sync updates. 270 218 */ 271 219 public function get_updates_after_cursor( string $room, int $cursor ): array { 272 $all_updates = $this->get_all_updates( $room ); 273 $updates = array(); 274 275 foreach ( $all_updates as $update ) { 276 if ( $update['timestamp'] > $cursor ) { 277 $updates[] = $update; 278 } 279 } 280 281 // Sort by timestamp to ensure order. 282 usort( 283 $updates, 284 fn ( $a, $b ) => $a['timestamp'] <=> $b['timestamp'] 285 ); 286 287 return wp_list_pluck( $updates, 'value' ); 220 global $wpdb; 221 222 $post_id = $this->get_storage_post_id( $room ); 223 if ( null === $post_id ) { 224 $this->room_cursors[ $room ] = 0; 225 $this->room_update_counts[ $room ] = 0; 226 return array(); 227 } 228 229 // Capture the current room state first so the returned cursor is race-safe. 230 $stats = $wpdb->get_row( 231 $wpdb->prepare( 232 "SELECT COUNT(*) AS total_updates, COALESCE( MAX(meta_id), 0 ) AS max_meta_id FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s", 233 $post_id, 234 self::SYNC_UPDATE_META_KEY 235 ) 236 ); 237 238 $total_updates = $stats ? (int) $stats->total_updates : 0; 239 $max_meta_id = $stats ? (int) $stats->max_meta_id : 0; 240 241 $this->room_update_counts[ $room ] = $total_updates; 242 $this->room_cursors[ $room ] = $max_meta_id; 243 244 if ( $max_meta_id <= $cursor ) { 245 return array(); 246 } 247 248 $rows = $wpdb->get_results( 249 $wpdb->prepare( 250 "SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s AND meta_id > %d AND meta_id <= %d ORDER BY meta_id ASC", 251 $post_id, 252 self::SYNC_UPDATE_META_KEY, 253 $cursor, 254 $max_meta_id 255 ) 256 ); 257 258 if ( ! $rows ) { 259 return array(); 260 } 261 262 $updates = array(); 263 foreach ( $rows as $row ) { 264 $updates[] = maybe_unserialize( $row->meta_value ); 265 } 266 267 return $updates; 288 268 } 289 269 … … 294 274 * 295 275 * @param string $room Room identifier. 296 * @param int $cursor Remove updates with m arkers< this cursor.276 * @param int $cursor Remove updates with meta_id < this cursor. 297 277 * @return bool True on success, false on failure. 298 278 */ 299 279 public function remove_updates_before_cursor( string $room, int $cursor ): bool { 280 global $wpdb; 281 300 282 $post_id = $this->get_storage_post_id( $room ); 301 283 if ( null === $post_id ) { … … 303 285 } 304 286 305 $all_updates = $this->get_all_updates( $room ); 306 307 // Remove all updates for the room and re-store only those that are newer than the cursor. 308 if ( ! delete_post_meta( $post_id, wp_slash( self::SYNC_UPDATE_META_KEY ) ) ) { 287 $deleted_rows = $wpdb->query( 288 $wpdb->prepare( 289 "DELETE FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = %s AND meta_id < %d", 290 $post_id, 291 self::SYNC_UPDATE_META_KEY, 292 $cursor 293 ) 294 ); 295 296 if ( false === $deleted_rows ) { 309 297 return false; 310 298 } 311 299 312 // Re-store envelopes directly to avoid double-wrapping by add_update(). 313 $add_result = true; 314 foreach ( $all_updates as $envelope ) { 315 if ( $add_result && $envelope['timestamp'] >= $cursor ) { 316 $add_result = (bool) add_post_meta( $post_id, self::SYNC_UPDATE_META_KEY, $envelope, false ); 317 } 318 } 319 320 return $add_result; 300 return true; 321 301 } 322 302 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)