Spaces:
Sleeping
Sleeping
File size: 3,560 Bytes
be7c937 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #include "wayy_db/database.hpp"
#include <filesystem>
#include <mutex>
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
|