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