Advertisement
scottish_esquire

Redka Compact Init ver 4.0

Mar 27th, 2025
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.65 KB | None | 0 0
  1. #include <iostream>
  2. #include <fstream>
  3. #include <string>
  4. #include <vector>
  5. #include <map>
  6. #include <filesystem>
  7. #include <chrono>
  8. #include <algorithm>
  9. #include <cmath>
  10. #include <sstream>
  11. #include <regex>
  12.  
  13. namespace fs = std::filesystem;
  14.  
  15. const std::string DB_DIR = "lsm_db";
  16. const size_t LEVEL_BASE_SIZE = 10;
  17.  
  18. #pragma pack(push, 1)
  19. struct SSTHeader {
  20.     uint32_t version = 2;
  21.     uint32_t entry_count;
  22.     uint64_t index_offset;
  23. };
  24.  
  25. struct SSTIndexEntry {
  26.     uint32_t key_length;
  27.     uint64_t data_offset;
  28.     uint32_t data_length;
  29. };
  30. #pragma pack(pop)
  31.  
  32. struct FieldValue {
  33.     uint32_t version;
  34.     std::string value;
  35. };
  36.  
  37. struct SSTEntry {
  38.     std::string key;
  39.     std::map<std::string, FieldValue> fields;
  40.  
  41.     bool operator<(const SSTEntry& other) const {
  42.         return key < other.key;
  43.     }
  44. };
  45.  
  46. class LSMTree {
  47. private:
  48.     std::vector<std::vector<std::string>> levels;
  49.  
  50.     void ensureDbDir() {
  51.         if (!fs::exists(DB_DIR)) {
  52.             fs::create_directory(DB_DIR);
  53.             for (int i = 0; i < 10; ++i) {
  54.                 fs::create_directory(DB_DIR + "/L" + std::to_string(i));
  55.             }
  56.         }
  57.     }
  58.  
  59.     void loadLevels() {
  60.         levels.clear();
  61.         for (int i = 0; ; ++i) {
  62.             std::string level_dir = DB_DIR + "/L" + std::to_string(i);
  63.             if (!fs::exists(level_dir)) break;
  64.  
  65.             std::vector<std::string> files;
  66.             for (const auto& entry : fs::directory_iterator(level_dir)) {
  67.                 if (entry.path().extension() == ".sst") {
  68.                     files.push_back(entry.path().string());
  69.                 }
  70.             }
  71.             std::sort(files.begin(), files.end());
  72.             std::reverse(files.begin(), files.end());
  73.             levels.push_back(files);
  74.         }
  75.     }
  76.  
  77.     void mergeEntries(SSTEntry& target, const SSTEntry& source) {
  78.         for (const auto& [field, src_val] : source.fields) {
  79.             auto it = target.fields.find(field);
  80.             if (it == target.fields.end() || src_val.version > it->second.version) {
  81.                 target.fields[field] = src_val;
  82.             }
  83.         }
  84.     }
  85.  
  86.     std::vector<SSTEntry> readSST(const std::string& path) {
  87.         std::ifstream file(path, std::ios::binary);
  88.         if (!file) return {};
  89.  
  90.         SSTHeader header;
  91.         file.read(reinterpret_cast<char*>(&header), sizeof(header));
  92.  
  93.         std::vector<SSTIndexEntry> index(header.entry_count);
  94.         file.seekg(header.index_offset);
  95.         file.read(reinterpret_cast<char*>(index.data()), header.entry_count * sizeof(SSTIndexEntry));
  96.  
  97.         std::vector<SSTEntry> entries;
  98.         for (const auto& idx : index) {
  99.             file.seekg(idx.data_offset);
  100.            
  101.             uint32_t total_len;
  102.             file.read(reinterpret_cast<char*>(&total_len), sizeof(total_len));
  103.  
  104.             std::string key(idx.key_length, '\0');
  105.             file.read(&key[0], idx.key_length);
  106.  
  107.             std::string fields_data(total_len - idx.key_length, '\0');
  108.             file.read(&fields_data[0], fields_data.size());
  109.  
  110.             SSTEntry entry;
  111.             entry.key = key;
  112.             entry.fields = parseFields(fields_data);
  113.             entries.push_back(entry);
  114.         }
  115.  
  116.         return entries;
  117.     }
  118.  
  119.     std::map<std::string, FieldValue> parseFields(const std::string& data) {
  120.         std::map<std::string, FieldValue> fields;
  121.         std::regex field_re(R"((\w+)(@(\d+))?:([^ ]+))");
  122.         std::smatch match;
  123.         std::string::const_iterator search_start(data.cbegin());
  124.  
  125.         while (std::regex_search(search_start, data.cend(), match, field_re)) {
  126.             std::string field = match[1].str();
  127.             uint32_t version = match[3].matched ? std::stoul(match[3].str()) : 1;
  128.             std::string value = match[4].str();
  129.  
  130.             fields[field] = {version, value};
  131.             search_start = match[0].second;
  132.         }
  133.  
  134.         return fields;
  135.     }
  136.  
  137.     std::string serializeFields(const std::map<std::string, FieldValue>& fields) {
  138.         std::stringstream ss;
  139.         ss << "{";
  140.         bool first = true;
  141.         for (const auto& [field, fv] : fields) {
  142.             if (!first) ss << " ";
  143.             first = false;
  144.             if (fv.version > 1) {
  145.                 ss << field << "@" << fv.version << ":" << fv.value;
  146.             } else {
  147.                 ss << field << ":" << fv.value;
  148.             }
  149.         }
  150.         ss << "}";
  151.         return ss.str();
  152.     }
  153.  
  154.     void writeSST(const std::string& path, const std::vector<SSTEntry>& entries) {
  155.         std::ofstream file(path, std::ios::binary);
  156.         SSTHeader header;
  157.         header.entry_count = entries.size();
  158.         file.write(reinterpret_cast<char*>(&header), sizeof(header));
  159.  
  160.         std::vector<SSTIndexEntry> index;
  161.         for (const auto& entry : entries) {
  162.             SSTIndexEntry idx;
  163.             idx.key_length = entry.key.size();
  164.             idx.data_offset = file.tellp();
  165.  
  166.             std::string fields_data = serializeFields(entry.fields);
  167.             uint32_t total_len = entry.key.size() + fields_data.size();
  168.            
  169.             file.write(reinterpret_cast<char*>(&total_len), sizeof(total_len));
  170.             file.write(entry.key.data(), entry.key.size());
  171.             file.write(fields_data.data(), fields_data.size());
  172.  
  173.             idx.data_length = total_len;
  174.             index.push_back(idx);
  175.         }
  176.  
  177.         header.index_offset = file.tellp();
  178.         for (const auto& idx : index) {
  179.             file.write(reinterpret_cast<const char*>(&idx), sizeof(idx));
  180.         }
  181.  
  182.         file.seekp(0);
  183.         file.write(reinterpret_cast<char*>(&header), sizeof(header));
  184.     }
  185.  
  186. public:
  187.     LSMTree() {
  188.         ensureDbDir();
  189.         loadLevels();
  190.     }
  191.  
  192.     void compactLevel(int level) {
  193.         if (level >= levels.size()) return;
  194.        
  195.         std::map<std::string, SSTEntry> merged_entries;
  196.        
  197.         // Собираем и мержим все записи с текущего уровня
  198.         for (const auto& sst_path : levels[level]) {
  199.             auto entries = readSST(sst_path);
  200.             for (const auto& entry : entries) {
  201.                 if (merged_entries.find(entry.key) == merged_entries.end()) {
  202.                     merged_entries[entry.key] = entry;
  203.                 } else {
  204.                     mergeEntries(merged_entries[entry.key], entry);
  205.                 }
  206.             }
  207.         }
  208.    
  209.         if (merged_entries.size() >= LEVEL_BASE_SIZE * std::pow(10, level)) {
  210.             // Преобразуем map в vector для записи
  211.             std::vector<SSTEntry> entries_to_write;
  212.             for (auto& [key, entry] : merged_entries) {
  213.                 entries_to_write.push_back(std::move(entry));
  214.             }
  215.             std::sort(entries_to_write.begin(), entries_to_write.end());
  216.    
  217.             // Записываем на следующий уровень
  218.             std::string new_sst = DB_DIR + "/L" + std::to_string(level + 1) + "/" +
  219.                                  std::to_string(std::chrono::system_clock::now().time_since_epoch().count()) + ".sst";
  220.             writeSST(new_sst, entries_to_write);
  221.    
  222.             // Удаляем старые файлы
  223.             for (const auto& sst_path : levels[level]) {
  224.                 fs::remove(sst_path);
  225.             }
  226.    
  227.             // Обновляем индексы и рекурсивно уплотняем
  228.             loadLevels();
  229.             compactLevel(level + 1);
  230.         }
  231.     }
  232. };
  233.  
  234. int main() {
  235.     LSMTree db;
  236.    
  237.     // Запуск компактизации всех уровней, начиная с 0
  238.     db.compactLevel(0);
  239.    
  240.     return 0;
  241. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement