@@ -343,28 +343,41 @@ impl<RT: Runtime> IndexWorker<RT> {
343343 index_documents. values ( ) ,
344344 self . persistence_version ,
345345 ) ?;
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.
358366 let ( backfill_begin_ts, index_name, indexed_fields) =
359367 self . begin_retention ( index_id) . await ?;
368+ log:: info!( "Started running retention for index {}" , index_name) ;
360369 self . index_writer
361370 . run_retention ( index_id, backfill_begin_ts, index_name, indexed_fields)
362371 . await ?;
372+
363373 self . finish_backfill ( index_id) . await ?;
364374 Ok ( ( ) )
365375 }
366376
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 ) > {
368381 let mut tx = self . database . begin ( Identity :: system ( ) ) . await ?;
369382 let index_table_id = tx. bootstrap_tables ( ) . index_id ;
370383
@@ -382,21 +395,23 @@ impl<RT: Runtime> IndexWorker<RT> {
382395 // the state to still be `Backfilling` here. If this assertion fails, we
383396 // somehow raced with another `IndexWorker`(!) or don't actually have the
384397 // 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+ } ,
390408 _ => anyhow:: bail!(
391409 "IndexWorker attempted to backfill an index {index_metadata:?} which wasn't a \
392410 database index."
393411 ) ,
394412 } ;
395413
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) )
400415 }
401416
402417 async fn begin_retention (
@@ -410,34 +425,48 @@ impl<RT: Runtime> IndexWorker<RT> {
410425 . get_with_ts ( ResolvedDocumentId :: new ( index_table_id, index_id) )
411426 . await ?
412427 . 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) ?;
414429
415430 // Assuming that the IndexWorker is the only writer of index state, we expect
416431 // the state to still be `Backfilling` here. If this assertion fails, we
417432 // somehow raced with another `IndexWorker`(!) or don't actually have the
418433 // database lease (!).
419- let indexed_fields = match & index_metadata. config {
434+ let ( index_ts , indexed_fields) = match & mut index_metadata. config {
420435 IndexConfig :: Database {
421436 on_disk_state,
422437 developer_config,
423438 } => {
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 ( ) )
430454 } ,
431455 _ => anyhow:: bail!(
432456 "IndexWorker attempted to backfill an index {index_metadata:?} which wasn't a \
433457 database index."
434458 ) ,
435459 } ;
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) )
441470 }
442471
443472 async fn finish_backfill ( & mut self , index_id : IndexId ) -> anyhow:: Result < ( ) > {
0 commit comments