diff --git a/.clangd b/.clangd index 8ba862b..1b411b0 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,2 @@ CompileFlags: - Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -DTHREAD_TEST, -fexceptions] + Add: [-DENABLE_MAIN, -UNDEBUG, -DENABLE_FUZZ, -DTHREAD_TEST, -fexceptions, -DDEBUG_VERBOSE=1] diff --git a/VersionedMap.cpp b/VersionedMap.cpp index c28e437..eabb043 100644 --- a/VersionedMap.cpp +++ b/VersionedMap.cpp @@ -9,6 +9,10 @@ #include #include +#ifndef DEBUG_VERBOSE +#define DEBUG_VERBOSE 0 +#endif + void *mmapSafe(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { void *result = mmap(addr, len, prot, flags, fd, offset); @@ -254,6 +258,9 @@ struct MemManager { if (newFirstUnaddressable < firstUnaddressable) { for (int i = newFirstUnaddressable; i < firstUnaddressable; ++i) { if (base[i].entry != nullptr) { +#if DEBUG_VERBOSE + printf("Collecting %u\n", i); +#endif base[i].entry->delref(); } } @@ -269,6 +276,9 @@ struct MemManager { reachable.iterateAbsentApproxBackwards( [&](uint32_t i) { if (base[i].entry != nullptr) { +#if DEBUG_VERBOSE + printf("Collecting %u\n", i); +#endif base[i].entry->delref(); base[i].entry = nullptr; } @@ -311,7 +321,7 @@ struct RootSet { /// Inform that there will be no calls to rootForVersion with a version less /// than `oldestVersion` void setOldestVersion(int64_t oldestVersion) { - const uint32_t firstToKeep = rootForVersion(oldestVersion); + const uint32_t firstToKeep = lastLeq(oldestVersion); if (firstToKeep != 0) { memmove(nodes, nodes + firstToKeep, @@ -321,29 +331,12 @@ struct RootSet { end -= firstToKeep; } assert(end > 0); - assert(nodes[0] <= oldestVersion); + assert(versions[0] <= oldestVersion); } /// Get a root node that can correctly be used for `version` uint32_t rootForVersion(int64_t version) const { - assert(end > 0); - assert(nodes[0] <= version); - - // Find the last version <= oldestVersion - int left = 0; - int right = end; - int result = 0; - while (left <= right) { - int mid = left + (right - left) / 2; - if (versions[mid] <= version) { - result = mid; - left = mid + 1; - } else { - right = mid - 1; - } - } - assert(result < end); - return result; + return nodes[lastLeq(version)]; } const uint32_t *roots() const { return nodes; } @@ -364,6 +357,26 @@ struct RootSet { } private: + uint32_t lastLeq(int64_t version) const { + assert(end > 0); + assert(versions[0] <= version); + + // Find the last version <= oldestVersion + int left = 1; + int right = end - 1; + int result = 0; + while (left <= right) { + int mid = left + (right - left) / 2; + if (versions[mid] <= version) { + result = mid; + left = mid + 1; + } else { + right = mid - 1; + } + } + assert(result < end); + return result; + } uint32_t *nodes; // versions[i] is the version of nodes[i] int64_t *versions; @@ -463,6 +476,27 @@ struct VersionedMap::Impl { return result; } + void setOldestVersion(int64_t oldestVersion) { + roots.setOldestVersion(oldestVersion); + mm.gc(roots.roots(), roots.rootCount(), oldestVersion); + } + + void printInOrder(int64_t version) { + printInOrderHelper(version, roots.rootForVersion(version)); + } + + void printInOrderHelper(int64_t version, uint32_t node) { + if (node == 0) { + return; + } + printInOrderHelper(version, + child(node, false, version)); + printf("%.*s\n", (int)mm.base[node].entry->keyLen, + mm.base[node].entry->getKey()); + printInOrderHelper(version, + child(node, true, version)); + } + MemManager mm; RootSet roots; }; @@ -472,6 +506,23 @@ struct VersionedMap::Impl { #include int main() { + + { + weaselab::VersionedMap::Impl impl; + impl.roots.add(impl.newNode(1, (const uint8_t *)"a", 1, nullptr, -1, false), + 1); + impl.roots.add(impl.newNode(2, (const uint8_t *)"b", 1, nullptr, -1, false), + 2); + impl.roots.add(impl.newNode(3, (const uint8_t *)"c", 1, nullptr, -1, false), + 3); + impl.printInOrder(0); + impl.printInOrder(1); + impl.printInOrder(2); + impl.printInOrder(3); + impl.setOldestVersion(3); + } + return 0; + ankerl::nanobench::Bench bench; bench.minEpochIterations(5000); weaselab::MemManager mm;