rippled
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 <ripple/basics/Log.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/core/DatabaseCon.h>
23 #include <ripple/core/SociDB.h>
24 
25 #include <boost/algorithm/string.hpp>
26 #include <boost/format.hpp>
27 
28 #include <memory>
29 #include <unordered_map>
30 
31 namespace 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 
44 public:
47  {
49  auto it = checkpointers_.find(id);
50  if (it != checkpointers_.end())
51  return it->second;
52  return {};
53  }
54 
55  void
57  {
58  std::lock_guard lock{mutex_};
59  checkpointers_.erase(id);
60  }
61 
64  std::shared_ptr<soci::session> const& session,
65  JobQueue& jobQueue,
66  Logs& logs)
67  {
68  std::lock_guard lock{mutex_};
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.reporting = c.reporting();
113  setup.dataDir = c.legacy("database_path");
114  if (!setup.standAlone && setup.dataDir.empty())
115  {
116  Throw<std::runtime_error>("database_path must be set.");
117  }
118 
119  if (!setup.globalPragma)
120  {
121  setup.globalPragma = [&c, &j]() {
122  auto const& sqlite = c.section("sqlite");
123  auto result = std::make_unique<std::vector<std::string>>();
124  result->reserve(3);
125 
126  // defaults
127  std::string safety_level;
128  std::string journal_mode = "wal";
129  std::string synchronous = "normal";
130  std::string temp_store = "file";
131  bool showRiskWarning = false;
132 
133  if (set(safety_level, "safety_level", sqlite))
134  {
135  if (boost::iequals(safety_level, "low"))
136  {
137  // low safety defaults
138  journal_mode = "memory";
139  synchronous = "off";
140  temp_store = "memory";
141  showRiskWarning = true;
142  }
143  else if (!boost::iequals(safety_level, "high"))
144  {
145  Throw<std::runtime_error>(
146  "Invalid safety_level value: " + safety_level);
147  }
148  }
149 
150  {
151  // #journal_mode Valid values : delete, truncate, persist,
152  // memory, wal, off
153  if (set(journal_mode, "journal_mode", sqlite) &&
154  !safety_level.empty())
155  {
156  Throw<std::runtime_error>(
157  "Configuration file may not define both "
158  "\"safety_level\" and \"journal_mode\"");
159  }
160  bool higherRisk = boost::iequals(journal_mode, "memory") ||
161  boost::iequals(journal_mode, "off");
162  showRiskWarning = showRiskWarning || higherRisk;
163  if (higherRisk || boost::iequals(journal_mode, "delete") ||
164  boost::iequals(journal_mode, "truncate") ||
165  boost::iequals(journal_mode, "persist") ||
166  boost::iequals(journal_mode, "wal"))
167  {
168  result->emplace_back(boost::str(
169  boost::format(CommonDBPragmaJournal) % journal_mode));
170  }
171  else
172  {
173  Throw<std::runtime_error>(
174  "Invalid journal_mode value: " + journal_mode);
175  }
176  }
177 
178  {
179  //#synchronous Valid values : off, normal, full, extra
180  if (set(synchronous, "synchronous", sqlite) &&
181  !safety_level.empty())
182  {
183  Throw<std::runtime_error>(
184  "Configuration file may not define both "
185  "\"safety_level\" and \"synchronous\"");
186  }
187  bool higherRisk = boost::iequals(synchronous, "off");
188  showRiskWarning = showRiskWarning || higherRisk;
189  if (higherRisk || boost::iequals(synchronous, "normal") ||
190  boost::iequals(synchronous, "full") ||
191  boost::iequals(synchronous, "extra"))
192  {
193  result->emplace_back(boost::str(
194  boost::format(CommonDBPragmaSync) % synchronous));
195  }
196  else
197  {
198  Throw<std::runtime_error>(
199  "Invalid synchronous value: " + synchronous);
200  }
201  }
202 
203  {
204  // #temp_store Valid values : default, file, memory
205  if (set(temp_store, "temp_store", sqlite) &&
206  !safety_level.empty())
207  {
208  Throw<std::runtime_error>(
209  "Configuration file may not define both "
210  "\"safety_level\" and \"temp_store\"");
211  }
212  bool higherRisk = boost::iequals(temp_store, "memory");
213  showRiskWarning = showRiskWarning || higherRisk;
214  if (higherRisk || boost::iequals(temp_store, "default") ||
215  boost::iequals(temp_store, "file"))
216  {
217  result->emplace_back(boost::str(
218  boost::format(CommonDBPragmaTemp) % temp_store));
219  }
220  else
221  {
222  Throw<std::runtime_error>(
223  "Invalid temp_store value: " + temp_store);
224  }
225  }
226 
227  if (showRiskWarning && j && c.LEDGER_HISTORY > SQLITE_TUNING_CUTOFF)
228  {
229  JLOG(j->warn())
230  << "reducing the data integrity guarantees from the "
231  "default [sqlite] behavior is not recommended for "
232  "nodes storing large amounts of history, because of the "
233  "difficulty inherent in rebuilding corrupted data.";
234  }
235  assert(result->size() == 3);
236  return result;
237  }();
238  }
239  setup.useGlobalPragma = true;
240 
241  return setup;
242 }
243 
246 
247 void
249 {
250  if (!q)
251  Throw<std::logic_error>("No JobQueue");
253 }
254 
255 } // namespace ripple
std::this_thread::sleep_for
T sleep_for(T... args)
ripple::CheckpointersCollection::checkpointers_
std::unordered_map< std::uintptr_t, std::shared_ptr< Checkpointer > > checkpointers_
Definition: DatabaseCon.cpp:42
ripple::DatabaseCon::Setup::globalPragma
static std::unique_ptr< std::vector< std::string > const > globalPragma
Definition: DatabaseCon.h:104
std::string
STL class.
std::shared_ptr
STL class.
ripple::Logs
Manages partitions for logging.
Definition: Log.h:48
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
ripple::setup_DatabaseCon
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition: DatabaseCon.cpp:106
ripple::DatabaseCon::Setup::startUp
Config::StartUpType startUp
Definition: DatabaseCon.h:88
std::chrono::milliseconds
ripple::checkpointerFromId
std::shared_ptr< Checkpointer > checkpointerFromId(std::uintptr_t id)
Definition: DatabaseCon.cpp:79
std::lock_guard
STL class.
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:91
ripple::checkpointers
CheckpointersCollection checkpointers
Definition: DatabaseCon.cpp:76
ripple::DatabaseCon::setupCheckpointing
void setupCheckpointing(JobQueue *, Logs &)
Definition: DatabaseCon.cpp:248
ripple::CheckpointersCollection::nextId_
std::uintptr_t nextId_
Definition: DatabaseCon.cpp:35
ripple::DatabaseCon::Setup::useGlobalPragma
bool useGlobalPragma
Definition: DatabaseCon.h:94
ripple::Config::reporting
bool reporting() const
Definition: Config.h:337
ripple::DatabaseCon::Setup::standAlone
bool standAlone
Definition: DatabaseCon.h:89
ripple::DatabaseCon::Setup::reporting
bool reporting
Definition: DatabaseCon.h:90
ripple::Config
Definition: Config.h:89
ripple::DatabaseCon::session_
const std::shared_ptr< soci::session > session_
Definition: DatabaseCon.h:225
ripple::Config::standalone
bool standalone() const
Definition: Config.h:332
ripple::set
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:313
ripple::CheckpointersCollection::create
std::shared_ptr< Checkpointer > create(std::shared_ptr< soci::session > const &session, JobQueue &jobQueue, Logs &logs)
Definition: DatabaseCon.cpp:63
ripple::BasicConfig::legacy
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Definition: BasicConfig.cpp:164
ripple::SQLITE_TUNING_CUTOFF
constexpr std::uint32_t SQLITE_TUNING_CUTOFF
Definition: DBInit.h:40
ripple::Config::START_UP
StartUpType START_UP
Definition: Config.h:154
std::uintptr_t
ripple::CommonDBPragmaTemp
constexpr char const * CommonDBPragmaTemp
Definition: DBInit.h:34
ripple::CommonDBPragmaJournal
constexpr char const * CommonDBPragmaJournal
Definition: DBInit.h:32
ripple::CheckpointersCollection::fromId
std::shared_ptr< Checkpointer > fromId(std::uintptr_t id)
Definition: DatabaseCon.cpp:46
memory
ripple::Config::LEDGER_HISTORY
std::uint32_t LEDGER_HISTORY
Definition: Config.h:212
ripple::JobQueue
A pool of threads to perform work.
Definition: JobQueue.h:55
std::weak_ptr
STL class.
ripple::DatabaseCon::~DatabaseCon
~DatabaseCon()
Definition: DatabaseCon.cpp:84
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::CheckpointersCollection
Definition: DatabaseCon.cpp:33
ripple::CheckpointersCollection::mutex_
std::mutex mutex_
Definition: DatabaseCon.cpp:37
std::string::empty
T empty(T... args)
std::optional
std::mutex
STL class.
ripple::CommonDBPragmaSync
constexpr char const * CommonDBPragmaSync
Definition: DBInit.h:33
std::weak_ptr::use_count
T use_count(T... args)
std::unique_ptr
STL class.
unordered_map
ripple::DatabaseCon::checkpointer_
std::shared_ptr< Checkpointer > checkpointer_
Definition: DatabaseCon.h:226
ripple::CheckpointersCollection::erase
void erase(std::uintptr_t id)
Definition: DatabaseCon.cpp:56
ripple::makeCheckpointer
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
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127