rippled
DatabaseNodeImp.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/nodestore/impl/DatabaseNodeImp.h>
22 #include <ripple/protocol/HashPrefix.h>
23 
24 namespace ripple {
25 namespace NodeStore {
26 
27 void
29  NodeObjectType type,
30  Blob&& data,
31  uint256 const& hash,
33 {
34  storeStats(1, data.size());
35 
36  auto obj = NodeObject::createObject(type, std::move(data), hash);
37  backend_->store(obj);
38  if (cache_)
39  {
40  // After the store, replace a negative cache entry if there is one
41  cache_->canonicalize(
42  hash, obj, [](std::shared_ptr<NodeObject> const& n) {
43  return n->getType() == hotDUMMY;
44  });
45  }
46 }
47 
48 void
50  uint256 const& hash,
51  std::uint32_t ledgerSeq,
52  std::function<void(std::shared_ptr<NodeObject> const&)>&& callback)
53 {
54  if (cache_)
55  {
56  std::shared_ptr<NodeObject> obj = cache_->fetch(hash);
57  if (obj)
58  {
59  callback(obj->getType() == hotDUMMY ? nullptr : obj);
60  return;
61  }
62  }
63  Database::asyncFetch(hash, ledgerSeq, std::move(callback));
64 }
65 
66 void
68 {
69  if (cache_)
70  cache_->sweep();
71 }
72 
75  uint256 const& hash,
77  FetchReport& fetchReport,
78  bool duplicate)
79 {
80  std::shared_ptr<NodeObject> nodeObject =
81  cache_ ? cache_->fetch(hash) : nullptr;
82 
83  if (!nodeObject)
84  {
85  JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record not "
86  << (cache_ ? "cached" : "found");
87 
88  Status status;
89 
90  try
91  {
92  status = backend_->fetch(hash.data(), &nodeObject);
93  }
94  catch (std::exception const& e)
95  {
96  JLOG(j_.fatal())
97  << "fetchNodeObject " << hash
98  << ": Exception fetching from backend: " << e.what();
99  Rethrow();
100  }
101 
102  switch (status)
103  {
104  case ok:
105  if (cache_)
106  {
107  if (nodeObject)
108  cache_->canonicalize_replace_client(hash, nodeObject);
109  else
110  {
111  auto notFound =
113  cache_->canonicalize_replace_client(hash, notFound);
114  if (notFound->getType() != hotDUMMY)
115  nodeObject = notFound;
116  }
117  }
118  break;
119  case notFound:
120  break;
121  case dataCorrupt:
122  JLOG(j_.fatal()) << "fetchNodeObject " << hash
123  << ": nodestore data is corrupted";
124  break;
125  default:
126  JLOG(j_.warn())
127  << "fetchNodeObject " << hash
128  << ": backend returns unknown result " << status;
129  break;
130  }
131  }
132  else
133  {
134  JLOG(j_.trace()) << "fetchNodeObject " << hash
135  << ": record found in cache";
136  if (nodeObject->getType() == hotDUMMY)
137  nodeObject.reset();
138  }
139 
140  if (nodeObject)
141  fetchReport.wasFound = true;
142 
143  return nodeObject;
144 }
145 
148 {
150  using namespace std::chrono;
151  auto const before = steady_clock::now();
153  std::vector<uint256 const*> cacheMisses;
154  uint64_t hits = 0;
155  uint64_t fetches = 0;
156  for (size_t i = 0; i < hashes.size(); ++i)
157  {
158  auto const& hash = hashes[i];
159  // See if the object already exists in the cache
160  auto nObj = cache_ ? cache_->fetch(hash) : nullptr;
161  ++fetches;
162  if (!nObj)
163  {
164  // Try the database
165  indexMap[&hash] = i;
166  cacheMisses.push_back(&hash);
167  }
168  else
169  {
170  results[i] = nObj->getType() == hotDUMMY ? nullptr : nObj;
171  // It was in the cache.
172  ++hits;
173  }
174  }
175 
176  JLOG(j_.debug()) << "fetchBatch - cache hits = "
177  << (hashes.size() - cacheMisses.size())
178  << " - cache misses = " << cacheMisses.size();
179  auto dbResults = backend_->fetchBatch(cacheMisses).first;
180 
181  for (size_t i = 0; i < dbResults.size(); ++i)
182  {
183  auto nObj = std::move(dbResults[i]);
184  size_t index = indexMap[cacheMisses[i]];
185  auto const& hash = hashes[index];
186 
187  if (nObj)
188  {
189  // Ensure all threads get the same object
190  if (cache_)
191  cache_->canonicalize_replace_client(hash, nObj);
192  }
193  else
194  {
195  JLOG(j_.error())
196  << "fetchBatch - "
197  << "record not found in db or cache. hash = " << strHex(hash);
198  if (cache_)
199  {
200  auto notFound = NodeObject::createObject(hotDUMMY, {}, hash);
201  cache_->canonicalize_replace_client(hash, notFound);
202  if (notFound->getType() != hotDUMMY)
203  nObj = std::move(notFound);
204  }
205  }
206  results[index] = std::move(nObj);
207  }
208 
209  auto fetchDurationUs =
210  std::chrono::duration_cast<std::chrono::microseconds>(
211  steady_clock::now() - before)
212  .count();
213  updateFetchMetrics(fetches, hits, fetchDurationUs);
214  return results;
215 }
216 
217 } // namespace NodeStore
218 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::NodeStore::DatabaseNodeImp::backend_
std::shared_ptr< Backend > backend_
Definition: DatabaseNodeImp.h:145
std::shared_ptr< NodeObject >
std::exception
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::NodeStore::ok
@ ok
Definition: nodestore/Types.h:45
ripple::NodeStore::DatabaseNodeImp::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t, FetchReport &fetchReport, bool duplicate) override
Definition: DatabaseNodeImp.cpp:74
std::vector< unsigned char >
std::vector::size
T size(T... args)
ripple::NodeObjectType
NodeObjectType
The types of node objects.
Definition: NodeObject.h:32
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::asyncFetch
virtual 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:198
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::NodeStore::FetchReport
Contains information about a fetch operation.
Definition: ripple/nodestore/Scheduler.h:32
std::function
std::shared_ptr::reset
T reset(T... args)
ripple::base_uint::data
pointer data()
Definition: base_uint.h:122
ripple::NodeStore::Database::updateFetchMetrics
void updateFetchMetrics(uint64_t fetches, uint64_t hits, uint64_t duration)
Definition: Database.h:349
std::vector::push_back
T push_back(T... args)
ripple::NodeStore::notFound
@ notFound
Definition: nodestore/Types.h:46
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::hotDUMMY
@ hotDUMMY
Definition: NodeObject.h:37
ripple::Rethrow
void Rethrow()
Rethrow the exception currently being handled.
Definition: contract.h:48
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::NodeStore::DatabaseNodeImp::cache_
std::shared_ptr< TaggedCache< uint256, NodeObject > > cache_
Definition: DatabaseNodeImp.h:143
ripple::NodeStore::dataCorrupt
@ dataCorrupt
Definition: nodestore/Types.h:47
std::uint32_t
ripple::NodeStore::Database::storeStats
void storeStats(std::uint64_t count, std::uint64_t sz)
Definition: Database.h:333
ripple::NodeStore::DatabaseNodeImp::store
void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t) override
Store the object.
Definition: DatabaseNodeImp.cpp:28
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::NodeStore::Database::j_
const beast::Journal j_
Definition: Database.h:301
ripple::NodeStore::DatabaseNodeImp::sweep
void sweep() override
Remove expired entries from the positive and negative caches.
Definition: DatabaseNodeImp.cpp:67
ripple::NodeStore::FetchReport::wasFound
bool wasFound
Definition: ripple/nodestore/Scheduler.h:40
ripple::NodeStore::DatabaseNodeImp::fetchBatch
std::vector< std::shared_ptr< NodeObject > > fetchBatch(std::vector< uint256 > const &hashes)
Definition: DatabaseNodeImp.cpp:147
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::unordered_map
STL class.
ripple::NodeStore::DatabaseNodeImp::asyncFetch
void asyncFetch(uint256 const &hash, std::uint32_t ledgerSeq, std::function< void(std::shared_ptr< NodeObject > const &)> &&callback) override
Fetch an object without waiting.
Definition: DatabaseNodeImp.cpp:49
std::exception::what
T what(T... args)
std::chrono