rippled
Database.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/app/ledger/Ledger.h>
21 #include <ripple/basics/chrono.h>
22 #include <ripple/beast/core/CurrentThreadName.h>
23 #include <ripple/nodestore/Database.h>
24 #include <ripple/protocol/HashPrefix.h>
25 
26 namespace ripple {
27 namespace NodeStore {
28 
30  std::string name,
31  Stoppable& parent,
32  Scheduler& scheduler,
33  int readThreads,
34  Section const& config,
35  beast::Journal journal)
36  : Stoppable(name, parent.getRoot())
37  , j_(journal)
38  , scheduler_(scheduler)
39  , earliestLedgerSeq_(
40  get<std::uint32_t>(config, "earliest_seq", XRP_LEDGER_EARLIEST_SEQ))
41 {
42  if (earliestLedgerSeq_ < 1)
43  Throw<std::runtime_error>("Invalid earliest_seq");
44 
45  while (readThreads-- > 0)
47 }
48 
50 {
51  // NOTE!
52  // Any derived class should call the stopReadThreads() method in its
53  // destructor. Otherwise, occasionally, the derived class may
54  // crash during shutdown when its members are accessed by one of
55  // these threads after the derived class is destroyed but before
56  // this base class is destroyed.
58 }
59 
60 void
62 {
63  // After stop time we can no longer use the JobQueue for background
64  // reads. Join the background read threads.
66 }
67 
68 void
70 {
71  stopped();
72 }
73 
74 void
76 {
77  {
79  if (readShut_) // Only stop threads once.
80  return;
81 
82  readShut_ = true;
84  }
85 
86  for (auto& e : readThreads_)
87  e.join();
88 }
89 
90 void
92  uint256 const& hash,
93  std::uint32_t ledgerSeq,
94  std::function<void(std::shared_ptr<NodeObject> const&)>&& cb)
95 {
96  // Post a read
98  read_[hash].emplace_back(ledgerSeq, std::move(cb));
100 }
101 
102 void
104 {
105  Batch batch;
107  auto storeBatch = [&]() {
108  try
109  {
110  dstBackend.storeBatch(batch);
111  }
112  catch (std::exception const& e)
113  {
114  JLOG(j_.error()) << "Exception caught in function " << __func__
115  << ". Error: " << e.what();
116  return;
117  }
118 
119  std::uint64_t sz{0};
120  for (auto const& nodeObject : batch)
121  sz += nodeObject->getData().size();
122  storeStats(batch.size(), sz);
123  batch.clear();
124  };
125 
126  srcDB.for_each([&](std::shared_ptr<NodeObject> nodeObject) {
127  assert(nodeObject);
128  if (!nodeObject) // This should never happen
129  return;
130 
131  batch.emplace_back(std::move(nodeObject));
132  if (batch.size() >= batchWritePreallocationSize)
133  storeBatch();
134  });
135 
136  if (!batch.empty())
137  storeBatch();
138 }
139 
140 // Perform a fetch and report the time it took
143  uint256 const& hash,
144  std::uint32_t ledgerSeq,
145  FetchType fetchType)
146 {
147  FetchReport fetchReport(fetchType);
148 
149  using namespace std::chrono;
150  auto const begin{steady_clock::now()};
151 
152  auto nodeObject{fetchNodeObject(hash, ledgerSeq, fetchReport)};
153  if (nodeObject)
154  {
155  ++fetchHitCount_;
156  fetchSz_ += nodeObject->getData().size();
157  }
159 
160  fetchReport.elapsed =
161  duration_cast<milliseconds>(steady_clock::now() - begin);
162  scheduler_.onFetch(fetchReport);
163  return nodeObject;
164 }
165 
166 bool
168  Ledger const& srcLedger,
169  std::shared_ptr<Backend> dstBackend)
170 {
171  auto fail = [&](std::string const& msg) {
172  JLOG(j_.error()) << "Source ledger sequence " << srcLedger.info().seq
173  << ". " << msg;
174  return false;
175  };
176 
177  if (srcLedger.info().hash.isZero())
178  return fail("Invalid hash");
179  if (srcLedger.info().accountHash.isZero())
180  return fail("Invalid account hash");
181 
182  auto& srcDB = const_cast<Database&>(srcLedger.stateMap().family().db());
183  if (&srcDB == this)
184  return fail("Source and destination databases are the same");
185 
186  Batch batch;
188  auto storeBatch = [&]() {
189  std::uint64_t sz{0};
190  for (auto const& nodeObject : batch)
191  sz += nodeObject->getData().size();
192 
193  try
194  {
195  dstBackend->storeBatch(batch);
196  }
197  catch (std::exception const& e)
198  {
199  fail(
200  std::string("Exception caught in function ") + __func__ +
201  ". Error: " + e.what());
202  return false;
203  }
204 
205  storeStats(batch.size(), sz);
206  batch.clear();
207  return true;
208  };
209 
210  // Store ledger header
211  {
212  Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo));
214  addRaw(srcLedger.info(), s);
215  auto nObj = NodeObject::createObject(
216  hotLEDGER, std::move(s.modData()), srcLedger.info().hash);
217  batch.emplace_back(std::move(nObj));
218  }
219 
220  bool error = false;
221  auto visit = [&](SHAMapTreeNode& node) {
222  if (!isStopping())
223  {
224  if (auto nodeObject = srcDB.fetchNodeObject(
225  node.getHash().as_uint256(), srcLedger.info().seq))
226  {
227  batch.emplace_back(std::move(nodeObject));
228  if (batch.size() < batchWritePreallocationSize || storeBatch())
229  return true;
230  }
231  }
232 
233  error = true;
234  return false;
235  };
236 
237  // Store the state map
238  if (srcLedger.stateMap().getHash().isNonZero())
239  {
240  if (!srcLedger.stateMap().isValid())
241  return fail("Invalid state map");
242 
243  srcLedger.stateMap().snapShot(false)->visitNodes(visit);
244  if (error)
245  return fail("Failed to store state map");
246  }
247 
248  // Store the transaction map
249  if (srcLedger.info().txHash.isNonZero())
250  {
251  if (!srcLedger.txMap().isValid())
252  return fail("Invalid transaction map");
253 
254  srcLedger.txMap().snapShot(false)->visitNodes(visit);
255  if (error)
256  return fail("Failed to store transaction map");
257  }
258 
259  if (!batch.empty() && !storeBatch())
260  return fail("Failed to store");
261 
262  return true;
263 }
264 
265 // Entry point for async read threads
266 void
268 {
269  beast::setCurrentThreadName("prefetch");
270  while (true)
271  {
272  uint256 lastHash;
276  entry;
277 
278  {
280  while (!readShut_ && read_.empty())
281  {
282  // All work is done
283  readCondVar_.wait(lock);
284  }
285  if (readShut_)
286  break;
287 
288  // Read in key order to make the back end more efficient
289  auto it = read_.lower_bound(readLastHash_);
290  if (it == read_.end())
291  {
292  // start over from the beginning
293  it = read_.begin();
294  }
295  lastHash = it->first;
296  entry = std::move(it->second);
297  read_.erase(it);
298  readLastHash_ = lastHash;
299  }
300 
301  auto seq = entry[0].first;
302  auto obj = fetchNodeObject(lastHash, seq, FetchType::async);
303 
304  for (auto const& req : entry)
305  {
306  if ((seq == req.first) || isSameDB(req.first, seq))
307  req.second(obj);
308  else
309  req.second(
310  fetchNodeObject(lastHash, req.first, FetchType::async));
311  }
312  }
313 }
314 
315 } // namespace NodeStore
316 } // namespace ripple
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::NodeStore::Database::readLastHash_
uint256 readLastHash_
Definition: Database.h:281
ripple::SHAMap::isValid
bool isValid() const
Definition: SHAMap.h:558
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:52
std::string
STL class.
ripple::NodeStore::Database::readShut_
bool readShut_
Definition: Database.h:284
std::shared_ptr< NodeObject >
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:783
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:444
ripple::Stoppable::stopped
void stopped()
Called by derived classes to indicate that the stoppable has stopped.
Definition: Stoppable.cpp:72
ripple::SHAMap::family
Family const & family() const
Definition: SHAMap.h:139
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
std::pair
std::vector::reserve
T reserve(T... args)
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:100
std::vector< std::shared_ptr< NodeObject > >
std::vector::size
T size(T... args)
ripple::NodeStore::Database::read_
std::map< uint256, std::vector< std::pair< std::uint32_t, std::function< void(std::shared_ptr< NodeObject > const &)> > > > read_
Definition: Database.h:278
ripple::NodeObject::createObject
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
Definition: NodeObject.cpp:37
ripple::NodeStore::Database::fetchTotalCount_
std::atomic< std::uint64_t > fetchTotalCount_
Definition: Database.h:267
ripple::NodeStore::Database::asyncFetch
void asyncFetch(uint256 const &hash, std::uint32_t ledgerSeq, std::function< void(std::shared_ptr< NodeObject > const &)> &&callback)
Fetch an object without waiting.
Definition: Database.cpp:91
ripple::NodeStore::Database::fetchSz_
std::atomic< std::uint32_t > fetchSz_
Definition: Database.h:239
std::lock_guard
STL class.
ripple::NodeStore::FetchReport
Contains information about a fetch operation.
Definition: ripple/nodestore/Scheduler.h:32
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
std::function
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
ripple::SHAMapHash::isNonZero
bool isNonZero() const
Definition: SHAMapTreeNode.h:73
ripple::SHAMap::snapShot
std::shared_ptr< SHAMap > snapShot(bool isMutable) const
Definition: SHAMap.cpp:70
ripple::NodeStore::Database::fetchHitCount_
std::atomic< std::uint32_t > fetchHitCount_
Definition: Database.h:238
ripple::Family::db
virtual NodeStore::Database & db()=0
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:101
ripple::NodeStore::batchWritePreallocationSize
@ batchWritePreallocationSize
Definition: nodestore/Types.h:34
ripple::NodeStore::Database::readLock_
std::mutex readLock_
Definition: Database.h:269
ripple::NodeStore::Database::onChildrenStopped
void onChildrenStopped() override
Override called when all children have stopped.
Definition: Database.cpp:69
ripple::base_uint< 256 >
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:149
ripple::Stoppable
Provides an interface for starting and stopping.
Definition: Stoppable.h:201
ripple::NodeStore::Database::importInternal
void importInternal(Backend &dstBackend, Database &srcDB)
Definition: Database.cpp:103
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:439
ripple::Ledger
Holds a ledger.
Definition: Ledger.h:77
ripple::Ledger::stateMap
SHAMap const & stateMap() const
Definition: Ledger.h:283
std::unique_lock
STL class.
ripple::NodeStore::Database::readCondVar_
std::condition_variable readCondVar_
Definition: Database.h:270
ripple::SHAMapTreeNode
Definition: SHAMapTreeNode.h:133
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::NodeStore::Scheduler::onFetch
virtual void onFetch(FetchReport const &report)=0
Reports completion of a fetch Allows the scheduler to monitor the node store's performance.
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
std::condition_variable::wait
T wait(T... args)
ripple::NodeStore::Scheduler
Scheduling for asynchronous backend activity.
Definition: ripple/nodestore/Scheduler.h:60
ripple::NodeStore::Database::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous)
Fetch a node object.
Definition: Database.cpp:142
ripple::NodeStore::Database::~Database
virtual ~Database()
Destroy the node store.
Definition: Database.cpp:49
ripple::NodeStore::Database::for_each
virtual void for_each(std::function< void(std::shared_ptr< NodeObject >)> f)=0
Visit every object in the database This is usually called during import.
ripple::NodeStore::Database::storeStats
void storeStats(std::uint64_t count, std::uint64_t sz)
Definition: Database.h:245
ripple::NodeStore::FetchType
FetchType
Definition: ripple/nodestore/Scheduler.h:29
std::condition_variable::notify_one
T notify_one(T... args)
ripple::NodeStore::Database::threadEntry
void threadEntry()
Definition: Database.cpp:267
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::Database::stopReadThreads
void stopReadThreads()
Definition: Database.cpp:75
ripple::Ledger::txMap
SHAMap const & txMap() const
Definition: Ledger.h:295
ripple::NodeStore::FetchType::async
@ async
beast::setCurrentThreadName
void setCurrentThreadName(std::string_view name)
Changes the name of the caller thread.
Definition: CurrentThreadName.cpp:119
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::NodeStore::Database::onStop
void onStop() override
Override called when the stop notification is issued.
Definition: Database.cpp:61
ripple::NodeStore::Database::storeLedger
virtual bool storeLedger(std::shared_ptr< Ledger const > const &srcLedger)=0
Store a ledger from a different database.
ripple::NodeStore::Database::j_
const beast::Journal j_
Definition: Database.h:234
ripple::NodeStore::Database::readThreads_
std::vector< std::thread > readThreads_
Definition: Database.h:283
std
STL namespace.
ripple::XRP_LEDGER_EARLIEST_SEQ
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ
The XRP ledger network's earliest allowed sequence.
Definition: SystemParameters.h:61
ripple::NodeStore::Database::earliestLedgerSeq_
const std::uint32_t earliestLedgerSeq_
Definition: Database.h:288
std::vector::empty
T empty(T... args)
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::LedgerInfo
Information about the notional ledger backing the view.
Definition: ReadView.h:84
ripple::NodeStore::Database::scheduler_
Scheduler & scheduler_
Definition: Database.h:235
ripple::NodeStore::Database::isSameDB
virtual bool isSameDB(std::uint32_t s1, std::uint32_t s2)=0
ripple::NodeStore::Backend::storeBatch
virtual void storeBatch(Batch const &batch)=0
Store a group of objects.
ripple::NodeStore::FetchReport::elapsed
std::chrono::milliseconds elapsed
Definition: ripple/nodestore/Scheduler.h:38
std::condition_variable::notify_all
T notify_all(T... args)
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:102
std::exception::what
T what(T... args)
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:116
ripple::NodeStore::Database::Database
Database()=delete
ripple::Stoppable::isStopping
bool isStopping() const
Returns true if the stoppable should stop.
Definition: Stoppable.cpp:54
std::chrono
ripple::NodeStore::Backend
A backend used for the NodeStore.
Definition: Backend.h:37