rippled
NuDBFactory.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/basics/contract.h>
21 #include <ripple/nodestore/Factory.h>
22 #include <ripple/nodestore/Manager.h>
23 #include <ripple/nodestore/impl/DecodedBlob.h>
24 #include <ripple/nodestore/impl/EncodedBlob.h>
25 #include <ripple/nodestore/impl/codec.h>
26 #include <boost/filesystem.hpp>
27 #include <cassert>
28 #include <chrono>
29 #include <cstdint>
30 #include <cstdio>
31 #include <exception>
32 #include <memory>
33 #include <nudb/nudb.hpp>
34 
35 namespace ripple {
36 namespace NodeStore {
37 
38 class NuDBBackend : public Backend
39 {
40 public:
41  static constexpr std::size_t currentType = 1;
42 
44  size_t const keyBytes_;
47  nudb::store db_;
50 
52  size_t keyBytes,
53  Section const& keyValues,
54  std::size_t burstSize,
55  Scheduler& scheduler,
56  beast::Journal journal)
57  : j_(journal)
58  , keyBytes_(keyBytes)
60  , name_(get<std::string>(keyValues, "path"))
61  , deletePath_(false)
62  , scheduler_(scheduler)
63  {
64  if (name_.empty())
65  Throw<std::runtime_error>(
66  "nodestore: Missing path in NuDB backend");
67  }
68 
70  size_t keyBytes,
71  Section const& keyValues,
72  std::size_t burstSize,
73  Scheduler& scheduler,
74  nudb::context& context,
75  beast::Journal journal)
76  : j_(journal)
77  , keyBytes_(keyBytes)
79  , name_(get<std::string>(keyValues, "path"))
80  , db_(context)
81  , deletePath_(false)
82  , scheduler_(scheduler)
83  {
84  if (name_.empty())
85  Throw<std::runtime_error>(
86  "nodestore: Missing path in NuDB backend");
87  }
88 
89  ~NuDBBackend() override
90  {
91  close();
92  }
93 
95  getName() override
96  {
97  return name_;
98  }
99 
100  void
101  open(bool createIfMissing) override
102  {
103  using namespace boost::filesystem;
104  if (db_.is_open())
105  {
106  assert(false);
107  JLOG(j_.error()) << "database is already open";
108  return;
109  }
110  auto const folder = path(name_);
111  auto const dp = (folder / "nudb.dat").string();
112  auto const kp = (folder / "nudb.key").string();
113  auto const lp = (folder / "nudb.log").string();
114  nudb::error_code ec;
115  if (createIfMissing)
116  {
117  create_directories(folder);
118  nudb::create<nudb::xxhasher>(
119  dp,
120  kp,
121  lp,
122  currentType,
123  nudb::make_salt(),
124  keyBytes_,
125  nudb::block_size(kp),
126  0.50,
127  ec);
128  if (ec == nudb::errc::file_exists)
129  ec = {};
130  if (ec)
131  Throw<nudb::system_error>(ec);
132  }
133  db_.open(dp, kp, lp, ec);
134  if (ec)
135  Throw<nudb::system_error>(ec);
136  if (db_.appnum() != currentType)
137  Throw<std::runtime_error>("nodestore: unknown appnum");
138  db_.set_burst(burstSize_);
139  }
140 
141  bool
142  isOpen() override
143  {
144  return db_.is_open();
145  }
146 
147  void
148  close() override
149  {
150  if (db_.is_open())
151  {
152  nudb::error_code ec;
153  db_.close(ec);
154  if (ec)
155  Throw<nudb::system_error>(ec);
156  if (deletePath_)
157  {
158  boost::filesystem::remove_all(name_);
159  }
160  }
161  }
162 
163  Status
164  fetch(void const* key, std::shared_ptr<NodeObject>* pno) override
165  {
166  Status status;
167  pno->reset();
168  nudb::error_code ec;
169  db_.fetch(
170  key,
171  [key, pno, &status](void const* data, std::size_t size) {
172  nudb::detail::buffer bf;
173  auto const result = nodeobject_decompress(data, size, bf);
174  DecodedBlob decoded(key, result.first, result.second);
175  if (!decoded.wasOk())
176  {
177  status = dataCorrupt;
178  return;
179  }
180  *pno = decoded.createObject();
181  status = ok;
182  },
183  ec);
184  if (ec == nudb::error::key_not_found)
185  return notFound;
186  if (ec)
187  Throw<nudb::system_error>(ec);
188  return status;
189  }
190 
191  bool
192  canFetchBatch() override
193  {
194  return true;
195  }
196 
198  fetchBatch(std::vector<uint256 const*> const& hashes) override
199  {
201  results.reserve(hashes.size());
202  for (auto const& h : hashes)
203  {
205  Status status = fetch(h->begin(), &nObj);
206  if (status != ok)
207  results.push_back({});
208  else
209  results.push_back(nObj);
210  }
211 
212  return {results, ok};
213  }
214 
215  void
217  {
218  EncodedBlob e;
219  e.prepare(no);
220  nudb::error_code ec;
221  nudb::detail::buffer bf;
222  auto const result = nodeobject_compress(e.getData(), e.getSize(), bf);
223  db_.insert(e.getKey(), result.first, result.second, ec);
224  if (ec && ec != nudb::error::key_exists)
225  Throw<nudb::system_error>(ec);
226  }
227 
228  void
229  store(std::shared_ptr<NodeObject> const& no) override
230  {
231  BatchWriteReport report;
232  report.writeCount = 1;
233  auto const start = std::chrono::steady_clock::now();
234  do_insert(no);
235  report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
237  scheduler_.onBatchWrite(report);
238  }
239 
240  void
241  storeBatch(Batch const& batch) override
242  {
243  BatchWriteReport report;
244  report.writeCount = batch.size();
245  auto const start = std::chrono::steady_clock::now();
246  for (auto const& e : batch)
247  do_insert(e);
248  report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
250  scheduler_.onBatchWrite(report);
251  }
252 
253  void
254  sync() override
255  {
256  }
257 
258  void
260  {
261  auto const dp = db_.dat_path();
262  auto const kp = db_.key_path();
263  auto const lp = db_.log_path();
264  // auto const appnum = db_.appnum();
265  nudb::error_code ec;
266  db_.close(ec);
267  if (ec)
268  Throw<nudb::system_error>(ec);
269  nudb::visit(
270  dp,
271  [&](void const* key,
272  std::size_t key_bytes,
273  void const* data,
274  std::size_t size,
275  nudb::error_code&) {
276  nudb::detail::buffer bf;
277  auto const result = nodeobject_decompress(data, size, bf);
278  DecodedBlob decoded(key, result.first, result.second);
279  if (!decoded.wasOk())
280  {
281  ec = make_error_code(nudb::error::missing_value);
282  return;
283  }
284  f(decoded.createObject());
285  },
286  nudb::no_progress{},
287  ec);
288  if (ec)
289  Throw<nudb::system_error>(ec);
290  db_.open(dp, kp, lp, ec);
291  if (ec)
292  Throw<nudb::system_error>(ec);
293  }
294 
295  int
296  getWriteLoad() override
297  {
298  return 0;
299  }
300 
301  void
302  setDeletePath() override
303  {
304  deletePath_ = true;
305  }
306 
307  void
308  verify() override
309  {
310  auto const dp = db_.dat_path();
311  auto const kp = db_.key_path();
312  auto const lp = db_.log_path();
313  nudb::error_code ec;
314  db_.close(ec);
315  if (ec)
316  Throw<nudb::system_error>(ec);
317  nudb::verify_info vi;
318  nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
319  if (ec)
320  Throw<nudb::system_error>(ec);
321  db_.open(dp, kp, lp, ec);
322  if (ec)
323  Throw<nudb::system_error>(ec);
324  }
325 
326  int
327  fdRequired() const override
328  {
329  return 3;
330  }
331 
332  Counters const&
333  counters() const override
334  {
335  static Counters counters;
336  return counters;
337  }
338 };
339 
340 //------------------------------------------------------------------------------
341 
342 class NuDBFactory : public Factory
343 {
344 public:
346  {
347  Manager::instance().insert(*this);
348  }
349 
350  ~NuDBFactory() override
351  {
352  Manager::instance().erase(*this);
353  }
354 
356  getName() const override
357  {
358  return "NuDB";
359  }
360 
363  size_t keyBytes,
364  Section const& keyValues,
365  std::size_t burstSize,
366  Scheduler& scheduler,
367  beast::Journal journal) override
368  {
369  return std::make_unique<NuDBBackend>(
370  keyBytes, keyValues, burstSize, scheduler, journal);
371  }
372 
375  size_t keyBytes,
376  Section const& keyValues,
377  std::size_t burstSize,
378  Scheduler& scheduler,
379  nudb::context& context,
380  beast::Journal journal) override
381  {
382  return std::make_unique<NuDBBackend>(
383  keyBytes, keyValues, burstSize, scheduler, context, journal);
384  }
385 };
386 
388 
389 } // namespace NodeStore
390 } // namespace ripple
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
ripple::NodeStore::DecodedBlob::wasOk
bool wasOk() const noexcept
Determine if the decoding was successful.
Definition: DecodedBlob.h:46
ripple::NodeStore::nodeobject_decompress
std::pair< void const *, std::size_t > nodeobject_decompress(void const *in, std::size_t in_size, BufferFactory &&bf)
Definition: codec.h:100
ripple::NodeStore::Factory
Base class for backend factories.
Definition: Factory.h:33
ripple::NodeStore::NuDBBackend::deletePath_
std::atomic< bool > deletePath_
Definition: NuDBFactory.cpp:48
ripple::NodeStore::NuDBBackend::store
void store(std::shared_ptr< NodeObject > const &no) override
Store a single object.
Definition: NuDBFactory.cpp:229
ripple::NodeStore::EncodedBlob::getSize
std::size_t getSize() const noexcept
Definition: EncodedBlob.h:47
ripple::NodeStore::NuDBBackend::setDeletePath
void setDeletePath() override
Remove contents on disk upon destruction.
Definition: NuDBFactory.cpp:302
ripple::NodeStore::DecodedBlob
Parsed key/value blob into NodeObject components.
Definition: DecodedBlob.h:38
ripple::NodeStore::NuDBBackend::counters
Counters const & counters() const override
Definition: NuDBFactory.cpp:333
std::string
STL class.
std::shared_ptr< NodeObject >
exception
ripple::NodeStore::ok
@ ok
Definition: nodestore/Types.h:45
ripple::NodeStore::Manager::erase
virtual void erase(Factory &factory)=0
Remove a factory.
std::pair
std::vector::reserve
T reserve(T... args)
ripple::NodeStore::NuDBBackend::do_insert
void do_insert(std::shared_ptr< NodeObject > const &no)
Definition: NuDBFactory.cpp:216
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::NodeStore::NuDBBackend::isOpen
bool isOpen() override
Returns true is the database is open.
Definition: NuDBFactory.cpp:142
ripple::NodeStore::NuDBBackend::fetchBatch
std::pair< std::vector< std::shared_ptr< NodeObject > >, Status > fetchBatch(std::vector< uint256 const * > const &hashes) override
Fetch a batch synchronously.
Definition: NuDBFactory.cpp:198
ripple::NodeStore::NuDBBackend::currentType
static constexpr std::size_t currentType
Definition: NuDBFactory.cpp:41
ripple::NodeStore::NuDBBackend::~NuDBBackend
~NuDBBackend() override
Definition: NuDBFactory.cpp:89
ripple::NodeStore::NuDBBackend::close
void close() override
Close the backend.
Definition: NuDBFactory.cpp:148
ripple::NodeStore::NuDBBackend::canFetchBatch
bool canFetchBatch() override
Return true if batch fetches are optimized.
Definition: NuDBFactory.cpp:192
ripple::NodeStore::EncodedBlob::getData
void const * getData() const noexcept
Definition: EncodedBlob.h:53
std::function
ripple::NodeStore::NuDBBackend::fdRequired
int fdRequired() const override
Returns the number of file descriptors the backend expects to need.
Definition: NuDBFactory.cpp:327
ripple::NodeStore::nuDBFactory
static NuDBFactory nuDBFactory
Definition: NuDBFactory.cpp:387
ripple::NodeStore::NuDBBackend::keyBytes_
const size_t keyBytes_
Definition: NuDBFactory.cpp:44
ripple::NodeStore::NuDBBackend::sync
void sync() override
Definition: NuDBFactory.cpp:254
std::shared_ptr::reset
T reset(T... args)
std::vector::push_back
T push_back(T... args)
ripple::NodeStore::notFound
@ notFound
Definition: nodestore/Types.h:46
ripple::NodeStore::NuDBBackend::j_
const beast::Journal j_
Definition: NuDBFactory.cpp:43
ripple::NodeStore::Manager::insert
virtual void insert(Factory &factory)=0
Add a factory.
ripple::NodeStore::NuDBBackend::name_
const std::string name_
Definition: NuDBFactory.cpp:46
ripple::NodeStore::DecodedBlob::createObject
std::shared_ptr< NodeObject > createObject()
Create a NodeObject from this data.
Definition: DecodedBlob.cpp:74
chrono
ripple::NodeStore::NuDBBackend
Definition: NuDBFactory.cpp:38
ripple::NodeStore::NuDBFactory
Definition: NuDBFactory.cpp:342
ripple::NodeStore::NuDBBackend::getWriteLoad
int getWriteLoad() override
Estimate the number of write operations pending.
Definition: NuDBFactory.cpp:296
beast::Journal::error
Stream error() const
Definition: Journal.h:333
cstdint
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::SizedItem::burstSize
@ burstSize
ripple::NodeStore::dataCorrupt
@ dataCorrupt
Definition: nodestore/Types.h:47
ripple::NodeStore::NuDBBackend::NuDBBackend
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)
Definition: NuDBFactory.cpp:51
std::atomic< bool >
ripple::NodeStore::Scheduler
Scheduling for asynchronous backend activity.
Definition: ripple/nodestore/Scheduler.h:60
ripple::NodeStore::NuDBBackend::open
void open(bool createIfMissing) override
Open the backend.
Definition: NuDBFactory.cpp:101
ripple::NodeStore::BatchWriteReport
Contains information about a batch write operation.
Definition: ripple/nodestore/Scheduler.h:44
ripple::NodeStore::NuDBFactory::~NuDBFactory
~NuDBFactory() override
Definition: NuDBFactory.cpp:350
ripple::NodeStore::NuDBBackend::verify
void verify() override
Perform consistency checks on database.
Definition: NuDBFactory.cpp:308
memory
ripple::NodeStore::NuDBBackend::getName
std::string getName() override
Get the human-readable name of this backend.
Definition: NuDBFactory.cpp:95
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple::NodeStore::NuDBFactory::createInstance
std::unique_ptr< Backend > createInstance(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, nudb::context &context, beast::Journal journal) override
Create an instance of this factory's backend.
Definition: NuDBFactory.cpp:374
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::NodeStore::NuDBBackend::scheduler_
Scheduler & scheduler_
Definition: NuDBFactory.cpp:49
ripple::NodeStore::NuDBFactory::getName
std::string getName() const override
Retrieve the name of this factory.
Definition: NuDBFactory.cpp:356
std
STL namespace.
cassert
ripple::NodeStore::NuDBBackend::burstSize_
const std::size_t burstSize_
Definition: NuDBFactory.cpp:45
ripple::NodeStore::NuDBFactory::createInstance
std::unique_ptr< Backend > createInstance(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal) override
Create an instance of this factory's backend.
Definition: NuDBFactory.cpp:362
std::string::empty
T empty(T... args)
ripple::NodeStore::NuDBBackend::db_
nudb::store db_
Definition: NuDBFactory.cpp:47
ripple::NodeStore::NuDBBackend::storeBatch
void storeBatch(Batch const &batch) override
Store a group of objects.
Definition: NuDBFactory.cpp:241
std::size_t
ripple::NodeStore::BatchWriteReport::writeCount
int writeCount
Definition: ripple/nodestore/Scheduler.h:49
ripple::NodeStore::nodeobject_compress
std::pair< void const *, std::size_t > nodeobject_compress(void const *in, std::size_t in_size, BufferFactory &&bf)
Definition: codec.h:211
ripple::NodeStore::EncodedBlob
Utility for producing flattened node objects.
Definition: EncodedBlob.h:34
ripple::NodeStore::NuDBBackend::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: NuDBFactory.cpp:259
ripple::NodeStore::Manager::instance
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:128
ripple::NodeStore::EncodedBlob::getKey
void const * getKey() const noexcept
Definition: EncodedBlob.h:41
ripple::NodeStore::BatchWriteReport::elapsed
std::chrono::milliseconds elapsed
Definition: ripple/nodestore/Scheduler.h:48
std::unique_ptr
STL class.
ripple::NodeStore::NuDBBackend::NuDBBackend
NuDBBackend(size_t keyBytes, Section const &keyValues, std::size_t burstSize, Scheduler &scheduler, nudb::context &context, beast::Journal journal)
Definition: NuDBFactory.cpp:69
cstdio
ripple::NodeStore::Scheduler::onBatchWrite
virtual void onBatchWrite(BatchWriteReport const &report)=0
Reports the completion of a batch write Allows the scheduler to monitor the node store's performance.
ripple::NodeStore::NuDBBackend::fetch
Status fetch(void const *key, std::shared_ptr< NodeObject > *pno) override
Fetch a single object.
Definition: NuDBFactory.cpp:164
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:116
ripple::NodeStore::EncodedBlob::prepare
void prepare(std::shared_ptr< NodeObject > const &object)
Definition: EncodedBlob.cpp:27
ripple::NodeStore::NuDBFactory::NuDBFactory
NuDBFactory()
Definition: NuDBFactory.cpp:345
ripple::NodeStore::Backend
A backend used for the NodeStore.
Definition: Backend.h:39
ripple::NodeStore::Backend::Counters
Definition: Backend.h:42
std::chrono::steady_clock::now
T now(T... args)