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