Electroneum
Loading...
Searching...
No Matches
database.cpp
Go to the documentation of this file.
1// Copyright (c) 2014-2018, The Monero Project
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are
5// permitted provided that the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of
8// conditions and the following disclaimer.
9//
10// 2. Redistributions in binary form must reproduce the above copyright notice, this list
11// of conditions and the following disclaimer in the documentation and/or other
12// materials provided with the distribution.
13//
14// 3. Neither the name of the copyright holder nor the names of its contributors may be
15// used to endorse or promote products derived from this software without specific
16// prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
19// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#include "database.h"
28#include "lmdb/error.h"
29#include "lmdb/util.h"
30
31#ifdef _WIN32
32namespace
33{
34 constexpr const mdb_mode_t open_flags = 0;
35}
36#else
37#include <sys/stat.h>
38
39namespace
40{
41 constexpr const mdb_mode_t open_flags = (S_IRUSR | S_IWUSR);
42}
43#endif
44
45namespace lmdb
46{
47 namespace
48 {
49 constexpr const mdb_size_t max_resize = 1 * 1024 * 1024 * 1024; // 1 GB
50 void acquire_context(context& ctx) noexcept
51 {
52 while (ctx.lock.test_and_set());
53 ++(ctx.active);
54 ctx.lock.clear();
55 }
56
57 void release_context(context& ctx) noexcept
58 {
59 --(ctx.active);
60 }
61 }
62
63 void release_read_txn::operator()(MDB_txn* ptr) const noexcept
64 {
65 if (ptr)
66 {
67 MDB_env* const env = mdb_txn_env(ptr);
68 abort_txn{}(ptr);
69 if (env)
70 {
71 context* ctx = reinterpret_cast<context*>(mdb_env_get_userctx(env));
72 if (ctx)
73 release_context(*ctx);
74 }
75 }
76 }
77
78 expect<environment> open_environment(const char* path, MDB_dbi max_dbs) noexcept
79 {
80 ELECTRONEUM_PRECOND(path != nullptr);
81
82 MDB_env* obj = nullptr;
83 ELECTRONEUM_LMDB_CHECK(mdb_env_create(std::addressof(obj)));
84 environment out{obj};
85
86 ELECTRONEUM_LMDB_CHECK(mdb_env_set_maxdbs(out.get(), max_dbs));
87 ELECTRONEUM_LMDB_CHECK(mdb_env_open(out.get(), path, 0, open_flags));
88 return {std::move(out)};
89 }
90
91 expect<write_txn> database::do_create_txn(unsigned int flags) noexcept
92 {
93 ELECTRONEUM_PRECOND(handle() != nullptr);
94
95 for (unsigned attempts = 0; attempts < 3; ++attempts)
96 {
97 acquire_context(ctx);
98
99 MDB_txn* txn = nullptr;
100 const int err =
101 mdb_txn_begin(handle(), nullptr, flags, &txn);
102 if (!err && txn != nullptr)
103 return write_txn{txn};
104
105 release_context(ctx);
106 if (err != MDB_MAP_RESIZED)
107 return {lmdb::error(err)};
108 ELECTRONEUM_CHECK(this->resize());
109 }
111 }
112
114 : env(std::move(env)), ctx{{}, ATOMIC_FLAG_INIT}
115 {
116 if (handle())
117 {
118 const int err = mdb_env_set_userctx(handle(), std::addressof(ctx));
119 if (err)
120 ELECTRONEUM_THROW(lmdb::error(err), "Failed to set user context");
121 }
122 }
123
125 {
126 while (ctx.active);
127 }
128
130 {
131 ELECTRONEUM_PRECOND(handle() != nullptr);
132
133 while (ctx.lock.test_and_set());
134 while (ctx.active);
135
138
139 const mdb_size_t resize = std::min(info.me_mapsize, max_resize);
140 const int err = mdb_env_set_mapsize(handle(), info.me_mapsize + resize);
141 ctx.lock.clear();
142 if (err)
143 return {lmdb::error(err)};
144 return success();
145 }
146
148 {
149 if (txn)
150 {
151 acquire_context(ctx);
152 const int err = mdb_txn_renew(txn.get());
153 if (err)
154 {
155 release_context(ctx);
156 return {lmdb::error(err)};
157 }
158 return read_txn{txn.release()};
159 }
160 auto new_txn = do_create_txn(MDB_RDONLY);
161 if (new_txn)
162 return read_txn{new_txn->release()};
163 return new_txn.error();
164 }
165
167 {
168 ELECTRONEUM_PRECOND(txn != nullptr);
169 mdb_txn_reset(txn.get());
170 release_context(ctx);
171 return suspended_txn{txn.release()};
172 }
173
175 {
176 return do_create_txn(0);
177 }
178
180 {
181 ELECTRONEUM_PRECOND(txn != nullptr);
183 txn.release();
184 release_context(ctx);
185 return success();
186 }
187} // lmdb
expect< suspended_txn > reset_txn(read_txn txn) noexcept
Definition database.cpp:166
expect< void > commit(write_txn txn) noexcept
Commit the read-write transaction.
Definition database.cpp:179
expect< write_txn > create_write_txn() noexcept
Definition database.cpp:174
expect< void > resize() noexcept
Definition database.cpp:129
virtual ~database() noexcept
Definition database.cpp:124
expect< read_txn > create_read_txn(suspended_txn txn=nullptr) noexcept
Definition database.cpp:147
database(environment env)
Definition database.cpp:113
#define ELECTRONEUM_PRECOND(...)
If precondition fails, return error::kInvalidArgument in current scope.
Definition expect.h:39
#define ELECTRONEUM_THROW(code, msg)
Definition expect.h:66
#define ELECTRONEUM_CHECK(...)
Check expect<void> and return errors in current scope.
Definition expect.h:47
#define MDB_MAP_RESIZED
Definition lmdb.h:465
void mdb_txn_reset(MDB_txn *txn)
Reset a read-only transaction.
int mdb_env_info(MDB_env *env, MDB_envinfo *stat)
Return information about the LMDB environment.
int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
Open an environment handle.
int mdb_env_set_mapsize(MDB_env *env, mdb_size_t size)
Set the size of the memory map to use for this environment.
int mdb_txn_renew(MDB_txn *txn)
Renew a read-only transaction.
void * mdb_env_get_userctx(MDB_env *env)
Get the application information associated with the MDB_env.
int mdb_txn_commit(MDB_txn *txn)
Commit all the operations of a transaction into the database.
int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
Set the maximum number of named databases for the environment.
int mdb_env_create(MDB_env **env)
Create an LMDB environment handle.
int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn)
Create a transaction for use with the environment.
int mdb_env_set_userctx(MDB_env *env, void *ctx)
Set application information associated with the MDB_env.
MDB_env * mdb_txn_env(MDB_txn *txn)
Returns the transaction's MDB_env.
#define MDB_RDONLY
Definition lmdb.h:320
struct MDB_env MDB_env
Opaque structure for a database environment.
Definition lmdb.h:260
struct MDB_txn MDB_txn
Opaque structure for a transaction handle.
Definition lmdb.h:267
unsigned int MDB_dbi
A handle for an individual database in the DB environment.
Definition lmdb.h:270
mode_t mdb_mode_t
Definition lmdb.h:181
size_t mdb_size_t
Definition lmdb.h:196
std::unique_ptr< MDB_txn, abort_write_txn > write_txn
Definition transaction.h:94
std::unique_ptr< MDB_env, close_env > environment
Definition database.h:51
std::unique_ptr< MDB_txn, release_read_txn > read_txn
Definition transaction.h:93
error
Tracks LMDB error codes.
Definition error.h:45
expect< environment > open_environment(const char *path, MDB_dbi max_dbs) noexcept
Definition database.cpp:78
std::unique_ptr< MDB_txn, abort_txn > suspended_txn
Definition transaction.h:92
STL namespace.
#define ELECTRONEUM_LMDB_CHECK(...)
Executes a LMDB command, and returns errors via lmdb::error enum.
Definition error.h:33
CXA_THROW_INFO_T * info
Information about the environment.
Definition lmdb.h:501
Context given to LMDB.
Definition database.h:58
std::atomic< std::size_t > active
Definition database.h:59
std::atomic_flag lock
Definition database.h:60
void operator()(MDB_txn *ptr) const noexcept
Definition database.cpp:63