Skip to content

Commit ef52284

Browse files
committed
fix
1 parent 08bcb3f commit ef52284

1 file changed

Lines changed: 169 additions & 95 deletions

File tree

tools/bigkey_analyzer/bigkey_analyzer.cc

Lines changed: 169 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -351,65 +351,104 @@ void AnalyzeSets(const std::string& path, std::vector<KeyInfo>& key_infos, const
351351

352352
std::cout << "Analyzing sets database at " << path << "..." << std::endl;
353353

354-
// 初始化存储选项
355-
storage::StorageOptions storage_options;
356-
storage::Storage storage;
357-
rocksdb::Status s = storage.Open(storage_options, path);
354+
// Open database with column families
355+
rocksdb::DBOptions db_options;
356+
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
357+
column_families.emplace_back(rocksdb::kDefaultColumnFamilyName, rocksdb::ColumnFamilyOptions());
358+
column_families.emplace_back("data_cf", rocksdb::ColumnFamilyOptions());
358359

359-
if (!s.ok()) {
360-
std::cerr << "Error opening sets database: " << s.ToString() << std::endl;
360+
std::vector<rocksdb::ColumnFamilyHandle*> handles;
361+
rocksdb::DB* db;
362+
rocksdb::Status status = rocksdb::DB::OpenForReadOnly(db_options, path, column_families, &handles, &db);
363+
364+
if (!status.ok()) {
365+
std::cerr << "Error opening sets database: " << status.ToString() << std::endl;
361366
return;
362367
}
363-
364-
// 使用Scan API遍历所有set keys
365-
std::string start_key;
366-
const std::string pattern("*");
367-
const int64_t count = 1000;
368-
std::string next_key;
369-
bool scan_finished = false;
370-
371-
while (!scan_finished) {
372-
std::vector<std::string> keys;
373-
s = storage.Scanx(storage::DataType::kSets, start_key, pattern, count, &keys, &next_key);
374-
if (!s.ok()) {
375-
std::cerr << "Error scanning sets: " << s.ToString() << std::endl;
376-
break;
377-
}
378-
379-
// 如果next_key为空,或者没有找到更多键,则结束扫描
380-
if (next_key.empty() || keys.empty()) {
381-
scan_finished = true;
382-
}
368+
369+
int64_t curtime;
370+
db->GetEnv()->GetCurrentTime(&curtime).ok();
371+
372+
rocksdb::ReadOptions read_options;
373+
374+
// Using an unordered_map to group set members by key
375+
std::unordered_map<std::string, std::pair<int64_t, int64_t>> set_sizes; // key -> (size, ttl)
376+
377+
// Read metadata from default column family (handles[0])
378+
auto meta_iter = db->NewIterator(read_options, handles[0]);
379+
for (meta_iter->SeekToFirst(); meta_iter->Valid(); meta_iter->Next()) {
380+
rocksdb::Slice key_slice = meta_iter->key();
381+
rocksdb::Slice value_slice = meta_iter->value();
382+
std::string key = key_slice.ToString();
383383

384-
start_key = next_key;
384+
int64_t ttl = -1;
385385

386-
// 处理每个集合键
387-
for (const auto& key : keys) {
388-
int64_t sum = 0;
389-
sum = sum + key.size() + 12; // 基础元数据大小
390-
391-
// 获取set的所有成员
392-
std::vector<std::string> members;
393-
int64_t ttl = -1;
386+
// Parse metadata value to get TTL
387+
if (value_slice.size() >= storage::ParsedBaseMetaValue::kBaseMetaValueSuffixLength) {
388+
storage::ParsedSetsMetaValue parsed_meta(value_slice);
394389

395-
s = storage.SMembersWithTTL(key, &members, &ttl);
396-
if (!s.ok()) {
390+
// Skip stale or empty sets
391+
if (parsed_meta.IsStale() || parsed_meta.count() == 0) {
397392
continue;
398393
}
399394

400-
// 计算每个成员的大小并加总
401-
for (const auto& member : members) {
402-
sum = sum + 4 + key.size() + 4 + member.size();
395+
int32_t timestamp = parsed_meta.timestamp();
396+
if (timestamp > 0 && !parsed_meta.IsPermanentSurvival()) {
397+
int64_t diff = timestamp - curtime;
398+
ttl = diff > 0 ? diff : -2;
403399
}
400+
}
401+
402+
// Initialize with base metadata size (key + 12 bytes overhead)
403+
int64_t sum = key.size() + 12;
404+
set_sizes[key] = std::make_pair(sum, ttl);
405+
}
406+
delete meta_iter;
407+
408+
// Read data members from data column family (handles[1])
409+
auto data_iter = db->NewIterator(read_options, handles[1]);
410+
for (data_iter->SeekToFirst(); data_iter->Valid(); data_iter->Next()) {
411+
rocksdb::Slice encoded_key_slice = data_iter->key();
412+
rocksdb::Slice value_slice = data_iter->value();
413+
414+
// Parse the data key to extract the set key and member
415+
try {
416+
storage::ParsedSetsMemberKey parsed_key(encoded_key_slice);
417+
std::string set_key = parsed_key.key().ToString();
418+
std::string member = parsed_key.member().ToString();
404419

405-
// 如果key大小超过阈值,添加到结果集
406-
if (sum >= config.min_size) {
407-
std::string display_key = ReplaceAll(key, "\n", "\\n");
408-
display_key = ReplaceAll(display_key, " ", "\\x20");
409-
key_infos.emplace_back("set", display_key, sum, ttl);
420+
// Calculate member size: 4 (size prefix) + key + 4 (size prefix) + member
421+
int64_t member_size = 4 + set_key.size() + 4 + member.size();
422+
423+
// Add member size to the corresponding set
424+
auto it = set_sizes.find(set_key);
425+
if (it != set_sizes.end()) {
426+
it->second.first += member_size;
427+
} else {
428+
// If metadata not found, initialize with member size and default ttl
429+
set_sizes[set_key] = std::make_pair(set_key.size() + 12 + member_size, -1);
410430
}
431+
} catch (...) {
432+
// Skip malformed keys
433+
continue;
411434
}
412435
}
436+
delete data_iter;
437+
438+
// Add set keys to the result
439+
for (const auto& entry : set_sizes) {
440+
if (entry.second.first >= config.min_size) {
441+
std::string display_key = ReplaceAll(entry.first, "\n", "\\n");
442+
display_key = ReplaceAll(display_key, " ", "\\x20");
443+
key_infos.emplace_back("set", display_key, entry.second.first, entry.second.second);
444+
}
445+
}
446+
447+
// Cleanup
448+
for (auto handle : handles) {
449+
delete handle;
450+
}
451+
delete db;
413452
}
414453

415454
// Analyze zsets database
@@ -607,68 +646,103 @@ void AnalyzeLists(const std::string& path, std::vector<KeyInfo>& key_infos, cons
607646

608647
std::cout << "Analyzing lists database at " << path << "..." << std::endl;
609648

610-
// 初始化存储选项
611-
storage::StorageOptions storage_options;
612-
storage::Storage storage;
613-
rocksdb::Status s = storage.Open(storage_options, path);
649+
// Open database with column families
650+
rocksdb::DBOptions db_options;
651+
std::vector<rocksdb::ColumnFamilyDescriptor> column_families;
652+
column_families.emplace_back(rocksdb::kDefaultColumnFamilyName, rocksdb::ColumnFamilyOptions());
653+
column_families.emplace_back("data_cf", rocksdb::ColumnFamilyOptions());
614654

615-
if (!s.ok()) {
616-
std::cerr << "Error opening lists database: " << s.ToString() << std::endl;
655+
std::vector<rocksdb::ColumnFamilyHandle*> handles;
656+
rocksdb::DB* db;
657+
rocksdb::Status status = rocksdb::DB::OpenForReadOnly(db_options, path, column_families, &handles, &db);
658+
659+
if (!status.ok()) {
660+
std::cerr << "Error opening lists database: " << status.ToString() << std::endl;
617661
return;
618662
}
619-
620-
// 使用Scan API遍历所有list keys
621-
std::string start_key;
622-
const std::string pattern("*");
623-
const int64_t count = 1000;
624-
const int64_t batch_count = 1000;
625-
std::string next_key;
626-
bool scan_finished = false;
627-
628-
while (!scan_finished) {
629-
std::vector<std::string> keys;
630-
s = storage.Scanx(storage::DataType::kLists, start_key, pattern, count, &keys, &next_key);
631-
if (!s.ok()) {
632-
std::cerr << "Error scanning lists: " << s.ToString() << std::endl;
633-
break;
634-
}
635-
636-
// 如果next_key为空,或者没有找到更多键,则结束扫描
637-
if (next_key.empty() || keys.empty()) {
638-
scan_finished = true;
639-
}
663+
664+
int64_t curtime;
665+
db->GetEnv()->GetCurrentTime(&curtime).ok();
666+
667+
rocksdb::ReadOptions read_options;
668+
669+
// Using an unordered_map to group list items by key
670+
std::unordered_map<std::string, std::pair<int64_t, int64_t>> list_sizes; // key -> (size, ttl)
671+
672+
// Read metadata from default column family (handles[0])
673+
auto meta_iter = db->NewIterator(read_options, handles[0]);
674+
for (meta_iter->SeekToFirst(); meta_iter->Valid(); meta_iter->Next()) {
675+
rocksdb::Slice key_slice = meta_iter->key();
676+
rocksdb::Slice value_slice = meta_iter->value();
677+
std::string key = key_slice.ToString();
640678

641-
start_key = next_key;
679+
int64_t ttl = -1;
642680

643-
// 处理每个列表键
644-
for (const auto& key : keys) {
645-
int64_t sum = 0;
646-
sum = sum + key.size() + 12 + 16; // 基础元数据大小
681+
// Parse metadata value to get TTL
682+
if (value_slice.size() >= storage::ParsedBaseMetaValue::kBaseMetaValueSuffixLength) {
683+
storage::ParsedListsMetaValue parsed_meta(value_slice);
647684

648-
// 获取list的所有元素,分批获取
649-
int64_t pos = 0;
650-
std::vector<std::string> list_items;
651-
int64_t ttl = -1;
685+
// Skip stale or empty lists
686+
if (parsed_meta.IsStale() || parsed_meta.count() == 0) {
687+
continue;
688+
}
652689

653-
s = storage.LRangeWithTTL(key, pos, pos + batch_count - 1, &list_items, &ttl);
654-
while (s.ok() && !list_items.empty()) {
655-
for (const auto& item : list_items) {
656-
sum = sum + 4 + key.size() + 4 + 8 + item.size();
657-
}
658-
659-
pos += batch_count;
660-
list_items.clear();
661-
s = storage.LRange(key, pos, pos + batch_count - 1, &list_items);
690+
int32_t timestamp = parsed_meta.timestamp();
691+
if (timestamp > 0 && !parsed_meta.IsPermanentSurvival()) {
692+
int64_t diff = timestamp - curtime;
693+
ttl = diff > 0 ? diff : -2;
662694
}
695+
}
696+
697+
// Initialize with base metadata size (key + 12 + 16 bytes overhead)
698+
int64_t sum = key.size() + 12 + 16;
699+
list_sizes[key] = std::make_pair(sum, ttl);
700+
}
701+
delete meta_iter;
702+
703+
// Read data items from data column family (handles[1])
704+
auto data_iter = db->NewIterator(read_options, handles[1]);
705+
for (data_iter->SeekToFirst(); data_iter->Valid(); data_iter->Next()) {
706+
rocksdb::Slice encoded_key_slice = data_iter->key();
707+
rocksdb::Slice value_slice = data_iter->value();
708+
709+
// Parse the data key to extract the list key
710+
try {
711+
storage::ParsedBaseDataKey parsed_key(encoded_key_slice); // Lists use BaseDataKey directly
712+
std::string list_key = parsed_key.key().ToString();
713+
714+
// Calculate element size: 4 + key + 4 + 8 (index) + element
715+
int64_t element_size = 4 + list_key.size() + 4 + 8 + value_slice.size();
663716

664-
// 如果key大小超过阈值,添加到结果集
665-
if (sum >= config.min_size) {
666-
std::string display_key = ReplaceAll(key, "\n", "\\n");
667-
display_key = ReplaceAll(display_key, " ", "\\x20");
668-
key_infos.emplace_back("list", display_key, sum, ttl);
717+
// Add element size to the corresponding list
718+
auto it = list_sizes.find(list_key);
719+
if (it != list_sizes.end()) {
720+
it->second.first += element_size;
721+
} else {
722+
// If metadata not found, initialize with element size and default ttl
723+
list_sizes[list_key] = std::make_pair(list_key.size() + 12 + 16 + element_size, -1);
669724
}
725+
} catch (...) {
726+
// Skip malformed keys
727+
continue;
670728
}
671729
}
730+
delete data_iter;
731+
732+
// Add list keys to the result
733+
for (const auto& entry : list_sizes) {
734+
if (entry.second.first >= config.min_size) {
735+
std::string display_key = ReplaceAll(entry.first, "\n", "\\n");
736+
display_key = ReplaceAll(display_key, " ", "\\x20");
737+
key_infos.emplace_back("list", display_key, entry.second.first, entry.second.second);
738+
}
739+
}
740+
741+
// Cleanup
742+
for (auto handle : handles) {
743+
delete handle;
744+
}
745+
delete db;
672746
}
673747

674748
// Get the prefix of a key

0 commit comments

Comments
 (0)