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