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  void
193  {
194  EncodedBlob e;
195  e.prepare(no);
196  nudb::error_code ec;
197  nudb::detail::buffer bf;
198  auto const result = nodeobject_compress(e.getData(), e.getSize(), bf);
199  db_.insert(e.getKey(), result.first, result.second, ec);
200  if (ec && ec != nudb::error::key_exists)
201  Throw<nudb::system_error>(ec);
202  }
203 
204  void
205  store(std::shared_ptr<NodeObject> const& no) override
206  {
207  BatchWriteReport report;
208  report.writeCount = 1;
209  auto const start = std::chrono::steady_clock::now();
210  do_insert(no);
211  report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
213  scheduler_.onBatchWrite(report);
214  }
215 
216  void
217  storeBatch(Batch const& batch) override
218  {
219  BatchWriteReport report;
220  report.writeCount = batch.size();
221  auto const start = std::chrono::steady_clock::now();
222  for (auto const& e : batch)
223  do_insert(e);
224  report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
226  scheduler_.onBatchWrite(report);
227  }
228 
229  void
231  {
232  auto const dp = db_.dat_path();
233  auto const kp = db_.key_path();
234  auto const lp = db_.log_path();
235  // auto const appnum = db_.appnum();
236  nudb::error_code ec;
237  db_.close(ec);
238  if (ec)
239  Throw<nudb::system_error>(ec);
240  nudb::visit(
241  dp,
242  [&](void const* key,
243  std::size_t key_bytes,
244  void const* data,
245  std::size_t size,
246  nudb::error_code&) {
247  nudb::detail::buffer bf;
248  auto const result = nodeobject_decompress(data, size, bf);
249  DecodedBlob decoded(key, result.first, result.second);
250  if (!decoded.wasOk())
251  {
252  ec = make_error_code(nudb::error::missing_value);
253  return;
254  }
255  f(decoded.createObject());
256  },
257  nudb::no_progress{},
258  ec);
259  if (ec)
260  Throw<nudb::system_error>(ec);
261  db_.open(dp, kp, lp, ec);
262  if (ec)
263  Throw<nudb::system_error>(ec);
264  }
265 
266  int
267  getWriteLoad() override
268  {
269  return 0;
270  }
271 
272  void
273  setDeletePath() override
274  {
275  deletePath_ = true;
276  }
277 
278  void
279  verify() override
280  {
281  auto const dp = db_.dat_path();
282  auto const kp = db_.key_path();
283  auto const lp = db_.log_path();
284  nudb::error_code ec;
285  db_.close(ec);
286  if (ec)
287  Throw<nudb::system_error>(ec);
288  nudb::verify_info vi;
289  nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
290  if (ec)
291  Throw<nudb::system_error>(ec);
292  db_.open(dp, kp, lp, ec);
293  if (ec)
294  Throw<nudb::system_error>(ec);
295  }
296 
297  int
298  fdRequired() const override
299  {
300  return 3;
301  }
302 };
303 
304 //------------------------------------------------------------------------------
305 
306 class NuDBFactory : public Factory
307 {
308 public:
310  {
311  Manager::instance().insert(*this);
312  }
313 
314  ~NuDBFactory() override
315  {
316  Manager::instance().erase(*this);
317  }
318 
320  getName() const override
321  {
322  return "NuDB";
323  }
324 
327  size_t keyBytes,
328  Section const& keyValues,
329  std::size_t burstSize,
330  Scheduler& scheduler,
331  beast::Journal journal) override
332  {
333  return std::make_unique<NuDBBackend>(
334  keyBytes, keyValues, burstSize, scheduler, journal);
335  }
336 
339  size_t keyBytes,
340  Section const& keyValues,
341  std::size_t burstSize,
342  Scheduler& scheduler,
343  nudb::context& context,
344  beast::Journal journal) override
345  {
346  return std::make_unique<NuDBBackend>(
347  keyBytes, keyValues, burstSize, scheduler, context, journal);
348  }
349 };
350 
352 
353 } // namespace NodeStore
354 } // 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:32
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:205
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:273
ripple::NodeStore::DecodedBlob
Parsed key/value blob into NodeObject components.
Definition: DecodedBlob.h:38
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.
ripple::NodeStore::NuDBBackend::do_insert
void do_insert(std::shared_ptr< NodeObject > const &no)
Definition: NuDBFactory.cpp:192
std::vector< std::shared_ptr< NodeObject > >
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::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::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:298
ripple::NodeStore::nuDBFactory
static NuDBFactory nuDBFactory
Definition: NuDBFactory.cpp:351
ripple::NodeStore::NuDBBackend::keyBytes_
const size_t keyBytes_
Definition: NuDBFactory.cpp:44
std::shared_ptr::reset
T reset(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:306
ripple::NodeStore::NuDBBackend::getWriteLoad
int getWriteLoad() override
Estimate the number of write operations pending.
Definition: NuDBFactory.cpp:267
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:314
ripple::NodeStore::NuDBBackend::verify
void verify() override
Perform consistency checks on database.
Definition: NuDBFactory.cpp:279
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:338
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:320
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:326
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:217
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:230
ripple::NodeStore::Manager::instance
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:119
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:309
ripple::NodeStore::Backend
A backend used for the NodeStore.
Definition: Backend.h:37
std::chrono::steady_clock::now
T now(T... args)