Spaces:
Sleeping
Sleeping
| namespace fs = std::filesystem; | |
| namespace wayy_db { | |
| Database::Database() = default; | |
| Database::Database(const std::string& path) : path_(path) { | |
| if (!path_.empty()) { | |
| fs::create_directories(path_); | |
| scan_tables(); | |
| } | |
| } | |
| std::vector<std::string> Database::tables() const { | |
| std::shared_lock lock(mutex_); | |
| std::vector<std::string> names; | |
| names.reserve(tables_.size()); | |
| for (const auto& [name, _] : tables_) { | |
| names.push_back(name); | |
| } | |
| // Also include tables on disk that aren't loaded yet | |
| for (const auto& [name, _] : loaded_) { | |
| if (!tables_.count(name)) { | |
| names.push_back(name); | |
| } | |
| } | |
| return names; | |
| } | |
| bool Database::has_table(const std::string& name) const { | |
| std::shared_lock lock(mutex_); | |
| return tables_.count(name) > 0 || loaded_.count(name) > 0; | |
| } | |
| Table& Database::table(const std::string& name) { | |
| // First try with shared lock (read-only) | |
| { | |
| std::shared_lock lock(mutex_); | |
| auto it = tables_.find(name); | |
| if (it != tables_.end()) { | |
| return it->second; | |
| } | |
| } | |
| // Need to lazy load - acquire exclusive lock | |
| std::unique_lock lock(mutex_); | |
| // Double-check after acquiring exclusive lock (another thread may have loaded it) | |
| auto it = tables_.find(name); | |
| if (it != tables_.end()) { | |
| return it->second; | |
| } | |
| // Try to load from disk | |
| if (is_persistent() && loaded_.count(name)) { | |
| tables_.emplace(name, Table::mmap(table_path(name))); | |
| return tables_.at(name); | |
| } | |
| throw WayyException("Table not found: " + name); | |
| } | |
| Table& Database::create_table(const std::string& name) { | |
| std::unique_lock lock(mutex_); | |
| if (tables_.count(name) > 0 || loaded_.count(name) > 0) { | |
| throw InvalidOperation("Table already exists: " + name); | |
| } | |
| tables_.emplace(name, Table(name)); | |
| if (is_persistent()) { | |
| loaded_[name] = true; | |
| } | |
| return tables_.at(name); | |
| } | |
| void Database::add_table(Table table) { | |
| const std::string& name = table.name(); | |
| std::unique_lock lock(mutex_); | |
| if (tables_.count(name) > 0 || loaded_.count(name) > 0) { | |
| throw InvalidOperation("Table already exists: " + name); | |
| } | |
| if (is_persistent()) { | |
| table.save(table_path(name)); | |
| loaded_[name] = true; | |
| } | |
| tables_.emplace(name, std::move(table)); | |
| } | |
| void Database::drop_table(const std::string& name) { | |
| std::unique_lock lock(mutex_); | |
| tables_.erase(name); | |
| loaded_.erase(name); | |
| if (is_persistent()) { | |
| fs::remove_all(table_path(name)); | |
| } | |
| } | |
| void Database::save() { | |
| if (!is_persistent()) return; | |
| std::shared_lock lock(mutex_); | |
| for (auto& [name, table] : tables_) { | |
| table.save(table_path(name)); | |
| } | |
| } | |
| void Database::refresh() { | |
| if (!is_persistent()) return; | |
| std::unique_lock lock(mutex_); | |
| scan_tables(); | |
| } | |
| std::string Database::table_path(const std::string& name) const { | |
| return path_ + "/" + name; | |
| } | |
| void Database::scan_tables() { | |
| if (!fs::exists(path_)) return; | |
| for (const auto& entry : fs::directory_iterator(path_)) { | |
| if (entry.is_directory()) { | |
| std::string meta_path = entry.path().string() + "/_meta.json"; | |
| if (fs::exists(meta_path)) { | |
| std::string name = entry.path().filename().string(); | |
| loaded_[name] = false; // Not loaded into memory yet | |
| } | |
| } | |
| } | |
| } | |
| } // namespace wayy_db | |