@@ -438,6 +438,29 @@ Status Redis::LongestNotCompactionSstCompact(const DataType& option_type, std::v
438438 return Status::OK ();
439439}
440440
441+ // Helper function to extract table file number from filename
442+ // e.g., "000123.sst" -> 123
443+ static uint64_t ExtractFileNumber (const std::string& name) {
444+ uint64_t number = 0 ;
445+ uint64_t base = 1 ;
446+ size_t pos = name.find_last_of (' .' );
447+ if (pos == std::string::npos) {
448+ return 0 ;
449+ }
450+ // Move backwards from '.' to find the digits
451+ while (pos > 0 ) {
452+ --pos;
453+ char c = name[pos];
454+ if (c >= ' 0' && c <= ' 9' ) {
455+ number += (c - ' 0' ) * base;
456+ base *= 10 ;
457+ } else {
458+ break ;
459+ }
460+ }
461+ return number;
462+ }
463+
441464Status Redis::IncrementalCompact (const DataType& option_type, std::vector<Status>* compact_result_vec,
442465 const ColumnFamilyType& type, int max_files, int max_time_ms,
443466 int min_rate, int target_level, int min_file_age) {
@@ -461,17 +484,19 @@ Status Redis::IncrementalCompact(const DataType& option_type, std::vector<Status
461484 compact_result_vec->clear ();
462485 }
463486
464- // 3. 记录开始时间
465- auto start_time = std::chrono::steady_clock::now ();
466487 int64_t now_sec = std::time (nullptr );
467488
468489 for (auto idx : handleIdxVec) {
490+ // 每个 CF 独立计时和配额
491+ auto cf_start_time = std::chrono::steady_clock::now ();
469492 int processed = 0 ;
493+
470494 while (processed < max_files) {
471- // 3.1 检查超时
472- auto elapsed = std::chrono::steady_clock::now () - start_time ;
495+ // 3.1 检查该 CF 的超时
496+ auto elapsed = std::chrono::steady_clock::now () - cf_start_time ;
473497 if (std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count () >= max_time_ms) {
474- LOG (INFO) << " IncrementalCompact timeout, processed " << processed << " files" ;
498+ LOG (INFO) << " IncrementalCompact timeout for cf=" << handles_[idx]->GetName ()
499+ << " , processed " << processed << " files" ;
475500 break ;
476501 }
477502
@@ -484,14 +509,19 @@ Status Redis::IncrementalCompact(const DataType& option_type, std::vector<Status
484509 uint64_t oldest_number = UINT64_MAX;
485510
486511 for (const auto & level_meta : meta.levels ) {
512+ // FIX: 跳过 L0,让 RocksDB 自动处理
513+ if (level_meta.level == 0 ) {
514+ continue ;
515+ }
516+
487517 for (const auto & file_meta : level_meta.files ) {
488518 // 跳过太新的文件
489519 if (file_meta.file_creation_time > 0 &&
490520 (now_sec - file_meta.file_creation_time ) < min_file_age) {
491521 continue ;
492522 }
493523
494- uint64_t number = TableFileNameToNumber (file_meta.name );
524+ uint64_t number = ExtractFileNumber (file_meta.name );
495525 if (number < oldest_number) {
496526 oldest_number = number;
497527 oldest_file = file_meta.db_path + " /" + file_meta.name ;
@@ -504,10 +534,22 @@ Status Redis::IncrementalCompact(const DataType& option_type, std::vector<Status
504534 break ; // 没有符合条件的文件
505535 }
506536
507- // 3.3 使用 CompactFiles 进行 compact
537+ // FIX: 跳过 L6 文件(没有上层了,避免 L6→L6 无效重写)
538+ if (oldest_level >= 6 ) {
539+ LOG (INFO) << " IncrementalCompact skip L6 file: " << oldest_file;
540+ break ;
541+ }
542+
543+ // 3.3 使用 CompactFiles 进行 compact(只处理 L1-L5)
508544 std::vector<std::string> input_files{oldest_file};
509545 rocksdb::CompactionOptions compact_options;
510- int dest_level = (target_level >= 0 ) ? target_level : oldest_level + 1 ;
546+ // 目标层 = 当前层 + 1(L1→L2, L2→L3, ... L5→L6)
547+ int dest_level = oldest_level + 1 ;
548+
549+ LOG (INFO) << " IncrementalCompact start: file=" << oldest_file
550+ << " , cf=" << handles_[idx]->GetName ()
551+ << " , from_level=" << oldest_level
552+ << " , to_level=" << dest_level;
511553
512554 rocksdb::CompactionJobInfo job_info;
513555 Status s = db_->CompactFiles (compact_options, handles_[idx],
0 commit comments