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