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>
31 #include <test/nodestore/TestBase.h>
97 for (
int j = 0; j < p; ++j)
104 }
while (from == to);
114 for (
int j = 0; j < 8; ++j)
135 using namespace test::jtx;
160 if (ledger->info().seq != i)
189 using namespace test::jtx;
194 for (
auto const& sles : ledger->sles)
200 const auto id = sles->getAccountID(
sfAccount);
202 for (
int i = 0; i < data.accounts_.size(); ++i)
204 if (
id == data.accounts_[i].id())
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)))
212 for (
int k = 0; k < data.payAccounts_[j].size();
214 if (data.payAccounts_[j][k].first == i)
225 reqsq = data.nAccounts_[seq] + 1;
228 BEAST_EXPECT(sq == reqsq);
233 BEAST_EXPECT(rootCount == 1);
234 BEAST_EXPECT(accCount == data.nAccounts_[seq]);
235 BEAST_EXPECT(sothCount == 3);
241 for (
auto const& tx : ledger->txs)
246 tx.first->getFieldAmount(
sfAmount).xrp().decimalXRP();
252 BEAST_EXPECT(xrpAmount == data.xrpAmount_[seq]);
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);
280 std::move(s.modData()),
288 node.serializeWithPrefix(s);
293 node.getHash().as_uint256(),
302 if (next && next->info().parentHash == ledger.
info().
hash)
304 auto have = next->stateMap().snapShot(
false);
313 auto visitTx = [&](SHAMapTreeNode& node) {
315 node.serializeWithPrefix(s);
319 std::move(s.modData()),
320 node.getHash().as_uint256(),
339 if (!BEAST_EXPECT(fetched))
360 node.serializeWithPrefix(s);
365 node.getHash().as_uint256())};
366 if (!BEAST_EXPECT(nSrc))
370 node.getHash().as_uint256(), ledger.
info().
seq);
371 if (!BEAST_EXPECT(nDst))
374 BEAST_EXPECT(
isSame(nSrc, nDst));
383 node.serializeWithPrefix(s);
388 node.getHash().as_uint256())};
389 if (!BEAST_EXPECT(nSrc))
393 node.getHash().as_uint256(), ledger.
info().
seq);
394 if (!BEAST_EXPECT(nDst))
397 BEAST_EXPECT(
isSame(nSrc, nDst));
415 if (bitmask & (1ll << i))
434 using namespace test::jtx;
441 "max_historical_shards",
473 auto end = start + timeout;
475 !boost::icl::contains(rs, shardIndex))
489 int maxShardNumber = 1,
490 int ledgerOffset = 0)
496 auto const ledgerSeq{
498 if (!BEAST_EXPECT(ledgerSeq != boost::none))
507 BEAST_EXPECT(
saveLedger(db, *data.ledgers_[arrInd]));
515 s.
addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8);
528 testcase(
"Standalone");
530 using namespace test::jtx;
541 BEAST_EXPECT(db->ledgersPerShard() == db->ledgersPerShardDefault);
542 BEAST_EXPECT(db->init());
551 BEAST_EXPECT(db->getRootDir().string() == shardDir.
path());
557 testcase(
"Create shard");
559 using namespace test::jtx;
567 if (!BEAST_EXPECT(data.makeLedgers(env)))
580 testcase(
"Reopen shard store");
582 using namespace test::jtx;
591 if (!BEAST_EXPECT(data.makeLedgers(env)))
604 if (!BEAST_EXPECT(data.makeLedgers(env)))
618 testcase(
"Get complete shards");
620 using namespace test::jtx;
628 if (!BEAST_EXPECT(data.makeLedgers(env)))
638 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
640 bitMask |= 1ll << *n;
648 testcase(
"Prepare shards");
650 using namespace test::jtx;
658 if (!BEAST_EXPECT(data.makeLedgers(env)))
667 if (bitMask & (1ll << n))
670 bitMask &= ~(1ll << n);
697 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
699 bitMask2 |= 1ll << *n;
702 BEAST_EXPECT((bitMask & bitMask2) == 0);
703 if ((bitMask | bitMask2) == ((1ll <<
nTestShards) - 1) << 1)
716 testcase(
"Import shard");
718 using namespace test::jtx;
728 if (!BEAST_EXPECT(data.makeLedgers(env)))
737 data.ledgers_.clear();
740 boost::filesystem::path importPath(importDir.
path());
749 if (!BEAST_EXPECT(data.makeLedgers(env)))
755 using namespace boost::filesystem;
765 if (!BEAST_EXPECT(n && *n == 1))
776 testcase(
"Corrupted shard store");
778 using namespace test::jtx;
788 if (!BEAST_EXPECT(data.makeLedgers(env)))
796 boost::filesystem::path path = shardDir.
path();
800 FILE* f = fopen(path.string().c_str(),
"r+b");
801 if (!BEAST_EXPECT(f))
805 BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256);
814 if (!BEAST_EXPECT(data.makeLedgers(env)))
829 testcase(
"Illegal finalKey");
831 using namespace test::jtx;
833 for (
int i = 0; i < 5; ++i)
842 if (!BEAST_EXPECT(data.makeLedgers(env)))
848 auto const ledgerSeq{
850 if (!BEAST_EXPECT(ledgerSeq != boost::none))
856 BEAST_EXPECT(
saveLedger(*db, *data.ledgers_[arrInd]));
865 data.ledgers_[arrInd - (i == 4)]
882 boost::filesystem::path path(shardDir.
path());
884 boost::system::error_code ec;
888 boost::filesystem::exists(path, ec))
905 if (!BEAST_EXPECT(data.makeLedgers(env)))
927 testcase(
"Import node store");
929 using namespace test::jtx;
936 Database& ndb = env.app().getNodeStore();
940 if (!BEAST_EXPECT(data.makeLedgers(env)))
944 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
958 if (!BEAST_EXPECT(data.makeLedgers(env)))
974 testcase(
"Import with historical paths");
976 using namespace test::jtx;
986 historicalDirs.
begin(),
987 historicalDirs.
end(),
988 historicalPaths.
begin(),
994 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
996 {historicalPaths[0].string(),
997 historicalPaths[1].
string(),
998 historicalPaths[2].
string(),
999 historicalPaths[3].
string()});
1001 Env env{*
this, std::move(c)};
1003 Database& ndb = env.app().getNodeStore();
1006 auto const ledgerCount = 4;
1008 TestData data(seedValue, 4, ledgerCount);
1009 if (!BEAST_EXPECT(data.makeLedgers(env)))
1013 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1024 boost::filesystem::directory_iterator(shardDir.
path()),
1025 boost::filesystem::directory_iterator());
1029 BEAST_EXPECT(mainPathCount == 2);
1032 historicalPaths.
begin(),
1033 historicalPaths.
end(),
1035 [](
int const sum, boost::filesystem::path
const& path) {
1038 boost::filesystem::directory_iterator(path),
1039 boost::filesystem::directory_iterator());
1044 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1056 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1057 historyPaths.append({historicalDir.
path()});
1059 Env env{*
this, std::move(c)};
1061 Database& ndb = env.app().getNodeStore();
1064 auto const ledgerCount = 4;
1066 TestData data(seedValue * 2, 4, ledgerCount);
1067 if (!BEAST_EXPECT(data.makeLedgers(env)))
1071 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1082 boost::filesystem::directory_iterator(shardDir.
path()),
1083 boost::filesystem::directory_iterator());
1087 BEAST_EXPECT(mainPathCount == 2);
1090 boost::filesystem::directory_iterator(historicalDir.
path()),
1091 boost::filesystem::directory_iterator());
1095 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1102 testcase(
"Prepare with historical paths");
1104 using namespace test::jtx;
1114 historicalDirs.
begin(),
1115 historicalDirs.
end(),
1116 historicalPaths.
begin(),
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()});
1129 Env env{*
this, std::move(c)};
1133 auto const ledgerCount = 4;
1135 TestData data(seedValue, 4, ledgerCount);
1136 if (!BEAST_EXPECT(data.makeLedgers(env)))
1146 if (!BEAST_EXPECT(n && *n >= 1 && *n <= ledgerCount))
1148 bitMask |= 1ll << *n;
1154 boost::filesystem::directory_iterator(shardDir.
path()),
1155 boost::filesystem::directory_iterator());
1159 BEAST_EXPECT(mainPathCount == 2);
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());
1169 BEAST_EXPECT(mainPathShards == actual);
1171 const auto generateHistoricalStems = [&historicalPaths, &actual] {
1172 for (
auto const& path : historicalPaths)
1174 for (
auto const& shard :
1175 boost::filesystem::directory_iterator(path))
1177 actual.
insert(boost::filesystem::path(shard).stem());
1186 historicalPathShards, historicalPathShards.
begin()),
1188 [n = 1]()
mutable { return std::to_string(n++); });
1190 generateHistoricalStems();
1192 BEAST_EXPECT(historicalPathShards == actual);
1195 historicalPaths.
begin(),
1196 historicalPaths.
end(),
1198 [](
int const sum, boost::filesystem::path
const& path) {
1201 boost::filesystem::directory_iterator(path),
1202 boost::filesystem::directory_iterator());
1207 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1209 data =
TestData(seedValue * 2, 4, ledgerCount);
1210 if (!BEAST_EXPECT(data.makeLedgers(env, ledgerCount)))
1217 auto n =
createShard(data, *db, ledgerCount * 2, ledgerCount);
1219 n && *n >= 1 + ledgerCount && *n <= ledgerCount * 2))
1221 bitMask |= 1ll << *n;
1227 boost::filesystem::directory_iterator(shardDir.
path()),
1228 boost::filesystem::directory_iterator());
1232 BEAST_EXPECT(mainPathCount == 2);
1236 shardDir.
path() / boost::filesystem::path(
"7"),
1237 shardDir.
path() / boost::filesystem::path(
"8")};
1239 boost::filesystem::directory_iterator(shardDir.
path()),
1240 boost::filesystem::directory_iterator()};
1242 BEAST_EXPECT(mainPathShards == actual);
1245 historicalPathShards.
clear();
1248 historicalPathShards, historicalPathShards.
begin()),
1250 [n = 1]()
mutable { return std::to_string(n++); });
1252 generateHistoricalStems();
1254 BEAST_EXPECT(historicalPathShards == actual);
1257 historicalPaths.
begin(),
1258 historicalPaths.
end(),
1260 [](
int const sum, boost::filesystem::path
const& path) {
1263 boost::filesystem::directory_iterator(path),
1264 boost::filesystem::directory_iterator());
1269 BEAST_EXPECT(historicalPathCount == (ledgerCount * 2) - 2);
1276 testcase(
"Open shard management");
1278 using namespace test::jtx;
1283 auto shardStore{env.app().getShardStore()};
1284 BEAST_EXPECT(shardStore);
1291 TestData data(seedValue, 2, numShards);
1292 if (!BEAST_EXPECT(data.makeLedgers(env)))
1295 BEAST_EXPECT(shardStore->getCompleteShards().empty());
1297 int oldestShardIndex{-1};
1299 for (
auto i = 0; i < numShards; ++i)
1301 auto shardIndex{
createShard(data, *shardStore, numShards)};
1303 shardIndex && *shardIndex >= 1 && *shardIndex <= numShards))
1306 bitMask |= (1ll << *shardIndex);
1308 if (oldestShardIndex == -1)
1309 oldestShardIndex = *shardIndex;
1314 shardStore->sweep();
1317 auto const ledgerSeq{shardStore->lastLedgerSeq(oldestShardIndex)};
1319 BEAST_EXPECT(shardStore->fetchNodeObject(
1320 data.ledgers_[index]->info().hash, ledgerSeq));