Add ApiTest.cpp
This commit is contained in:
132
VersionedMap.cpp
132
VersionedMap.cpp
@@ -427,33 +427,32 @@ struct Finger {
|
||||
|
||||
void setSearchPathSizeUnsafe(int size) { searchPathSize_ = size; }
|
||||
|
||||
Finger() : searchPathSize_(0) {}
|
||||
Finger() { clear(); }
|
||||
|
||||
Finger(const Finger &other) {
|
||||
void clear() {
|
||||
#ifndef NDEBUG
|
||||
memset(searchPath, 0, sizeof(searchPath));
|
||||
memset(direction, 0, sizeof(direction));
|
||||
#endif
|
||||
memcpy(searchPath, other.searchPath,
|
||||
other.searchPathSize_ * sizeof(searchPath[0]));
|
||||
memcpy(direction, other.direction,
|
||||
other.searchPathSize_ * sizeof(direction[0]));
|
||||
searchPathSize_ = other.searchPathSize_;
|
||||
searchPathSize_ = 0;
|
||||
}
|
||||
|
||||
Finger &operator=(const Finger &other) {
|
||||
void copyTo(Finger &result) {
|
||||
#ifndef NDEBUG
|
||||
memset(searchPath, 0, sizeof(searchPath));
|
||||
memset(direction, 0, sizeof(direction));
|
||||
memset(result.searchPath, 0, sizeof(searchPath));
|
||||
memset(result.direction, 0, sizeof(direction));
|
||||
#endif
|
||||
memcpy(searchPath, other.searchPath,
|
||||
other.searchPathSize_ * sizeof(searchPath[0]));
|
||||
memcpy(direction, other.direction,
|
||||
other.searchPathSize_ * sizeof(direction[0]));
|
||||
searchPathSize_ = other.searchPathSize_;
|
||||
return *this;
|
||||
memcpy(result.searchPath, searchPath,
|
||||
searchPathSize_ * sizeof(searchPath[0]));
|
||||
memcpy(result.direction, direction, searchPathSize_ * sizeof(direction[0]));
|
||||
result.searchPathSize_ = searchPathSize_;
|
||||
}
|
||||
|
||||
Finger(const Finger &) = delete;
|
||||
Finger &operator=(const Finger &) = delete;
|
||||
Finger(Finger &&) = delete;
|
||||
Finger &operator=(Finger &&) = delete;
|
||||
|
||||
private:
|
||||
uint32_t searchPath[kPathLengthUpperBound];
|
||||
bool direction[kPathLengthUpperBound];
|
||||
@@ -483,6 +482,7 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
|
||||
template <std::memory_order kOrder>
|
||||
uint32_t child(uint32_t node, bool which, int64_t at) const {
|
||||
assert(node != 0);
|
||||
static_assert(kOrder == std::memory_order_acquire ||
|
||||
kOrder == std::memory_order_relaxed);
|
||||
auto &n = mm.base[node];
|
||||
@@ -579,11 +579,11 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
};
|
||||
|
||||
template <std::memory_order kOrder, class T>
|
||||
Finger search(Key key, T root, int64_t version) const {
|
||||
void search(Key key, T root, int64_t version, Finger &finger) const {
|
||||
finger.clear();
|
||||
static_assert(std::is_same_v<T, uint32_t>);
|
||||
Finger finger;
|
||||
if (root == 0) {
|
||||
return finger;
|
||||
return;
|
||||
}
|
||||
bool ignored;
|
||||
finger.push(root, ignored);
|
||||
@@ -601,7 +601,6 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
}
|
||||
finger.push(child<kOrder>(n, c > 0, version), c > 0);
|
||||
}
|
||||
return finger;
|
||||
}
|
||||
|
||||
// If `val` is set, then this is a point mutation at `latestVersion`.
|
||||
@@ -633,7 +632,8 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
if (val.has_value()) {
|
||||
pointVersion = latestVersion;
|
||||
if (inserted) {
|
||||
auto copy = finger;
|
||||
Finger copy;
|
||||
finger.copyTo(copy);
|
||||
move<std::memory_order_relaxed>(copy, latestVersion, true);
|
||||
if (copy.searchPathSize() == 0) {
|
||||
rangeVersion = -1;
|
||||
@@ -694,6 +694,16 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
// entry.
|
||||
void remove(Finger &finger) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
uint32_t expected;
|
||||
{
|
||||
Finger copy;
|
||||
finger.copyTo(copy);
|
||||
move<std::memory_order_relaxed>(copy, latestVersion, true);
|
||||
expected = copy.searchPathSize() > 0 ? copy.backNode() : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// True if finger is pointing to an entry > than the entry we're removing
|
||||
// after we rotate it down
|
||||
bool greaterThan;
|
||||
@@ -743,7 +753,7 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
}
|
||||
finger.setSearchPathSizeUnsafe(oldSize);
|
||||
|
||||
if (greaterThan) {
|
||||
if (greaterThan && finger.backNode() != 0) {
|
||||
uint32_t c;
|
||||
while ((c = child<std::memory_order_relaxed>(finger.backNode(), false,
|
||||
latestVersion)) != 0) {
|
||||
@@ -753,10 +763,11 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
move<std::memory_order_relaxed>(finger, latestVersion, true);
|
||||
}
|
||||
|
||||
if (finger.backNode() == 0) {
|
||||
finger.pop();
|
||||
assert(finger.searchPathSize() == 0);
|
||||
#ifndef NDEBUG
|
||||
if (finger.searchPathSize() > 0) {
|
||||
assert(finger.backNode() == expected);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t newNode(int64_t version, int64_t rangeVersion, const uint8_t *key,
|
||||
@@ -802,8 +813,9 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
|
||||
case Clear: {
|
||||
insert({m.param1, m.param1Len}, {{nullptr, -1}});
|
||||
if (m.param2Len > 0) {
|
||||
auto iter = search<std::memory_order_relaxed>(
|
||||
{m.param1, m.param1Len}, latestRoot, latestVersion);
|
||||
Finger iter;
|
||||
search<std::memory_order_relaxed>({m.param1, m.param1Len}, latestRoot,
|
||||
latestVersion, iter);
|
||||
move<std::memory_order_relaxed>(iter, latestVersion, true);
|
||||
while (iter.searchPathSize() > 0 &&
|
||||
mm.base[iter.backNode()] < Key{m.param2, m.param2Len}) {
|
||||
@@ -881,6 +893,17 @@ struct VersionedMap::Iterator::Impl {
|
||||
int mutationCount;
|
||||
int mutationIndex;
|
||||
VersionedMutation mutations[2];
|
||||
|
||||
void copyTo(Impl &result) {
|
||||
result.cmp = cmp;
|
||||
result.map = map;
|
||||
result.version = version;
|
||||
result.mutationCount = mutationCount;
|
||||
result.mutationIndex = mutationIndex;
|
||||
result.mutations[0] = mutations[0];
|
||||
result.mutations[1] = mutations[1];
|
||||
finger.copyTo(result.finger);
|
||||
}
|
||||
};
|
||||
|
||||
VersionedMap::Iterator::~Iterator() {
|
||||
@@ -891,7 +914,9 @@ VersionedMap::Iterator::~Iterator() {
|
||||
}
|
||||
|
||||
VersionedMap::Iterator::Iterator(const Iterator &other)
|
||||
: impl(new(safe_malloc(sizeof(Impl))) Impl(*other.impl)) {}
|
||||
: impl(new(safe_malloc(sizeof(Impl))) Impl()) {
|
||||
other.impl->copyTo(*impl);
|
||||
}
|
||||
|
||||
VersionedMap::Iterator &
|
||||
VersionedMap::Iterator::operator=(const Iterator &other) {
|
||||
@@ -899,7 +924,8 @@ VersionedMap::Iterator::operator=(const Iterator &other) {
|
||||
impl->~Impl();
|
||||
safe_free(impl, sizeof(*impl));
|
||||
}
|
||||
impl = new (safe_malloc(sizeof(Impl))) Impl(*other.impl);
|
||||
impl = new (safe_malloc(sizeof(Impl))) Impl();
|
||||
other.impl->copyTo(*impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -932,7 +958,8 @@ VersionedMap::Iterator::operator*() const {
|
||||
void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
|
||||
const Entry *next) {
|
||||
if (prev == nullptr) {
|
||||
auto copy = impl->finger;
|
||||
Finger copy;
|
||||
impl->finger.copyTo(copy);
|
||||
impl->map->move<std::memory_order_acquire>(copy, impl->version, false);
|
||||
if (copy.searchPathSize() > 0) {
|
||||
prev = impl->map->mm.base[copy.backNode()].entry;
|
||||
@@ -941,7 +968,8 @@ void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
|
||||
}
|
||||
}
|
||||
if (next == nullptr) {
|
||||
auto copy = impl->finger;
|
||||
Finger copy;
|
||||
impl->finger.copyTo(copy);
|
||||
impl->map->move<std::memory_order_acquire>(copy, impl->version, true);
|
||||
if (copy.searchPathSize() > 0) {
|
||||
next = impl->map->mm.base[copy.backNode()].entry;
|
||||
@@ -1058,7 +1086,8 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
|
||||
iterator[i].impl =
|
||||
new (safe_malloc(sizeof(Iterator::Impl))) Iterator::Impl();
|
||||
}
|
||||
auto finger = search<std::memory_order_acquire>(key[i], root, version[i]);
|
||||
Finger &finger = iterator[i].impl->finger;
|
||||
search<std::memory_order_acquire>(key[i], root, version[i], finger);
|
||||
|
||||
if (finger.searchPathSize() == 0) {
|
||||
iterator[i].impl->cmp = 1;
|
||||
@@ -1072,13 +1101,12 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
|
||||
iterator[i].impl->cmp = 0;
|
||||
}
|
||||
|
||||
iterator[i].impl->finger = finger;
|
||||
iterator[i].impl->version = version[i];
|
||||
iterator[i].impl->map = this;
|
||||
|
||||
const Entry *prev = nullptr;
|
||||
for (;;) {
|
||||
if (iterator[i].impl->finger.searchPathSize() > 0) {
|
||||
if (finger.searchPathSize() > 0) {
|
||||
materializeMutations(iterator[i].impl, prev, nullptr);
|
||||
if (iterator[i].impl->mutationCount > 0) {
|
||||
break;
|
||||
@@ -1086,11 +1114,9 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
prev = iterator[i]
|
||||
.impl->map->mm.base[iterator[i].impl->finger.backNode()]
|
||||
.entry;
|
||||
prev = iterator[i].impl->map->mm.base[finger.backNode()].entry;
|
||||
iterator[i].impl->map->move<std::memory_order_acquire>(
|
||||
iterator[i].impl->finger, iterator[i].impl->version, true);
|
||||
finger, iterator[i].impl->version, true);
|
||||
}
|
||||
if (iterator[i].impl->cmp == 0) {
|
||||
iterator[i].impl->mutationIndex = iterator[i].impl->mutationCount - 1;
|
||||
@@ -1230,6 +1256,8 @@ struct __attribute__((visibility("default"))) PeakPrinter {
|
||||
#ifdef ENABLE_MAIN
|
||||
#include <nanobench.h>
|
||||
|
||||
#include "PrintMutation.h"
|
||||
|
||||
void breakpoint_me() {}
|
||||
|
||||
int main() {
|
||||
@@ -1272,33 +1300,7 @@ int main() {
|
||||
printf("Bytes: %" PRId64 "\n", versionedMap.getBytes());
|
||||
breakpoint_me();
|
||||
for (auto end = versionedMap.end(v); iter != end; ++iter) {
|
||||
const auto &m = *iter;
|
||||
switch (m.type) {
|
||||
case weaselab::VersionedMap::Set:
|
||||
printf("set ");
|
||||
for (int i = 0; i < m.param1Len; ++i) {
|
||||
printf("x%02x", m.param1[i]);
|
||||
}
|
||||
printf(" -> '");
|
||||
for (int i = 0; i < m.param2Len; ++i) {
|
||||
printf("x%02x", m.param2[i]);
|
||||
}
|
||||
printf("' @ %" PRId64 "\n", m.version);
|
||||
break;
|
||||
case weaselab::VersionedMap::Clear:
|
||||
printf("clear [");
|
||||
for (int i = 0; i < m.param1Len; ++i) {
|
||||
printf("x%02x", m.param1[i]);
|
||||
}
|
||||
printf(", ");
|
||||
for (int i = 0; i < m.param2Len; ++i) {
|
||||
printf("x%02x", m.param2[i]);
|
||||
}
|
||||
printf(") @ %" PRId64 "\n", m.version);
|
||||
break;
|
||||
default: // GCOVR_EXCL_LINE
|
||||
__builtin_unreachable(); // GCOVR_EXCL_LINE
|
||||
}
|
||||
printMutation(*iter);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user