rippled
Loading...
Searching...
No Matches
DatabaseCon.cpp
1#include <xrpld/core/DatabaseCon.h>
2#include <xrpld/core/SociDB.h>
3
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/contract.h>
6
7#include <boost/algorithm/string.hpp>
8#include <boost/format.hpp>
9
10#include <memory>
11#include <unordered_map>
12
13namespace ripple {
14
16{
18 // Mutex protects the CheckpointersCollection
20 // Each checkpointer is given a unique id. All the checkpointers that are
21 // part of a DatabaseCon are part of this collection. When the DatabaseCon
22 // is destroyed, its checkpointer is removed from the collection
25
26public:
29 {
31 auto it = checkpointers_.find(id);
32 if (it != checkpointers_.end())
33 return it->second;
34 return {};
35 }
36
37 void
39 {
41 checkpointers_.erase(id);
42 }
43
46 std::shared_ptr<soci::session> const& session,
47 JobQueue& jobQueue,
48 Logs& logs)
49 {
51 auto const id = nextId_++;
52 auto const r = makeCheckpointer(id, session, jobQueue, logs);
53 checkpointers_[id] = r;
54 return r;
55 }
56};
57
59
65
67{
68 if (checkpointer_)
69 {
71
73 checkpointer_.reset();
74
75 // The references to our Checkpointer held by 'checkpointer_' and
76 // 'checkpointers' have been removed, so if the use count is nonzero, a
77 // checkpoint is currently in progress. Wait for it to end, otherwise
78 // creating a new DatabaseCon to the same database may fail due to the
79 // database being locked by our (now old) Checkpointer.
80 while (wk.use_count())
81 {
83 }
84 }
85}
86
89{
91
92 setup.startUp = c.START_UP;
93 setup.standAlone = c.standalone();
94 setup.dataDir = c.legacy("database_path");
95 if (!setup.standAlone && setup.dataDir.empty())
96 {
97 Throw<std::runtime_error>("database_path must be set.");
98 }
99
100 if (!setup.globalPragma)
101 {
102 setup.globalPragma = [&c, &j]() {
103 auto const& sqlite = c.section("sqlite");
105 result->reserve(3);
106
107 // defaults
108 std::string safety_level;
109 std::string journal_mode = "wal";
110 std::string synchronous = "normal";
111 std::string temp_store = "file";
112 bool showRiskWarning = false;
113
114 if (set(safety_level, "safety_level", sqlite))
115 {
116 if (boost::iequals(safety_level, "low"))
117 {
118 // low safety defaults
119 journal_mode = "memory";
120 synchronous = "off";
121 temp_store = "memory";
122 showRiskWarning = true;
123 }
124 else if (!boost::iequals(safety_level, "high"))
125 {
126 Throw<std::runtime_error>(
127 "Invalid safety_level value: " + safety_level);
128 }
129 }
130
131 {
132 // #journal_mode Valid values : delete, truncate, persist,
133 // memory, wal, off
134 if (set(journal_mode, "journal_mode", sqlite) &&
135 !safety_level.empty())
136 {
137 Throw<std::runtime_error>(
138 "Configuration file may not define both "
139 "\"safety_level\" and \"journal_mode\"");
140 }
141 bool higherRisk = boost::iequals(journal_mode, "memory") ||
142 boost::iequals(journal_mode, "off");
143 showRiskWarning = showRiskWarning || higherRisk;
144 if (higherRisk || boost::iequals(journal_mode, "delete") ||
145 boost::iequals(journal_mode, "truncate") ||
146 boost::iequals(journal_mode, "persist") ||
147 boost::iequals(journal_mode, "wal"))
148 {
149 result->emplace_back(boost::str(
150 boost::format(CommonDBPragmaJournal) % journal_mode));
151 }
152 else
153 {
154 Throw<std::runtime_error>(
155 "Invalid journal_mode value: " + journal_mode);
156 }
157 }
158
159 {
160 // #synchronous Valid values : off, normal, full, extra
161 if (set(synchronous, "synchronous", sqlite) &&
162 !safety_level.empty())
163 {
164 Throw<std::runtime_error>(
165 "Configuration file may not define both "
166 "\"safety_level\" and \"synchronous\"");
167 }
168 bool higherRisk = boost::iequals(synchronous, "off");
169 showRiskWarning = showRiskWarning || higherRisk;
170 if (higherRisk || boost::iequals(synchronous, "normal") ||
171 boost::iequals(synchronous, "full") ||
172 boost::iequals(synchronous, "extra"))
173 {
174 result->emplace_back(boost::str(
175 boost::format(CommonDBPragmaSync) % synchronous));
176 }
177 else
178 {
179 Throw<std::runtime_error>(
180 "Invalid synchronous value: " + synchronous);
181 }
182 }
183
184 {
185 // #temp_store Valid values : default, file, memory
186 if (set(temp_store, "temp_store", sqlite) &&
187 !safety_level.empty())
188 {
189 Throw<std::runtime_error>(
190 "Configuration file may not define both "
191 "\"safety_level\" and \"temp_store\"");
192 }
193 bool higherRisk = boost::iequals(temp_store, "memory");
194 showRiskWarning = showRiskWarning || higherRisk;
195 if (higherRisk || boost::iequals(temp_store, "default") ||
196 boost::iequals(temp_store, "file"))
197 {
198 result->emplace_back(boost::str(
199 boost::format(CommonDBPragmaTemp) % temp_store));
200 }
201 else
202 {
203 Throw<std::runtime_error>(
204 "Invalid temp_store value: " + temp_store);
205 }
206 }
207
208 if (showRiskWarning && j && c.LEDGER_HISTORY > SQLITE_TUNING_CUTOFF)
209 {
210 JLOG(j->warn())
211 << "reducing the data integrity guarantees from the "
212 "default [sqlite] behavior is not recommended for "
213 "nodes storing large amounts of history, because of the "
214 "difficulty inherent in rebuilding corrupted data.";
215 }
216 XRPL_ASSERT(
217 result->size() == 3,
218 "ripple::setup_DatabaseCon::globalPragma : result size is 3");
219 return result;
220 }();
221 }
222 setup.useGlobalPragma = true;
223
224 auto setPragma =
225 [](std::string& pragma, std::string const& key, int64_t value) {
226 pragma = "PRAGMA " + key + "=" + std::to_string(value) + ";";
227 };
228
229 // Lgr Pragma
230 setPragma(setup.lgrPragma[0], "journal_size_limit", 1582080);
231
232 // TX Pragma
233 int64_t page_size = 4096;
234 int64_t journal_size_limit = 1582080;
235 if (c.exists("sqlite"))
236 {
237 auto& s = c.section("sqlite");
238 set(journal_size_limit, "journal_size_limit", s);
239 set(page_size, "page_size", s);
240 if (page_size < 512 || page_size > 65536)
241 Throw<std::runtime_error>(
242 "Invalid page_size. Must be between 512 and 65536.");
243
244 if (page_size & (page_size - 1))
245 Throw<std::runtime_error>(
246 "Invalid page_size. Must be a power of 2.");
247 }
248
249 setPragma(setup.txPragma[0], "page_size", page_size);
250 setPragma(setup.txPragma[1], "journal_size_limit", journal_size_limit);
251 setPragma(setup.txPragma[2], "max_page_count", 4294967294);
252 setPragma(setup.txPragma[3], "mmap_size", 17179869184);
253
254 return setup;
255}
256
259
260void
262{
263 if (!q)
264 Throw<std::logic_error>("No JobQueue");
266}
267
268} // 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)
std::shared_ptr< Checkpointer > create(std::shared_ptr< soci::session > const &session, JobQueue &jobQueue, Logs &logs)
std::shared_ptr< Checkpointer > fromId(std::uintptr_t id)
std::unordered_map< std::uintptr_t, std::shared_ptr< Checkpointer > > checkpointers_
std::uint32_t LEDGER_HISTORY
Definition Config.h:188
bool standalone() const
Definition Config.h:317
StartUpType START_UP
Definition Config.h:128
void setupCheckpointing(JobQueue *, Logs &)
std::shared_ptr< soci::session > const session_
std::shared_ptr< Checkpointer > checkpointer_
A pool of threads to perform work.
Definition JobQueue.h:39
Manages partitions for logging.
Definition Log.h:33
T empty(T... args)
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
constexpr char const * CommonDBPragmaSync
Definition DBInit.h:14
CheckpointersCollection checkpointers
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,...
constexpr char const * CommonDBPragmaTemp
Definition DBInit.h:15
constexpr std::uint32_t SQLITE_TUNING_CUTOFF
Definition DBInit.h:21
constexpr char const * CommonDBPragmaJournal
Definition DBInit.h:13
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:317
std::shared_ptr< Checkpointer > checkpointerFromId(std::uintptr_t id)
T sleep_for(T... args)
boost::filesystem::path dataDir
Definition DatabaseCon.h:75
static std::unique_ptr< std::vector< std::string > const > globalPragma
Definition DatabaseCon.h:91
std::array< std::string, 1 > lgrPragma
Definition DatabaseCon.h:93
Config::StartUpType startUp
Definition DatabaseCon.h:73
std::array< std::string, 4 > txPragma
Definition DatabaseCon.h:92
T to_string(T... args)
T use_count(T... args)