Spaces:
Runtime error
Runtime error
File size: 3,865 Bytes
bf20cb7 | 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 145 146 147 148 149 150 151 152 153 154 155 156 157 | #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();
// Initialize WAL
wal_ = std::make_unique<WriteAheadLog>(path_);
// Replay any unprocessed WAL entries from a crash
if (wal_->has_entries()) {
wal_->replay(*this);
}
}
}
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();
}
void Database::checkpoint() {
if (!wal_) return;
wal_->checkpoint(*this);
}
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
|