@@ -337,6 +337,7 @@ impl SchemaApiTestSuite {
337
337
suite. table_index_create_drop ( & b. build ( ) . await ) . await ?;
338
338
suite. index_create_list_drop ( & b. build ( ) . await ) . await ?;
339
339
suite. table_lock_revision ( & b. build ( ) . await ) . await ?;
340
+ suite. gc_dropped_db_after_undrop ( & b. build ( ) . await ) . await ?;
340
341
suite. catalog_create_get_list_drop ( & b. build ( ) . await ) . await ?;
341
342
suite. table_least_visible_time ( & b. build ( ) . await ) . await ?;
342
343
suite
@@ -6946,6 +6947,79 @@ impl SchemaApiTestSuite {
6946
6947
Ok ( ( ) )
6947
6948
}
6948
6949
6950
+ async fn gc_dropped_db_after_undrop < MT : SchemaApi + kvapi:: AsKVApi < Error = MetaError > > (
6951
+ self ,
6952
+ mt : & MT ,
6953
+ ) -> anyhow:: Result < ( ) > {
6954
+ let tenant_name = "tenant1_gc_dropped_db_after_undrop" ;
6955
+ let db_name = "db1_gc_dropped_db_after_undrop" ;
6956
+ let mut util = Util :: new ( mt, tenant_name, db_name, "" , "eng" ) ;
6957
+
6958
+ let tenant = Tenant :: new_or_err ( tenant_name, func_name ! ( ) ) ?;
6959
+ let db_name_ident = DatabaseNameIdent :: new ( & tenant, db_name) ;
6960
+
6961
+ // 1. Create database
6962
+ util. create_db ( ) . await ?;
6963
+ let db_id = util. db_id ;
6964
+
6965
+ info ! ( "Created database with ID: {}" , db_id) ;
6966
+
6967
+ // 2. Drop database
6968
+ util. drop_db ( ) . await ?;
6969
+
6970
+ // 2.1. Check database is marked as dropped
6971
+ let req = ListDroppedTableReq :: new ( & tenant) ;
6972
+ let resp = mt. get_drop_table_infos ( req) . await ?;
6973
+
6974
+ // Filter for our specific database ID
6975
+ let drop_ids: Vec < DroppedId > = resp
6976
+ . drop_ids
6977
+ . into_iter ( )
6978
+ . filter ( |id| {
6979
+ if let DroppedId :: Db { db_id : id, .. } = id {
6980
+ * id == db_id
6981
+ } else {
6982
+ false
6983
+ }
6984
+ } )
6985
+ . collect ( ) ;
6986
+
6987
+ assert ! (
6988
+ !drop_ids. is_empty( ) ,
6989
+ "Database being tested should be dropped"
6990
+ ) ;
6991
+
6992
+ // 3. Undrop the database
6993
+ //
6994
+ // A more rigorous test would verify the race condition protection, but difficult to implement as an integration test:
6995
+ // Ideally, we would undrop the database precisely after the `gc_drop_tables` process has verified
6996
+ // that the database is marked as dropped, but before committing the kv transaction that removes the database metadata.
6997
+
6998
+ let undrop_req = UndropDatabaseReq {
6999
+ name_ident : db_name_ident. clone ( ) ,
7000
+ } ;
7001
+ mt. undrop_database ( undrop_req) . await ?;
7002
+
7003
+ let req = GcDroppedTableReq {
7004
+ tenant : tenant. clone ( ) ,
7005
+ drop_ids,
7006
+ } ;
7007
+
7008
+ // 4. Check that gc_drop_tables operation has NOT removed database's meta data
7009
+ mt. gc_drop_tables ( req. clone ( ) ) . await ?;
7010
+
7011
+ // 5. Verify the database is still accessible
7012
+ let get_req = GetDatabaseReq :: new ( tenant. clone ( ) , db_name. to_string ( ) ) ;
7013
+ let db_info = mt. get_database ( get_req) . await ?;
7014
+ assert_eq ! ( db_info. database_id. db_id, db_id, "Database ID should match" ) ;
7015
+ assert ! (
7016
+ db_info. meta. drop_on. is_none( ) ,
7017
+ "Database should not be marked as dropped"
7018
+ ) ;
7019
+
7020
+ Ok ( ( ) )
7021
+ }
7022
+
6949
7023
// pub async fn share_create_get_drop<MT: SchemaApi>(&self, mt: &MT) -> anyhow::Result<()> {
6950
7024
// let tenant1 = "tenant1";
6951
7025
// let share_name1 = "share1";
0 commit comments