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