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 
106 setup_DatabaseCon(Config const& c, boost::optional<beast::Journal> j)
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  assert(result->size() == 3);
235  return result;
236  }();
237  }
238  setup.useGlobalPragma = true;
239 
240  return setup;
241 }
242 
245 
246 void
248 {
249  if (!q)
250  Throw<std::logic_error>("No JobQueue");
252 }
253 
254 } // 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:103
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::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:90
ripple::checkpointers
CheckpointersCollection checkpointers
Definition: DatabaseCon.cpp:76
ripple::DatabaseCon::setupCheckpointing
void setupCheckpointing(JobQueue *, Logs &)
Definition: DatabaseCon.cpp:247
ripple::CheckpointersCollection::nextId_
std::uintptr_t nextId_
Definition: DatabaseCon.cpp:35
ripple::DatabaseCon::Setup::useGlobalPragma
bool useGlobalPragma
Definition: DatabaseCon.h:93
ripple::DatabaseCon::Setup::standAlone
bool standAlone
Definition: DatabaseCon.h:89
ripple::Config
Definition: Config.h:69
ripple::DatabaseCon::session_
const std::shared_ptr< soci::session > session_
Definition: DatabaseCon.h:223
ripple::Config::standalone
bool standalone() const
Definition: Config.h:236
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:276
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:175
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:125
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:165
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::setup_DatabaseCon
DatabaseCon::Setup setup_DatabaseCon(Config const &c, boost::optional< beast::Journal > j=boost::none)
Definition: DatabaseCon.cpp:106
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::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:224
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:335
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:138