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()),
290 node.getType() == SHAMapAbstractNode::TNType::tnINNER
294 node.getNodeHash().as_uint256(),
303 if (next && next->info().parentHash == ledger.
info().
hash)
305 auto have = next->stateMap().snapShot(
false);
314 auto visitTx = [&](SHAMapAbstractNode& node) {
318 node.getType() == SHAMapAbstractNode::TNType::tnINNER
321 std::move(s.modData()),
322 node.getNodeHash().as_uint256(),
341 if (!BEAST_EXPECT(fetched))
364 node.getType() == SHAMapAbstractNode::TNType::tnINNER
368 node.getNodeHash().as_uint256())};
369 if (!BEAST_EXPECT(nSrc))
373 node.getNodeHash().as_uint256(), ledger.
info().
seq);
374 if (!BEAST_EXPECT(nDst))
377 BEAST_EXPECT(
isSame(nSrc, nDst));
388 node.getType() == SHAMapAbstractNode::TNType::tnINNER
392 node.getNodeHash().as_uint256())};
393 if (!BEAST_EXPECT(nSrc))
397 node.getNodeHash().as_uint256(), ledger.
info().
seq);
398 if (!BEAST_EXPECT(nDst))
401 BEAST_EXPECT(
isSame(nSrc, nDst));
419 if (bitmask & (1ll << i))
438 using namespace test::jtx;
445 "max_historical_shards",
477 auto end = start + timeout;
479 !boost::icl::contains(rs, shardIndex))
493 int maxShardNumber = 1,
494 int ledgerOffset = 0)
500 auto const ledgerSeq{
502 if (!BEAST_EXPECT(ledgerSeq != boost::none))
511 BEAST_EXPECT(
saveLedger(db, *data.ledgers_[arrInd]));
519 s.
addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8);
532 testcase(
"Standalone");
534 using namespace test::jtx;
545 BEAST_EXPECT(db->ledgersPerShard() == db->ledgersPerShardDefault);
546 BEAST_EXPECT(db->init());
555 BEAST_EXPECT(db->getRootDir().string() == shardDir.
path());
561 testcase(
"Create shard");
563 using namespace test::jtx;
571 if (!BEAST_EXPECT(data.makeLedgers(env)))
584 testcase(
"Reopen shard store");
586 using namespace test::jtx;
595 if (!BEAST_EXPECT(data.makeLedgers(env)))
608 if (!BEAST_EXPECT(data.makeLedgers(env)))
622 testcase(
"Get complete shards");
624 using namespace test::jtx;
632 if (!BEAST_EXPECT(data.makeLedgers(env)))
642 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
644 bitMask |= 1ll << *n;
652 testcase(
"Prepare shards");
654 using namespace test::jtx;
662 if (!BEAST_EXPECT(data.makeLedgers(env)))
671 if (bitMask & (1ll << n))
674 bitMask &= ~(1ll << n);
701 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
703 bitMask2 |= 1ll << *n;
706 BEAST_EXPECT((bitMask & bitMask2) == 0);
707 if ((bitMask | bitMask2) == ((1ll <<
nTestShards) - 1) << 1)
720 testcase(
"Import shard");
722 using namespace test::jtx;
732 if (!BEAST_EXPECT(data.makeLedgers(env)))
741 data.ledgers_.clear();
744 boost::filesystem::path importPath(importDir.
path());
753 if (!BEAST_EXPECT(data.makeLedgers(env)))
759 using namespace boost::filesystem;
769 if (!BEAST_EXPECT(n && *n == 1))
780 testcase(
"Corrupted shard store");
782 using namespace test::jtx;
792 if (!BEAST_EXPECT(data.makeLedgers(env)))
800 boost::filesystem::path path = shardDir.
path();
804 FILE* f = fopen(path.string().c_str(),
"r+b");
805 if (!BEAST_EXPECT(f))
809 BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256);
818 if (!BEAST_EXPECT(data.makeLedgers(env)))
833 testcase(
"Illegal finalKey");
835 using namespace test::jtx;
837 for (
int i = 0; i < 5; ++i)
846 if (!BEAST_EXPECT(data.makeLedgers(env)))
852 auto const ledgerSeq{
854 if (!BEAST_EXPECT(ledgerSeq != boost::none))
860 BEAST_EXPECT(
saveLedger(*db, *data.ledgers_[arrInd]));
869 data.ledgers_[arrInd - (i == 4)]
886 boost::filesystem::path path(shardDir.
path());
888 boost::system::error_code ec;
892 boost::filesystem::exists(path, ec))
909 if (!BEAST_EXPECT(data.makeLedgers(env)))
931 testcase(
"Import node store");
933 using namespace test::jtx;
940 Database& ndb = env.app().getNodeStore();
944 if (!BEAST_EXPECT(data.makeLedgers(env)))
948 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
962 if (!BEAST_EXPECT(data.makeLedgers(env)))
978 testcase(
"Import with historical paths");
980 using namespace test::jtx;
990 historicalDirs.
begin(),
991 historicalDirs.
end(),
992 historicalPaths.
begin(),
998 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1000 {historicalPaths[0].string(),
1001 historicalPaths[1].
string(),
1002 historicalPaths[2].
string(),
1003 historicalPaths[3].
string()});
1005 Env env{*
this, std::move(c)};
1007 Database& ndb = env.app().getNodeStore();
1010 auto const ledgerCount = 4;
1012 TestData data(seedValue, 4, ledgerCount);
1013 if (!BEAST_EXPECT(data.makeLedgers(env)))
1017 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1028 boost::filesystem::directory_iterator(shardDir.
path()),
1029 boost::filesystem::directory_iterator());
1033 BEAST_EXPECT(mainPathCount == 2);
1036 historicalPaths.
begin(),
1037 historicalPaths.
end(),
1039 [](
int const sum, boost::filesystem::path
const& path) {
1042 boost::filesystem::directory_iterator(path),
1043 boost::filesystem::directory_iterator());
1048 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1060 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1061 historyPaths.append({historicalDir.
path()});
1063 Env env{*
this, std::move(c)};
1065 Database& ndb = env.app().getNodeStore();
1068 auto const ledgerCount = 4;
1070 TestData data(seedValue * 2, 4, ledgerCount);
1071 if (!BEAST_EXPECT(data.makeLedgers(env)))
1075 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1086 boost::filesystem::directory_iterator(shardDir.
path()),
1087 boost::filesystem::directory_iterator());
1091 BEAST_EXPECT(mainPathCount == 2);
1094 boost::filesystem::directory_iterator(historicalDir.
path()),
1095 boost::filesystem::directory_iterator());
1099 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1106 testcase(
"Prepare with historical paths");
1108 using namespace test::jtx;
1118 historicalDirs.
begin(),
1119 historicalDirs.
end(),
1120 historicalPaths.
begin(),
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()});
1133 Env env{*
this, std::move(c)};
1137 auto const ledgerCount = 4;
1139 TestData data(seedValue, 4, ledgerCount);
1140 if (!BEAST_EXPECT(data.makeLedgers(env)))
1150 if (!BEAST_EXPECT(n && *n >= 1 && *n <= ledgerCount))
1152 bitMask |= 1ll << *n;
1158 boost::filesystem::directory_iterator(shardDir.
path()),
1159 boost::filesystem::directory_iterator());
1163 BEAST_EXPECT(mainPathCount == 2);
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());
1173 BEAST_EXPECT(mainPathShards == actual);
1175 const auto generateHistoricalStems = [&historicalPaths, &actual] {
1176 for (
auto const& path : historicalPaths)
1178 for (
auto const& shard :
1179 boost::filesystem::directory_iterator(path))
1181 actual.
insert(boost::filesystem::path(shard).stem());
1190 historicalPathShards, historicalPathShards.
begin()),
1192 [n = 1]()
mutable { return std::to_string(n++); });
1194 generateHistoricalStems();
1196 BEAST_EXPECT(historicalPathShards == actual);
1199 historicalPaths.
begin(),
1200 historicalPaths.
end(),
1202 [](
int const sum, boost::filesystem::path
const& path) {
1205 boost::filesystem::directory_iterator(path),
1206 boost::filesystem::directory_iterator());
1211 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1213 data =
TestData(seedValue * 2, 4, ledgerCount);
1214 if (!BEAST_EXPECT(data.makeLedgers(env, ledgerCount)))
1221 auto n =
createShard(data, *db, ledgerCount * 2, ledgerCount);
1223 n && *n >= 1 + ledgerCount && *n <= ledgerCount * 2))
1225 bitMask |= 1ll << *n;
1231 boost::filesystem::directory_iterator(shardDir.
path()),
1232 boost::filesystem::directory_iterator());
1236 BEAST_EXPECT(mainPathCount == 2);
1240 shardDir.
path() / boost::filesystem::path(
"7"),
1241 shardDir.
path() / boost::filesystem::path(
"8")};
1243 boost::filesystem::directory_iterator(shardDir.
path()),
1244 boost::filesystem::directory_iterator()};
1246 BEAST_EXPECT(mainPathShards == actual);
1249 historicalPathShards.
clear();
1252 historicalPathShards, historicalPathShards.
begin()),
1254 [n = 1]()
mutable { return std::to_string(n++); });
1256 generateHistoricalStems();
1258 BEAST_EXPECT(historicalPathShards == actual);
1261 historicalPaths.
begin(),
1262 historicalPaths.
end(),
1264 [](
int const sum, boost::filesystem::path
const& path) {
1267 boost::filesystem::directory_iterator(path),
1268 boost::filesystem::directory_iterator());
1273 BEAST_EXPECT(historicalPathCount == (ledgerCount * 2) - 2);
1280 testcase(
"Open shard management");
1282 using namespace test::jtx;
1287 auto shardStore{env.app().getShardStore()};
1288 BEAST_EXPECT(shardStore);
1295 TestData data(seedValue, 2, numShards);
1296 if (!BEAST_EXPECT(data.makeLedgers(env)))
1299 BEAST_EXPECT(shardStore->getCompleteShards().empty());
1301 int oldestShardIndex{-1};
1303 for (
auto i = 0; i < numShards; ++i)
1305 auto shardIndex{
createShard(data, *shardStore, numShards)};
1307 shardIndex && *shardIndex >= 1 && *shardIndex <= numShards))
1310 bitMask |= (1ll << *shardIndex);
1312 if (oldestShardIndex == -1)
1313 oldestShardIndex = *shardIndex;
1318 shardStore->sweep();
1321 auto const ledgerSeq{shardStore->lastLedgerSeq(oldestShardIndex)};
1323 BEAST_EXPECT(shardStore->fetchNodeObject(
1324 data.ledgers_[index]->info().hash, ledgerSeq));