Skip to content

Commit 93adae4

Browse files
committed
Collaboration: Fix labels and add table verification to data loss proof
- Fix usage comment to match actual filename - Update beta references from "beta 1" to "beta 1–3" - Rename "Table (proposed)" to "Table (this PR)" - Replace "Gap" column with side-by-side comparison that measures both backends at each scale: post meta shows data loss window, table shows rows visible after compaction - Drop "Sync" prefix from output header
1 parent 540a003 commit 93adae4

1 file changed

Lines changed: 51 additions & 32 deletions

File tree

tools/local-env/scripts/collaboration-perf/DO_NOT_RELEASE_prove-beta3-post_meta_data_loss.php

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
* The 10 newest rows are never deleted, never absent. There is no step 2.
1212
*
13-
* Post meta compaction (beta 1) does this:
13+
* Post meta compaction (beta 1–3) does this:
1414
* 1. delete_post_meta() — removes ALL 50 updates in one call.
1515
* 2. add_post_meta() — re-inserts the 10 newest updates one at a time.
1616
*
@@ -19,7 +19,7 @@
1919
* should still exist.
2020
*
2121
* Usage:
22-
* npm run env:cli -- eval-file tools/local-env/scripts/collaboration-perf/DO_NOT_RELEASE_prove-data-loss.php
22+
* npm run env:cli -- eval-file tools/local-env/scripts/collaboration-perf/DO_NOT_RELEASE_prove-beta3-post_meta_data_loss.php
2323
*
2424
* @package WordPress
2525
*/
@@ -113,13 +113,14 @@
113113
// Step 2 of 2 (re-insert kept updates) would happen here, but the gap already occurred.
114114

115115
// =====================================================================
116-
// Gap at scale.
116+
// Compaction at scale.
117117
//
118-
// The gap is the time between delete_post_meta() and the last
119-
// add_post_meta() the window where all updates are missing.
120-
// More updates to keep = more add_post_meta() calls = wider gap.
118+
// Post meta: the data loss window is the time between
119+
// delete_post_meta() and the last add_post_meta() — more updates
120+
// to keep = more add_post_meta() calls = wider window.
121121
//
122-
// Table compaction has no gap. The kept rows are never removed.
122+
// Table: rows are never absent — verify by reading immediately
123+
// after compaction at each scale.
123124
// =====================================================================
124125

125126
$gap_scales = array( 50, 200, 500, 1000 );
@@ -135,7 +136,8 @@
135136

136137
WP_CLI::log( " Scale: {$gap_total} updates (keep {$gap_keep})" );
137138

138-
// Seed post meta for this scale.
139+
// --- Post meta: measure the data loss window. ---
140+
139141
$gap_post_id = wp_insert_post( array(
140142
'post_type' => 'wp_sync_storage',
141143
'post_status' => 'publish',
@@ -148,30 +150,46 @@
148150
) );
149151
}
150152

151-
// The cursor: timestamp of the first update to keep.
152-
$gap_cursor = 1000 + $gap_discard;
153-
154-
// Read all updates before deleting (same as production code path).
153+
$gap_cursor = 1000 + $gap_discard;
155154
$all_updates = get_post_meta( $gap_post_id, 'wp_sync_update', false );
156155

157-
// Measure the full gap: delete all, then re-insert each kept update.
158156
$gap_start = microtime( true );
159157
delete_post_meta( $gap_post_id, 'wp_sync_update' );
160158
foreach ( $all_updates as $envelope ) {
161159
if ( is_array( $envelope ) && $envelope['timestamp'] >= $gap_cursor ) {
162160
add_post_meta( $gap_post_id, 'wp_sync_update', $envelope );
163161
}
164162
}
165-
$gap_ms = ( microtime( true ) - $gap_start ) * 1000;
163+
$meta_gap_ms = ( microtime( true ) - $gap_start ) * 1000;
164+
165+
wp_delete_post( $gap_post_id, true );
166+
167+
// --- Table: verify rows are never absent. ---
168+
169+
$wpdb->query( "TRUNCATE TABLE {$wpdb->collaboration}" );
170+
$storage = new WP_Collaboration_Table_Storage();
171+
for ( $i = 0; $i < $gap_total; $i++ ) {
172+
$storage->add_update( $gap_room, array( 'edit' => $i ) );
173+
}
174+
175+
$table_cursor = (int) $wpdb->get_var( $wpdb->prepare(
176+
"SELECT id FROM {$wpdb->collaboration} WHERE room = %s ORDER BY id DESC LIMIT 1 OFFSET %d",
177+
$gap_room,
178+
$gap_keep - 1
179+
) );
180+
181+
$storage->remove_updates_before_cursor( $gap_room, $table_cursor );
182+
183+
$reader = new WP_Collaboration_Table_Storage();
184+
$table_after = $reader->get_updates_after_cursor( $gap_room, 0 );
185+
$table_visible_count = count( $table_after );
166186

