@@ -42,6 +42,7 @@ use databend_common_meta_app::tenant::Tenant;
42
42
use databend_common_meta_kvapi:: kvapi;
43
43
use databend_common_meta_kvapi:: kvapi:: DirName ;
44
44
use databend_common_meta_kvapi:: kvapi:: Key ;
45
+ use databend_common_meta_types:: txn_op:: Request ;
45
46
use databend_common_meta_types:: txn_op_response:: Response ;
46
47
use databend_common_meta_types:: MetaError ;
47
48
use databend_common_meta_types:: TxnRequest ;
@@ -77,19 +78,26 @@ where
77
78
Self : Send + Sync ,
78
79
Self : kvapi:: KVApi < Error = MetaError > ,
79
80
{
81
+ /// Garbage collect dropped tables.
82
+ ///
83
+ /// Returns the approximate number of metadata keys removed.
84
+ /// Note: DeleteByPrefix operations count as 1 but may remove multiple keys.
80
85
#[ fastrace:: trace]
81
- async fn gc_drop_tables ( & self , req : GcDroppedTableReq ) -> Result < ( ) , KVAppError > {
86
+ async fn gc_drop_tables ( & self , req : GcDroppedTableReq ) -> Result < usize , KVAppError > {
87
+ let mut num_meta_key_removed = 0 ;
82
88
for drop_id in req. drop_ids {
83
89
match drop_id {
84
90
DroppedId :: Db { db_id, db_name } => {
85
- gc_dropped_db_by_id ( self , db_id, & req. tenant , & req. catalog , db_name) . await ?
91
+ num_meta_key_removed +=
92
+ gc_dropped_db_by_id ( self , db_id, & req. tenant , & req. catalog , db_name) . await ?
86
93
}
87
94
DroppedId :: Table { name, id } => {
88
- gc_dropped_table_by_id ( self , & req. tenant , & req. catalog , & name, & id) . await ?
95
+ num_meta_key_removed +=
96
+ gc_dropped_table_by_id ( self , & req. tenant , & req. catalog , & name, & id) . await ?
89
97
}
90
98
}
91
99
}
92
- Ok ( ( ) )
100
+ Ok ( num_meta_key_removed )
93
101
}
94
102
}
95
103
@@ -107,12 +115,15 @@ pub const ORPHAN_POSTFIX: &str = "orphan";
107
115
///
108
116
/// Dropped table can not be accessed by any query,
109
117
/// so it is safe to remove all the copied files in multiple sub transactions.
118
+ ///
119
+ /// Returns the number of copied file entries removed.
110
120
async fn remove_copied_files_for_dropped_table (
111
121
kv_api : & ( impl kvapi:: KVApi < Error = MetaError > + ?Sized ) ,
112
122
table_id : & TableId ,
113
- ) -> Result < ( ) , MetaError > {
123
+ ) -> Result < usize , MetaError > {
114
124
let batch_size = 1024 ;
115
125
126
+ let mut num_removed_copied_files = 0 ;
116
127
// Loop until:
117
128
// - all cleaned
118
129
// - or table is removed from meta-service
@@ -122,7 +133,7 @@ async fn remove_copied_files_for_dropped_table(
122
133
123
134
let seq_meta = kv_api. get_pb ( table_id) . await ?;
124
135
let Some ( seq_table_meta) = seq_meta else {
125
- return Ok ( ( ) ) ;
136
+ return Ok ( num_removed_copied_files ) ;
126
137
} ;
127
138
128
139
// TODO: enable this check. Currently when gc db, the table may not be dropped.
@@ -145,7 +156,7 @@ async fn remove_copied_files_for_dropped_table(
145
156
let copied_files = key_stream. take ( batch_size) . try_collect :: < Vec < _ > > ( ) . await ?;
146
157
147
158
if copied_files. is_empty ( ) {
148
- return Ok ( ( ) ) ;
159
+ return Ok ( num_removed_copied_files ) ;
149
160
}
150
161
151
162
for copied_ident in copied_files. iter ( ) {
@@ -163,6 +174,8 @@ async fn remove_copied_files_for_dropped_table(
163
174
copied_files. display( )
164
175
) ;
165
176
177
+ num_removed_copied_files += copied_files. len ( ) ;
178
+
166
179
// Txn failures are ignored for simplicity, since copied files kv pairs are put with ttl,
167
180
// they will not be leaked permanently, will be cleaned eventually.
168
181
send_txn ( kv_api, txn) . await ?;
@@ -322,37 +335,45 @@ pub async fn get_history_tables_for_gc(
322
335
323
336
/// Permanently remove a dropped database from the meta-service.
324
337
/// then remove all **dropped and non-dropped** tables in the database.
338
+ ///
339
+ /// Returns the approximate number of metadata keys removed.
340
+ /// Note: DeleteByPrefix operations count as 1 but may remove multiple keys.
325
341
async fn gc_dropped_db_by_id (
326
342
kv_api : & ( impl GarbageCollectionApi + IndexApi + ?Sized ) ,
327
343
db_id : u64 ,
328
344
tenant : & Tenant ,
329
345
catalog : & String ,
330
346
db_name : String ,
331
- ) -> Result < ( ) , KVAppError > {
347
+ ) -> Result < usize , KVAppError > {
348
+ let mut num_meta_keys_removed = 0 ;
332
349
// List tables by tenant, db_id, table_name.
333
350
let db_id_history_ident = DatabaseIdHistoryIdent :: new ( tenant, db_name. clone ( ) ) ;
334
351
let Some ( seq_dbid_list) = kv_api. get_pb ( & db_id_history_ident) . await ? else {
335
- return Ok ( ( ) ) ;
352
+ info ! ( "db_id_history_ident not found for db_id {}" , db_id) ;
353
+ return Ok ( num_meta_keys_removed) ;
336
354
} ;
337
355
338
356
let mut db_id_list = seq_dbid_list. data ;
339
357
340
358
// If the db_id is not in the list, return.
341
359
if db_id_list. id_list . remove_first ( & db_id) . is_none ( ) {
342
- return Ok ( ( ) ) ;
360
+ info ! ( "db_id_history_ident of db_id {} is empty" , db_id) ;
361
+ return Ok ( num_meta_keys_removed) ;
343
362
}
344
363
345
364
let dbid = DatabaseId { db_id } ;
346
365
let Some ( seq_db_meta) = kv_api. get_pb ( & dbid) . await ? else {
347
- return Ok ( ( ) ) ;
366
+ info ! ( "database meta of db_id {} is empty" , db_id) ;
367
+ return Ok ( num_meta_keys_removed) ;
348
368
} ;
349
369
350
370
if seq_db_meta. drop_on . is_none ( ) {
351
371
// If db is not marked as dropped, just ignore the gc request and return directly.
352
372
// In subsequent KV transactions, we also verify that db_meta hasn't changed
353
373
// to ensure we don't reclaim metadata of the given database that might have been
354
374
// successfully undropped in a parallel operation.
355
- return Ok ( ( ) ) ;
375
+ info ! ( "database of db_id {} is not marked as dropped" , db_id) ;
376
+ return Ok ( num_meta_keys_removed) ;
356
377
}
357
378
358
379
// Mark database meta as gc_in_progress if necessary
@@ -397,13 +418,15 @@ async fn gc_dropped_db_by_id(
397
418
} ;
398
419
let dir_name = DirName :: new_with_level ( db_id_table_name, 1 ) ;
399
420
421
+ let mut num_db_id_table_name_keys_removed = 0 ;
400
422
let batch_size = 1024 ;
401
423
let key_stream = kv_api. list_pb_keys ( & dir_name) . await ?;
402
424
let mut chunks = key_stream. chunks ( batch_size) ;
403
425
while let Some ( targets) = chunks. next ( ) . await {
404
426
let mut txn = TxnRequest :: default ( ) ;
405
427
use itertools:: Itertools ;
406
428
let targets: Vec < DBIdTableName > = targets. into_iter ( ) . try_collect ( ) ?;
429
+ num_db_id_table_name_keys_removed += targets. len ( ) ;
407
430
for target in & targets {
408
431
txn. if_then . push ( txn_op_del ( target) ) ;
409
432
}
@@ -423,11 +446,17 @@ async fn gc_dropped_db_by_id(
423
446
) ;
424
447
}
425
448
}
449
+ info ! (
450
+ "{} DbIdTableNames cleaned for database {}[{}]" ,
451
+ num_db_id_table_name_keys_removed, db_name, db_id,
452
+ ) ;
453
+ num_meta_keys_removed += num_db_id_table_name_keys_removed;
426
454
}
427
455
428
456
let id_to_name = DatabaseIdToName { db_id } ;
429
457
let Some ( seq_name) = kv_api. get_pb ( & id_to_name) . await ? else {
430
- return Ok ( ( ) ) ;
458
+ info ! ( "id_to_name not found for db_id {}" , db_id) ;
459
+ return Ok ( num_meta_keys_removed) ;
431
460
} ;
432
461
433
462
let table_history_ident = TableIdHistoryIdent {
@@ -444,7 +473,8 @@ async fn gc_dropped_db_by_id(
444
473
for tb_id in table_history. id_list . iter ( ) {
445
474
let table_id_ident = TableId { table_id : * tb_id } ;
446
475
447
- remove_copied_files_for_dropped_table ( kv_api, & table_id_ident) . await ?;
476
+ let num_removed_copied_files =
477
+ remove_copied_files_for_dropped_table ( kv_api, & table_id_ident) . await ?;
448
478
let _ = remove_data_for_dropped_table (
449
479
kv_api,
450
480
tenant,
@@ -454,7 +484,7 @@ async fn gc_dropped_db_by_id(
454
484
& mut txn,
455
485
)
456
486
. await ?;
457
- remove_index_for_dropped_table ( kv_api , tenant , & table_id_ident , & mut txn ) . await ? ;
487
+ num_meta_keys_removed += num_removed_copied_files ;
458
488
}
459
489
460
490
txn. condition
@@ -481,24 +511,35 @@ async fn gc_dropped_db_by_id(
481
511
. push ( txn_cond_eq_seq ( & id_to_name, seq_name. seq ) ) ;
482
512
txn. if_then . push ( txn_op_del ( & id_to_name) ) ;
483
513
514
+ // Count removed keys (approximate for DeleteByPrefix operations)
515
+ for op in & txn. if_then {
516
+ if let Some ( Request :: Delete ( _) | Request :: DeleteByPrefix ( _) ) = & op. request {
517
+ num_meta_keys_removed += 1 ;
518
+ }
519
+ }
520
+
484
521
let _resp = kv_api. transaction ( txn) . await ?;
485
522
486
- Ok ( ( ) )
523
+ Ok ( num_meta_keys_removed )
487
524
}
488
525
489
526
/// Permanently remove a dropped table from the meta-service.
490
527
///
491
528
/// The data of the table should already have been removed before calling this method.
529
+ ///
530
+ /// Returns the approximate number of metadata keys removed.
531
+ /// Note: DeleteByPrefix operations count as 1 but may remove multiple keys.
492
532
async fn gc_dropped_table_by_id (
493
533
kv_api : & ( impl GarbageCollectionApi + IndexApi + ?Sized ) ,
494
534
tenant : & Tenant ,
495
535
catalog : & String ,
496
536
db_id_table_name : & DBIdTableName ,
497
537
table_id_ident : & TableId ,
498
- ) -> Result < ( ) , KVAppError > {
538
+ ) -> Result < usize , KVAppError > {
499
539
// First remove all copied files for the dropped table.
500
540
// These markers are not part of the table and can be removed in separate transactions.
501
- remove_copied_files_for_dropped_table ( kv_api, table_id_ident) . await ?;
541
+ let num_removed_copied_files =
542
+ remove_copied_files_for_dropped_table ( kv_api, table_id_ident) . await ?;
502
543
503
544
let mut trials = txn_backoff ( None , func_name ! ( ) ) ;
504
545
loop {
@@ -532,12 +573,22 @@ async fn gc_dropped_table_by_id(
532
573
. await ?;
533
574
534
575
// 3)
576
+
535
577
remove_index_for_dropped_table ( kv_api, tenant, table_id_ident, & mut txn) . await ?;
536
578
579
+ // Count removed keys (approximate for DeleteByPrefix operations)
580
+ let mut num_meta_keys_removed = 0 ;
581
+ for op in & txn. if_then {
582
+ if let Some ( Request :: Delete ( _) | Request :: DeleteByPrefix ( _) ) = & op. request {
583
+ num_meta_keys_removed += 1 ;
584
+ }
585
+ }
586
+ num_meta_keys_removed += num_removed_copied_files;
587
+
537
588
let ( succ, _responses) = send_txn ( kv_api, txn) . await ?;
538
589
539
590
if succ {
540
- return Ok ( ( ) ) ;
591
+ return Ok ( num_meta_keys_removed ) ;
541
592
}
542
593
}
543
594
}
0 commit comments