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  }
90 }
91 
93 setup_DatabaseCon(Config const& c, boost::optional<beast::Journal> j)
94 {
95  DatabaseCon::Setup setup;
96 
97  setup.startUp = c.START_UP;
98  setup.standAlone = c.standalone();
99  setup.dataDir = c.legacy("database_path");
100  if (!setup.standAlone && setup.dataDir.empty())
101  {
102  Throw<std::runtime_error>("database_path must be set.");
103  }
104 
105  if (!setup.globalPragma)
106  {
107  setup.globalPragma = [&c, &j]() {
108  auto const& sqlite = c.section("sqlite");
109  auto result = std::make_unique<std::vector<std::string>>();
110  result->reserve(3);
111 
112  // defaults
113  std::string safety_level;
114  std::string journal_mode = "wal";
115  std::string synchronous = "normal";
116  std::string temp_store = "file";
117  bool showRiskWarning = false;
118 
119  if (set(safety_level, "safety_level", sqlite))
120  {
121  if (boost::iequals(safety_level, "low"))
122  {
123  // low safety defaults
124  journal_mode = "memory";
125  synchronous = "off";
126  temp_store = "memory";
127  showRiskWarning = true;
128  }
129  else if (!boost::iequals(safety_level, "high"))
130  {
131  Throw<std::runtime_error>(
132  "Invalid safety_level value: " + safety_level);
133  }
134  }
135 
136  {
137  // #journal_mode Valid values : delete, truncate, persist,
138  // memory, wal, off
139  if (set(journal_mode, "journal_mode", sqlite) &&
140  !safety_level.empty())
141  {
142  Throw<std::runtime_error>(
143  "Configuration file may not define both "
144  "\"safety_level\" and \"journal_mode\"");
145  }
146  bool higherRisk = boost::iequals(journal_mode, "memory") ||
147  boost::iequals(journal_mode, "off");
148  showRiskWarning = showRiskWarning || higherRisk;
149  if (higherRisk || boost::iequals(journal_mode, "delete") ||
150  boost::iequals(journal_mode, "truncate") ||
151  boost::iequals(journal_mode, "persist") ||
152  boost::iequals(journal_mode, "wal"))
153  {
154  result->emplace_back(boost::str(
155  boost::format(CommonDBPragmaJournal) % journal_mode));
156  }
157  else
158  {
159  Throw<std::runtime_error>(
160  "Invalid journal_mode value: " + journal_mode);
161  }
162  }
163 
164  {
165  //#synchronous Valid values : off, normal, full, extra
166  if (set(synchronous, "synchronous", sqlite) &&
167  !safety_level.empty())
168  {
169  Throw<std::runtime_error>(
170  "Configuration file may not define both "
171  "\"safety_level\" and \"synchronous\"");
172  }
173  bool higherRisk = boost::iequals(synchronous, "off");
174  showRiskWarning = showRiskWarning || higherRisk;
175  if (higherRisk || boost::iequals(synchronous, "normal") ||
176  boost::iequals(synchronous, "full") ||
177  boost::iequals(synchronous, "extra"))
178  {
179  result->emplace_back(boost::str(
180  boost::format(CommonDBPragmaSync) % synchronous));
181  }
182  else
183  {
184  Throw<std::runtime_error>(
185  "Invalid synchronous value: " + synchronous);
186  }
187  }
188 
189  {
190  // #temp_store Valid values : default, file, memory
191  if (set(temp_store, "temp_store", sqlite) &&
192  !safety_level.empty())
193  {
194  Throw<std::runtime_error>(
195  "Configuration file may not define both "
196  "\"safety_level\" and \"temp_store\"");
197  }
198  bool higherRisk = boost::iequals(temp_store, "memory");
199  showRiskWarning = showRiskWarning || higherRisk;
200  if (higherRisk || boost::iequals(temp_store, "default") ||
201  boost::iequals(temp_store, "file"))
202  {
203  result->emplace_back(boost::str(
204  boost::format(CommonDBPragmaTemp) % temp_store));
205  }
206  else
207  {
208  Throw<std::runtime_error>(
209  "Invalid temp_store value: " + temp_store);
210  }
211  }
212 
213  if (showRiskWarning && j && c.LEDGER_HISTORY > SQLITE_TUNING_CUTOFF)
214  {
215  JLOG(j->warn())
216  << "reducing the data integrity guarantees from the "
217  "default [sqlite] behavior is not recommended for "
218  "nodes storing large amounts of history, because of the "
219  "difficulty inherent in rebuilding corrupted data.";
220  }
221  assert(result->size() == 3);
222  return result;
223  }();
224  }
225  setup.useGlobalPragma = true;
226 
227  return setup;
228 }
229 
232 
233 void
235 {
236  if (!q)
237  Throw<std::logic_error>("No JobQueue");
239 }
240 
241 } // namespace ripple
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
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:234
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:67
ripple::DatabaseCon::session_
const std::shared_ptr< soci::session > session_
Definition: DatabaseCon.h:223
ripple::Config::standalone
bool standalone() const
Definition: Config.h:222
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:124
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:164
ripple::JobQueue
A pool of threads to perform work.
Definition: JobQueue.h:55
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:93
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::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