@@ -720,9 +720,12 @@ impl Timeline {
720720 "inconsistent v1/v2 reldir keyspace for rel {}: v1_exists={}, v2_exists={}" ,
721721 tag,
722722 v1_exists,
723- v2_exists
723+ v2_exists,
724724 ) ;
725725 }
726+ Err ( e) if e. is_cancel ( ) => {
727+ // Cancellation errors are fine to ignore, do not log.
728+ }
726729 Err ( e) => {
727730 tracing:: warn!( "failed to get rel exists in v2: {e}" ) ;
728731 }
@@ -811,11 +814,11 @@ impl Timeline {
811814 forknum : key. field5 ,
812815 } ;
813816 if val == RelDirExists :: Removed {
814- debug_assert ! ( !rels. contains( & tag) , "removed reltag in v2" ) ;
817+ debug_assert ! ( !rels. contains( & tag) , "removed reltag in v2: {tag} " ) ;
815818 continue ;
816819 }
817820 let did_not_contain = rels. insert ( tag) ;
818- debug_assert ! ( did_not_contain, "duplicate reltag in v2" ) ;
821+ debug_assert ! ( did_not_contain, "duplicate reltag in v2: {tag} " ) ;
819822 }
820823 Ok ( rels)
821824 }
@@ -863,6 +866,9 @@ impl Timeline {
863866 rels_v2. len( )
864867 ) ;
865868 }
869+ Err ( e) if e. is_cancel ( ) => {
870+ // Cancellation errors are fine to ignore, do not log.
871+ }
866872 Err ( e) => {
867873 tracing:: warn!( "failed to list rels in v2: {e}" ) ;
868874 }
@@ -1724,6 +1730,8 @@ pub struct RelDirMode {
17241730 current_status : RelSizeMigration ,
17251731 // Whether we should initialize the v2 keyspace or not.
17261732 initialize : bool ,
1733+ // Whether we should disable v1 access starting this LSNor not
1734+ disable_v1 : bool ,
17271735}
17281736
17291737impl DatadirModification < ' _ > {
@@ -2085,44 +2093,82 @@ impl DatadirModification<'_> {
20852093 ///
20862094 /// As this function is only used on the write path, we do not need to read the migrated_at
20872095 /// field.
2088- pub fn maybe_enable_rel_size_v2 ( & mut self , is_create : bool ) -> anyhow:: Result < RelDirMode > {
2096+ pub ( crate ) fn maybe_enable_rel_size_v2 (
2097+ & mut self ,
2098+ lsn : Lsn ,
2099+ is_create : bool ,
2100+ ) -> anyhow:: Result < RelDirMode > {
20892101 // TODO: define the behavior of the tenant-level config flag and use feature flag to enable this feature
2102+ let expected_status = self . tline . get_rel_size_v2_expected_state ( ) ;
2103+ let ( persistent_status, migrated_at) = self . tline . get_rel_size_v2_status ( ) ;
2104+
2105+ // migrated_at LSN means the LSN where we "enable_v2" (but not "disable_v1")
2106+ if let Some ( migrated_at) = migrated_at
2107+ && lsn <= migrated_at
2108+ && persistent_status == RelSizeMigration :: Migrating
2109+ {
2110+ // Revert the status to legacy if the write head LSN is before the migrating LSN.
2111+ self . tline
2112+ . update_rel_size_v2_status ( RelSizeMigration :: Legacy , None ) ?;
2113+ }
2114+ // TODO: what if the migration is at "migrated" state but we need to revert?
2115+
2116+ // Only initialize the v2 keyspace on new relation creation. No initialization
2117+ // during `timeline_create` (TODO: fix this, we should allow, but currently it
2118+ // hits expected consistency issues; need to ignore warnings).
2119+ let can_update = is_create && !self . is_importing_pgdata ;
20902120
2091- let ( status, _) = self . tline . get_rel_size_v2_status ( ) ;
2092- let config = self . tline . get_rel_size_v2_enabled ( ) ;
2093- match ( config, status) {
2094- ( false , RelSizeMigration :: Legacy ) => {
2121+ match ( expected_status, persistent_status) {
2122+ ( RelSizeMigration :: Legacy , RelSizeMigration :: Legacy ) => {
20952123 // tenant config didn't enable it and we didn't write any reldir_v2 key yet
20962124 Ok ( RelDirMode {
20972125 current_status : RelSizeMigration :: Legacy ,
20982126 initialize : false ,
2127+ disable_v1 : false ,
20992128 } )
21002129 }
2101- ( false , status @ RelSizeMigration :: Migrating | status @ RelSizeMigration :: Migrated ) => {
2102- // index_part already persisted that the timeline has enabled rel_size_v2
2130+ (
2131+ RelSizeMigration :: Legacy ,
2132+ current_status @ RelSizeMigration :: Migrating
2133+ | current_status @ RelSizeMigration :: Migrated ,
2134+ ) => {
2135+ // already persisted that the timeline has enabled rel_size_v2, cannot rollback
21032136 Ok ( RelDirMode {
2104- current_status : status ,
2137+ current_status,
21052138 initialize : false ,
2139+ disable_v1 : false ,
21062140 } )
21072141 }
2108- ( true , RelSizeMigration :: Legacy ) => {
2142+ (
2143+ expected_status @ RelSizeMigration :: Migrating
2144+ | expected_status @ RelSizeMigration :: Migrated ,
2145+ RelSizeMigration :: Legacy ,
2146+ ) => {
21092147 // The first time we enable it, we need to persist it in `index_part.json`
21102148 // The caller should update the reldir status once the initialization is done.
2111- //
2112- // Only initialize the v2 keyspace on new relation creation. No initialization
2113- // during `timeline_create` (TODO: fix this, we should allow, but currently it
2114- // hits consistency issues).
2149+
21152150 Ok ( RelDirMode {
21162151 current_status : RelSizeMigration :: Legacy ,
2117- initialize : is_create && !self . is_importing_pgdata ,
2152+ initialize : can_update,
2153+ disable_v1 : can_update && expected_status == RelSizeMigration :: Migrated ,
21182154 } )
21192155 }
2120- ( true , status @ RelSizeMigration :: Migrating | status @ RelSizeMigration :: Migrated ) => {
2121- // index_part already persisted that the timeline has enabled rel_size_v2
2122- // and we don't need to do anything
2156+ ( RelSizeMigration :: Migrating , current_status @ RelSizeMigration :: Migrating )
2157+ | ( RelSizeMigration :: Migrated , current_status @ RelSizeMigration :: Migrated )
2158+ | ( RelSizeMigration :: Migrating , current_status @ RelSizeMigration :: Migrated ) => {
2159+ // Keep the current state
21232160 Ok ( RelDirMode {
2124- current_status : status ,
2161+ current_status,
21252162 initialize : false ,
2163+ disable_v1 : false ,
2164+ } )
2165+ }
2166+ ( RelSizeMigration :: Migrated , RelSizeMigration :: Migrating ) => {
2167+ // Switch to v2-only mode
2168+ Ok ( RelDirMode {
2169+ current_status : RelSizeMigration :: Migrating ,
2170+ initialize : false ,
2171+ disable_v1 : can_update,
21262172 } )
21272173 }
21282174 }
@@ -2137,8 +2183,8 @@ impl DatadirModification<'_> {
21372183 ctx : & RequestContext ,
21382184 ) -> Result < ( ) , WalIngestError > {
21392185 let v2_mode = self
2140- . maybe_enable_rel_size_v2 ( false )
2141- . map_err ( WalIngestErrorKind :: MaybeRelSizeV2Error ) ?;
2186+ . maybe_enable_rel_size_v2 ( self . lsn , false )
2187+ . map_err ( WalIngestErrorKind :: RelSizeV2Error ) ?;
21422188
21432189 // Add it to the directory (if it doesn't exist already)
21442190 let buf = self . get ( DBDIR_KEY , ctx) . await ?;
@@ -2290,15 +2336,6 @@ impl DatadirModification<'_> {
22902336 sparse_rel_dir_key,
22912337 Value :: Image ( RelDirExists :: Exists . encode ( ) ) ,
22922338 ) ;
2293- tracing:: info!(
2294- "migrated rel_size_v2: {}" ,
2295- RelTag {
2296- spcnode,
2297- dbnode,
2298- relnode,
2299- forknum
2300- }
2301- ) ;
23022339 rel_cnt += 1 ;
23032340 }
23042341 }
@@ -2307,9 +2344,6 @@ impl DatadirModification<'_> {
23072344 self . lsn,
23082345 rel_cnt
23092346 ) ;
2310- self . tline
2311- . update_rel_size_v2_status ( RelSizeMigration :: Migrating , Some ( self . lsn ) )
2312- . map_err ( WalIngestErrorKind :: MaybeRelSizeV2Error ) ?;
23132347 Ok :: < _ , WalIngestError > ( ( ) )
23142348 }
23152349
@@ -2392,35 +2426,50 @@ impl DatadirModification<'_> {
23922426 // It's possible that this is the first rel for this db in this
23932427 // tablespace. Create the reldir entry for it if so.
23942428 let mut dbdir = DbDirectory :: des ( & self . get ( DBDIR_KEY , ctx) . await ?) ?;
2429+ let mut is_dbdir_dirty = false ;
23952430
23962431 let dbdir_exists =
23972432 if let hash_map:: Entry :: Vacant ( e) = dbdir. dbdirs . entry ( ( rel. spcnode , rel. dbnode ) ) {
23982433 // Didn't exist. Update dbdir
23992434 e. insert ( false ) ;
2400- let buf = DbDirectory :: ser ( & dbdir) ?;
24012435 self . pending_directory_entries . push ( (
24022436 DirectoryKind :: Db ,
24032437 MetricsUpdate :: Set ( dbdir. dbdirs . len ( ) as u64 ) ,
24042438 ) ) ;
2405- self . put ( DBDIR_KEY , Value :: Image ( buf . into ( ) ) ) ;
2439+ is_dbdir_dirty = true ;
24062440 false
24072441 } else {
24082442 true
24092443 } ;
24102444
24112445 let mut v2_mode = self
2412- . maybe_enable_rel_size_v2 ( true )
2413- . map_err ( WalIngestErrorKind :: MaybeRelSizeV2Error ) ?;
2446+ . maybe_enable_rel_size_v2 ( self . lsn , true )
2447+ . map_err ( WalIngestErrorKind :: RelSizeV2Error ) ?;
24142448
24152449 if v2_mode. initialize {
24162450 if let Err ( e) = self . initialize_rel_size_v2_keyspace ( ctx, & dbdir) . await {
24172451 tracing:: warn!( "error initializing rel_size_v2 keyspace: {}" , e) ;
24182452 // TODO: circuit breaker so that it won't retry forever
24192453 } else {
24202454 v2_mode. current_status = RelSizeMigration :: Migrating ;
2455+ self . tline
2456+ . update_rel_size_v2_status ( RelSizeMigration :: Migrating , Some ( self . lsn ) )
2457+ . map_err ( WalIngestErrorKind :: RelSizeV2Error ) ?;
24212458 }
24222459 }
24232460
2461+ if v2_mode. disable_v1 {
2462+ v2_mode. current_status = RelSizeMigration :: Migrated ;
2463+ self . tline
2464+ . update_rel_size_v2_status ( RelSizeMigration :: Migrated , Some ( self . lsn ) )
2465+ . map_err ( WalIngestErrorKind :: RelSizeV2Error ) ?;
2466+ }
2467+
2468+ if is_dbdir_dirty {
2469+ let buf = DbDirectory :: ser ( & dbdir) ?;
2470+ self . put ( DBDIR_KEY , Value :: Image ( buf. into ( ) ) ) ;
2471+ }
2472+
24242473 if v2_mode. current_status != RelSizeMigration :: Migrated {
24252474 self . put_rel_creation_v1 ( rel, dbdir_exists, ctx) . await ?;
24262475 }
@@ -2581,8 +2630,8 @@ impl DatadirModification<'_> {
25812630 ctx : & RequestContext ,
25822631 ) -> Result < ( ) , WalIngestError > {
25832632 let v2_mode = self
2584- . maybe_enable_rel_size_v2 ( false )
2585- . map_err ( WalIngestErrorKind :: MaybeRelSizeV2Error ) ?;
2633+ . maybe_enable_rel_size_v2 ( self . lsn , false )
2634+ . map_err ( WalIngestErrorKind :: RelSizeV2Error ) ?;
25862635 match v2_mode. current_status {
25872636 RelSizeMigration :: Legacy => {
25882637 self . put_rel_drop_v1 ( drop_relations, ctx) . await ?;
@@ -2600,6 +2649,12 @@ impl DatadirModification<'_> {
26002649 ) ;
26012650 }
26022651 }
2652+ Err ( WalIngestError {
2653+ kind : WalIngestErrorKind :: Cancelled ,
2654+ ..
2655+ } ) => {
2656+ // Cancellation errors are fine to ignore, do not log.
2657+ }
26032658 Err ( e) => {
26042659 tracing:: warn!( "error dropping rels: {}" , e) ;
26052660 }
0 commit comments