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 db_init();
119 } catch (...) {
120 if (m_env && mdbx_env_close(m_env) == MDBX_SUCCESS) {
121 m_env = nullptr;
122 }
123 throw;
124 }
125 }
126
127 inline void Connection::cleanup(bool use_throw) {
128 if (m_env) {
129 int rc = mdbx_env_close(m_env);
130 if (rc != MDBX_SUCCESS && use_throw) {
131 check_mdbx(rc, "Failed to close environment");
132 }
133 m_env = nullptr;
134 }
135 }
136
137 inline void Connection::db_init() {
138#if __cplusplus >= 201703L
139 namespace fs = std::filesystem;
140#endif
141
142 int rc = 0;
144 mdbx_env_create(&m_env),
145 "Failed to create environment"
146 );
147
149 mdbx_env_set_geometry(
150 m_env,
151 m_config->size_lower,
152 m_config->size_now,
153 m_config->size_upper,
154 m_config->growth_step,
155 m_config->shrink_threshold,
156 m_config->page_size
157 ),
158 "Failed to set environment geometry"
159 );
160
162 mdbx_env_set_maxdbs(m_env, m_config->max_dbs),
163 "Failed to set max databases"
164 );
165
166 int readers = m_config->max_readers > 0
167 ? static_cast<int>(m_config->max_readers)
168 : static_cast<int>(std::thread::hardware_concurrency()) * 2;
170 mdbx_env_set_maxreaders(m_env, readers),
171 "Failed to set max readers"
172 );
173
174 MDBX_env_flags_t env_flags = MDBX_ACCEDE;
175 if (m_config->no_subdir) env_flags |= MDBX_NOSUBDIR;
176 if (m_config->sync_durable) env_flags |= MDBX_SYNC_DURABLE;
177 if (m_config->read_only) env_flags |= MDBX_RDONLY;
178 if (!m_config->readahead) env_flags |= MDBX_NORDAHEAD;
179 if (m_config->writemap_mode) env_flags |= MDBX_WRITEMAP;
180
181 std::string pathname = m_config->pathname;
182 if (m_config->relative_to_exe &&
183 !is_absolute_path(pathname) &&
184 !is_explicitly_relative(pathname)) {
185# if __cplusplus >= 201703L
186# if __cplusplus >= 202002L
187 pathname = u8string_to_string((fs::u8path(get_exec_dir()) / fs::u8path(pathname)).u8string());
188# else
189 pathname = (fs::u8path(get_exec_dir()) / fs::u8path(pathname)).u8string();
190# endif
191# else
192# ifdef _WIN32
193 pathname = get_exec_dir() + "\\" + pathname;
194# else
195 pathname = get_exec_dir() + "/" + pathname;
196# endif
197# endif
198 }
199 create_directories(pathname);
200
201#ifdef _WIN32
202# if __cplusplus >= 201703L
203# if __cplusplus >= 202002L
204 fs::path file_path = fs::u8path(pathname);
205# else
206 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
207 std::wstring wide_path = converter.from_bytes(pathname);
208 fs::path file_path = fs::path(wide_path);
209# endif
210 file_path = file_path.lexically_normal();
212 mdbx_env_openW(m_env, file_path.c_str(), env_flags, 0664),
213 "Failed to open environment"
214 );
215# else
216 pathname = lexically_normal_compat(pathname);
217 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
218 std::wstring wide_path = converter.from_bytes(pathname);
220 mdbx_env_openW(m_env, wide_path.c_str(), env_flags, 0664),
221 "Failed to open environment"
222 );
223# endif
224
225#else
227 mdbx_env_open(m_env, pathname.c_str(), env_flags, 0664),
228 "Failed to open environment"
229 );
230#endif
231 }
232
233} // 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.
bool is_explicitly_relative(const std::string &s) noexcept
Check if path starts with explicit relative prefix.
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:23
TransactionMode
Specifies the access mode of a transaction.
std::string lexically_normal_compat(const std::string &in)
Normalize path removing '.