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 xrpl {
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
24
25public:
28 {
30 auto it = checkpointers_.find(id);
31 if (it != checkpointers_.end())
32 return it->second;
33 return {};
34 }
35
36 void
38 {
40 checkpointers_.erase(id);
41 }
42
44 create(std::shared_ptr<soci::session> const& session, JobQueue& jobQueue, Logs& logs)
45 {
47 auto const id = nextId_++;
48 auto const r = makeCheckpointer(id, session, jobQueue, logs);
49 checkpointers_[id] = r;
50 return r;
51 }
52};
53
55
61
63{
64 if (checkpointer_)
65 {
67
69 checkpointer_.reset();
70
71 // The references to our Checkpointer held by 'checkpointer_' and
72 // 'checkpointers' have been removed, so if the use count is nonzero, a
73 // checkpoint is currently in progress. Wait for it to end, otherwise
74 // creating a new DatabaseCon to the same database may fail due to the
75 // database being locked by our (now old) Checkpointer.
76 while (wk.use_count())
77 {
79 }
80 }
81}
82
85{
87
88 setup.startUp = c.START_UP;
89 setup.standAlone = c.standalone();
90 setup.dataDir = c.legacy("database_path");
91 if (!setup.standAlone && setup.dataDir.empty())
92 {
93 Throw<std::runtime_error>("database_path must be set.");
94 }
95
96 if (!setup.globalPragma)
97 {
98 setup.globalPragma = [&c, &j]() {
99 auto const& sqlite = c.section("sqlite");
101 result->reserve(3);
102
103 // defaults
104 std::string safety_level;
105 std::string journal_mode = "wal";
106 std::string synchronous = "normal";
107 std::string temp_store = "file";
108 bool showRiskWarning = false;
109
110 if (set(safety_level, "safety_level", sqlite))
111 {
112 if (boost::iequals(safety_level, "low"))
113 {
114 // low safety defaults
115 journal_mode = "memory";
116 synchronous = "off";
117 temp_store = "memory";
118 showRiskWarning = true;
119 }
120 else if (!boost::iequals(safety_level, "high"))
121 {
122 Throw<std::runtime_error>("Invalid safety_level value: " + safety_level);
123 }
124 }
125
126 {
127 // #journal_mode Valid values : delete, truncate, persist,
128 // memory, wal, off
129 if (set(journal_mode, "journal_mode", sqlite) && !safety_level.empty())
130 {
131 Throw<std::runtime_error>(
132 "Configuration file may not define both "
133 "\"safety_level\" and \"journal_mode\"");
134 }
135 bool higherRisk = boost::iequals(journal_mode, "memory") || boost::iequals(journal_mode, "off");
136 showRiskWarning = showRiskWarning || higherRisk;
137 if (higherRisk || boost::iequals(journal_mode, "delete") || boost::iequals(journal_mode, "truncate") ||
138 boost::iequals(journal_mode, "persist") || boost::iequals(journal_mode, "wal"))
139 {
140 result->emplace_back(boost::str(boost::format(CommonDBPragmaJournal) % journal_mode));
141 }
142 else
143 {
144 Throw<std::runtime_error>("Invalid journal_mode value: " + journal_mode);
145 }
146 }
147
148 {
149 // #synchronous Valid values : off, normal, full, extra
150 if (set(synchronous, "synchronous", sqlite) && !safety_level.empty())
151 {
152 Throw<std::runtime_error>(
153 "Configuration file may not define both "
154 "\"safety_level\" and \"synchronous\"");
155 }
156 bool higherRisk = boost::iequals(synchronous, "off");
157 showRiskWarning = showRiskWarning || higherRisk;
158 if (higherRisk || boost::iequals(synchronous, "normal") || boost::iequals(synchronous, "full") ||
159 boost::iequals(synchronous, "extra"))
160 {
161 result->emplace_back(boost::str(boost::format(CommonDBPragmaSync) % synchronous));
162 }
163 else
164 {
165 Throw<std::runtime_error>("Invalid synchronous value: " + synchronous);
166 }
167 }
168
169 {
170 // #temp_store Valid values : default, file, memory
171 if (set(temp_store, "temp_store", sqlite) && !safety_level.empty())
172 {
173 Throw<std::runtime_error>(
174 "Configuration file may not define both "
175 "\"safety_level\" and \"temp_store\"");
176 }
177 bool higherRisk = boost::iequals(temp_store, "memory");
178 showRiskWarning = showRiskWarning || higherRisk;
179 if (higherRisk || boost::iequals(temp_store, "default") || boost::iequals(temp_store, "file"))
180 {
181 result->emplace_back(boost::str(boost::format(CommonDBPragmaTemp) % temp_store));
182 }
183 else
184 {
185 Throw<std::runtime_error>("Invalid temp_store value: " + temp_store);
186 }
187 }
188
189 if (showRiskWarning && j && c.LEDGER_HISTORY > SQLITE_TUNING_CUTOFF)
190 {
191 JLOG(j->warn()) << "reducing the data integrity guarantees from the "
192 "default [sqlite] behavior is not recommended for "
193 "nodes storing large amounts of history, because of the "
194 "difficulty inherent in rebuilding corrupted data.";
195 }
196 XRPL_ASSERT(result->size() == 3, "xrpl::setup_DatabaseCon::globalPragma : result size is 3");
197 return result;
198 }();
199 }
200 setup.useGlobalPragma = true;
201
202 auto setPragma = [](std::string& pragma, std::string const& key, int64_t value) {
203 pragma = "PRAGMA " + key + "=" + std::to_string(value) + ";";
204 };
205
206 // Lgr Pragma
207 setPragma(setup.lgrPragma[0], "journal_size_limit", 1582080);
208
209 // TX Pragma
210 int64_t page_size = 4096;
211 int64_t journal_size_limit = 1582080;
212 if (c.exists("sqlite"))
213 {
214 auto& s = c.section("sqlite");
215 set(journal_size_limit, "journal_size_limit", s);
216 set(page_size, "page_size", s);
217 if (page_size < 512 || page_size > 65536)
218 Throw<std::runtime_error>("Invalid page_size. Must be between 512 and 65536.");
219
220 if (page_size & (page_size - 1))
221 Throw<std::runtime_error>("Invalid page_size. Must be a power of 2.");
222 }
223
224 setPragma(setup.txPragma[0], "page_size", page_size);
225 setPragma(setup.txPragma[1], "journal_size_limit", journal_size_limit);
226 setPragma(setup.txPragma[2], "max_page_count", 4294967294);
227 setPragma(setup.txPragma[3], "mmap_size", 17179869184);
228
229 return setup;
230}
231
233
234void
236{
237 if (!q)
238 Throw<std::logic_error>("No JobQueue");
240}
241
242} // namespace xrpl
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Section & section(std::string const &name)
Returns the section with the given name.
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_
StartUpType START_UP
Definition Config.h:129
bool standalone() const
Definition Config.h:312
std::uint32_t LEDGER_HISTORY
Definition Config.h:188
std::shared_ptr< soci::session > const session_
void setupCheckpointing(JobQueue *, Logs &)
std::shared_ptr< Checkpointer > checkpointer_
A pool of threads to perform work.
Definition JobQueue.h:38
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
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,...
CheckpointersCollection checkpointers
constexpr char const * CommonDBPragmaTemp
Definition DBInit.h:15
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
constexpr std::uint32_t SQLITE_TUNING_CUTOFF
Definition DBInit.h:21
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:290
constexpr char const * CommonDBPragmaSync
Definition DBInit.h:14
std::shared_ptr< Checkpointer > checkpointerFromId(std::uintptr_t id)
constexpr char const * CommonDBPragmaJournal
Definition DBInit.h:13
T sleep_for(T... args)
std::array< std::string, 4 > txPragma
Definition DatabaseCon.h:90
Config::StartUpType startUp
Definition DatabaseCon.h:72
static std::unique_ptr< std::vector< std::string > const > globalPragma
Definition DatabaseCon.h:89
boost::filesystem::path dataDir
Definition DatabaseCon.h:74
std::array< std::string, 1 > lgrPragma
Definition DatabaseCon.h:91
T to_string(T... args)
T use_count(T... args)