167187
$gap_results[] = array(
168-
'total' => $gap_total,
169-
'keep' => $gap_keep,
170-
'gap_ms' => $gap_ms,
188+
'total' => $gap_total,
189+
'keep' => $gap_keep,
190+
'meta_gap_ms' => $meta_gap_ms,
191+
'table_visible' => $table_visible_count,
171192
);
172-
173-
// Cleanup this scale.
174-
wp_delete_post( $gap_post_id, true );
175193
}
176194

177195
// =====================================================================
@@ -181,15 +199,15 @@
181199
$separator = str_repeat( '', 60 );
182200

183201
WP_CLI::log( '' );
184-
WP_CLI::log( WP_CLI::colorize( '%_Sync Compaction Data Integrity Test%n' ) );
202+
WP_CLI::log( WP_CLI::colorize( '%_Compaction Data Integrity Test%n' ) );
185203
WP_CLI::log( 'Run: ' . gmdate( 'Y-m-d H:i:s' ) . ' UTC' );
186204
WP_CLI::log( '' );
187205
WP_CLI::log( "Compaction triggers at {$total} updates. Keeps {$keep} newest, discards {$discard} oldest." );
188206
WP_CLI::log( WP_CLI::colorize( "%_Expected: {$keep} newest updates remain visible after compaction.%n" ) );
189207

190208
WP_CLI::log( '' );
191209
WP_CLI::log( $separator );
192-
WP_CLI::log( WP_CLI::colorize( '%_Table (proposed)%n' ) );
210+
WP_CLI::log( WP_CLI::colorize( '%_Table (this PR)%n' ) );
193211
WP_CLI::log( $separator );
194212
WP_CLI::log( " DELETE WHERE id < cutoff — only the {$discard} oldest removed." );
195213
WP_CLI::log( '' );
@@ -201,7 +219,7 @@
201219

202220
WP_CLI::log( '' );
203221
WP_CLI::log( $separator );
204-
WP_CLI::log( WP_CLI::colorize( '%_Post Meta (current beta 1)%n' ) );
222+
WP_CLI::log( WP_CLI::colorize( '%_Post Meta (beta 1–3)%n' ) );
205223
WP_CLI::log( $separator );
206224
WP_CLI::log( " delete_post_meta() removes all {$total}, then add_post_meta() re-inserts {$keep}." );
207225
WP_CLI::log( '' );
@@ -213,22 +231,23 @@
213231

214232
WP_CLI::log( '' );
215233
WP_CLI::log( $separator );
216-
WP_CLI::log( WP_CLI::colorize( '%_Post Meta gap at scale%n' ) );
234+
WP_CLI::log( WP_CLI::colorize( '%_Compaction at scale%n' ) );
217235
WP_CLI::log( $separator );
218-
WP_CLI::log( ' Duration where all updates are missing:' );
219236
WP_CLI::log( '' );
220237

221-
$scale_items = array();
238+
$scale_fields = array( 'Updates (keep 20%)', 'Post meta data loss window', 'Table rows visible' );
239+
$scale_items = array();
222240
foreach ( $gap_results as $gap ) {
241+
$table_label = $gap['table_visible'] >= $gap['keep']
242+
? "{$gap['table_visible']} of {$gap['keep']} — OK"
243+
: "{$gap['table_visible']} of {$gap['keep']} — UNEXPECTED";
223244
$scale_items[] = array(
224-
'Updates (keep 20%)' => sprintf( '%d (keep %d)', $gap['total'], $gap['keep'] ),
225-
'Gap' => sprintf( '%.1f ms', $gap['gap_ms'] ),
245+
'Updates (keep 20%)' => sprintf( '%d (keep %d)', $gap['total'], $gap['keep'] ),
246+
'Post meta data loss window' => sprintf( '%.1f ms', $gap['meta_gap_ms'] ),
247+
'Table rows visible' => $table_label,
226248
);
227249
}
228-
WP_CLI\Utils\format_items( 'table', $scale_items, array( 'Updates (keep 20%)', 'Gap' ) );
229-
230-
WP_CLI::log( '' );
231-
WP_CLI::log( WP_CLI::colorize( ' %GTable: no gap at any scale.%n' ) );
250+
WP_CLI\Utils\format_items( 'table', $scale_items, $scale_fields );
232251

233252
// Cleanup.
234253
wp_delete_post( $post_id, true );

0 commit comments

Comments
 (0)