@@ -343,28 +343,41 @@ impl<RT: Runtime> IndexWorker<RT> {
343
343
index_documents. values ( ) ,
344
344
self . persistence_version ,
345
345
) ?;
346
- let index_name = self . begin_backfill ( index_id) . await ?;
347
- let index_selector = IndexSelector :: Index {
348
- name : index_name,
349
- id : index_id,
350
- } ;
351
- self . index_writer
352
- . perform_backfill (
353
- self . database . now_ts_for_reads ( ) ,
354
- & index_registry,
355
- index_selector,
356
- )
357
- . await ?;
346
+
347
+ // If retention is already started, we have already done with the initial
348
+ // step of the backfill.
349
+ let ( index_name, retention_started) = self . begin_backfill ( index_id) . await ?;
350
+ if !retention_started {
351
+ log:: info!( "Starting backfill of index {}" , index_name) ;
352
+ let index_selector = IndexSelector :: Index {
353
+ name : index_name,
354
+ id : index_id,
355
+ } ;
356
+ self . index_writer
357
+ . perform_backfill (
358
+ self . database . now_ts_for_reads ( ) ,
359
+ & index_registry,
360
+ index_selector,
361
+ )
362
+ . await ?;
363
+ }
364
+
365
+ // Run retention.
358
366
let ( backfill_begin_ts, index_name, indexed_fields) =
359
367
self . begin_retention ( index_id) . await ?;
368
+ log:: info!( "Started running retention for index {}" , index_name) ;
360
369
self . index_writer
361
370
. run_retention ( index_id, backfill_begin_ts, index_name, indexed_fields)
362
371
. await ?;
372
+
363
373
self . finish_backfill ( index_id) . await ?;
364
374
Ok ( ( ) )
365
375
}
366
376
367
- async fn begin_backfill ( & mut self , index_id : IndexId ) -> anyhow:: Result < TabletIndexName > {
377
+ async fn begin_backfill (
378
+ & mut self ,
379
+ index_id : IndexId ,
380
+ ) -> anyhow:: Result < ( TabletIndexName , bool ) > {
368
381
let mut tx = self . database . begin ( Identity :: system ( ) ) . await ?;
369
382
let index_table_id = tx. bootstrap_tables ( ) . index_id ;
370
383
@@ -382,21 +395,23 @@ impl<RT: Runtime> IndexWorker<RT> {
382
395
// the state to still be `Backfilling` here. If this assertion fails, we
383
396
// somehow raced with another `IndexWorker`(!) or don't actually have the
384
397
// database lease (!).
385
- match & index_metadata. config {
386
- IndexConfig :: Database { on_disk_state, .. } => anyhow:: ensure!(
387
- matches!( * on_disk_state, DatabaseIndexState :: Backfilling ( _) ) ,
388
- "IndexWorker started backfilling index {index_metadata:?} not in Backfilling state" ,
389
- ) ,
398
+ let retention_started = match & index_metadata. config {
399
+ IndexConfig :: Database { on_disk_state, .. } => {
400
+ let DatabaseIndexState :: Backfilling ( state) = on_disk_state else {
401
+ anyhow:: bail!(
402
+ "IndexWorker started backfilling index {index_metadata:?} not in \
403
+ Backfilling state"
404
+ ) ;
405
+ } ;
406
+ state. retention_started
407
+ } ,
390
408
_ => anyhow:: bail!(
391
409
"IndexWorker attempted to backfill an index {index_metadata:?} which wasn't a \
392
410
database index."
393
411
) ,
394
412
} ;
395
413
396
- let ts = tx. begin_timestamp ( ) ;
397
- drop ( tx) ;
398
- log:: info!( "Starting backfill of index {} @ {ts}" , index_metadata. name) ;
399
- Ok ( index_metadata. name . clone ( ) )
414
+ Ok ( ( index_metadata. name . clone ( ) , retention_started) )
400
415
}
401
416
402
417
async fn begin_retention (
@@ -410,34 +425,48 @@ impl<RT: Runtime> IndexWorker<RT> {
410
425
. get_with_ts ( ResolvedDocumentId :: new ( index_table_id, index_id) )
411
426
. await ?
412
427
. ok_or_else ( || anyhow:: anyhow!( "Index {index_id:?} no longer exists" ) ) ?;
413
- let index_metadata = TabletIndexMetadata :: from_document ( index_doc) ?;
428
+ let mut index_metadata = TabletIndexMetadata :: from_document ( index_doc) ?;
414
429
415
430
// Assuming that the IndexWorker is the only writer of index state, we expect
416
431
// the state to still be `Backfilling` here. If this assertion fails, we
417
432
// somehow raced with another `IndexWorker`(!) or don't actually have the
418
433
// database lease (!).
419
- let indexed_fields = match & index_metadata. config {
434
+ let ( index_ts , indexed_fields) = match & mut index_metadata. config {
420
435
IndexConfig :: Database {
421
436
on_disk_state,
422
437
developer_config,
423
438
} => {
424
- anyhow:: ensure!(
425
- matches!( * on_disk_state, DatabaseIndexState :: Backfilling ( _) ) ,
426
- "IndexWorker started backfilling index {index_metadata:?} not in Backfilling \
427
- state",
428
- ) ;
429
- developer_config. fields . clone ( )
439
+ let DatabaseIndexState :: Backfilling ( state) = on_disk_state else {
440
+ anyhow:: bail!(
441
+ "IndexWorker started backfilling index {index_metadata:?} not in \
442
+ Backfilling state"
443
+ )
444
+ } ;
445
+
446
+ state. retention_started = true ;
447
+
448
+ // TODO(presley): Remove the fallback to commit_ts.
449
+ let WriteTimestamp :: Committed ( committed_ts) = index_ts else {
450
+ anyhow:: bail!( "index {index_id} is pending write" ) ;
451
+ } ;
452
+ let index_created = state. index_created_lower_bound . unwrap_or ( committed_ts) ;
453
+ ( index_created, developer_config. fields . clone ( ) )
430
454
} ,
431
455
_ => anyhow:: bail!(
432
456
"IndexWorker attempted to backfill an index {index_metadata:?} which wasn't a \
433
457
database index."
434
458
) ,
435
459
} ;
436
- drop ( tx) ;
437
- let WriteTimestamp :: Committed ( index_ts) = index_ts else {
438
- anyhow:: bail!( "index {index_id} is pending write" ) ;
439
- } ;
440
- Ok ( ( index_ts, index_metadata. name . clone ( ) , indexed_fields) )
460
+
461
+ let name = index_metadata. name . clone ( ) ;
462
+ SystemMetadataModel :: new ( & mut tx)
463
+ . replace ( index_metadata. id ( ) , index_metadata. into_value ( ) . try_into ( ) ?)
464
+ . await ?;
465
+ self . database
466
+ . commit_with_write_source ( tx, "index_worker_start_retention" )
467
+ . await ?;
468
+
469
+ Ok ( ( index_ts, name, indexed_fields) )
441
470
}
442
471
443
472
async fn finish_backfill ( & mut self , index_id : IndexId ) -> anyhow:: Result < ( ) > {
0 commit comments