MDBX Containers
Loading...
Searching...
No Matches
Connection.ipp
Go to the documentation of this file.
1#include <string>
2#include <memory>
3#include <mutex>
4#include <thread>
5#include <unordered_map>
6#include <filesystem>
7
8#if __cplusplus < 202002L
9# include <codecvt>
10# include <locale>
11#endif
12
13#include <mdbx.h>
14
15namespace mdbxc {
16
17 inline Connection::Connection(const Config& config) {
18 connect(config);
19 }
20
22 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
23 cleanup(false);
24 }
25
26 inline std::shared_ptr<Connection> Connection::create(const Config& config) {
27 auto conn = std::make_shared<Connection>();
28 conn->connect(config);
29 return conn;
30 }
31
32 inline void Connection::configure(const Config& config) {
33 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
34# if __cplusplus >= 201703L
35 m_config = config;
36# else
37 m_config.reset(new Config(config));
38# endif
39 }
40
41 inline void Connection::connect() {
42 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
43 if (m_env) return;
44 if (!m_config) throw std::logic_error("No configuration provided.");
45 initialize();
46 }
47
48 inline void Connection::connect(const Config& config) {
49 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
50 if (m_env) return;
51# if __cplusplus >= 201703L
52 m_config = config;
53# else
54 m_config.reset(new Config(config));
55# endif
56 initialize();
57 }
58
59 inline void Connection::disconnect() {
60 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
61 cleanup();
62 }
63
64 inline bool Connection::is_connected() const {
65 std::lock_guard<std::mutex> locker(m_mdbx_mutex);
66 return m_env != nullptr;
67 }
68
70 return Transaction(static_cast<TransactionTracker*>(this), m_env, mode);
71 }
72
74 std::lock_guard<std::mutex> lock(m_mdbx_mutex);
75 auto tid = std::this_thread::get_id();
76 auto it = m_transactions.find(tid);
77 if (it != m_transactions.end()) {
78 throw std::logic_error("Transaction already started for this thread.");
79 }
80 auto txn = std::make_shared<Transaction>(static_cast<TransactionTracker*>(this), m_env, mode);
81 m_transactions[tid] = txn;
82 }
83
84 inline void Connection::commit() {
85 std::lock_guard<std::mutex> lock(m_mdbx_mutex);
86 auto tid = std::this_thread::get_id();
87 auto it = m_transactions.find(tid);
88 if (it == m_transactions.end()) {
89 throw std::logic_error("No transaction for this thread.");
90 }
91 it->second->commit();
92 m_transactions.erase(it);
93 }
94
95 inline void Connection::rollback() {
96 std::lock_guard<std::mutex> lock(m_mdbx_mutex);
97 auto tid = std::this_thread::get_id();
98 auto it = m_transactions.find(tid);
99 if (it == m_transactions.end()) {
100 throw std::logic_error("No transaction for this thread.");
101 }
102 it->second->rollback();
103 m_transactions.erase(it);
104 }
105
106 inline std::shared_ptr<Transaction> Connection::current_txn() const {
107 std::lock_guard<std::mutex> lock(m_mdbx_mutex);
108 auto it = m_transactions.find(std::this_thread::get_id());
109 return (it != m_transactions.end()) ? it->second : nullptr;
110 }
111
112 inline MDBX_env* Connection::env_handle() noexcept {
113 return m_env;
114 }
115
117 try {
118 create_directories(m_config->pathname);
119 db_init();
120 } catch (...) {
121 if (m_env && mdbx_env_close(m_env) == MDBX_SUCCESS) {
122 m_env = nullptr;
123 }
124 throw;
125 }
126 }
127
128 inline void Connection::cleanup(bool use_throw) {
129 if (m_env) {
130 int rc = mdbx_env_close(m_env);
131 if (rc != MDBX_SUCCESS && use_throw) {
132 check_mdbx(rc, "Failed to close environment");
133 }
134 m_env = nullptr;
135 }
136 }
137
138 inline void Connection::db_init() {
139#if __cplusplus >= 201703L
140 namespace fs = std::filesystem;
141#endif
142
143 int rc = 0;
145 mdbx_env_create(&m_env),
146 "Failed to create environment"
147 );
148
150 mdbx_env_set_geometry(
151 m_env,
152 m_config->size_lower,
153 m_config->size_now,
154 m_config->size_upper,
155 m_config->growth_step,
156 m_config->shrink_threshold,
157 m_config->page_size
158 ),
159 "Failed to set environment geometry"
160 );
161
163 mdbx_env_set_maxdbs(m_env, m_config->max_dbs),
164 "Failed to set max databases"
165 );
166
167 int readers = m_config->max_readers > 0
168 ? static_cast<int>(m_config->max_readers)
169 : static_cast<int>(std::thread::hardware_concurrency()) * 2;
171 mdbx_env_set_maxreaders(m_env, readers),
172 "Failed to set max readers"
173 );
174
175 MDBX_env_flags_t env_flags = MDBX_ACCEDE;
176 if (m_config->no_subdir) env_flags |= MDBX_NOSUBDIR;
177 if (m_config->sync_durable) env_flags |= MDBX_SYNC_DURABLE;
178 if (m_config->read_only) env_flags |= MDBX_RDONLY;
179 if (!m_config->readahead) env_flags |= MDBX_NORDAHEAD;
180 if (m_config->writemap_mode) env_flags |= MDBX_WRITEMAP;
181
182 std::string pathname = m_config->pathname;
183 if (m_config->relative_to_exe && !is_absolute_path(pathname)) {
184#if __cplusplus >= 201703L
185 pathname = (fs::u8path(get_exec_dir()) / fs::u8path(pathname)).u8string();
186#else
187# ifdef _WIN32
188 pathname = get_exec_dir() + "\\" + pathname;
189# else
190 pathname = get_exec_dir() + "/" + pathname;
191# endif
192#endif
193 }
194
195#ifdef _WIN32
196# if __cplusplus >= 201703L
197# if __cplusplus >= 202002L
198 fs::path file_path = fs::u8path(pathname);
199# else
200 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
201 std::wstring wide_path = converter.from_bytes(pathname);
202 fs::path file_path = fs::path(wide_path);
203# endif
205 mdbx_env_openW(m_env, file_path.c_str(), env_flags, 0664),
206 "Failed to open environment"
207 );
208# else
209 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
210 std::wstring wide_path = converter.from_bytes(pathname);
212 mdbx_env_openW(m_env, wide_path.c_str(), env_flags, 0664),
213 "Failed to open environment"
214 );
215# endif
216
217#else
219 mdbx_env_open(m_env, pathname.c_str(), env_flags, 0664),
220 "Failed to open environment"
221 );
222#endif
223 }
224
225} // namespace mdbxc
Parameters used by Connection to create the MDBX environment.
Definition Config.hpp:17
std::shared_ptr< Transaction > current_txn() const
Returns the transaction associated with the current thread.
bool is_connected() const
Checks whether the environment is currently open.
MDBX_env * m_env
Pointer to the MDBX environment handle.
Transaction transaction(TransactionMode mode=TransactionMode::WRITABLE)
Creates a RAII transaction object.
MDBX_env * env_handle() noexcept
Returns the environment handle.
void begin(TransactionMode mode=TransactionMode::WRITABLE)
Begins a manual transaction (must be committed or rolled back later).
friend class Transaction
void disconnect()
Disconnects from the MDBX environment and releases resources.
void db_init()
Initializes MDBX environment and opens a read-only transaction.
void rollback()
Rolls back the current manual transaction.
config_t m_config
Database configuration object.
Connection()=default
Default constructor.
void cleanup(bool use_throw=true)
Safely closes the environment and aborts transaction if needed.
void connect()
Connects to the database using the current configuration.
void configure(const Config &config)
Sets the MDBX configuration (must be called before connect()).
~Connection()
Destructor. Closes the MDBX environment and aborts any open transactions.
std::mutex m_mdbx_mutex
Mutex for thread-safe access.
void commit()
Commits the current manual transaction.
static std::shared_ptr< Connection > create(const Config &config)
Creates and connects a new shared Connection instance.
void initialize()
Initializes the environment and sets up read-only transaction.
std::unordered_map< std::thread::id, std::shared_ptr< Transaction > > m_transactions
Associates MDBX transactions with threads.
void create_directories(const std::string &path)
Creates directories recursively for the given path.
std::string get_exec_dir()
Retrieves the directory of the executable file.
bool is_absolute_path(const std::string &path)
Checks whether the given path is absolute (cross-platform).
void check_mdbx(int rc, const std::string &context)
Throws an MdbxException if MDBX return code indicates an error.
Definition utils.hpp:18
TransactionMode
Specifies the access mode of a transaction.