rippled
DatabaseShard_test.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/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/LedgerToJson.h>
22 #include <ripple/beast/utility/temp_dir.h>
23 #include <ripple/core/ConfigSections.h>
24 #include <ripple/nodestore/DatabaseShard.h>
25 #include <ripple/nodestore/DummyScheduler.h>
26 #include <ripple/nodestore/Manager.h>
27 #include <ripple/nodestore/impl/DecodedBlob.h>
28 #include <ripple/nodestore/impl/EncodedBlob.h>
29 #include <ripple/nodestore/impl/Shard.h>
30 #include <chrono>
31 #include <test/jtx.h>
32 #include <test/nodestore/TestBase.h>
33 
34 namespace ripple {
35 namespace NodeStore {
36 
37 // Tests DatabaseShard class
38 //
40 {
41  static constexpr std::uint32_t maxSizeGb = 10;
42  static constexpr std::uint32_t ledgersPerShard = 256;
43  static constexpr std::uint32_t earliestSeq = ledgersPerShard + 1;
44  static constexpr std::uint32_t dataSizeMax = 4;
45  static constexpr std::uint32_t iniAmount = 1000000;
46  static constexpr std::uint32_t nTestShards = 4;
51 
52  struct TestData
53  {
54  /* ring used to generate pseudo-random sequence */
56  /* number of shards to generate */
57  int nShards_;
58  /* vector of accounts used to send test transactions */
60  /* nAccounts_[i] is the number of these accounts existed before i-th
61  * ledger */
63  /* payAccounts_[i][j] = {from, to} is the pair which consists of two
64  * number of acoounts: source and destinations, which participate in
65  * j-th payment on i-th ledger */
67  /* xrpAmount_[i] is the amount for all payments on i-th ledger */
69  /* ledgers_[i] is the i-th ledger which contains the above described
70  * accounts and payments */
72 
74  std::uint64_t const seedValue,
75  int dataSize = dataSizeMax,
76  int nShards = 1)
77  : rng_(seedValue), nShards_(nShards)
78  {
79  std::uint32_t n = 0;
80  std::uint32_t nLedgers = ledgersPerShard * nShards;
81 
82  nAccounts_.reserve(nLedgers);
83  payAccounts_.reserve(nLedgers);
84  xrpAmount_.reserve(nLedgers);
85 
86  for (std::uint32_t i = 0; i < nLedgers; ++i)
87  {
88  int p;
89  if (n >= 2)
90  p = rand_int(rng_, 2 * dataSize);
91  else
92  p = 0;
93 
95  pay.reserve(p);
96 
97  for (int j = 0; j < p; ++j)
98  {
99  int from, to;
100  do
101  {
102  from = rand_int(rng_, n - 1);
103  to = rand_int(rng_, n - 1);
104  } while (from == to);
105 
106  pay.push_back(std::make_pair(from, to));
107  }
108 
109  n += !rand_int(rng_, nLedgers / dataSize);
110 
111  if (n > accounts_.size())
112  {
113  char str[9];
114  for (int j = 0; j < 8; ++j)
115  str[j] = 'a' + rand_int(rng_, 'z' - 'a');
116  str[8] = 0;
117  accounts_.emplace_back(str);
118  }
119 
121  payAccounts_.push_back(std::move(pay));
122  xrpAmount_.push_back(rand_int(rng_, 90) + 10);
123  }
124  }
125 
126  bool
127  isNewAccounts(int seq)
128  {
129  return nAccounts_[seq] > (seq ? nAccounts_[seq - 1] : 0);
130  }
131 
132  void
134  {
135  using namespace test::jtx;
136 
137  if (isNewAccounts(seq))
138  env_.fund(XRP(iniAmount), accounts_[nAccounts_[seq] - 1]);
139 
140  for (std::uint32_t i = 0; i < payAccounts_[seq].size(); ++i)
141  {
142  env_(
143  pay(accounts_[payAccounts_[seq][i].first],
144  accounts_[payAccounts_[seq][i].second],
145  XRP(xrpAmount_[seq])));
146  }
147  }
148 
149  bool
151  {
152  for (std::uint32_t i = 3; i <= ledgersPerShard; ++i)
153  {
154  if (!env_.close())
155  return false;
158  if (ledger->info().seq != i)
159  return false;
160  }
161 
162  for (std::uint32_t i = 0; i < ledgersPerShard * nShards_; ++i)
163  {
164  makeLedgerData(env_, i);
165  if (!env_.close())
166  return false;
169  if (ledger->info().seq != i + ledgersPerShard + 1)
170  return false;
171  ledgers_.push_back(ledger);
172  }
173 
174  return true;
175  }
176  };
177 
178  void
180  TestData& data,
182  std::uint32_t seq)
183  {
184  using namespace test::jtx;
185 
186  auto rootCount{0};
187  auto accCount{0};
188  auto sothCount{0};
189  for (auto const& sles : ledger->sles)
190  {
191  if (sles->getType() == ltACCOUNT_ROOT)
192  {
193  int sq = sles->getFieldU32(sfSequence);
194  int reqsq = -1;
195  const auto id = sles->getAccountID(sfAccount);
196 
197  for (int i = 0; i < data.accounts_.size(); ++i)
198  {
199  if (id == data.accounts_[i].id())
200  {
201  reqsq = ledgersPerShard + 1;
202  for (int j = 0; j <= seq; ++j)
203  if (data.nAccounts_[j] > i + 1 ||
204  (data.nAccounts_[j] == i + 1 &&
205  !data.isNewAccounts(j)))
206  {
207  for (int k = 0; k < data.payAccounts_[j].size();
208  ++k)
209  if (data.payAccounts_[j][k].first == i)
210  reqsq++;
211  }
212  else
213  reqsq++;
214  ++accCount;
215  break;
216  }
217  }
218  if (reqsq == -1)
219  {
220  reqsq = data.nAccounts_[seq] + 1;
221  ++rootCount;
222  }
223  BEAST_EXPECT(sq == reqsq);
224  }
225  else
226  ++sothCount;
227  }
228  BEAST_EXPECT(rootCount == 1);
229  BEAST_EXPECT(accCount == data.nAccounts_[seq]);
230  BEAST_EXPECT(sothCount == 3);
231 
232  auto iniCount{0};
233  auto setCount{0};
234  auto payCount{0};
235  auto tothCount{0};
236  for (auto const& tx : ledger->txs)
237  {
238  if (tx.first->getTxnType() == ttPAYMENT)
239  {
240  std::int64_t xrpAmount =
241  tx.first->getFieldAmount(sfAmount).xrp().decimalXRP();
242  if (xrpAmount == iniAmount)
243  ++iniCount;
244  else
245  {
246  ++payCount;
247  BEAST_EXPECT(xrpAmount == data.xrpAmount_[seq]);
248  }
249  }
250  else if (tx.first->getTxnType() == ttACCOUNT_SET)
251  ++setCount;
252  else
253  ++tothCount;
254  }
255  int newacc = data.isNewAccounts(seq) ? 1 : 0;
256  BEAST_EXPECT(iniCount == newacc);
257  BEAST_EXPECT(setCount == newacc);
258  BEAST_EXPECT(payCount == data.payAccounts_[seq].size());
259  BEAST_EXPECT(tothCount == !seq);
260  }
261 
262  bool
264  Database& db,
265  Ledger const& ledger,
266  std::shared_ptr<Ledger const> const& next = {})
267  {
268  // Store header
269  {
270  Serializer s(128);
271  s.add32(HashPrefix::ledgerMaster);
272  addRaw(ledger.info(), s);
273  db.store(
274  hotLEDGER,
275  std::move(s.modData()),
276  ledger.info().hash,
277  ledger.info().seq);
278  }
279 
280  // Store the state map
281  auto visitAcc = [&](SHAMapAbstractNode& node) {
282  Serializer s;
283  node.addRaw(s, snfPREFIX);
284  db.store(
285  node.getType() == SHAMapAbstractNode::TNType::tnINNER
286  ? hotUNKNOWN
287  : hotACCOUNT_NODE,
288  std::move(s.modData()),
289  node.getNodeHash().as_uint256(),
290  ledger.info().seq);
291  return true;
292  };
293 
294  if (ledger.stateMap().getHash().isNonZero())
295  {
296  if (!ledger.stateMap().isValid())
297  return false;
298  if (next && next->info().parentHash == ledger.info().hash)
299  {
300  auto have = next->stateMap().snapShot(false);
301  ledger.stateMap().snapShot(false)->visitDifferences(
302  &(*have), visitAcc);
303  }
304  else
305  ledger.stateMap().snapShot(false)->visitNodes(visitAcc);
306  }
307 
308  // Store the transaction map
309  auto visitTx = [&](SHAMapAbstractNode& node) {
310  Serializer s;
311  node.addRaw(s, snfPREFIX);
312  db.store(
313  node.getType() == SHAMapAbstractNode::TNType::tnINNER
314  ? hotUNKNOWN
316  std::move(s.modData()),
317  node.getNodeHash().as_uint256(),
318  ledger.info().seq);
319  return true;
320  };
321 
322  if (ledger.info().txHash.isNonZero())
323  {
324  if (!ledger.txMap().isValid())
325  return false;
326  ledger.txMap().snapShot(false)->visitNodes(visitTx);
327  }
328 
329  return true;
330  }
331 
332  void
333  checkLedger(TestData& data, DatabaseShard& db, Ledger const& ledger)
334  {
335  auto fetched = db.fetchLedger(ledger.info().hash, ledger.info().seq);
336  if (!BEAST_EXPECT(fetched))
337  return;
338 
339  testLedgerData(data, fetched, ledger.info().seq - ledgersPerShard - 1);
340 
341  // verify the metadata/header info by serializing to json
342  BEAST_EXPECT(
343  getJson(
345  getJson(
347 
348  BEAST_EXPECT(
349  getJson(
351  getJson(
353 
354  // walk shamap and validate each node
355  auto fcompAcc = [&](SHAMapAbstractNode& node) -> bool {
356  Serializer s;
357  node.addRaw(s, snfPREFIX);
358  auto nSrc{NodeObject::createObject(
359  node.getType() == SHAMapAbstractNode::TNType::tnINNER
360  ? hotUNKNOWN
361  : hotACCOUNT_NODE,
362  std::move(s.modData()),
363  node.getNodeHash().as_uint256())};
364  if (!BEAST_EXPECT(nSrc))
365  return false;
366 
367  auto nDst =
368  db.fetch(node.getNodeHash().as_uint256(), ledger.info().seq);
369  if (!BEAST_EXPECT(nDst))
370  return false;
371 
372  BEAST_EXPECT(isSame(nSrc, nDst));
373 
374  return true;
375  };
376  if (ledger.stateMap().getHash().isNonZero())
377  ledger.stateMap().snapShot(false)->visitNodes(fcompAcc);
378 
379  auto fcompTx = [&](SHAMapAbstractNode& node) -> bool {
380  Serializer s;
381  node.addRaw(s, snfPREFIX);
382  auto nSrc{NodeObject::createObject(
383  node.getType() == SHAMapAbstractNode::TNType::tnINNER
384  ? hotUNKNOWN
386  std::move(s.modData()),
387  node.getNodeHash().as_uint256())};
388  if (!BEAST_EXPECT(nSrc))
389  return false;
390 
391  auto nDst =
392  db.fetch(node.getNodeHash().as_uint256(), ledger.info().seq);
393  if (!BEAST_EXPECT(nDst))
394  return false;
395 
396  BEAST_EXPECT(isSame(nSrc, nDst));
397 
398  return true;
399  };
400  if (ledger.info().txHash.isNonZero())
401  ledger.txMap().snapShot(false)->visitNodes(fcompTx);
402  }
403 
406  {
408  if (!bitmask)
409  return set;
410  bool empty = true;
411 
412  for (std::uint32_t i = 0; i < 64 && bitmask; i++)
413  {
414  if (bitmask & (1ll << i))
415  {
416  if (!empty)
417  set += ",";
418  set += std::to_string(i);
419  empty = false;
420  }
421  }
422 
424  from_string(rs, set);
425  return to_string(rs);
426  }
427 
430  std::string const& testName,
431  std::string const& backendType,
432  std::string const& shardDir,
433  std::string const& nodeDir = std::string())
434  {
435  using namespace test::jtx;
436 
437  if (testName != "")
438  {
439  std::string caseName =
440  "DatabaseShard " + testName + " with backend " + backendType;
441  testcase(caseName);
442  }
443 
444  return envconfig([&](std::unique_ptr<Config> cfg) {
445  cfg->overwrite(ConfigSection::shardDatabase(), "type", backendType);
446  cfg->overwrite(ConfigSection::shardDatabase(), "path", shardDir);
447  cfg->overwrite(
449  "max_size_gb",
451  cfg->overwrite(
453  "ledgers_per_shard",
455  cfg->overwrite(
457  "earliest_seq",
459  cfg->overwrite(ConfigSection::nodeDatabase(), "type", backendType);
460  cfg->overwrite(
462  "max_size_gb",
464  cfg->overwrite(
466  "earliest_seq",
468  if (nodeDir.empty())
469  cfg->overwrite(
471  else
472  cfg->overwrite(ConfigSection::nodeDatabase(), "path", nodeDir);
473  return cfg;
474  });
475  }
476 
479  DatabaseShard& db,
480  int shardNumber,
482  {
484  auto start = std::chrono::system_clock::now();
485  auto end = start + timeout;
486  while (!from_string(rs, db.getCompleteShards()) ||
487  !boost::icl::contains(rs, shardNumber))
488  {
489  if (!BEAST_EXPECT(std::chrono::system_clock::now() < end))
490  return {};
492  }
493 
494  return shardNumber;
495  }
496 
498  createShard(TestData& data, DatabaseShard& db, int maxShardNumber)
499  {
500  int shardNumber = -1;
501 
502  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
503  {
504  auto ind = db.prepareLedger((maxShardNumber + 1) * ledgersPerShard);
505  if (!BEAST_EXPECT(ind != boost::none))
506  return {};
507  shardNumber = db.seqToShardIndex(*ind);
508  int arrInd = *ind - ledgersPerShard - 1;
509  BEAST_EXPECT(
510  arrInd >= 0 && arrInd < maxShardNumber * ledgersPerShard);
511  BEAST_EXPECT(saveLedger(db, *data.ledgers_[arrInd]));
512  if (arrInd % ledgersPerShard == (ledgersPerShard - 1))
513  {
514  uint256 const finalKey_{0};
515  Serializer s;
517  s.add32(db.firstLedgerSeq(shardNumber));
518  s.add32(db.lastLedgerSeq(shardNumber));
519  s.addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8);
520  db.store(hotUNKNOWN, std::move(s.modData()), finalKey_, *ind);
521  }
522  db.setStored(data.ledgers_[arrInd]);
523  }
524 
525  return waitShard(db, shardNumber);
526  }
527 
528  void
529  testStandalone(std::string const& backendType)
530  {
531  using namespace test::jtx;
532 
533  beast::temp_dir shardDir;
534  Env env{*this, testConfig("standalone", backendType, shardDir.path())};
535  DummyScheduler scheduler;
536  RootStoppable parent("TestRootStoppable");
537 
539  make_ShardStore(env.app(), parent, scheduler, 2, journal_);
540 
541  BEAST_EXPECT(db);
542  BEAST_EXPECT(db->ledgersPerShard() == db->ledgersPerShardDefault);
543  BEAST_EXPECT(db->init());
544  BEAST_EXPECT(db->ledgersPerShard() == ledgersPerShard);
545  BEAST_EXPECT(db->seqToShardIndex(ledgersPerShard + 1) == 1);
546  BEAST_EXPECT(db->seqToShardIndex(2 * ledgersPerShard) == 1);
547  BEAST_EXPECT(db->seqToShardIndex(2 * ledgersPerShard + 1) == 2);
548  BEAST_EXPECT(
549  db->earliestShardIndex() == (earliestSeq - 1) / ledgersPerShard);
550  BEAST_EXPECT(db->firstLedgerSeq(1) == ledgersPerShard + 1);
551  BEAST_EXPECT(db->lastLedgerSeq(1) == 2 * ledgersPerShard);
552  BEAST_EXPECT(db->getRootDir().string() == shardDir.path());
553  }
554 
555  void
557  std::string const& backendType,
558  std::uint64_t const seedValue)
559  {
560  using namespace test::jtx;
561 
562  beast::temp_dir shardDir;
563  Env env{*this, testConfig("createShard", backendType, shardDir.path())};
564  DatabaseShard* db = env.app().getShardStore();
565  BEAST_EXPECT(db);
566 
567  TestData data(seedValue);
568  if (!BEAST_EXPECT(data.makeLedgers(env)))
569  return;
570 
571  if (!createShard(data, *db, 1))
572  return;
573 
574  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
575  checkLedger(data, *db, *data.ledgers_[i]);
576  }
577 
578  void
580  std::string const& backendType,
581  std::uint64_t const seedValue)
582  {
583  using namespace test::jtx;
584 
585  beast::temp_dir shardDir;
586  {
587  Env env{
588  *this,
589  testConfig("reopenDatabase", backendType, shardDir.path())};
590  DatabaseShard* db = env.app().getShardStore();
591  BEAST_EXPECT(db);
592 
593  TestData data(seedValue, 4, 2);
594  if (!BEAST_EXPECT(data.makeLedgers(env)))
595  return;
596 
597  for (std::uint32_t i = 0; i < 2; ++i)
598  if (!createShard(data, *db, 2))
599  return;
600  }
601  {
602  Env env{*this, testConfig("", backendType, shardDir.path())};
603  DatabaseShard* db = env.app().getShardStore();
604  BEAST_EXPECT(db);
605 
606  TestData data(seedValue, 4, 2);
607  if (!BEAST_EXPECT(data.makeLedgers(env)))
608  return;
609 
610  for (std::uint32_t i = 1; i <= 2; ++i)
611  waitShard(*db, i);
612 
613  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
614  checkLedger(data, *db, *data.ledgers_[i]);
615  }
616  }
617 
618  void
620  std::string const& backendType,
621  std::uint64_t const seedValue)
622  {
623  using namespace test::jtx;
624 
625  beast::temp_dir shardDir;
626  Env env{
627  *this,
628  testConfig("getCompleteShards", backendType, shardDir.path())};
629  DatabaseShard* db = env.app().getShardStore();
630  BEAST_EXPECT(db);
631 
632  TestData data(seedValue, 2, nTestShards);
633  if (!BEAST_EXPECT(data.makeLedgers(env)))
634  return;
635 
636  BEAST_EXPECT(db->getCompleteShards() == "");
637 
638  std::uint64_t bitMask = 0;
639 
640  for (std::uint32_t i = 0; i < nTestShards; ++i)
641  {
642  auto n = createShard(data, *db, nTestShards);
643  if (!BEAST_EXPECT(n && *n >= 1 && *n <= nTestShards))
644  return;
645  bitMask |= 1ll << *n;
646  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(bitMask));
647  }
648  }
649 
650  void
652  std::string const& backendType,
653  std::uint64_t const seedValue)
654  {
655  using namespace test::jtx;
656 
657  beast::temp_dir shardDir;
658  Env env{
659  *this, testConfig("prepareShard", backendType, shardDir.path())};
660  DatabaseShard* db = env.app().getShardStore();
661  BEAST_EXPECT(db);
662 
663  TestData data(seedValue, 1, nTestShards);
664  if (!BEAST_EXPECT(data.makeLedgers(env)))
665  return;
666 
667  std::uint64_t bitMask = 0;
668  BEAST_EXPECT(db->getPreShards() == "");
669 
670  for (std::uint32_t i = 0; i < nTestShards * 2; ++i)
671  {
672  std::uint32_t n = rand_int(data.rng_, nTestShards - 1) + 1;
673  if (bitMask & (1ll << n))
674  {
675  db->removePreShard(n);
676  bitMask &= ~(1ll << n);
677  }
678  else
679  {
680  db->prepareShard(n);
681  bitMask |= 1ll << n;
682  }
683  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
684  }
685 
686  // test illegal cases
687  // adding shards with too large number
688  db->prepareShard(0);
689  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
690  db->prepareShard(nTestShards + 1);
691  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
692  db->prepareShard(nTestShards + 2);
693  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
694 
695  // create shards which are not prepared for import
696  BEAST_EXPECT(db->getCompleteShards() == "");
697 
698  std::uint64_t bitMask2 = 0;
699 
700  for (std::uint32_t i = 0; i < nTestShards; ++i)
701  {
702  auto n = createShard(data, *db, nTestShards);
703  if (!BEAST_EXPECT(n && *n >= 1 && *n <= nTestShards))
704  return;
705  bitMask2 |= 1ll << *n;
706  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
707  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(bitMask2));
708  BEAST_EXPECT((bitMask & bitMask2) == 0);
709  if ((bitMask | bitMask2) == ((1ll << nTestShards) - 1) << 1)
710  break;
711  }
712 
713  // try to create another shard
714  BEAST_EXPECT(
716  boost::none);
717  }
718 
719  void
721  std::string const& backendType,
722  std::uint64_t const seedValue)
723  {
724  using namespace test::jtx;
725 
726  beast::temp_dir importDir;
727  TestData data(seedValue, 2);
728 
729  {
730  Env env{
731  *this,
732  testConfig("importShard", backendType, importDir.path())};
733  DatabaseShard* db = env.app().getShardStore();
734  BEAST_EXPECT(db);
735 
736  if (!BEAST_EXPECT(data.makeLedgers(env)))
737  return;
738 
739  if (!createShard(data, *db, 1))
740  return;
741 
742  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
743  checkLedger(data, *db, *data.ledgers_[i]);
744 
745  data.ledgers_.clear();
746  }
747 
748  boost::filesystem::path importPath(importDir.path());
749  importPath /= "1";
750 
751  {
752  beast::temp_dir shardDir;
753  Env env{*this, testConfig("", backendType, shardDir.path())};
754  DatabaseShard* db = env.app().getShardStore();
755  BEAST_EXPECT(db);
756 
757  if (!BEAST_EXPECT(data.makeLedgers(env)))
758  return;
759 
760  db->prepareShard(1);
761  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(2));
762  if (!BEAST_EXPECT(db->importShard(1, importPath)))
763  return;
764  BEAST_EXPECT(db->getPreShards() == "");
765 
766  auto n = waitShard(*db, 1);
767  if (!BEAST_EXPECT(n && *n == 1))
768  return;
769 
770  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
771  checkLedger(data, *db, *data.ledgers_[i]);
772  }
773  }
774 
775  void
777  std::string const& backendType,
778  std::uint64_t const seedValue)
779  {
780  using namespace test::jtx;
781 
782  beast::temp_dir shardDir;
783  {
784  TestData data(seedValue, 4, 2);
785  {
786  Env env{
787  *this,
788  testConfig(
789  "corruptedDatabase", backendType, shardDir.path())};
790  DatabaseShard* db = env.app().getShardStore();
791  BEAST_EXPECT(db);
792 
793  if (!BEAST_EXPECT(data.makeLedgers(env)))
794  return;
795 
796  for (std::uint32_t i = 0; i < 2; ++i)
797  if (!BEAST_EXPECT(createShard(data, *db, 2)))
798  return;
799  }
800 
801  boost::filesystem::path path = shardDir.path();
802  path /= std::string("2");
803  path /= backendType + ".dat";
804 
805  FILE* f = fopen(path.string().c_str(), "r+b");
806  if (!BEAST_EXPECT(f))
807  return;
808  char buf[256];
809  beast::rngfill(buf, sizeof(buf), data.rng_);
810  BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256);
811  fclose(f);
812  }
813  {
814  Env env{*this, testConfig("", backendType, shardDir.path())};
815  DatabaseShard* db = env.app().getShardStore();
816  BEAST_EXPECT(db);
817 
818  TestData data(seedValue, 4, 2);
819  if (!BEAST_EXPECT(data.makeLedgers(env)))
820  return;
821 
822  for (std::uint32_t i = 1; i <= 1; ++i)
823  waitShard(*db, i);
824 
825  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x2));
826 
827  for (std::uint32_t i = 0; i < 1 * ledgersPerShard; ++i)
828  checkLedger(data, *db, *data.ledgers_[i]);
829  }
830  }
831 
832  void
834  std::string const& backendType,
835  std::uint64_t const seedValue)
836  {
837  using namespace test::jtx;
838 
839  for (int i = 0; i < 5; ++i)
840  {
841  beast::temp_dir shardDir;
842  {
843  Env env{
844  *this,
845  testConfig(
846  (i == 0 ? "illegalFinalKey" : ""),
847  backendType,
848  shardDir.path())};
849  DatabaseShard* db = env.app().getShardStore();
850  BEAST_EXPECT(db);
851 
852  TestData data(seedValue + i, 2);
853  if (!BEAST_EXPECT(data.makeLedgers(env)))
854  return;
855 
856  int shardNumber = -1;
857  for (std::uint32_t j = 0; j < ledgersPerShard; ++j)
858  {
859  auto ind = db->prepareLedger(2 * ledgersPerShard);
860  if (!BEAST_EXPECT(ind != boost::none))
861  return;
862  shardNumber = db->seqToShardIndex(*ind);
863  int arrInd = *ind - ledgersPerShard - 1;
864  BEAST_EXPECT(arrInd >= 0 && arrInd < ledgersPerShard);
865  BEAST_EXPECT(saveLedger(*db, *data.ledgers_[arrInd]));
866  if (arrInd % ledgersPerShard == (ledgersPerShard - 1))
867  {
868  uint256 const finalKey_{0};
869  Serializer s;
870  s.add32(Shard::version + (i == 0));
871  s.add32(db->firstLedgerSeq(shardNumber) + (i == 1));
872  s.add32(db->lastLedgerSeq(shardNumber) - (i == 3));
873  s.addRaw(
874  data.ledgers_[arrInd - (i == 4)]
875  ->info()
876  .hash.data(),
877  256 / 8);
878  db->store(
879  hotUNKNOWN,
880  std::move(s.modData()),
881  finalKey_,
882  *ind);
883  }
884  db->setStored(data.ledgers_[arrInd]);
885  }
886 
887  if (i == 2)
888  waitShard(*db, shardNumber);
889  else
890  {
891  boost::filesystem::path path(shardDir.path());
892  path /= "1";
893  boost::system::error_code ec;
894  auto start = std::chrono::system_clock::now();
895  auto end = start + shardStoreTimeout;
896  while (std::chrono::system_clock::now() < end &&
897  boost::filesystem::exists(path, ec))
898  {
900  }
901  }
902 
903  BEAST_EXPECT(
904  db->getCompleteShards() ==
905  bitmask2Rangeset(i == 2 ? 2 : 0));
906  }
907 
908  {
909  Env env{*this, testConfig("", backendType, shardDir.path())};
910  DatabaseShard* db = env.app().getShardStore();
911  BEAST_EXPECT(db);
912 
913  TestData data(seedValue + i, 2);
914  if (!BEAST_EXPECT(data.makeLedgers(env)))
915  return;
916 
917  if (i == 2)
918  waitShard(*db, 1);
919 
920  BEAST_EXPECT(
921  db->getCompleteShards() ==
922  bitmask2Rangeset(i == 2 ? 2 : 0));
923 
924  if (i == 2)
925  {
926  for (std::uint32_t j = 0; j < ledgersPerShard; ++j)
927  checkLedger(data, *db, *data.ledgers_[j]);
928  }
929  }
930  }
931  }
932 
933  void
934  testImport(std::string const& backendType, std::uint64_t const seedValue)
935  {
936  using namespace test::jtx;
937 
938  beast::temp_dir shardDir;
939  {
940  beast::temp_dir nodeDir;
941  Env env{
942  *this,
943  testConfig(
944  "import", backendType, shardDir.path(), nodeDir.path())};
945  DatabaseShard* db = env.app().getShardStore();
946  Database& ndb = env.app().getNodeStore();
947  BEAST_EXPECT(db);
948 
949  TestData data(seedValue, 4, 2);
950  if (!BEAST_EXPECT(data.makeLedgers(env)))
951  return;
952 
953  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
954  BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i]));
955 
956  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0));
957  db->import(ndb);
958  for (std::uint32_t i = 1; i <= 2; ++i)
959  waitShard(*db, i);
960  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x6));
961  }
962  {
963  Env env{*this, testConfig("", backendType, shardDir.path())};
964  DatabaseShard* db = env.app().getShardStore();
965  BEAST_EXPECT(db);
966 
967  TestData data(seedValue, 4, 2);
968  if (!BEAST_EXPECT(data.makeLedgers(env)))
969  return;
970 
971  for (std::uint32_t i = 1; i <= 2; ++i)
972  waitShard(*db, i);
973 
974  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x6));
975 
976  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
977  checkLedger(data, *db, *data.ledgers_[i]);
978  }
979  }
980 
981  void
982  testAll(std::string const& backendType)
983  {
984  std::uint64_t const seedValue = 51;
985  testStandalone(backendType);
986  testCreateShard(backendType, seedValue);
987  testReopenDatabase(backendType, seedValue + 5);
988  testGetCompleteShards(backendType, seedValue + 10);
989  testPrepareShard(backendType, seedValue + 20);
990  testImportShard(backendType, seedValue + 30);
991  testCorruptedDatabase(backendType, seedValue + 40);
992  testIllegalFinalKey(backendType, seedValue + 50);
993  testImport(backendType, seedValue + 60);
994  }
995 
996 public:
997  DatabaseShard_test() : journal_("DatabaseShard_test", *this)
998  {
999  }
1000 
1001  void
1002  run() override
1003  {
1004  testAll("nudb");
1005 
1006 #if RIPPLE_ROCKSDB_AVAILABLE
1007 // testAll ("rocksdb");
1008 #endif
1009 
1010 #if RIPPLE_ENABLE_SQLITE_BACKEND_TESTS
1011  testAll("sqlite");
1012 #endif
1013  }
1014 };
1015 
1016 BEAST_DEFINE_TESTSUITE(DatabaseShard, NodeStore, ripple);
1017 
1018 } // namespace NodeStore
1019 } // namespace ripple
ripple::NodeStore::make_ShardStore
std::unique_ptr< DatabaseShard > make_ShardStore(Application &app, Stoppable &parent, Scheduler &scheduler, int readThreads, beast::Journal j)
Definition: DatabaseShardImp.cpp:1426
ripple::NodeStore::DummyScheduler
Simple NodeStore Scheduler that just peforms the tasks synchronously.
Definition: DummyScheduler.h:29
ripple::hotUNKNOWN
@ hotUNKNOWN
Definition: NodeObject.h:33
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::SHAMap::isValid
bool isValid() const
Definition: SHAMap.h:523
ripple::NodeStore::DatabaseShard_test::testLedgerData
void testLedgerData(TestData &data, std::shared_ptr< Ledger > ledger, std::uint32_t seq)
Definition: DatabaseShard_test.cpp:179
ripple::NodeStore::DatabaseShard_test::TestData::nAccounts_
std::vector< int > nAccounts_
Definition: DatabaseShard_test.cpp:62
ripple::NodeStore::Database
Persistency layer for NodeObject.
Definition: Database.h:53
ripple::NodeStore::DatabaseShard_test::testGetCompleteShards
void testGetCompleteShards(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:619
ripple::NodeStore::DatabaseShard_test::ledgersPerShard
static constexpr std::uint32_t ledgersPerShard
Definition: DatabaseShard_test.cpp:42
ripple::NodeStore::TestBase
Definition: TestBase.h:68
std::string
STL class.
std::shared_ptr
STL class.
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:791
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:480
ripple::NodeStore::DatabaseShard::seqToShardIndex
virtual std::uint32_t seqToShardIndex(std::uint32_t seq) const =0
Calculates the shard index for a given ledger sequence.
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:176
ripple::NodeStore::DatabaseShard_test::TestData::ledgers_
std::vector< std::shared_ptr< const Ledger > > ledgers_
Definition: DatabaseShard_test.cpp:71
std::vector::reserve
T reserve(T... args)
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:96
ripple::NodeStore::DatabaseShard_test::journal_
test::SuiteJournal journal_
Definition: DatabaseShard_test.cpp:49
ripple::NodeStore::DatabaseShard_test::TestData::accounts_
std::vector< test::jtx::Account > accounts_
Definition: DatabaseShard_test.cpp:59
ripple::hotACCOUNT_NODE
@ hotACCOUNT_NODE
Definition: NodeObject.h:35
std::vector
STL class.
ripple::ConfigSection::shardDatabase
static std::string shardDatabase()
Definition: ConfigSections.h:38
std::vector::size
T size(T... args)
ripple::sfSequence
const SF_U32 sfSequence(access, STI_UINT32, 4, "Sequence")
Definition: SField.h:355
ripple::snfPREFIX
@ snfPREFIX
Definition: SHAMapTreeNode.h:36
ripple::NodeObject::createObject
static std::shared_ptr< NodeObject > createObject(NodeObjectType type, Blob &&data, uint256 const &hash)
Create an object from fields.
Definition: NodeObject.cpp:37
ripple::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:476
std::chrono::seconds
ripple::NodeStore::DatabaseShard_test::TestData::TestData
TestData(std::uint64_t const seedValue, int dataSize=dataSizeMax, int nShards=1)
Definition: DatabaseShard_test.cpp:73
ripple::NodeStore::DatabaseShard_test::testConfig
std::unique_ptr< Config > testConfig(std::string const &testName, std::string const &backendType, std::string const &shardDir, std::string const &nodeDir=std::string())
Definition: DatabaseShard_test.cpp:429
ripple::NodeStore::DatabaseShard_test::TestData::payAccounts_
std::vector< std::vector< std::pair< int, int > > > payAccounts_
Definition: DatabaseShard_test.cpp:66
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::NodeStore::DatabaseShard_test::testAll
void testAll(std::string const &backendType)
Definition: DatabaseShard_test.cpp:982
ripple::NodeStore::DatabaseShard_test::checkLedger
void checkLedger(TestData &data, DatabaseShard &db, Ledger const &ledger)
Definition: DatabaseShard_test.cpp:333
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
ripple::from_string
bool from_string(RangeSet< T > &rs, std::string const &s)
Convert the given styled string to a RangeSet.
Definition: RangeSet.h:126
ripple::NodeStore::DatabaseShard_test::earliestSeq
static constexpr std::uint32_t earliestSeq
Definition: DatabaseShard_test.cpp:43
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:238
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:88
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::SHAMapHash::isNonZero
bool isNonZero() const
Definition: SHAMapTreeNode.h:69
ripple::NodeStore::DatabaseShard_test::TestData
Definition: DatabaseShard_test.cpp:52
ripple::hotTRANSACTION_NODE
@ hotTRANSACTION_NODE
Definition: NodeObject.h:36
ripple::sfAmount
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
Definition: SField.h:439
ripple::NodeStore::DatabaseShard_test::nTestShards
static constexpr std::uint32_t nTestShards
Definition: DatabaseShard_test.cpp:46
ripple::NodeStore::DatabaseShard_test::run
void run() override
Definition: DatabaseShard_test.cpp:1002
ripple::SHAMap::snapShot
std::shared_ptr< SHAMap > snapShot(bool isMutable) const
Definition: SHAMap.cpp:51
ripple::NodeStore::DatabaseShard_test::iniAmount
static constexpr std::uint32_t iniAmount
Definition: DatabaseShard_test.cpp:45
ripple::NodeStore::DatabaseShard::getCompleteShards
virtual std::string getCompleteShards()=0
Query which complete shards are stored.
ripple::NodeStore::DatabaseShard_test::TestData::nShards_
int nShards_
Definition: DatabaseShard_test.cpp:57
ripple::LedgerFill::expand
@ expand
Definition: LedgerToJson.h:46
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:97
ripple::ttPAYMENT
@ ttPAYMENT
Definition: TxFormats.h:36
ripple::NodeStore::Shard::version
static constexpr std::uint32_t version
Definition: Shard.h:153
std::vector::push_back
T push_back(T... args)
ripple::base_uint< 256 >
ripple::NodeStore::DatabaseShard_test::DatabaseShard_test
DatabaseShard_test()
Definition: DatabaseShard_test.cpp:997
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:155
ripple::NodeStore::DatabaseShard_test::shardStoreTimeout
static constexpr std::chrono::seconds shardStoreTimeout
Definition: DatabaseShard_test.cpp:47
ripple::NodeStore::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(Backend, ripple_core, ripple)
ripple::NodeStore::Database::store
virtual void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t seq)=0
Store the object.
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::RootStoppable
Definition: Stoppable.h:352
ripple::Ledger
Holds a ledger.
Definition: Ledger.h:77
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::NodeStore::Database::fetch
virtual std::shared_ptr< NodeObject > fetch(uint256 const &hash, std::uint32_t seq)=0
Fetch an object.
chrono
ripple::NodeStore::DatabaseShard_test::testCorruptedDatabase
void testCorruptedDatabase(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:776
ripple::NodeStore::DatabaseShard_test::defNodeDir
beast::temp_dir defNodeDir
Definition: DatabaseShard_test.cpp:50
ripple::Ledger::stateMap
SHAMap const & stateMap() const
Definition: Ledger.h:289
ripple::NodeStore::DatabaseShard_test::waitShard
std::optional< int > waitShard(DatabaseShard &db, int shardNumber, std::chrono::seconds timeout=shardStoreTimeout)
Definition: DatabaseShard_test.cpp:478
ripple::LedgerFill::full
@ full
Definition: LedgerToJson.h:47
ripple::NodeStore::DatabaseShard
A collection of historical shards.
Definition: DatabaseShard.h:37
ripple::Serializer::addRaw
int addRaw(Blob const &vector)
Definition: Serializer.cpp:100
std::to_string
T to_string(T... args)
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:276
ripple::NodeStore::DatabaseShard_test::testStandalone
void testStandalone(std::string const &backendType)
Definition: DatabaseShard_test.cpp:529
ripple::NodeStore::DatabaseShard_test::testIllegalFinalKey
void testIllegalFinalKey(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:833
ripple::NodeStore::DatabaseShard_test::TestData::rng_
beast::xor_shift_engine rng_
Definition: DatabaseShard_test.cpp:55
ripple::NodeStore::DatabaseShard_test
Definition: DatabaseShard_test.cpp:39
std::uint32_t
ripple::NodeStore::DatabaseShard::firstLedgerSeq
virtual std::uint32_t firstLedgerSeq(std::uint32_t shardIndex) const =0
Calculates the first ledger sequence for a given shard index.
ripple::NodeStore::DatabaseShard_test::createShard
std::optional< int > createShard(TestData &data, DatabaseShard &db, int maxShardNumber)
Definition: DatabaseShard_test.cpp:498
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
beast::temp_dir::path
std::string path() const
Get the native path for the temporary directory.
Definition: temp_dir.h:66
ripple::Serializer
Definition: Serializer.h:39
ripple::LedgerFill::binary
@ binary
Definition: LedgerToJson.h:48
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:283
ripple::Ledger::txMap
SHAMap const & txMap() const
Definition: Ledger.h:301
ripple::NodeStore::DatabaseShard::fetchLedger
virtual std::shared_ptr< Ledger > fetchLedger(uint256 const &hash, std::uint32_t seq)=0
Fetch a ledger from the shard store.
ripple::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:83
ripple::NodeStore::DatabaseShard_test::testReopenDatabase
void testReopenDatabase(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:579
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::NodeStore::DatabaseShard_test::testImportShard
void testImportShard(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:720
ripple::NodeStore::DatabaseShard_test::TestData::makeLedgers
bool makeLedgers(test::jtx::Env &env_)
Definition: DatabaseShard_test.cpp:150
ripple::ttACCOUNT_SET
@ ttACCOUNT_SET
Definition: TxFormats.h:39
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, boost::optional< std::chrono::milliseconds > consensusDelay=boost::none)
Close and advance the ledger.
Definition: Env.cpp:111
ripple::NodeStore::DatabaseShard_test::saveLedger
bool saveLedger(Database &db, Ledger const &ledger, std::shared_ptr< Ledger const > const &next={})
Definition: DatabaseShard_test.cpp:263
beast::rngfill
void rngfill(void *buffer, std::size_t bytes, Generator &g)
Definition: rngfill.h:32
ripple::NodeStore::DatabaseShard::prepareShard
virtual bool prepareShard(std::uint32_t shardIndex)=0
Prepare a shard index to be imported into the database.
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:209
ripple::NodeStore::isSame
bool isSame(std::shared_ptr< NodeObject > const &lhs, std::shared_ptr< NodeObject > const &rhs)
Returns true if objects are identical.
Definition: TestBase.h:57
ripple::NodeStore::DatabaseShard_test::TestData::isNewAccounts
bool isNewAccounts(int seq)
Definition: DatabaseShard_test.cpp:127
ripple::NodeStore::DatabaseShard::getPreShards
virtual std::string getPreShards()=0
Get shard indexes being imported.
ripple::NodeStore::DatabaseShard::setStored
virtual void setStored(std::shared_ptr< Ledger const > const &ledger)=0
Notifies the database that the given ledger has been fully acquired and stored.
ripple::NodeStore::DatabaseShard_test::testCreateShard
void testCreateShard(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:556
ripple::NodeStore::DatabaseShard_test::dataSizeMax
static constexpr std::uint32_t dataSizeMax
Definition: DatabaseShard_test.cpp:44
ripple::NodeStore::DatabaseShard_test::testImport
void testImport(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:934
ripple::SHAMapAbstractNode
Definition: SHAMapTreeNode.h:122
ripple::NodeStore::DatabaseShard::prepareLedger
virtual boost::optional< std::uint32_t > prepareLedger(std::uint32_t validLedgerSeq)=0
Prepare to store a new ledger in the shard being acquired.
std::optional
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
std::make_pair
T make_pair(T... args)
beast::detail::xor_shift_engine
Definition: xor_shift_engine.h:32
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::RangeSet
boost::icl::interval_set< T, std::less, ClosedInterval< T > > RangeSet
A set of closed intervals over the domain T.
Definition: RangeSet.h:69
ripple::NodeStore::DatabaseShard_test::TestData::makeLedgerData
void makeLedgerData(test::jtx::Env &env_, std::uint32_t seq)
Definition: DatabaseShard_test.cpp:133
ripple::NodeStore::DatabaseShard::removePreShard
virtual void removePreShard(std::uint32_t shardIndex)=0
Remove a previously prepared shard index for import.
ripple::NodeStore::DatabaseShard_test::testPrepareShard
void testPrepareShard(std::string const &backendType, std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:651
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
Definition: LedgerFormats.h:53
std::unique_ptr
STL class.
ripple::NodeStore::Database::import
virtual void import(Database &source)=0
Import objects from another database.
ripple::LedgerFill
Definition: LedgerToJson.h:32
ripple::NodeStore::DatabaseShard_test::bitmask2Rangeset
std::string bitmask2Rangeset(std::uint64_t bitmask)
Definition: DatabaseShard_test.cpp:405
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:114
ripple::ConfigSection::nodeDatabase
static std::string nodeDatabase()
Definition: ConfigSections.h:33
std::this_thread::yield
T yield(T... args)
beast::temp_dir
RAII temporary directory.
Definition: temp_dir.h:33
ripple::NodeStore::DatabaseShard_test::TestData::xrpAmount_
std::vector< int > xrpAmount_
Definition: DatabaseShard_test.cpp:68
ripple::NodeStore::DatabaseShard_test::maxSizeGb
static constexpr std::uint32_t maxSizeGb
Definition: DatabaseShard_test.cpp:41
std::chrono::system_clock::now
T now(T... args)