#include #include #include #include #include #include "negentropy.h" #include "negentropy/storage/Vector.h" #include "negentropy/storage/BTreeMem.h" #include "negentropy/storage/SubRange.h" std::string sha256(std::string_view input) { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256(reinterpret_cast(input.data()), input.size(), hash); return std::string((const char*)&hash[0], SHA256_DIGEST_LENGTH); } std::string uintToId(uint64_t id) { return sha256(std::string((char*)&id, 8)); } template void testSubRange() { T vecBig; T vecSmall; for (size_t i = 0; i < 1000; i++) { vecBig.insert(100 + i, uintToId(i)); } for (size_t i = 400; i < 600; i++) { vecSmall.insert(100 + i, uintToId(i)); } vecBig.seal(); vecSmall.seal(); negentropy::storage::SubRange subRange(vecBig, negentropy::Bound(100 + 400), negentropy::Bound(100 + 600)); if (vecSmall.size() != subRange.size()) throw hoytech::error("size mismatch"); if (vecSmall.fingerprint(0, vecSmall.size()).sv() != subRange.fingerprint(0, subRange.size()).sv()) throw hoytech::error("fingerprint mismatch"); if (vecSmall.getItem(10) != subRange.getItem(10)) throw hoytech::error("getItem mismatch"); if (vecBig.getItem(400 + 10) != subRange.getItem(10)) throw hoytech::error("getItem mismatch"); { auto lb = subRange.findLowerBound(0, subRange.size(), negentropy::Bound(550)); auto lb2 = vecSmall.findLowerBound(0, vecSmall.size(), negentropy::Bound(550)); if (lb != lb2) throw hoytech::error("findLowerBound mismatch"); } { auto lb = subRange.findLowerBound(0, subRange.size(), negentropy::Bound(20)); auto lb2 = vecSmall.findLowerBound(0, vecSmall.size(), negentropy::Bound(20)); if (lb != lb2) throw hoytech::error("findLowerBound mismatch"); } { auto lb = subRange.findLowerBound(0, subRange.size(), negentropy::Bound(5000)); auto lb2 = vecSmall.findLowerBound(0, vecSmall.size(), negentropy::Bound(5000)); if (lb != lb2) throw hoytech::error("findLowerBound mismatch"); } } template void testSync(bool emptySide1, bool emptySide2) { T vecBig; T vecSmall; std::set expectedHave; std::set expectedNeed; size_t const lowerLimit = 20'000; size_t const upperLimit = 90'000; for (size_t i = lowerLimit; i < upperLimit; i++) { auto id = uintToId(i); if (emptySide1 || i % 15'000 == 0) { if (i >= lowerLimit && i < upperLimit) expectedNeed.insert(id); continue; } vecSmall.insert(100 + i, id); } for (size_t i = 0; i < 100'000; i++) { auto id = uintToId(i); if (emptySide2 || i % 22'000 == 0) { if (i >= lowerLimit && i < upperLimit) expectedHave.insert(id); continue; } vecBig.insert(100 + i, id); } // Get rid of common std::set commonItems; for (const auto &item : expectedHave) { if (expectedNeed.contains(item)) commonItems.insert(item); } for (const auto &item : commonItems) { expectedHave.erase(item); expectedNeed.erase(item); } vecBig.seal(); vecSmall.seal(); negentropy::storage::SubRange subRange(vecBig, negentropy::Bound(100 + lowerLimit), negentropy::Bound(100 + upperLimit)); auto ne1 = Negentropy(vecSmall, 20'000); auto ne2 = Negentropy(subRange, 20'000); std::string msg = ne1.initiate(); while (true) { msg = ne2.reconcile(msg); std::vector have, need; auto newMsg = ne1.reconcile(msg, have, need); for (const auto &item : have) { if (!expectedHave.contains(item)) throw hoytech::error("unexpected have: ", hoytech::to_hex(item)); expectedHave.erase(item); } for (const auto &item : need) { if (!expectedNeed.contains(item)) throw hoytech::error("unexpected need: ", hoytech::to_hex(item)); expectedNeed.erase(item); } if (!newMsg) break; else std::swap(msg, *newMsg); } if (expectedHave.size()) throw hoytech::error("missed have"); if (expectedNeed.size()) throw hoytech::error("missed need"); } int main() { testSubRange(); testSubRange(); testSync(false, false); testSync(true, false); testSync(false, true); std::cout << "OK" << std::endl; return 0; }