rippled
DatabaseRotatingImp.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/DatabaseRotatingImp.h>
22 #include <ripple/protocol/HashPrefix.h>
23 
24 namespace ripple {
25 namespace NodeStore {
26 
28  std::string const& name,
29  Scheduler& scheduler,
30  int readThreads,
31  Stoppable& parent,
32  std::shared_ptr<Backend> writableBackend,
33  std::shared_ptr<Backend> archiveBackend,
34  Section const& config,
36  : DatabaseRotating(name, parent, scheduler, readThreads, config, j)
37  , pCache_(std::make_shared<TaggedCache<uint256, NodeObject>>(
38  name,
41  stopwatch(),
42  j))
43  , nCache_(std::make_shared<KeyCache<uint256>>(
44  name,
45  stopwatch(),
48  , writableBackend_(std::move(writableBackend))
49  , archiveBackend_(std::move(archiveBackend))
50 {
51  if (writableBackend_)
52  fdRequired_ += writableBackend_->fdRequired();
53  if (archiveBackend_)
54  fdRequired_ += archiveBackend_->fdRequired();
55  setParent(parent);
56 }
57 
58 void
61  std::string const& writableBackendName)> const& f)
62 {
63  std::lock_guard lock(mutex_);
64 
65  auto newBackend = f(writableBackend_->getName());
66  archiveBackend_->setDeletePath();
67  archiveBackend_ = std::move(writableBackend_);
68  writableBackend_ = std::move(newBackend);
69 }
70 
73 {
74  std::lock_guard lock(mutex_);
75  return writableBackend_->getName();
76 }
77 
80 {
81  std::lock_guard lock(mutex_);
82  return writableBackend_->getWriteLoad();
83 }
84 
85 void
87 {
88  auto const backend = [&] {
89  std::lock_guard lock(mutex_);
90  return writableBackend_;
91  }();
92 
93  importInternal(*backend, source);
94 }
95 
96 bool
98 {
99  auto const backend = [&] {
100  std::lock_guard lock(mutex_);
101  return writableBackend_;
102  }();
103 
104  return Database::storeLedger(*srcLedger, backend, pCache_, nCache_);
105 }
106 
107 void
109  NodeObjectType type,
110  Blob&& data,
111  uint256 const& hash,
113 {
114  auto nObj = NodeObject::createObject(type, std::move(data), hash);
115  pCache_->canonicalize_replace_cache(hash, nObj);
116 
117  auto const backend = [&] {
118  std::lock_guard lock(mutex_);
119  return writableBackend_;
120  }();
121  backend->store(nObj);
122 
123  nCache_->erase(hash);
124  storeStats(1, nObj->getData().size());
125 }
126 
127 bool
129  uint256 const& hash,
130  std::uint32_t ledgerSeq,
131  std::shared_ptr<NodeObject>& nodeObject)
132 {
133  // See if the object is in cache
134  nodeObject = pCache_->fetch(hash);
135  if (nodeObject || nCache_->touch_if_exists(hash))
136  return true;
137 
138  // Otherwise post a read
139  Database::asyncFetch(hash, ledgerSeq);
140  return false;
141 }
142 
143 void
145 {
146  pCache_->setTargetSize(size);
147  pCache_->setTargetAge(age);
148  nCache_->setTargetSize(size);
149  nCache_->setTargetAge(age);
150 }
151 
152 void
154 {
155  pCache_->sweep();
156  nCache_->sweep();
157 }
158 
161  uint256 const& hash,
163  FetchReport& fetchReport)
164 {
165  auto fetch = [&](std::shared_ptr<Backend> const& backend) {
166  Status status;
167  std::shared_ptr<NodeObject> nodeObject;
168  try
169  {
170  status = backend->fetch(hash.data(), &nodeObject);
171  }
172  catch (std::exception const& e)
173  {
174  JLOG(j_.fatal()) << "Exception, " << e.what();
175  Rethrow();
176  }
177 
178  switch (status)
179  {
180  case ok:
181  ++fetchHitCount_;
182  if (nodeObject)
183  fetchSz_ += nodeObject->getData().size();
184  break;
185  case notFound:
186  break;
187  case dataCorrupt:
188  JLOG(j_.fatal()) << "Corrupt NodeObject #" << hash;
189  break;
190  default:
191  JLOG(j_.warn()) << "Unknown status=" << status;
192  break;
193  }
194 
195  return nodeObject;
196  };
197 
198  // See if the node object exists in the cache
199  auto nodeObject{pCache_->fetch(hash)};
200  if (!nodeObject && !nCache_->touch_if_exists(hash))
201  {
202  auto [writable, archive] = [&] {
203  std::lock_guard lock(mutex_);
205  }();
206 
207  fetchReport.wentToDisk = true;
208 
209  // Try to fetch from the writable backend
210  nodeObject = fetch(writable);
211  if (!nodeObject)
212  {
213  // Otherwise try to fetch from the archive backend
214  nodeObject = fetch(archive);
215  if (nodeObject)
216  {
217  {
218  // Refresh the writable backend pointer
219  std::lock_guard lock(mutex_);
220  writable = writableBackend_;
221  }
222 
223  // Update writable backend with data from the archive backend
224  writable->store(nodeObject);
225  nCache_->erase(hash);
226  }
227  }
228 
229  if (!nodeObject)
230  {
231  // Just in case a write occurred
232  nodeObject = pCache_->fetch(hash);
233  if (!nodeObject)
234  // We give up
235  nCache_->insert(hash);
236  }
237  else
238  {
239  fetchReport.wasFound = true;
240 
241  // Ensure all threads get the same object
242  pCache_->canonicalize_replace_client(hash, nodeObject);
243 
244  // Since this was a 'hard' fetch, we will log it
245  JLOG(j_.trace()) << "HOS: " << hash << " fetch: in shard db";
246  }
247  }
248 
249  return nodeObject;
250 }
251 
252 void
255 {
256  auto [writable, archive] = [&] {
257  std::lock_guard lock(mutex_);
259  }();
260 
261  // Iterate the writable backend
262  writable->for_each(f);
263 
264  // Iterate the archive backend
265  archive->for_each(f);
266 }
267 
268 } // namespace NodeStore
269 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::NodeStore::DatabaseRotatingImp::rotateWithLock
void rotateWithLock(std::function< std::unique_ptr< NodeStore::Backend >(std::string const &writableBackendName)> const &f) override
Rotates the backends.
Definition: DatabaseRotatingImp.cpp:59
ripple::NodeStore::cacheTargetSize
@ cacheTargetSize
Definition: nodestore/impl/Tuning.h:28
ripple::NodeStore::DatabaseRotatingImp::archiveBackend_
std::shared_ptr< Backend > archiveBackend_
Definition: DatabaseRotatingImp.h:113
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:53
std::string
STL class.
std::shared_ptr
STL class.
ripple::TaggedCache
Map/cache combination.
Definition: TaggedCache.h:52
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::DatabaseRotatingImp::sweep
void sweep() override
Remove expired entries from the positive and negative caches.
Definition: DatabaseRotatingImp.cpp:153
ripple::NodeStore::DatabaseRotatingImp::tune
void tune(int size, std::chrono::seconds age) override
Set the maximum number of entries and maximum cache age for both caches.
Definition: DatabaseRotatingImp.cpp:144
ripple::NodeStore::Database::fdRequired_
int fdRequired_
Definition: Database.h:249
std::vector< unsigned char >
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
std::chrono::seconds
ripple::NodeStore::DatabaseRotatingImp::DatabaseRotatingImp
DatabaseRotatingImp()=delete
ripple::NodeStore::DatabaseRotatingImp::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t, FetchReport &fetchReport) override
Definition: DatabaseRotatingImp.cpp:160
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::NodeStore::Database::fetchSz_
std::atomic< std::uint32_t > fetchSz_
Definition: Database.h:252
std::lock_guard
STL class.
ripple::NodeStore::FetchReport
Contains information about a fetch operation.
Definition: ripple/nodestore/Scheduler.h:32
ripple::stopwatch
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:86
std::function
ripple::NodeStore::DatabaseRotatingImp::getName
std::string getName() const override
Retrieve the name associated with this backend.
Definition: DatabaseRotatingImp.cpp:72
ripple::NodeStore::Database::fetchHitCount_
std::atomic< std::uint32_t > fetchHitCount_
Definition: Database.h:251
ripple::base_uint::data
pointer data()
Definition: base_uint.h:113
ripple::Stoppable::setParent
void setParent(Stoppable &parent)
Set the parent of this Stoppable.
Definition: Stoppable.cpp:43
ripple::NodeStore::notFound
@ notFound
Definition: nodestore/Types.h:46
ripple::base_uint< 256 >
ripple::NodeStore::DatabaseRotatingImp::getWriteLoad
std::int32_t getWriteLoad() const override
Retrieve the estimated number of pending write operations.
Definition: DatabaseRotatingImp.cpp:79
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:119
ripple::Rethrow
void Rethrow()
Rethrow the exception currently being handled.
Definition: contract.h:48
ripple::NodeStore::cacheTargetAge
constexpr std::chrono::seconds cacheTargetAge
Definition: nodestore/impl/Tuning.h:36
ripple::NodeStore::DatabaseRotatingImp::mutex_
std::mutex mutex_
Definition: DatabaseRotatingImp.h:114
ripple::NodeStore::DatabaseRotatingImp::storeLedger
bool storeLedger(std::shared_ptr< Ledger const > const &srcLedger) override
Store a ledger from a different database.
Definition: DatabaseRotatingImp.cpp:97
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::NodeStore::dataCorrupt
@ dataCorrupt
Definition: nodestore/Types.h:47
std::int32_t
ripple::NodeStore::DatabaseRotating
Definition: DatabaseRotating.h:33
ripple::NodeStore::Scheduler
Scheduling for asynchronous backend activity.
Definition: ripple/nodestore/Scheduler.h:61
ripple::NodeStore::DatabaseRotatingImp::import
void import(Database &source) override
Import objects from another database.
Definition: DatabaseRotatingImp.cpp:86
ripple::NodeStore::Database::storeStats
void storeStats(std::uint64_t count, std::uint64_t sz)
Definition: Database.h:258
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::NodeStore::DatabaseRotatingImp::asyncFetch
bool asyncFetch(uint256 const &hash, std::uint32_t ledgerSeq, std::shared_ptr< NodeObject > &nodeObject) override
Fetch an object without waiting.
Definition: DatabaseRotatingImp.cpp:128
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
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::asyncFetch
virtual bool asyncFetch(uint256 const &hash, std::uint32_t ledgerSeq, std::shared_ptr< NodeObject > &nodeObject)=0
Fetch an object without waiting.
ripple::NodeStore::DatabaseRotatingImp::store
void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t) override
Store the object.
Definition: DatabaseRotatingImp.cpp:108
ripple::NodeStore::Database::j_
const beast::Journal j_
Definition: Database.h:247
ripple::NodeStore::FetchReport::wasFound
bool wasFound
Definition: ripple/nodestore/Scheduler.h:41
std
STL namespace.
std::make_pair
T make_pair(T... args)
ripple::NodeObject
A simple object that the Ledger uses to store entries.
Definition: NodeObject.h:48
ripple::KeyCache
Maintains a cache of keys with no associated data.
Definition: KeyCache.h:43
ripple::NodeStore::FetchReport::wentToDisk
bool wentToDisk
Definition: ripple/nodestore/Scheduler.h:40
std::unique_ptr
STL class.
ripple::NodeStore::DatabaseRotatingImp::for_each
void for_each(std::function< void(std::shared_ptr< NodeObject >)> f) override
Visit every object in the database This is usually called during import.
Definition: DatabaseRotatingImp.cpp:253
ripple::NodeStore::DatabaseRotatingImp::writableBackend_
std::shared_ptr< Backend > writableBackend_
Definition: DatabaseRotatingImp.h:112
ripple::NodeStore::DatabaseRotatingImp::nCache_
std::shared_ptr< KeyCache< uint256 > > nCache_
Definition: DatabaseRotatingImp.h:110
std::exception::what
T what(T... args)
ripple::NodeStore::DatabaseRotatingImp::pCache_
std::shared_ptr< TaggedCache< uint256, NodeObject > > pCache_
Definition: DatabaseRotatingImp.h:107