xrpld
Loading...
Searching...
No Matches
DatabaseRotatingImp.cpp
1#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
2
3#include <xrpl/basics/Blob.h>
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/basics/contract.h>
7#include <xrpl/beast/utility/Journal.h>
8#include <xrpl/config/BasicConfig.h>
9#include <xrpl/nodestore/Backend.h>
10#include <xrpl/nodestore/Database.h>
11#include <xrpl/nodestore/DatabaseRotating.h>
12#include <xrpl/nodestore/NodeObject.h>
13#include <xrpl/nodestore/Scheduler.h>
14#include <xrpl/nodestore/Types.h>
15
16#include <atomic>
17#include <cstdint>
18#include <exception>
19#include <functional>
20#include <memory>
21#include <mutex>
22#include <string>
23#include <utility>
24
25namespace xrpl::node_store {
26
28 Scheduler& scheduler,
29 int readThreads,
30 std::shared_ptr<Backend> writableBackend,
31 std::shared_ptr<Backend> archiveBackend,
32 Section const& config,
34 : DatabaseRotating(scheduler, readThreads, config, j)
35 , writableBackend_(std::move(writableBackend))
36 , archiveBackend_(std::move(archiveBackend))
37{
39 fdRequired_ += writableBackend_->fdRequired();
41 fdRequired_ += archiveBackend_->fdRequired();
42}
43
44void
47 std::function<void(std::string const& writableName, std::string const& archiveName)> const& f)
48{
49 // Pass these two names to the callback function
50 std::string const newWritableBackendName = newBackend->getName();
51 std::string newArchiveBackendName;
52 // Hold on to current archive backend pointer until after the
53 // callback finishes. Only then will the archive directory be
54 // deleted.
56 std::uint64_t copyForwards = 0;
57 {
58 std::scoped_lock const lock(mutex_);
59
60 archiveBackend_->setDeletePath();
61 oldArchiveBackend = std::move(archiveBackend_);
62
64 newArchiveBackendName = archiveBackend_->getName();
65
66 writableBackend_ = std::move(newBackend);
67
68 copyForwards = copyForwardCount_.exchange(0, std::memory_order_relaxed);
69 }
70
71 if (copyForwards > 0)
72 {
73 JLOG(j_.warn()) << "Rotating: copied forward " << copyForwards
74 << " archive-served reads into the writable backend "
75 "during the rotation window";
76 }
77
78 f(newWritableBackendName, newArchiveBackendName);
79}
80
81void
83{
84 rotationInFlight_.store(inFlight, std::memory_order_release);
85 JLOG(j_.debug()) << "Rotating: copy-forward on archive reads "
86 << (inFlight ? "enabled" : "disabled");
87}
88
91{
92 std::scoped_lock const lock(mutex_);
93 return writableBackend_->getName();
94}
95
98{
99 std::scoped_lock const lock(mutex_);
100 return writableBackend_->getWriteLoad();
101}
102
103void
105{
106 auto const backend = [&] {
107 std::scoped_lock const lock(mutex_);
108 return writableBackend_;
109 }();
110
111 importInternal(*backend, source);
112}
113
114void
116{
117 std::scoped_lock const lock(mutex_);
118 writableBackend_->sync();
119}
120
121void
123{
124 auto nObj = NodeObject::createObject(type, std::move(data), hash);
125
126 auto const backend = [&] {
127 std::scoped_lock const lock(mutex_);
128 return writableBackend_;
129 }();
130
131 backend->store(nObj);
132 storeStats(1, nObj->getData().size());
133}
134
135void
137{
138 // Nothing to do.
139}
140
143 uint256 const& hash,
145 FetchReport& fetchReport,
146 bool duplicate)
147{
148 auto fetch = [&](std::shared_ptr<Backend> const& backend) {
149 Status status = Status::Ok;
151 try
152 {
153 status = backend->fetch(hash, &nodeObject);
154 }
155 catch (std::exception const& e)
156 {
157 JLOG(j_.fatal()) << "Exception, " << e.what();
158 rethrow();
159 }
160
161 switch (status)
162 {
163 case Status::Ok:
164 case Status::NotFound:
165 break;
167 JLOG(j_.fatal()) << "Corrupt NodeObject #" << hash;
168 break;
169 default:
170 JLOG(j_.warn()) << "Unknown status=" << static_cast<int>(status);
171 break;
172 }
173
174 return nodeObject;
175 };
176
177 // See if the node object exists in the cache
179
180 auto [writable, archive] = [&] {
181 std::scoped_lock const lock(mutex_);
183 }();
184
185 // Try to fetch from the writable backend
186 nodeObject = fetch(writable);
187 if (!nodeObject)
188 {
189 // Otherwise try to fetch from the archive backend
190 nodeObject = fetch(archive);
191 if (nodeObject)
192 {
193 {
194 // Refresh the writable backend pointer
195 std::scoped_lock const lock(mutex_);
196 writable = writableBackend_;
197 }
198
199 // Update writable backend with data from the archive backend.
200 // While a rotation is in flight, ordinary (duplicate == false)
201 // reads served by the archive are copied forward too: the
202 // archive is about to be deleted, and a body canonicalized
203 // into the cache after the freshen getKeys() snapshot would
204 // otherwise survive only in RAM once the archive is dropped.
205 if (duplicate || rotationInFlight_.load(std::memory_order_acquire))
206 {
207 if (!duplicate)
208 copyForwardCount_.fetch_add(1, std::memory_order_relaxed);
209 writable->store(nodeObject);
210 }
211 }
212 }
213
214 if (nodeObject)
215 fetchReport.wasFound = true;
216
217 return nodeObject;
218}
219
220void
222{
223 auto [writable, archive] = [&] {
224 std::scoped_lock const lock(mutex_);
226 }();
227
228 // Iterate the writable backend
229 writable->forEach(f);
230
231 // Iterate the archive backend
232 archive->forEach(f);
233}
234
235} // namespace xrpl::node_store
A generic endpoint for log messages.
Definition Journal.h:44
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
Holds a collection of configuration values.
Definition BasicConfig.h:29
void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t) override
Store the object.
void setRotationInFlight(bool inFlight) override
Marks an online-delete rotation as in progress (or completed).
void importDatabase(Database &source) override
Import objects from another database.
std::atomic< std::uint64_t > copyForwardCount_
std::string getName() const override
Retrieve the name associated with this backend.
std::int32_t getWriteLoad() const override
Retrieve the estimated number of pending write operations.
std::shared_ptr< Backend > writableBackend_
void sweep() override
Remove expired entries from the positive and negative caches.
void rotate(std::unique_ptr< node_store::Backend > &&newBackend, std::function< void(std::string const &writableName, std::string const &archiveName)> const &f) override
Rotates the backends.
std::shared_ptr< Backend > archiveBackend_
void forEach(std::function< void(std::shared_ptr< NodeObject >)> f) override
Visit every object in the database This is usually called during import.
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t, FetchReport &fetchReport, bool duplicate) override
DatabaseRotating(Scheduler &scheduler, int readThreads, Section const &config, beast::Journal journal)
Persistency layer for NodeObject.
Definition Database.h:45
void storeStats(std::uint64_t count, std::uint64_t sz)
Definition Database.h:249
void importInternal(Backend &dstBackend, Database &srcDB)
beast::Journal const j_
Definition Database.h:228
Scheduling for asynchronous backend activity.
T make_pair(T... args)
STL namespace.
Status
Return codes from Backend operations.
NodeObjectType
The types of node objects.
Definition NodeObject.h:18
XRPL_NO_SANITIZE_ADDRESS void rethrow()
Rethrow the exception currently being handled.
Definition contract.h:36
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:11
BaseUInt< 256 > uint256
Definition base_uint.h:580
Contains information about a fetch operation.
T what(T... args)