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