rippled
DeterministicShard.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2020 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/main/Application.h>
21 #include <ripple/beast/hash/hash_append.h>
22 #include <ripple/core/ConfigSections.h>
23 #include <ripple/nodestore/Manager.h>
24 #include <ripple/nodestore/impl/DeterministicShard.h>
25 #include <ripple/nodestore/impl/Shard.h>
26 #include <ripple/protocol/digest.h>
27 #include <fstream>
28 #include <nudb/detail/format.hpp>
29 #include <nudb/nudb.hpp>
30 #include <openssl/ripemd.h>
31 
32 namespace ripple {
33 namespace NodeStore {
34 
36  Application& app,
37  boost::filesystem::path const& dir,
38  std::uint32_t index,
40  : app_(app)
41  , index_(index)
42  , dir_(dir / "tmp")
43  , ctx_(std::make_unique<nudb::context>())
44  , j_(j)
45  , curMemObjs_(0)
46  , maxMemObjs_(
47  app_.getShardStore()->ledgersPerShard() <= 256 ? maxMemObjsTest
48  : maxMemObjsDefault)
49 {
50 }
51 
53 {
54  close(true);
55 }
56 
57 bool
59 {
60  auto db = app_.getShardStore();
61 
62  auto fail = [&](std::string const& msg) {
63  JLOG(j_.error()) << "deterministic shard " << index_
64  << " not created: " << msg;
65  backend_.reset();
66  try
67  {
68  remove_all(dir_);
69  }
70  catch (std::exception const& e)
71  {
72  JLOG(j_.error()) << "deterministic shard " << index_
73  << ". Exception caught in function " << __func__
74  << ". Error: " << e.what();
75  }
76  return false;
77  };
78 
79  if (!db)
80  return fail("shard store not exists");
81 
82  if (index_ < db->earliestShardIndex())
83  return fail("Invalid shard index");
84 
85  Config const& config{app_.config()};
86  Section section{config.section(ConfigSection::shardDatabase())};
87  auto const type{get(section, "type", "nudb")};
88  auto const factory{Manager::instance().find(type)};
89  if (!factory)
90  return fail("failed to find factory for " + type);
91 
92  section.set("path", dir_.string());
93  backend_ = factory->createInstance(
94  NodeObject::keyBytes, section, 1, scheduler_, *ctx_, j_);
95 
96  if (!backend_)
97  return fail("failed to create database");
98 
100  h(finalKey.data(), finalKey.size());
101  auto const result{static_cast<ripemd160_hasher::result_type>(h)};
102  auto const hash{uint160::fromVoid(result.data())};
103 
104  auto digest = [&](int n) {
105  auto const data{hash.data()};
106  std::uint64_t result{0};
107 
108  switch (n)
109  {
110  case 0:
111  case 1:
112  // Construct 64 bits from sequential eight bytes
113  for (int i = 0; i < 8; i++)
114  result = (result << 8) + data[n * 8 + i];
115  break;
116 
117  case 2:
118  // Construct 64 bits using the last four bytes of data
119  result = (static_cast<std::uint64_t>(data[16]) << 24) +
120  (static_cast<std::uint64_t>(data[17]) << 16) +
121  (static_cast<std::uint64_t>(data[18]) << 8) +
122  (static_cast<std::uint64_t>(data[19]));
123  break;
124  }
125 
126  return result;
127  };
128  auto const uid{digest(0)};
129  auto const salt{digest(1)};
130  auto const appType{digest(2) | deterministicType};
131 
132  // Open or create the NuDB key/value store
133  try
134  {
135  if (exists(dir_))
136  remove_all(dir_);
137 
138  backend_->open(true, appType, uid, salt);
139  }
140  catch (std::exception const& e)
141  {
142  return fail(
143  std::string(". Exception caught in function ") + __func__ +
144  ". Error: " + e.what());
145  }
146 
147  return true;
148 }
149 
152  Application& app,
153  boost::filesystem::path const& shardDir,
154  std::uint32_t shardIndex,
155  Serializer const& finalKey,
156  beast::Journal j)
157 {
159  new DeterministicShard(app, shardDir, shardIndex, j));
160  if (!dShard->init(finalKey))
161  return {};
162  return dShard;
163 }
164 
165 void
167 {
168  try
169  {
170  if (cancel)
171  {
172  backend_.reset();
173  remove_all(dir_);
174  }
175  else
176  {
177  ctx_->flush();
178  curMemObjs_ = 0;
179  backend_.reset();
180  }
181  }
182  catch (std::exception const& e)
183  {
184  JLOG(j_.error()) << "deterministic shard " << index_
185  << ". Exception caught in function " << __func__
186  << ". Error: " << e.what();
187  }
188 }
189 
190 bool
192 {
193  try
194  {
195  backend_->store(nodeObject);
196 
197  // Flush to the backend if at threshold
198  if (++curMemObjs_ >= maxMemObjs_)
199  {
200  ctx_->flush();
201  curMemObjs_ = 0;
202  }
203  }
204  catch (std::exception const& e)
205  {
206  JLOG(j_.error()) << "deterministic shard " << index_
207  << ". Exception caught in function " << __func__
208  << ". Error: " << e.what();
209  return false;
210  }
211 
212  return true;
213 }
214 
215 } // namespace NodeStore
216 } // namespace ripple
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::Application
Definition: Application.h:115
ripple::NodeStore::DeterministicShard::~DeterministicShard
~DeterministicShard()
Definition: DeterministicShard.cpp:52
ripple::NodeStore::DeterministicShard::DeterministicShard
DeterministicShard(DeterministicShard const &)=delete
ripple::NodeStore::DeterministicShard::deterministicType
constexpr static std::uint64_t deterministicType
Definition: DeterministicShard.h:46
fstream
std::string
STL class.
std::shared_ptr
STL class.
ripple::NodeStore::DeterministicShard::init
bool init(Serializer const &finalKey)
Initializes the deterministic shard.
Definition: DeterministicShard.cpp:58
std::exception
STL class.
ripple::NodeStore::DeterministicShard::backend_
std::shared_ptr< Backend > backend_
Definition: DeterministicShard.h:130
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
ripple::NodeStore::DeterministicShard::store
bool store(std::shared_ptr< NodeObject > const &nodeObject)
Store a node object in memory.
Definition: DeterministicShard.cpp:191
ripple::NodeStore::make_DeterministicShard
std::shared_ptr< DeterministicShard > make_DeterministicShard(Application &app, boost::filesystem::path const &shardDir, std::uint32_t shardIndex, Serializer const &finalKey, beast::Journal j)
Creates shared pointer to deterministic shard and initializes it.
Definition: DeterministicShard.cpp:151
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::NodeStore::DeterministicShard::j_
const beast::Journal j_
Definition: DeterministicShard.h:133
ripple::NodeStore::DeterministicShard::ctx_
std::unique_ptr< nudb::context > ctx_
Definition: DeterministicShard.h:127
ripple::NodeStore::DeterministicShard::index_
const std::uint32_t index_
Definition: DeterministicShard.h:118
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:75
ripple::digest
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition: tokens.cpp:47
ripple::NodeStore::DeterministicShard
DeterministicShard class.
Definition: DeterministicShard.h:40
ripple::Config
Definition: Config.h:89
ripple::NodeStore::DeterministicShard::scheduler_
DummyScheduler scheduler_
Definition: DeterministicShard.h:124
ripple::NodeStore::DeterministicShard::curMemObjs_
std::uint32_t curMemObjs_
Definition: DeterministicShard.h:136
ripple::NodeStore::DeterministicShard::app_
Application & app_
Definition: DeterministicShard.h:115
ripple::Application::config
virtual Config & config()=0
std::array
STL class.
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::Serializer
Definition: Serializer.h:39
ripple::NodeStore::Manager::find
virtual Factory * find(std::string const &name)=0
Return a pointer to the matching factory if it exists.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:69
ripple::NodeObject::keyBytes
static constexpr std::size_t keyBytes
Definition: NodeObject.h:52
ripple::NodeStore::DeterministicShard::dir_
const boost::filesystem::path dir_
Definition: DeterministicShard.h:121
std
STL namespace.
ripple::base_uint::fromVoid
static base_uint fromVoid(void const *data)
Definition: base_uint.h:312
ripple::NodeStore::DeterministicShard::close
void close()
Finalizes and closes the shard.
Definition: DeterministicShard.h:84
ripple::NodeStore::DeterministicShard::maxMemObjs_
const std::uint32_t maxMemObjs_
Definition: DeterministicShard.h:139
ripple::openssl_ripemd160_hasher
Message digest functions used in the codebase.
Definition: digest.h:46
ripple::NodeStore::Manager::instance
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:120
ripple::getShardStore
static NodeStore::Database & getShardStore(Application &app)
Definition: ShardFamily.cpp:30
std::exception::what
T what(T... args)
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118