rippled
ShardArchiveHandler.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 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/misc/NetworkOPs.h>
21 #include <ripple/app/rdb/ShardArchive.h>
22 #include <ripple/basics/Archive.h>
23 #include <ripple/basics/BasicConfig.h>
24 #include <ripple/core/ConfigSections.h>
25 #include <ripple/nodestore/DatabaseShard.h>
26 #include <ripple/rpc/ShardArchiveHandler.h>
27 #include <ripple/rpc/impl/Handler.h>
28 
29 #include <memory>
30 
31 namespace ripple {
32 namespace RPC {
33 
34 using namespace boost::filesystem;
35 using namespace std::chrono_literals;
36 
37 boost::filesystem::path
39 {
40  return boost::filesystem::path{
42  "download_path",
44  "path",
45  ""))} /
46  "download";
47 }
48 
51 {
52  return std::make_unique<ShardArchiveHandler>(app);
53 }
54 
57 {
58  auto const downloadDir(getDownloadDirectory(app.config()));
59 
60  // Create the handler iff the database
61  // is present.
62  if (exists(downloadDir / stateDBName) &&
63  is_regular_file(downloadDir / stateDBName))
64  {
65  return std::make_unique<RecoveryHandler>(app);
66  }
67 
68  return nullptr;
69 }
70 
72  : process_(false)
73  , app_(app)
74  , j_(app.journal("ShardArchiveHandler"))
75  , downloadDir_(getDownloadDirectory(app.config()))
76  , timer_(app_.getIOService())
77  , verificationScheduler_(
78  std::chrono::seconds(get<std::uint32_t>(
79  app.config().section(ConfigSection::shardDatabase()),
80  "shard_verification_retry_interval")),
81 
82  get<std::uint32_t>(
83  app.config().section(ConfigSection::shardDatabase()),
84  "shard_verification_max_attempts"))
85 {
86  assert(app_.getShardStore());
87 }
88 
89 bool
91 {
92  std::lock_guard lock(m_);
93 
94  if (process_ || downloader_ != nullptr || sqlDB_ != nullptr)
95  {
96  JLOG(j_.warn()) << "Archives already being processed";
97  return false;
98  }
99 
100  // Initialize from pre-existing database
101  if (exists(downloadDir_ / stateDBName) &&
102  is_regular_file(downloadDir_ / stateDBName))
103  {
104  downloader_ =
106 
107  return initFromDB(lock);
108  }
109 
110  // Fresh initialization
111  else
112  {
113  try
114  {
115  create_directories(downloadDir_);
116 
118  }
119  catch (std::exception const& e)
120  {
121  JLOG(j_.error())
122  << "exception: " << e.what() << " in function: " << __func__;
123 
124  return false;
125  }
126  }
127 
128  return true;
129 }
130 
131 bool
133 {
134  try
135  {
136  using namespace boost::filesystem;
137 
138  assert(
139  exists(downloadDir_ / stateDBName) &&
140  is_regular_file(downloadDir_ / stateDBName));
141 
143 
144  readArchiveDB(*sqlDB_, [&](std::string const& url_, int state) {
145  parsedURL url;
146 
147  if (!parseUrl(url, url_))
148  {
149  JLOG(j_.error()) << "Failed to parse url: " << url_;
150 
151  return;
152  }
153 
154  add(state, std::move(url), lock);
155  });
156 
157  // Failed to load anything
158  // from the state database.
159  if (archives_.empty())
160  {
161  release();
162  return false;
163  }
164  }
165  catch (std::exception const& e)
166  {
167  JLOG(j_.error()) << "exception: " << e.what()
168  << " in function: " << __func__;
169 
170  return false;
171  }
172 
173  return true;
174 }
175 
176 void
178 {
179  stopping_ = true;
180  {
182 
183  if (downloader_)
184  {
185  downloader_->stop();
186  downloader_.reset();
187  }
188 
189  timer_.cancel();
190  }
191 
193  "ShardArchiveHandler", std::chrono::milliseconds(2000), j_);
194 
196  "ShardArchiveHandler", std::chrono::milliseconds(2000), j_);
197 }
198 
199 bool
201  std::uint32_t shardIndex,
203 {
205 
206  if (!add(shardIndex, std::forward<parsedURL>(url.first), lock))
207  return false;
208 
209  insertArchiveDB(*sqlDB_, shardIndex, url.second);
210 
211  return true;
212 }
213 
214 bool
216  std::uint32_t shardIndex,
217  parsedURL&& url,
219 {
220  if (process_)
221  {
222  JLOG(j_.error()) << "Download and import already in progress";
223  return false;
224  }
225 
226  auto const it{archives_.find(shardIndex)};
227  if (it != archives_.end())
228  return url == it->second;
229 
230  archives_.emplace(shardIndex, std::move(url));
231 
232  return true;
233 }
234 
235 bool
237 {
238  std::lock_guard lock(m_);
239  if (!app_.getShardStore())
240  {
241  JLOG(j_.error()) << "No shard store available";
242  return false;
243  }
244  if (process_)
245  {
246  JLOG(j_.warn()) << "Archives already being processed";
247  return false;
248  }
249  if (archives_.empty())
250  {
251  JLOG(j_.warn()) << "No archives to process";
252  return false;
253  }
254 
255  std::vector<std::uint32_t> shardIndexes(archives_.size());
257  archives_.begin(),
258  archives_.end(),
259  shardIndexes.begin(),
260  [](auto const& entry) { return entry.first; });
261 
262  if (!app_.getShardStore()->prepareShards(shardIndexes))
263  return false;
264 
265  try
266  {
267  // Create temp root download directory
268  create_directories(downloadDir_);
269 
270  if (!downloader_)
271  {
272  // will throw if can't initialize ssl context
273  downloader_ =
275  }
276  }
277  catch (std::exception const& e)
278  {
279  JLOG(j_.error()) << "exception: " << e.what();
280  return false;
281  }
282 
283  process_ = true;
284  return next(lock);
285 }
286 
287 void
289 {
291  doRelease(lock);
292 }
293 
294 bool
296 {
297  if (stopping_)
298  return false;
299 
300  if (archives_.empty())
301  {
302  doRelease(l);
303  return false;
304  }
305 
306  auto const shardIndex{archives_.begin()->first};
307 
308  // We use the sequence of the last validated ledger
309  // to determine whether or not we have stored a ledger
310  // that comes after the last ledger in this shard. A
311  // later ledger must be present in order to reliably
312  // retrieve the hash of the shard's last ledger.
313  std::optional<uint256> expectedHash;
314  bool shouldHaveHash = false;
315  if (auto const seq = app_.getShardStore()->lastLedgerSeq(shardIndex);
316  (shouldHaveHash = app_.getLedgerMaster().getValidLedgerIndex() > seq))
317  {
318  expectedHash = app_.getLedgerMaster().walkHashBySeq(
320  }
321 
322  if (!expectedHash)
323  {
324  auto wrapper =
325  timerCounter_.wrap([this](boost::system::error_code const& ec) {
326  if (ec != boost::asio::error::operation_aborted)
327  {
328  std::lock_guard lock(m_);
329  this->next(lock);
330  }
331  });
332 
333  if (!wrapper)
334  return onClosureFailed(
335  "failed to wrap closure for last ledger confirmation timer", l);
336 
337  if (!verificationScheduler_.retry(app_, shouldHaveHash, *wrapper))
338  {
339  JLOG(j_.error()) << "failed to find last ledger hash for shard "
340  << shardIndex << ", maximum attempts reached";
341 
342  return removeAndProceed(l);
343  }
344 
345  return true;
346  }
347 
348  // Create a temp archive directory at the root
349  auto const dstDir{downloadDir_ / std::to_string(shardIndex)};
350  try
351  {
352  create_directory(dstDir);
353  }
354  catch (std::exception const& e)
355  {
356  JLOG(j_.error()) << "exception: " << e.what();
357  return removeAndProceed(l);
358  }
359 
360  // Download the archive. Process in another thread
361  // to prevent holding up the lock if the downloader
362  // sleeps.
363  auto const& url{archives_.begin()->second};
364  auto wrapper = jobCounter_.wrap([this, url, dstDir]() {
365  auto const ssl = (url.scheme == "https");
366  auto const defaultPort = ssl ? 443 : 80;
367 
368  if (!downloader_->download(
369  url.domain,
370  std::to_string(url.port.value_or(defaultPort)),
371  url.path,
372  11,
373  dstDir / "archive.tar.lz4",
374  [this](path dstPath) { complete(dstPath); },
375  ssl))
376  {
378  removeAndProceed(l);
379  }
380  });
381 
382  if (!wrapper)
383  return onClosureFailed(
384  "failed to wrap closure for starting download", l);
385 
386  app_.getJobQueue().addJob(jtCLIENT_SHARD, "ShardArchiveHandler", *wrapper);
387 
388  return true;
389 }
390 
391 void
393 {
394  if (stopping_)
395  return;
396 
397  {
398  std::lock_guard lock(m_);
399  try
400  {
401  if (!is_regular_file(dstPath))
402  {
403  auto ar{archives_.begin()};
404  JLOG(j_.error())
405  << "Downloading shard id " << ar->first << " from URL "
406  << ar->second.domain << ar->second.path;
407  removeAndProceed(lock);
408  return;
409  }
410  }
411  catch (std::exception const& e)
412  {
413  JLOG(j_.error()) << "exception: " << e.what();
414  removeAndProceed(lock);
415  return;
416  }
417  }
418 
419  // Make lambdas mutable captured vars can be moved from
420  auto wrapper =
421  jobCounter_.wrap([=, this, dstPath = std::move(dstPath)]() mutable {
422  if (stopping_)
423  return;
424 
425  // If not synced then defer and retry
426  auto const mode{app_.getOPs().getOperatingMode()};
427  if (mode != OperatingMode::FULL)
428  {
429  std::lock_guard lock(m_);
430  timer_.expires_from_now(static_cast<std::chrono::seconds>(
431  (static_cast<std::size_t>(OperatingMode::FULL) -
432  static_cast<std::size_t>(mode)) *
433  10));
434 
435  auto wrapper = timerCounter_.wrap(
436  [=, this, dstPath = std::move(dstPath)](
437  boost::system::error_code const& ec) mutable {
438  if (ec != boost::asio::error::operation_aborted)
439  complete(std::move(dstPath));
440  });
441 
442  if (!wrapper)
444  "failed to wrap closure for operating mode timer",
445  lock);
446  else
447  timer_.async_wait(*wrapper);
448  }
449  else
450  {
451  process(dstPath);
452  std::lock_guard lock(m_);
453  removeAndProceed(lock);
454  }
455  });
456 
457  if (!wrapper)
458  {
459  if (stopping_)
460  return;
461 
462  JLOG(j_.error()) << "failed to wrap closure for process()";
463 
464  std::lock_guard lock(m_);
465  removeAndProceed(lock);
466  }
467 
468  // Process in another thread to not hold up the IO service
469  app_.getJobQueue().addJob(jtCLIENT_SHARD, "ShardArchiveHandler", *wrapper);
470 }
471 
472 void
473 ShardArchiveHandler::process(path const& dstPath)
474 {
475  std::uint32_t shardIndex;
476  {
477  std::lock_guard lock(m_);
478  shardIndex = archives_.begin()->first;
479  }
480 
481  auto const shardDir{dstPath.parent_path() / std::to_string(shardIndex)};
482  try
483  {
484  // Extract the downloaded archive
485  extractTarLz4(dstPath, dstPath.parent_path());
486 
487  // The extracted root directory name must match the shard index
488  if (!is_directory(shardDir))
489  {
490  JLOG(j_.error()) << "Shard " << shardIndex
491  << " mismatches archive shard directory";
492  return;
493  }
494  }
495  catch (std::exception const& e)
496  {
497  JLOG(j_.error()) << "exception: " << e.what();
498  return;
499  }
500 
501  // Import the shard into the shard store
502  if (!app_.getShardStore()->importShard(shardIndex, shardDir))
503  {
504  JLOG(j_.error()) << "Importing shard " << shardIndex;
505  return;
506  }
507 
508  JLOG(j_.debug()) << "Shard " << shardIndex << " downloaded and imported";
509 }
510 
511 void
513 {
515 
516  auto const shardIndex{archives_.begin()->first};
517  app_.getShardStore()->removePreShard(shardIndex);
518  archives_.erase(shardIndex);
519 
520  deleteFromArchiveDB(*sqlDB_, shardIndex);
521 
522  auto const dstDir{downloadDir_ / std::to_string(shardIndex)};
523  try
524  {
525  remove_all(dstDir);
526  }
527  catch (std::exception const& e)
528  {
529  JLOG(j_.error()) << "exception: " << e.what();
530  }
531 }
532 
533 void
535 {
536  timer_.cancel();
537  for (auto const& ar : archives_)
538  app_.getShardStore()->removePreShard(ar.first);
539  archives_.clear();
540 
542 
543  sqlDB_.reset();
544 
545  // Remove temp root download directory
546  try
547  {
548  remove_all(downloadDir_);
549  }
550  catch (std::exception const& e)
551  {
552  JLOG(j_.error()) << "exception: " << e.what()
553  << " in function: " << __func__;
554  }
555 
556  downloader_.reset();
557  process_ = false;
558 }
559 
560 bool
562  std::string const& errorMsg,
563  std::lock_guard<std::mutex> const& lock)
564 {
565  if (stopping_)
566  return false;
567 
568  JLOG(j_.error()) << errorMsg;
569 
570  return removeAndProceed(lock);
571 }
572 
573 bool
575 {
576  remove(lock);
577  return next(lock);
578 }
579 
581 {
582 }
583 
584 } // namespace RPC
585 } // namespace ripple
ripple::NodeStore::Database::lastLedgerSeq
std::uint32_t lastLedgerSeq(std::uint32_t shardIndex) const noexcept
Calculates the last ledger sequence for a given shard index.
Definition: Database.h:271
ripple::Application
Definition: Application.h:115
ripple::RPC::ShardArchiveHandler::getDownloadDirectory
static boost::filesystem::path getDownloadDirectory(Config const &config)
Definition: ShardArchiveHandler.cpp:38
ripple::RPC::ShardArchiveHandler::downloader_
std::shared_ptr< DatabaseDownloader > downloader_
Definition: ShardArchiveHandler.h:139
ripple::RPC::ShardArchiveHandler::downloadDir_
const boost::filesystem::path downloadDir_
Definition: ShardArchiveHandler.h:147
ripple::RPC::ShardArchiveHandler::remove
void remove(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:512
ripple::RPC::ShardArchiveHandler::timerCounter_
TimerOpCounter timerCounter_
Definition: ShardArchiveHandler.h:150
ripple::RPC::ShardArchiveHandler::verificationScheduler_
ShardVerificationScheduler verificationScheduler_
Definition: ShardArchiveHandler.h:151
ripple::RPC::ShardArchiveHandler::stop
void stop()
Definition: ShardArchiveHandler.cpp:177
ripple::RPC::ShardArchiveHandler::makeShardArchiveHandler
static std::unique_ptr< ShardArchiveHandler > makeShardArchiveHandler(Application &app)
Definition: ShardArchiveHandler.cpp:50
std::string
STL class.
ripple::RPC::ShardArchiveHandler::removeAndProceed
bool removeAndProceed(std::lock_guard< std::mutex > const &lock)
Definition: ShardArchiveHandler.cpp:574
ripple::RPC::ShardArchiveHandler::start
bool start()
Starts downloading and importing archives.
Definition: ShardArchiveHandler.cpp:236
std::exception
STL class.
ripple::RPC::ShardArchiveHandler::add
bool add(std::uint32_t shardIndex, std::pair< parsedURL, std::string > &&url)
Definition: ShardArchiveHandler.cpp:200
ripple::parsedURL
Definition: StringUtilities.h:116
std::pair
ripple::RPC::ShardVerificationScheduler::reset
void reset()
Definition: ShardVerificationScheduler.cpp:62
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:213
ripple::InboundLedger::Reason::GENERIC
@ GENERIC
std::vector
STL class.
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
std::chrono::milliseconds
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::RPC::ShardArchiveHandler::doRelease
void doRelease(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:534
std::lock_guard
STL class.
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::RPC::RecoveryHandler::RecoveryHandler
RecoveryHandler(Application &app)
Definition: ShardArchiveHandler.cpp:580
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::RPC::ShardArchiveHandler::initFromDB
bool initFromDB(std::lock_guard< std::mutex > const &)
Definition: ShardArchiveHandler.cpp:132
ripple::RPC::ShardArchiveHandler::onClosureFailed
bool onClosureFailed(std::string const &errorMsg, std::lock_guard< std::mutex > const &lock)
Definition: ShardArchiveHandler.cpp:561
ripple::extractTarLz4
void extractTarLz4(boost::filesystem::path const &src, boost::filesystem::path const &dst)
Extract a tar archive compressed with lz4.
Definition: Archive.cpp:31
ripple::LedgerMaster::walkHashBySeq
std::optional< LedgerHash > walkHashBySeq(std::uint32_t index, InboundLedger::Reason reason)
Walk to a ledger's hash using the skip list.
Definition: LedgerMaster.cpp:1754
ripple::RPC::ShardArchiveHandler::stopping_
std::atomic_bool stopping_
Definition: ShardArchiveHandler.h:138
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::RPC::ShardArchiveHandler::timer_
boost::asio::basic_waitable_timer< std::chrono::steady_clock > timer_
Definition: ShardArchiveHandler.h:148
ripple::RPC::ShardArchiveHandler::release
void release()
Definition: ShardArchiveHandler.cpp:288
ripple::RPC::ShardArchiveHandler::process
void process(boost::filesystem::path const &dstPath)
Definition: ShardArchiveHandler.cpp:473
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Config
Definition: Config.h:89
ripple::deleteFromArchiveDB
void deleteFromArchiveDB(DatabaseCon &db, std::uint32_t shardIndex)
deleteFromArchiveDB Deletes an entry from the shard archive database.
Definition: ShardArchive.cpp:56
ripple::Application::config
virtual Config & config()=0
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::dropArchiveDB
void dropArchiveDB(DatabaseCon &db)
dropArchiveDB Removes a table in the shard archive database.
Definition: ShardArchive.cpp:63
ripple::parseUrl
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
Definition: StringUtilities.cpp:47
beast::Journal::error
Stream error() const
Definition: Journal.h:333
ripple::ConfigSection
Definition: ConfigSections.h:28
ripple::RPC::ShardArchiveHandler::complete
void complete(boost::filesystem::path dstPath)
Definition: ShardArchiveHandler.cpp:392
std::uint32_t
ripple::RPC::ShardVerificationScheduler::retry
bool retry(Application &app, bool shouldHaveHash, retryFunction f)
Definition: ShardVerificationScheduler.cpp:37
ripple::NodeStore::DatabaseShard::prepareShards
virtual bool prepareShards(std::vector< std::uint32_t > const &shardIndexes)=0
Prepare one or more shard indexes to be imported into the database.
std::transform
T transform(T... args)
ripple::RPC::ShardArchiveHandler::j_
const beast::Journal j_
Definition: ShardArchiveHandler.h:146
memory
ripple::Application::getIOService
virtual boost::asio::io_service & getIOService()=0
ripple::stateDBName
static constexpr auto stateDBName
Definition: DBInit.h:252
ripple::NodeStore::DatabaseShard::importShard
virtual bool importShard(std::uint32_t shardIndex, boost::filesystem::path const &srcDir)=0
Import a shard from the shard archive handler into the shard database.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::ShardArchiveHandler::next
bool next(std::lock_guard< std::mutex > const &l)
Definition: ShardArchiveHandler.cpp:295
ripple::readArchiveDB
void readArchiveDB(DatabaseCon &db, std::function< void(std::string const &, int)> const &func)
readArchiveDB Reads entries from the shard archive database and invokes the given callback for each e...
Definition: ShardArchive.cpp:32
ripple::RPC::ShardArchiveHandler::tryMakeRecoveryHandler
static std::unique_ptr< ShardArchiveHandler > tryMakeRecoveryHandler(Application &app)
Definition: ShardArchiveHandler.cpp:56
ripple::RPC::ShardArchiveHandler::archives_
std::map< std::uint32_t, parsedURL > archives_
Definition: ShardArchiveHandler.h:140
std::vector::begin
T begin(T... args)
std
STL namespace.
ripple::RPC::ShardArchiveHandler::app_
Application & app_
Definition: ShardArchiveHandler.h:145
ripple::RPC::ShardArchiveHandler
Handles the download and import of one or more shard archives.
Definition: ShardArchiveHandler.h:42
ripple::RPC::ShardArchiveHandler::ShardArchiveHandler
ShardArchiveHandler()=delete
ripple::ClosureCounter::join
void join(char const *name, std::chrono::milliseconds wait, beast::Journal j)
Returns once all counted in-flight closures are destroyed.
Definition: ClosureCounter.h:166
std::optional
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::insertArchiveDB
void insertArchiveDB(DatabaseCon &db, std::uint32_t shardIndex, std::string const &url)
insertArchiveDB Adds an entry to the shard archive database.
Definition: ShardArchive.cpp:46
ripple::RPC::ShardArchiveHandler::m_
std::mutex m_
Definition: ShardArchiveHandler.h:137
ripple::RPC::ShardArchiveHandler::jobCounter_
JobCounter jobCounter_
Definition: ShardArchiveHandler.h:149
ripple::makeArchiveDB
std::unique_ptr< DatabaseCon > makeArchiveDB(boost::filesystem::path const &dir, std::string const &dbName)
makeArchiveDB Opens the shard archive database and returns its descriptor.
Definition: ShardArchive.cpp:25
ripple::NodeStore::DatabaseShard::removePreShard
virtual void removePreShard(std::uint32_t shardIndex)=0
Remove a previously prepared shard index for import.
std::unique_ptr
STL class.
ripple::RPC::ShardArchiveHandler::process_
bool process_
Definition: ShardArchiveHandler.h:141
ripple::RPC::ShardArchiveHandler::init
bool init()
Definition: ShardArchiveHandler.cpp:90
ripple::make_DatabaseDownloader
std::shared_ptr< DatabaseDownloader > make_DatabaseDownloader(boost::asio::io_service &io_service, Config const &config, beast::Journal j)
Definition: DatabaseDownloader.cpp:25
ripple::jtCLIENT_SHARD
@ jtCLIENT_SHARD
Definition: Job.h:50
ripple::RPC::ShardArchiveHandler::sqlDB_
std::unique_ptr< DatabaseCon > sqlDB_
Definition: ShardArchiveHandler.h:142
std::exception::what
T what(T... args)
ripple::get
T & get(EitherAmount &amt)
Definition: AmountSpec.h:118
ripple::BasicConfig::section
Section & section(std::string const &name)
Returns the section with the given name.
Definition: BasicConfig.cpp:127
ripple::ClosureCounter::wrap
std::optional< Substitute< Closure > > wrap(Closure &&closure)
Wrap the passed closure with a reference counter.
Definition: ClosureCounter.h:192
ripple::OperatingMode::FULL
@ FULL
we have the ledger and can even validate