rippled
Loading...
Searching...
No Matches
DatabaseCon.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/core/DatabaseCon.h>
21#include <xrpld/core/SociDB.h>
22#include <xrpl/basics/Log.h>
23#include <xrpl/basics/contract.h>
24
25#include <boost/algorithm/string.hpp>
26#include <boost/format.hpp>
27
28#include <memory>
29#include <unordered_map>
30
31namespace ripple {
32
34{
36 // Mutex protects the CheckpointersCollection
38 // Each checkpointer is given a unique id. All the checkpointers that are
39 // part of a DatabaseCon are part of this collection. When the DatabaseCon
40 // is destroyed, its checkpointer is removed from the collection
43
44public:
47 {
49 auto it = checkpointers_.find(id);
50 if (it != checkpointers_.end())
51 return it->second;
52 return {};
53 }
54
55 void
57 {
59 checkpointers_.erase(id);
60 }
61
64 std::shared_ptr<soci::session> const& session,
65 JobQueue& jobQueue,
66 Logs& logs)
67 {
69 auto const id = nextId_++;
70 auto const r = makeCheckpointer(id, session, jobQueue, logs);
71 checkpointers_[id] = r;
72 return r;
73 }
74};
75
77
80{
81 return checkpointers.fromId(id);
82}
83
85{
86 if (checkpointer_)
87 {
89
91 checkpointer_.reset();
92
93 // The references to our Checkpointer held by 'checkpointer_' and
94 // 'checkpointers' have been removed, so if the use count is nonzero, a
95 // checkpoint is currently in progress. Wait for it to end, otherwise
96 // creating a new DatabaseCon to the same database may fail due to the
97 // database being locked by our (now old) Checkpointer.
98 while (wk.use_count())
99 {
101 }
102 }
103}
104
107{
108 DatabaseCon::Setup setup;
109
110 setup.startUp = c.START_UP;
111 setup.standAlone = c.standalone();
112 setup.dataDir = c.legacy("database_path");
113 if (!setup.standAlone && setup.dataDir.empty())
114 {
115 Throw<std::runtime_error>("database_path must be set.");
116 }
117
118 if (!setup.globalPragma)
119 {
120 setup.globalPragma = [&c, &j]() {
121 auto const& sqlite = c.section("sqlite");
122 auto result = std::make_unique<std::vector<std::string>>();
123 result->reserve(3);
124
125 // defaults
126 std::string safety_level;
127 std::string journal_mode = "wal";
128 std::string synchronous = "normal";
129 std::string temp_store = "file";
130 bool showRiskWarning = false;
131
132 if (set(safety_level, "safety_level", sqlite))
133 {
134 if (boost::iequals(safety_level, "low"))
135 {
136 // low safety defaults
137 journal_mode = "memory";
138 synchronous = "off";
139 temp_store = "memory";
140 showRiskWarning = true;
141 }
142 else if (!boost::iequals(safety_level, "high"))
143 {
144 Throw<std::runtime_error>(
145 "Invalid safety_level value: " + safety_level);
146 }
147 }
148
149 {
150 // #journal_mode Valid values : delete, truncate, persist,
151 // memory, wal, off
152 if (set(journal_mode, "journal_mode", sqlite) &&
153 !safety_level.empty())
154 {
155 Throw<std::runtime_error>(
156 "Configuration file may not define both "
157 "\"safety_level\" and \"journal_mode\"");
158 }
159 bool higherRisk = boost::iequals(journal_mode, "memory") ||
160 boost::iequals(journal_mode, "off");
161 showRiskWarning = showRiskWarning || higherRisk;
162 if (higherRisk || boost::iequals(journal_mode, "delete") ||
163 boost::iequals(journal_mode, "truncate") ||
164 boost::iequals(journal_mode, "persist") ||
165 boost::iequals(journal_mode, "wal"))
166 {
167 result->emplace_back(boost::str(
168 boost::format(CommonDBPragmaJournal) % journal_mode));
169 }
170 else
171 {
172 Throw<std::runtime_error>(
173 "Invalid journal_mode value: " + journal_mode);
174 }
175 }
176
177 {
178 // #synchronous Valid values : off, normal, full, extra
179 if (set(synchronous, "synchronous", sqlite) &&
180 !safety_level.empty())
181 {
182 Throw<std::runtime_error>(
183 "Configuration file may not define both "
184 "\"safety_level\" and \"synchronous\"");
185 }
186 bool higherRisk = boost::iequals(synchronous, "off");
187 showRiskWarning = showRiskWarning || higherRisk;
188 if (higherRisk || boost::iequals(synchronous, "normal") ||
189 boost::iequals(synchronous, "full") ||
190 boost::iequals(synchronous, "extra"))
191 {
192 result->emplace_back(boost::str(
193 boost::format(CommonDBPragmaSync) % synchronous));
194 }
195 else
196 {
197 Throw<std::runtime_error>(
198 "Invalid synchronous value: " + synchronous);
199 }
200 }
201
202 {
203 // #temp_store Valid values : default, file, memory
204 if (set(temp_store, "temp_store", sqlite) &&
205 !safety_level.empty())
206 {
207 Throw<std::runtime_error>(
208 "Configuration file may not define both "
209 "\"safety_level\" and \"temp_store\"");
210 }
211 bool higherRisk = boost::iequals(temp_store, "memory");
212 showRiskWarning = showRiskWarning || higherRisk;
213 if (higherRisk || boost::iequals(temp_store, "default") ||
214 boost::iequals(temp_store, "file"))
215 {
216 result->emplace_back(boost::str(
217 boost::format(CommonDBPragmaTemp) % temp_store));
218 }
219 else
220 {
221 Throw<std::runtime_error>(
222 "Invalid temp_store value: " + temp_store);
223 }
224 }
225
226 if (showRiskWarning && j && c.LEDGER_HISTORY > SQLITE_TUNING_CUTOFF)
227 {
228 JLOG(j->warn())
229 << "reducing the data integrity guarantees from the "
230 "default [sqlite] behavior is not recommended for "
231 "nodes storing large amounts of history, because of the "
232 "difficulty inherent in rebuilding corrupted data.";
233 }
234 XRPL_ASSERT(
235 result->size() == 3,
236 "ripple::setup_DatabaseCon::globalPragma : result size is 3");
237 return result;
238 }();
239 }
240 setup.useGlobalPragma = true;
241
242 auto setPragma =
243 [](std::string& pragma, std::string const& key, int64_t value) {
244 pragma = "PRAGMA " + key + "=" + std::to_string(value) + ";";
245 };
246
247 // Lgr Pragma
248 setPragma(setup.lgrPragma[0], "journal_size_limit", 1582080);
249
250 // TX Pragma
251 int64_t page_size = 4096;
252 int64_t journal_size_limit = 1582080;
253 if (c.exists("sqlite"))
254 {
255 auto& s = c.section("sqlite");
256 set(journal_size_limit, "journal_size_limit", s);
257 set(page_size, "page_size", s);
258 if (page_size < 512 || page_size > 65536)
259 Throw<std::runtime_error>(
260 "Invalid page_size. Must be between 512 and 65536.");
261
262 if (page_size & (page_size - 1))
263 Throw<std::runtime_error>(
264 "Invalid page_size. Must be a power of 2.");
265 }
266
267 setPragma(setup.txPragma[0], "page_size", page_size);
268 setPragma(setup.txPragma[1], "journal_size_limit", journal_size_limit);
269 setPragma(setup.txPragma[2], "max_page_count", 4294967294);
270 setPragma(setup.txPragma[3], "mmap_size", 17179869184);
271
272 return setup;
273}
274
277
278void
280{
281 if (!q)
282 Throw<std::logic_error>("No JobQueue");
284}
285
286} // namespace ripple
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Section & section(std::string const &name)
Returns the section with the given name.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
void erase(std::uintptr_t id)
Definition: DatabaseCon.cpp:56
std::shared_ptr< Checkpointer > create(std::shared_ptr< soci::session > const &session, JobQueue &jobQueue, Logs &logs)
Definition: DatabaseCon.cpp:63
std::shared_ptr< Checkpointer > fromId(std::uintptr_t id)
Definition: DatabaseCon.cpp:46
std::unordered_map< std::uintptr_t, std::shared_ptr< Checkpointer > > checkpointers_
Definition: DatabaseCon.cpp:42
std::uint32_t LEDGER_HISTORY
Definition: Config.h:214
bool standalone() const
Definition: Config.h:344
StartUpType START_UP
Definition: Config.h:154
void setupCheckpointing(JobQueue *, Logs &)
std::shared_ptr< soci::session > const session_
Definition: DatabaseCon.h:245
std::shared_ptr< Checkpointer > checkpointer_
Definition: DatabaseCon.h:246
A pool of threads to perform work.
Definition: JobQueue.h:56
Manages partitions for logging.
Definition: Log.h:49
T empty(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
constexpr char const * CommonDBPragmaSync
Definition: DBInit.h:33
CheckpointersCollection checkpointers
Definition: DatabaseCon.cpp:76
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:316
constexpr char const * CommonDBPragmaTemp
Definition: DBInit.h:34
constexpr std::uint32_t SQLITE_TUNING_CUTOFF
Definition: DBInit.h:40
constexpr char const * CommonDBPragmaJournal
Definition: DBInit.h:32
std::shared_ptr< Checkpointer > makeCheckpointer(std::uintptr_t id, std::weak_ptr< soci::session > session, JobQueue &queue, Logs &logs)
Returns a new checkpointer which makes checkpoints of a soci database every checkpointPageCount pages...
Definition: SociDB.cpp:333
std::shared_ptr< Checkpointer > checkpointerFromId(std::uintptr_t id)
Definition: DatabaseCon.cpp:79
T sleep_for(T... args)
boost::filesystem::path dataDir
Definition: DatabaseCon.h:92
static std::unique_ptr< std::vector< std::string > const > globalPragma
Definition: DatabaseCon.h:108
std::array< std::string, 1 > lgrPragma
Definition: DatabaseCon.h:110
Config::StartUpType startUp
Definition: DatabaseCon.h:90
std::array< std::string, 4 > txPragma
Definition: DatabaseCon.h:109
T to_string(T... args)
T use_count(T... args)