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/impl/DecodedBlob.h>
27 #include <ripple/nodestore/impl/Shard.h>
28 #include <chrono>
29 #include <numeric>
30 #include <test/jtx.h>
31 #include <test/nodestore/TestBase.h>
32 
33 namespace ripple {
34 namespace NodeStore {
35 
36 // Tests DatabaseShard class
37 //
39 {
40  static constexpr std::uint32_t maxSizeGb = 10;
41  static constexpr std::uint32_t maxHistoricalShards = 100;
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 accounts: 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
150  makeLedgers(test::jtx::Env& env_, std::uint32_t startIndex = 0)
151  {
152  if (startIndex == 0)
153  {
154  for (std::uint32_t i = 3; i <= ledgersPerShard; ++i)
155  {
156  if (!env_.close())
157  return false;
160  if (ledger->info().seq != i)
161  return false;
162  }
163  }
164 
165  for (std::uint32_t i = 0; i < ledgersPerShard * nShards_; ++i)
166  {
167  auto const index = i + (startIndex * ledgersPerShard);
168 
169  makeLedgerData(env_, i);
170  if (!env_.close())
171  return false;
174  if (ledger->info().seq != index + ledgersPerShard + 1)
175  return false;
176  ledgers_.push_back(ledger);
177  }
178 
179  return true;
180  }
181  };
182 
183  void
185  TestData& data,
187  std::uint32_t seq)
188  {
189  using namespace test::jtx;
190 
191  auto rootCount{0};
192  auto accCount{0};
193  auto sothCount{0};
194  for (auto const& sles : ledger->sles)
195  {
196  if (sles->getType() == ltACCOUNT_ROOT)
197  {
198  int sq = sles->getFieldU32(sfSequence);
199  int reqsq = -1;
200  const auto id = sles->getAccountID(sfAccount);
201 
202  for (int i = 0; i < data.accounts_.size(); ++i)
203  {
204  if (id == data.accounts_[i].id())
205  {
206  reqsq = ledgersPerShard + 1;
207  for (int j = 0; j <= seq; ++j)
208  if (data.nAccounts_[j] > i + 1 ||
209  (data.nAccounts_[j] == i + 1 &&
210  !data.isNewAccounts(j)))
211  {
212  for (int k = 0; k < data.payAccounts_[j].size();
213  ++k)
214  if (data.payAccounts_[j][k].first == i)
215  reqsq++;
216  }
217  else
218  reqsq++;
219  ++accCount;
220  break;
221  }
222  }
223  if (reqsq == -1)
224  {
225  reqsq = data.nAccounts_[seq] + 1;
226  ++rootCount;
227  }
228  BEAST_EXPECT(sq == reqsq);
229  }
230  else
231  ++sothCount;
232  }
233  BEAST_EXPECT(rootCount == 1);
234  BEAST_EXPECT(accCount == data.nAccounts_[seq]);
235  BEAST_EXPECT(sothCount == 3);
236 
237  auto iniCount{0};
238  auto setCount{0};
239  auto payCount{0};
240  auto tothCount{0};
241  for (auto const& tx : ledger->txs)
242  {
243  if (tx.first->getTxnType() == ttPAYMENT)
244  {
245  std::int64_t xrpAmount =
246  tx.first->getFieldAmount(sfAmount).xrp().decimalXRP();
247  if (xrpAmount == iniAmount)
248  ++iniCount;
249  else
250  {
251  ++payCount;
252  BEAST_EXPECT(xrpAmount == data.xrpAmount_[seq]);
253  }
254  }
255  else if (tx.first->getTxnType() == ttACCOUNT_SET)
256  ++setCount;
257  else
258  ++tothCount;
259  }
260  int newacc = data.isNewAccounts(seq) ? 1 : 0;
261  BEAST_EXPECT(iniCount == newacc);
262  BEAST_EXPECT(setCount == newacc);
263  BEAST_EXPECT(payCount == data.payAccounts_[seq].size());
264  BEAST_EXPECT(tothCount == !seq);
265  }
266 
267  bool
269  Database& db,
270  Ledger const& ledger,
271  std::shared_ptr<Ledger const> const& next = {})
272  {
273  // Store header
274  {
275  Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo));
276  s.add32(HashPrefix::ledgerMaster);
277  addRaw(ledger.info(), s);
278  db.store(
279  hotLEDGER,
280  std::move(s.modData()),
281  ledger.info().hash,
282  ledger.info().seq);
283  }
284 
285  // Store the state map
286  auto visitAcc = [&](SHAMapAbstractNode& node) {
287  Serializer s;
288  node.addRaw(s, snfPREFIX);
289  db.store(
290  node.getType() == SHAMapAbstractNode::TNType::tnINNER
291  ? hotUNKNOWN
292  : hotACCOUNT_NODE,
293  std::move(s.modData()),
294  node.getNodeHash().as_uint256(),
295  ledger.info().seq);
296  return true;
297  };
298 
299  if (ledger.stateMap().getHash().isNonZero())
300  {
301  if (!ledger.stateMap().isValid())
302  return false;
303  if (next && next->info().parentHash == ledger.info().hash)
304  {
305  auto have = next->stateMap().snapShot(false);
306  ledger.stateMap().snapShot(false)->visitDifferences(
307  &(*have), visitAcc);
308  }
309  else
310  ledger.stateMap().snapShot(false)->visitNodes(visitAcc);
311  }
312 
313  // Store the transaction map
314  auto visitTx = [&](SHAMapAbstractNode& node) {
315  Serializer s;
316  node.addRaw(s, snfPREFIX);
317  db.store(
318  node.getType() == SHAMapAbstractNode::TNType::tnINNER
319  ? hotUNKNOWN
321  std::move(s.modData()),
322  node.getNodeHash().as_uint256(),
323  ledger.info().seq);
324  return true;
325  };
326 
327  if (ledger.info().txHash.isNonZero())
328  {
329  if (!ledger.txMap().isValid())
330  return false;
331  ledger.txMap().snapShot(false)->visitNodes(visitTx);
332  }
333 
334  return true;
335  }
336 
337  void
338  checkLedger(TestData& data, DatabaseShard& db, Ledger const& ledger)
339  {
340  auto fetched = db.fetchLedger(ledger.info().hash, ledger.info().seq);
341  if (!BEAST_EXPECT(fetched))
342  return;
343 
344  testLedgerData(data, fetched, ledger.info().seq - ledgersPerShard - 1);
345 
346  // verify the metadata/header info by serializing to json
347  BEAST_EXPECT(
348  getJson(
350  getJson(
352 
353  BEAST_EXPECT(
354  getJson(
356  getJson(
358 
359  // walk shamap and validate each node
360  auto fcompAcc = [&](SHAMapAbstractNode& node) -> bool {
361  Serializer s;
362  node.addRaw(s, snfPREFIX);
363  auto nSrc{NodeObject::createObject(
364  node.getType() == SHAMapAbstractNode::TNType::tnINNER
365  ? hotUNKNOWN
366  : hotACCOUNT_NODE,
367  std::move(s.modData()),
368  node.getNodeHash().as_uint256())};
369  if (!BEAST_EXPECT(nSrc))
370  return false;
371 
372  auto nDst = db.fetchNodeObject(
373  node.getNodeHash().as_uint256(), ledger.info().seq);
374  if (!BEAST_EXPECT(nDst))
375  return false;
376 
377  BEAST_EXPECT(isSame(nSrc, nDst));
378 
379  return true;
380  };
381  if (ledger.stateMap().getHash().isNonZero())
382  ledger.stateMap().snapShot(false)->visitNodes(fcompAcc);
383 
384  auto fcompTx = [&](SHAMapAbstractNode& node) -> bool {
385  Serializer s;
386  node.addRaw(s, snfPREFIX);
387  auto nSrc{NodeObject::createObject(
388  node.getType() == SHAMapAbstractNode::TNType::tnINNER
389  ? hotUNKNOWN
391  std::move(s.modData()),
392  node.getNodeHash().as_uint256())};
393  if (!BEAST_EXPECT(nSrc))
394  return false;
395 
396  auto nDst = db.fetchNodeObject(
397  node.getNodeHash().as_uint256(), ledger.info().seq);
398  if (!BEAST_EXPECT(nDst))
399  return false;
400 
401  BEAST_EXPECT(isSame(nSrc, nDst));
402 
403  return true;
404  };
405  if (ledger.info().txHash.isNonZero())
406  ledger.txMap().snapShot(false)->visitNodes(fcompTx);
407  }
408 
411  {
413  if (!bitmask)
414  return set;
415  bool empty = true;
416 
417  for (std::uint32_t i = 0; i < 64 && bitmask; i++)
418  {
419  if (bitmask & (1ll << i))
420  {
421  if (!empty)
422  set += ",";
423  set += std::to_string(i);
424  empty = false;
425  }
426  }
427 
429  from_string(rs, set);
430  return to_string(rs);
431  }
432 
435  std::string const& shardDir,
436  std::string const& nodeDir = std::string())
437  {
438  using namespace test::jtx;
439 
440  return envconfig([&](std::unique_ptr<Config> cfg) {
441  // Shard store configuration
442  cfg->overwrite(ConfigSection::shardDatabase(), "path", shardDir);
443  cfg->overwrite(
445  "max_historical_shards",
447  cfg->overwrite(
449  "ledgers_per_shard",
451  cfg->overwrite(
453  "earliest_seq",
455 
456  // Node store configuration
457  cfg->overwrite(
459  "earliest_seq",
461  cfg->overwrite(
463  "path",
464  nodeDir.empty() ? defNodeDir.path() : nodeDir);
465  return cfg;
466  });
467  }
468 
471  DatabaseShard& db,
472  int shardIndex,
474  {
476  auto start = std::chrono::system_clock::now();
477  auto end = start + timeout;
478  while (!from_string(rs, db.getCompleteShards()) ||
479  !boost::icl::contains(rs, shardIndex))
480  {
481  if (!BEAST_EXPECT(std::chrono::system_clock::now() < end))
482  return {};
484  }
485 
486  return shardIndex;
487  }
488 
491  TestData& data,
492  DatabaseShard& db,
493  int maxShardNumber = 1,
494  int ledgerOffset = 0)
495  {
496  int shardIndex{-1};
497 
498  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
499  {
500  auto const ledgerSeq{
501  db.prepareLedger((maxShardNumber + 1) * ledgersPerShard)};
502  if (!BEAST_EXPECT(ledgerSeq != boost::none))
503  return {};
504 
505  shardIndex = db.seqToShardIndex(*ledgerSeq);
506 
507  int const arrInd = *ledgerSeq - (ledgersPerShard * ledgerOffset) -
508  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(shardIndex));
518  s.add32(db.lastLedgerSeq(shardIndex));
519  s.addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8);
520  db.store(
521  hotUNKNOWN, std::move(s.modData()), finalKey_, *ledgerSeq);
522  }
523  db.setStored(data.ledgers_[arrInd]);
524  }
525 
526  return waitShard(db, shardIndex);
527  }
528 
529  void
531  {
532  testcase("Standalone");
533 
534  using namespace test::jtx;
535 
536  beast::temp_dir shardDir;
537  Env env{*this, testConfig(shardDir.path())};
538  DummyScheduler scheduler;
539  RootStoppable parent("TestRootStoppable");
540 
542  make_ShardStore(env.app(), parent, scheduler, 2, journal_);
543 
544  BEAST_EXPECT(db);
545  BEAST_EXPECT(db->ledgersPerShard() == db->ledgersPerShardDefault);
546  BEAST_EXPECT(db->init());
547  BEAST_EXPECT(db->ledgersPerShard() == ledgersPerShard);
548  BEAST_EXPECT(db->seqToShardIndex(ledgersPerShard + 1) == 1);
549  BEAST_EXPECT(db->seqToShardIndex(2 * ledgersPerShard) == 1);
550  BEAST_EXPECT(db->seqToShardIndex(2 * ledgersPerShard + 1) == 2);
551  BEAST_EXPECT(
552  db->earliestShardIndex() == (earliestSeq - 1) / ledgersPerShard);
553  BEAST_EXPECT(db->firstLedgerSeq(1) == ledgersPerShard + 1);
554  BEAST_EXPECT(db->lastLedgerSeq(1) == 2 * ledgersPerShard);
555  BEAST_EXPECT(db->getRootDir().string() == shardDir.path());
556  }
557 
558  void
560  {
561  testcase("Create shard");
562 
563  using namespace test::jtx;
564 
565  beast::temp_dir shardDir;
566  Env env{*this, testConfig(shardDir.path())};
567  DatabaseShard* db = env.app().getShardStore();
568  BEAST_EXPECT(db);
569 
570  TestData data(seedValue);
571  if (!BEAST_EXPECT(data.makeLedgers(env)))
572  return;
573 
574  if (!createShard(data, *db, 1))
575  return;
576 
577  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
578  checkLedger(data, *db, *data.ledgers_[i]);
579  }
580 
581  void
583  {
584  testcase("Reopen shard store");
585 
586  using namespace test::jtx;
587 
588  beast::temp_dir shardDir;
589  {
590  Env env{*this, testConfig(shardDir.path())};
591  DatabaseShard* db = env.app().getShardStore();
592  BEAST_EXPECT(db);
593 
594  TestData data(seedValue, 4, 2);
595  if (!BEAST_EXPECT(data.makeLedgers(env)))
596  return;
597 
598  for (std::uint32_t i = 0; i < 2; ++i)
599  if (!createShard(data, *db, 2))
600  return;
601  }
602  {
603  Env env{*this, testConfig(shardDir.path())};
604  DatabaseShard* db = env.app().getShardStore();
605  BEAST_EXPECT(db);
606 
607  TestData data(seedValue, 4, 2);
608  if (!BEAST_EXPECT(data.makeLedgers(env)))
609  return;
610 
611  for (std::uint32_t i = 1; i <= 2; ++i)
612  waitShard(*db, i);
613 
614  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
615  checkLedger(data, *db, *data.ledgers_[i]);
616  }
617  }
618 
619  void
621  {
622  testcase("Get complete shards");
623 
624  using namespace test::jtx;
625 
626  beast::temp_dir shardDir;
627  Env env{*this, testConfig(shardDir.path())};
628  DatabaseShard* db = env.app().getShardStore();
629  BEAST_EXPECT(db);
630 
631  TestData data(seedValue, 2, nTestShards);
632  if (!BEAST_EXPECT(data.makeLedgers(env)))
633  return;
634 
635  BEAST_EXPECT(db->getCompleteShards() == "");
636 
637  std::uint64_t bitMask = 0;
638 
639  for (std::uint32_t i = 0; i < nTestShards; ++i)
640  {
641  auto n = createShard(data, *db, nTestShards);
642  if (!BEAST_EXPECT(n && *n >= 1 && *n <= nTestShards))
643  return;
644  bitMask |= 1ll << *n;
645  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(bitMask));
646  }
647  }
648 
649  void
651  {
652  testcase("Prepare shards");
653 
654  using namespace test::jtx;
655 
656  beast::temp_dir shardDir;
657  Env env{*this, testConfig(shardDir.path())};
658  DatabaseShard* db = env.app().getShardStore();
659  BEAST_EXPECT(db);
660 
661  TestData data(seedValue, 1, nTestShards);
662  if (!BEAST_EXPECT(data.makeLedgers(env)))
663  return;
664 
665  std::uint64_t bitMask = 0;
666  BEAST_EXPECT(db->getPreShards() == "");
667 
668  for (std::uint32_t i = 0; i < nTestShards * 2; ++i)
669  {
670  std::uint32_t n = rand_int(data.rng_, nTestShards - 1) + 1;
671  if (bitMask & (1ll << n))
672  {
673  db->removePreShard(n);
674  bitMask &= ~(1ll << n);
675  }
676  else
677  {
678  db->prepareShards({n});
679  bitMask |= 1ll << n;
680  }
681  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
682  }
683 
684  // test illegal cases
685  // adding shards with too large number
686  db->prepareShards({0});
687  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
688  db->prepareShards({nTestShards + 1});
689  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
690  db->prepareShards({nTestShards + 2});
691  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
692 
693  // create shards which are not prepared for import
694  BEAST_EXPECT(db->getCompleteShards() == "");
695 
696  std::uint64_t bitMask2 = 0;
697 
698  for (std::uint32_t i = 0; i < nTestShards; ++i)
699  {
700  auto n = createShard(data, *db, nTestShards);
701  if (!BEAST_EXPECT(n && *n >= 1 && *n <= nTestShards))
702  return;
703  bitMask2 |= 1ll << *n;
704  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask));
705  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(bitMask2));
706  BEAST_EXPECT((bitMask & bitMask2) == 0);
707  if ((bitMask | bitMask2) == ((1ll << nTestShards) - 1) << 1)
708  break;
709  }
710 
711  // try to create another shard
712  BEAST_EXPECT(
714  boost::none);
715  }
716 
717  void
719  {
720  testcase("Import shard");
721 
722  using namespace test::jtx;
723 
724  beast::temp_dir importDir;
725  TestData data(seedValue, 2);
726 
727  {
728  Env env{*this, testConfig(importDir.path())};
729  DatabaseShard* db = env.app().getShardStore();
730  BEAST_EXPECT(db);
731 
732  if (!BEAST_EXPECT(data.makeLedgers(env)))
733  return;
734 
735  if (!createShard(data, *db, 1))
736  return;
737 
738  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
739  checkLedger(data, *db, *data.ledgers_[i]);
740 
741  data.ledgers_.clear();
742  }
743 
744  boost::filesystem::path importPath(importDir.path());
745  importPath /= "1";
746 
747  {
748  beast::temp_dir shardDir;
749  Env env{*this, testConfig(shardDir.path())};
750  DatabaseShard* db = env.app().getShardStore();
751  BEAST_EXPECT(db);
752 
753  if (!BEAST_EXPECT(data.makeLedgers(env)))
754  return;
755 
756  db->prepareShards({1});
757  BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(2));
758 
759  using namespace boost::filesystem;
760  remove_all(importPath / LgrDBName);
761  remove_all(importPath / TxDBName);
762 
763  if (!BEAST_EXPECT(db->importShard(1, importPath)))
764  return;
765 
766  BEAST_EXPECT(db->getPreShards() == "");
767 
768  auto n = waitShard(*db, 1);
769  if (!BEAST_EXPECT(n && *n == 1))
770  return;
771 
772  for (std::uint32_t i = 0; i < ledgersPerShard; ++i)
773  checkLedger(data, *db, *data.ledgers_[i]);
774  }
775  }
776 
777  void
779  {
780  testcase("Corrupted shard store");
781 
782  using namespace test::jtx;
783 
784  beast::temp_dir shardDir;
785  {
786  TestData data(seedValue, 4, 2);
787  {
788  Env env{*this, testConfig(shardDir.path())};
789  DatabaseShard* db = env.app().getShardStore();
790  BEAST_EXPECT(db);
791 
792  if (!BEAST_EXPECT(data.makeLedgers(env)))
793  return;
794 
795  for (std::uint32_t i = 0; i < 2; ++i)
796  if (!BEAST_EXPECT(createShard(data, *db, 2)))
797  return;
798  }
799 
800  boost::filesystem::path path = shardDir.path();
801  path /= std::string("2");
802  path /= "nudb.dat";
803 
804  FILE* f = fopen(path.string().c_str(), "r+b");
805  if (!BEAST_EXPECT(f))
806  return;
807  char buf[256];
808  beast::rngfill(buf, sizeof(buf), data.rng_);
809  BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256);
810  fclose(f);
811  }
812 
813  Env env{*this, testConfig(shardDir.path())};
814  DatabaseShard* db = env.app().getShardStore();
815  BEAST_EXPECT(db);
816 
817  TestData data(seedValue, 4, 2);
818  if (!BEAST_EXPECT(data.makeLedgers(env)))
819  return;
820 
821  for (std::uint32_t i = 1; i <= 1; ++i)
822  waitShard(*db, i);
823 
824  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x2));
825 
826  for (std::uint32_t i = 0; i < 1 * ledgersPerShard; ++i)
827  checkLedger(data, *db, *data.ledgers_[i]);
828  }
829 
830  void
832  {
833  testcase("Illegal finalKey");
834 
835  using namespace test::jtx;
836 
837  for (int i = 0; i < 5; ++i)
838  {
839  beast::temp_dir shardDir;
840  {
841  Env env{*this, testConfig(shardDir.path())};
842  DatabaseShard* db = env.app().getShardStore();
843  BEAST_EXPECT(db);
844 
845  TestData data(seedValue + i, 2);
846  if (!BEAST_EXPECT(data.makeLedgers(env)))
847  return;
848 
849  int shardIndex{-1};
850  for (std::uint32_t j = 0; j < ledgersPerShard; ++j)
851  {
852  auto const ledgerSeq{
853  db->prepareLedger(2 * ledgersPerShard)};
854  if (!BEAST_EXPECT(ledgerSeq != boost::none))
855  return;
856 
857  shardIndex = db->seqToShardIndex(*ledgerSeq);
858  int arrInd = *ledgerSeq - ledgersPerShard - 1;
859  BEAST_EXPECT(arrInd >= 0 && arrInd < ledgersPerShard);
860  BEAST_EXPECT(saveLedger(*db, *data.ledgers_[arrInd]));
861  if (arrInd % ledgersPerShard == (ledgersPerShard - 1))
862  {
863  uint256 const finalKey_{0};
864  Serializer s;
865  s.add32(Shard::version + (i == 0));
866  s.add32(db->firstLedgerSeq(shardIndex) + (i == 1));
867  s.add32(db->lastLedgerSeq(shardIndex) - (i == 3));
868  s.addRaw(
869  data.ledgers_[arrInd - (i == 4)]
870  ->info()
871  .hash.data(),
872  256 / 8);
873  db->store(
874  hotUNKNOWN,
875  std::move(s.modData()),
876  finalKey_,
877  *ledgerSeq);
878  }
879  db->setStored(data.ledgers_[arrInd]);
880  }
881 
882  if (i == 2)
883  waitShard(*db, shardIndex);
884  else
885  {
886  boost::filesystem::path path(shardDir.path());
887  path /= "1";
888  boost::system::error_code ec;
889  auto start = std::chrono::system_clock::now();
890  auto end = start + shardStoreTimeout;
891  while (std::chrono::system_clock::now() < end &&
892  boost::filesystem::exists(path, ec))
893  {
895  }
896  }
897 
898  BEAST_EXPECT(
899  db->getCompleteShards() ==
900  bitmask2Rangeset(i == 2 ? 2 : 0));
901  }
902 
903  {
904  Env env{*this, testConfig(shardDir.path())};
905  DatabaseShard* db = env.app().getShardStore();
906  BEAST_EXPECT(db);
907 
908  TestData data(seedValue + i, 2);
909  if (!BEAST_EXPECT(data.makeLedgers(env)))
910  return;
911 
912  if (i == 2)
913  waitShard(*db, 1);
914 
915  BEAST_EXPECT(
916  db->getCompleteShards() ==
917  bitmask2Rangeset(i == 2 ? 2 : 0));
918 
919  if (i == 2)
920  {
921  for (std::uint32_t j = 0; j < ledgersPerShard; ++j)
922  checkLedger(data, *db, *data.ledgers_[j]);
923  }
924  }
925  }
926  }
927 
928  void
929  testImport(std::uint64_t const seedValue)
930  {
931  testcase("Import node store");
932 
933  using namespace test::jtx;
934 
935  beast::temp_dir shardDir;
936  {
937  beast::temp_dir nodeDir;
938  Env env{*this, testConfig(shardDir.path(), nodeDir.path())};
939  DatabaseShard* db = env.app().getShardStore();
940  Database& ndb = env.app().getNodeStore();
941  BEAST_EXPECT(db);
942 
943  TestData data(seedValue, 4, 2);
944  if (!BEAST_EXPECT(data.makeLedgers(env)))
945  return;
946 
947  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
948  BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i]));
949 
950  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0));
951  db->import(ndb);
952  for (std::uint32_t i = 1; i <= 2; ++i)
953  waitShard(*db, i);
954  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x6));
955  }
956  {
957  Env env{*this, testConfig(shardDir.path())};
958  DatabaseShard* db = env.app().getShardStore();
959  BEAST_EXPECT(db);
960 
961  TestData data(seedValue, 4, 2);
962  if (!BEAST_EXPECT(data.makeLedgers(env)))
963  return;
964 
965  for (std::uint32_t i = 1; i <= 2; ++i)
966  waitShard(*db, i);
967 
968  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0x6));
969 
970  for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i)
971  checkLedger(data, *db, *data.ledgers_[i]);
972  }
973  }
974 
975  void
977  {
978  testcase("Import with historical paths");
979 
980  using namespace test::jtx;
981 
982  // Test importing with multiple historical
983  // paths
984  {
985  beast::temp_dir shardDir;
986  std::array<beast::temp_dir, 4> historicalDirs;
988 
990  historicalDirs.begin(),
991  historicalDirs.end(),
992  historicalPaths.begin(),
993  [](const beast::temp_dir& dir) { return dir.path(); });
994 
995  beast::temp_dir nodeDir;
996  auto c = testConfig(shardDir.path(), nodeDir.path());
997 
998  auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
999  historyPaths.append(
1000  {historicalPaths[0].string(),
1001  historicalPaths[1].string(),
1002  historicalPaths[2].string(),
1003  historicalPaths[3].string()});
1004 
1005  Env env{*this, std::move(c)};
1006  DatabaseShard* db = env.app().getShardStore();
1007  Database& ndb = env.app().getNodeStore();
1008  BEAST_EXPECT(db);
1009 
1010  auto const ledgerCount = 4;
1011 
1012  TestData data(seedValue, 4, ledgerCount);
1013  if (!BEAST_EXPECT(data.makeLedgers(env)))
1014  return;
1015 
1016  for (std::uint32_t i = 0; i < ledgerCount * ledgersPerShard; ++i)
1017  BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i]));
1018 
1019  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0));
1020 
1021  db->import(ndb);
1022  for (std::uint32_t i = 1; i <= ledgerCount; ++i)
1023  waitShard(*db, i);
1024 
1025  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0b11110));
1026 
1027  auto const mainPathCount = std::distance(
1028  boost::filesystem::directory_iterator(shardDir.path()),
1029  boost::filesystem::directory_iterator());
1030 
1031  // Only the two most recent shards
1032  // should be stored at the main path
1033  BEAST_EXPECT(mainPathCount == 2);
1034 
1035  auto const historicalPathCount = std::accumulate(
1036  historicalPaths.begin(),
1037  historicalPaths.end(),
1038  0,
1039  [](int const sum, boost::filesystem::path const& path) {
1040  return sum +
1041  std::distance(
1042  boost::filesystem::directory_iterator(path),
1043  boost::filesystem::directory_iterator());
1044  });
1045 
1046  // All historical shards should be stored
1047  // at historical paths
1048  BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1049  }
1050 
1051  // Test importing with a single historical
1052  // path
1053  {
1054  beast::temp_dir shardDir;
1055  beast::temp_dir historicalDir;
1056  beast::temp_dir nodeDir;
1057 
1058  auto c = testConfig(shardDir.path(), nodeDir.path());
1059 
1060  auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1061  historyPaths.append({historicalDir.path()});
1062 
1063  Env env{*this, std::move(c)};
1064  DatabaseShard* db = env.app().getShardStore();
1065  Database& ndb = env.app().getNodeStore();
1066  BEAST_EXPECT(db);
1067 
1068  auto const ledgerCount = 4;
1069 
1070  TestData data(seedValue * 2, 4, ledgerCount);
1071  if (!BEAST_EXPECT(data.makeLedgers(env)))
1072  return;
1073 
1074  for (std::uint32_t i = 0; i < ledgerCount * ledgersPerShard; ++i)
1075  BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i]));
1076 
1077  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0));
1078 
1079  db->import(ndb);
1080  for (std::uint32_t i = 1; i <= ledgerCount; ++i)
1081  waitShard(*db, i);
1082 
1083  BEAST_EXPECT(db->getCompleteShards() == bitmask2Rangeset(0b11110));
1084 
1085  auto const mainPathCount = std::distance(
1086  boost::filesystem::directory_iterator(shardDir.path()),
1087  boost::filesystem::directory_iterator());
1088 
1089  // Only the two most recent shards
1090  // should be stored at the main path
1091  BEAST_EXPECT(mainPathCount == 2);
1092 
1093  auto const historicalPathCount = std::distance(
1094  boost::filesystem::directory_iterator(historicalDir.path()),
1095  boost::filesystem::directory_iterator());
1096 
1097  // All historical shards should be stored
1098  // at historical paths
1099  BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1100  }
1101  }
1102 
1103  void
1105  {
1106  testcase("Prepare with historical paths");
1107 
1108  using namespace test::jtx;
1109 
1110  // Test importing with multiple historical
1111  // paths
1112  {
1113  beast::temp_dir shardDir;
1114  std::array<beast::temp_dir, 4> historicalDirs;
1116 
1118  historicalDirs.begin(),
1119  historicalDirs.end(),
1120  historicalPaths.begin(),
1121  [](const beast::temp_dir& dir) { return dir.path(); });
1122 
1123  beast::temp_dir nodeDir;
1124  auto c = testConfig(shardDir.path());
1125 
1126  auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1127  historyPaths.append(
1128  {historicalPaths[0].string(),
1129  historicalPaths[1].string(),
1130  historicalPaths[2].string(),
1131  historicalPaths[3].string()});
1132 
1133  Env env{*this, std::move(c)};
1134  DatabaseShard* db = env.app().getShardStore();
1135  BEAST_EXPECT(db);
1136 
1137  auto const ledgerCount = 4;
1138 
1139  TestData data(seedValue, 4, ledgerCount);
1140  if (!BEAST_EXPECT(data.makeLedgers(env)))
1141  return;
1142 
1143  BEAST_EXPECT(db->getCompleteShards() == "");
1144  std::uint64_t bitMask = 0;
1145 
1146  // Add ten shards to the Shard Database
1147  for (std::uint32_t i = 0; i < ledgerCount; ++i)
1148  {
1149  auto n = createShard(data, *db, ledgerCount);
1150  if (!BEAST_EXPECT(n && *n >= 1 && *n <= ledgerCount))
1151  return;
1152  bitMask |= 1ll << *n;
1153  BEAST_EXPECT(
1154  db->getCompleteShards() == bitmask2Rangeset(bitMask));
1155  }
1156 
1157  auto mainPathCount = std::distance(
1158  boost::filesystem::directory_iterator(shardDir.path()),
1159  boost::filesystem::directory_iterator());
1160 
1161  // Only the two most recent shards
1162  // should be stored at the main path
1163  BEAST_EXPECT(mainPathCount == 2);
1164 
1165  // Confirm recent shard locations
1166  std::set<boost::filesystem::path> mainPathShards{
1167  shardDir.path() / boost::filesystem::path("3"),
1168  shardDir.path() / boost::filesystem::path("4")};
1170  boost::filesystem::directory_iterator(shardDir.path()),
1171  boost::filesystem::directory_iterator());
1172 
1173  BEAST_EXPECT(mainPathShards == actual);
1174 
1175  const auto generateHistoricalStems = [&historicalPaths, &actual] {
1176  for (auto const& path : historicalPaths)
1177  {
1178  for (auto const& shard :
1179  boost::filesystem::directory_iterator(path))
1180  {
1181  actual.insert(boost::filesystem::path(shard).stem());
1182  }
1183  }
1184  };
1185 
1186  // Confirm historical shard locations
1187  std::set<boost::filesystem::path> historicalPathShards;
1189  std::inserter(
1190  historicalPathShards, historicalPathShards.begin()),
1191  2,
1192  [n = 1]() mutable { return std::to_string(n++); });
1193  actual.clear();
1194  generateHistoricalStems();
1195 
1196  BEAST_EXPECT(historicalPathShards == actual);
1197 
1198  auto historicalPathCount = std::accumulate(
1199  historicalPaths.begin(),
1200  historicalPaths.end(),
1201  0,
1202  [](int const sum, boost::filesystem::path const& path) {
1203  return sum +
1204  std::distance(
1205  boost::filesystem::directory_iterator(path),
1206  boost::filesystem::directory_iterator());
1207  });
1208 
1209  // All historical shards should be stored
1210  // at historical paths
1211  BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1212 
1213  data = TestData(seedValue * 2, 4, ledgerCount);
1214  if (!BEAST_EXPECT(data.makeLedgers(env, ledgerCount)))
1215  return;
1216 
1217  // Add ten more shards to the Shard Database
1218  // to exercise recent shard rotation
1219  for (std::uint32_t i = 0; i < ledgerCount; ++i)
1220  {
1221  auto n = createShard(data, *db, ledgerCount * 2, ledgerCount);
1222  if (!BEAST_EXPECT(
1223  n && *n >= 1 + ledgerCount && *n <= ledgerCount * 2))
1224  return;
1225  bitMask |= 1ll << *n;
1226  BEAST_EXPECT(
1227  db->getCompleteShards() == bitmask2Rangeset(bitMask));
1228  }
1229 
1230  mainPathCount = std::distance(
1231  boost::filesystem::directory_iterator(shardDir.path()),
1232  boost::filesystem::directory_iterator());
1233 
1234  // Only the two most recent shards
1235  // should be stored at the main path
1236  BEAST_EXPECT(mainPathCount == 2);
1237 
1238  // Confirm recent shard locations
1239  mainPathShards = {
1240  shardDir.path() / boost::filesystem::path("7"),
1241  shardDir.path() / boost::filesystem::path("8")};
1242  actual = {
1243  boost::filesystem::directory_iterator(shardDir.path()),
1244  boost::filesystem::directory_iterator()};
1245 
1246  BEAST_EXPECT(mainPathShards == actual);
1247 
1248  // Confirm historical shard locations
1249  historicalPathShards.clear();
1251  std::inserter(
1252  historicalPathShards, historicalPathShards.begin()),
1253  6,
1254  [n = 1]() mutable { return std::to_string(n++); });
1255  actual.clear();
1256  generateHistoricalStems();
1257 
1258  BEAST_EXPECT(historicalPathShards == actual);
1259 
1260  historicalPathCount = std::accumulate(
1261  historicalPaths.begin(),
1262  historicalPaths.end(),
1263  0,
1264  [](int const sum, boost::filesystem::path const& path) {
1265  return sum +
1266  std::distance(
1267  boost::filesystem::directory_iterator(path),
1268  boost::filesystem::directory_iterator());
1269  });
1270 
1271  // All historical shards should be stored
1272  // at historical paths
1273  BEAST_EXPECT(historicalPathCount == (ledgerCount * 2) - 2);
1274  }
1275  }
1276 
1277  void
1279  {
1280  testcase("Open shard management");
1281 
1282  using namespace test::jtx;
1283 
1284  beast::temp_dir shardDir;
1285  Env env{*this, testConfig(shardDir.path())};
1286 
1287  auto shardStore{env.app().getShardStore()};
1288  BEAST_EXPECT(shardStore);
1289 
1290  // Create one shard more than the open final limit
1291  auto const openFinalLimit{env.app().config().getValueFor(
1292  SizedItem::openFinalLimit, boost::none)};
1293  auto const numShards{openFinalLimit + 1};
1294 
1295  TestData data(seedValue, 2, numShards);
1296  if (!BEAST_EXPECT(data.makeLedgers(env)))
1297  return;
1298 
1299  BEAST_EXPECT(shardStore->getCompleteShards().empty());
1300 
1301  int oldestShardIndex{-1};
1302  std::uint64_t bitMask{0};
1303  for (auto i = 0; i < numShards; ++i)
1304  {
1305  auto shardIndex{createShard(data, *shardStore, numShards)};
1306  if (!BEAST_EXPECT(
1307  shardIndex && *shardIndex >= 1 && *shardIndex <= numShards))
1308  return;
1309 
1310  bitMask |= (1ll << *shardIndex);
1311 
1312  if (oldestShardIndex == -1)
1313  oldestShardIndex = *shardIndex;
1314  }
1315 
1316  // The number of open shards exceeds the open limit by one.
1317  // A sweep will close enough shards to be within the limit.
1318  shardStore->sweep();
1319 
1320  // Read from the closed shard and automatically open it
1321  auto const ledgerSeq{shardStore->lastLedgerSeq(oldestShardIndex)};
1322  auto const index{ledgerSeq - ledgersPerShard - 1};
1323  BEAST_EXPECT(shardStore->fetchNodeObject(
1324  data.ledgers_[index]->info().hash, ledgerSeq));
1325  }
1326 
1327 public:
1328  DatabaseShard_test() : journal_("DatabaseShard_test", *this)
1329  {
1330  }
1331 
1332  void
1333  run() override
1334  {
1335  std::uint64_t const seedValue = 51;
1336 
1337  testStandalone();
1338  testCreateShard(seedValue);
1339  testReopenDatabase(seedValue + 10);
1340  testGetCompleteShards(seedValue + 20);
1341  testPrepareShards(seedValue + 30);
1342  testImportShard(seedValue + 40);
1343  testCorruptedDatabase(seedValue + 50);
1344  testIllegalFinalKey(seedValue + 60);
1345  testImport(seedValue + 70);
1346  testImportWithHistoricalPaths(seedValue + 80);
1347  testPrepareWithHistoricalPaths(seedValue + 90);
1348  testOpenShardManagement(seedValue + 100);
1349  }
1350 };
1351 
1352 BEAST_DEFINE_TESTSUITE_MANUAL(DatabaseShard, NodeStore, ripple);
1353 
1354 } // namespace NodeStore
1355 } // 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:1934
ripple::NodeStore::DummyScheduler
Simple NodeStore Scheduler that just peforms the tasks synchronously.
Definition: DummyScheduler.h:29
ripple::SizedItem::openFinalLimit
@ openFinalLimit
ripple::NodeStore::DatabaseShard_test::testIllegalFinalKey
void testIllegalFinalKey(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:831
ripple::NodeStore::DatabaseShard_test::testCreateShard
void testCreateShard(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:559
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:522
std::generate_n
T generate_n(T... args)
ripple::NodeStore::DatabaseShard_test::testLedgerData
void testLedgerData(TestData &data, std::shared_ptr< Ledger > ledger, std::uint32_t seq)
Definition: DatabaseShard_test.cpp:184
ripple::NodeStore::DatabaseShard_test::testReopenDatabase
void testReopenDatabase(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:582
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::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:796
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::NodeStore::DatabaseShard_test::testStandalone
void testStandalone()
Definition: DatabaseShard_test.cpp:530
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:100
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:356
ripple::NodeStore::DatabaseShard_test::waitShard
std::optional< int > waitShard(DatabaseShard &db, int shardIndex, std::chrono::seconds timeout=shardStoreTimeout)
Definition: DatabaseShard_test.cpp:470
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:481
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::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.
std::distance
T distance(T... args)
ripple::NodeStore::DatabaseShard_test::testPrepareWithHistoricalPaths
void testPrepareWithHistoricalPaths(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:1104
ripple::NodeStore::DatabaseShard_test::checkLedger
void checkLedger(TestData &data, DatabaseShard &db, Ledger const &ledger)
Definition: DatabaseShard_test.cpp:338
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
ripple::NodeStore::DatabaseShard_test::maxHistoricalShards
static constexpr std::uint32_t maxHistoricalShards
Definition: DatabaseShard_test.cpp:41
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:240
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
ripple::NodeStore::Database::store
virtual void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t ledgerSeq)=0
Store the object.
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
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:441
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:1333
ripple::SHAMap::snapShot
std::shared_ptr< SHAMap > snapShot(bool isMutable) const
Definition: SHAMap.cpp:55
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:101
ripple::ttPAYMENT
@ ttPAYMENT
Definition: TxFormats.h:36
std::set::clear
T clear(T... args)
ripple::NodeStore::Shard::version
static constexpr std::uint32_t version
Definition: Shard.h:212
ripple::NodeStore::DatabaseShard_test::createShard
std::optional< int > createShard(TestData &data, DatabaseShard &db, int maxShardNumber=1, int ledgerOffset=0)
Definition: DatabaseShard_test.cpp:490
std::vector::push_back
T push_back(T... args)
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint< 256 >
ripple::NodeStore::DatabaseShard_test::TestData::makeLedgers
bool makeLedgers(test::jtx::Env &env_, std::uint32_t startIndex=0)
Definition: DatabaseShard_test.cpp:150
ripple::NodeStore::DatabaseShard_test::DatabaseShard_test
DatabaseShard_test()
Definition: DatabaseShard_test.cpp:1328
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::DatabaseShard_test::testImportShard
void testImportShard(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:718
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::NodeStore::DatabaseShard_test::testConfig
std::unique_ptr< Config > testConfig(std::string const &shardDir, std::string const &nodeDir=std::string())
Definition: DatabaseShard_test.cpp:434
ripple::RootStoppable
Definition: Stoppable.h:353
ripple::Ledger
Holds a ledger.
Definition: Ledger.h:77
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
chrono
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::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
std::array
STL class.
ripple::NodeStore::DatabaseShard_test::testCorruptedDatabase
void testCorruptedDatabase(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:778
ripple::NodeStore::BEAST_DEFINE_TESTSUITE_MANUAL
BEAST_DEFINE_TESTSUITE_MANUAL(DatabaseShard, NodeStore, ripple)
ripple::NodeStore::DatabaseShard_test::TestData::rng_
beast::xor_shift_engine rng_
Definition: DatabaseShard_test.cpp:55
ripple::NodeStore::DatabaseShard_test
Definition: DatabaseShard_test.cpp:38
std::accumulate
T accumulate(T... args)
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::Database::fetchNodeObject
std::shared_ptr< NodeObject > fetchNodeObject(uint256 const &hash, std::uint32_t ledgerSeq=0, FetchType fetchType=FetchType::synchronous)
Fetch a node object.
Definition: Database.cpp:158
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::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:280
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:87
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::testImportWithHistoricalPaths
void testImportWithHistoricalPaths(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:976
ripple::NodeStore::DatabaseShard_test::testImport
void testImport(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:929
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:121
std::array::begin
T begin(T... args)
ripple::NodeStore::DatabaseShard_test::saveLedger
bool saveLedger(Database &db, Ledger const &ledger, std::shared_ptr< Ledger const > const &next={})
Definition: DatabaseShard_test.cpp:268
beast::rngfill
void rngfill(void *buffer, std::size_t bytes, Generator &g)
Definition: rngfill.h:32
std::set::insert
T insert(T... args)
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:219
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::dataSizeMax
static constexpr std::uint32_t dataSizeMax
Definition: DatabaseShard_test.cpp:44
ripple::SHAMapAbstractNode
Definition: SHAMapTreeNode.h:122
std::string::empty
T empty(T... args)
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< int >
ripple::NodeStore::DatabaseShard_test::testGetCompleteShards
void testGetCompleteShards(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:620
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::LedgerInfo
Information about the notional ledger backing the view.
Definition: ReadView.h:84
std::array::end
T end(T... args)
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
numeric
ripple::NodeStore::DatabaseShard::removePreShard
virtual void removePreShard(std::uint32_t shardIndex)=0
Remove a previously prepared shard index for import.
std::inserter
T inserter(T... args)
ripple::NodeStore::DatabaseShard_test::testOpenShardManagement
void testOpenShardManagement(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:1278
ripple::ltACCOUNT_ROOT
@ ltACCOUNT_ROOT
Definition: LedgerFormats.h:53
std::unique_ptr
STL class.
ripple::sum
static auto sum(TCollection const &col)
Definition: BookStep.cpp:693
ripple::NodeStore::DatabaseShard_test::testPrepareShards
void testPrepareShards(std::uint64_t const seedValue)
Definition: DatabaseShard_test.cpp:650
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:410
std::set
STL class.
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:115
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:40
ripple::LgrDBName
constexpr auto LgrDBName
Definition: DBInit.h:43
std::chrono::system_clock::now
T now(T... args)