Expand clears

This commit is contained in:
2024-05-29 17:45:23 -07:00
parent dab6929e88
commit 887f400a47

View File

@@ -75,11 +75,12 @@ namespace weaselab {
constexpr int kPathLengthUpperBound = 96;
struct Entry {
// If there is a point mutation at key, then pointVersion is its version.
// Otherwise it's negative.
// If there is a point mutation at key, then pointVersion is >= 0 and key has
// not been modified since pointVersion. Otherwise it's negative.
int64_t pointVersion;
// If there is a range mutation ending at key, then rangeVersion is its
// version. Otherwise it's negative.
// If there is a range mutation ending at key, then rangeVersion is >= 0 and
// the range has not been modified since rangeVersion. Otherwise it's
// negative.
int64_t rangeVersion;
int keyLen;
// Negative if this key is cleared. Only meaningful if this is a point
@@ -91,6 +92,7 @@ struct Entry {
// True if the entry is a point mutation. If false, this entry's key should be
// read through to the underlying data structure.
bool pointMutation() const { return pointVersion >= 0; }
bool pointSet() const { return pointVersion >= 0 && valLen >= 0; }
bool pointClear() const { return pointVersion >= 0 && valLen < 0; }
// True if mutations in (pred, this) are cleared. If false, (pred, this)
@@ -388,6 +390,18 @@ auto operator<=>(const VersionedMap::Key &lhs, const Node &rhs) {
return lhs.len <=> rhs.entry->keyLen;
}
auto operator<=>(const weaselab::VersionedMap::Key &lhs,
const weaselab::VersionedMap::Key &rhs) {
int cl = std::min(lhs.len, rhs.len);
if (cl > 0) {
int c = memcmp(lhs.p, rhs.p, cl);
if (c != 0) {
return c <=> 0;
}
}
return lhs.len <=> rhs.len;
}
constexpr int orderToInt(std::strong_ordering o) {
return o == std::strong_ordering::less ? -1
: o == std::strong_ordering::equal ? 0
@@ -883,10 +897,38 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
insert({m.param1, m.param1Len}, {{m.param2, m.param2Len}}, iter);
} break;
case Clear: {
search<std::memory_order_relaxed>({m.param1, m.param1Len}, latestRoot,
latestVersion, iter);
insert({m.param1, m.param1Len}, {{nullptr, -1}}, iter);
if (m.param2Len > 0) {
// TODO we can avoid some insertions here. Complexity is getting out of
// hand though.
if (m.param2Len == 0) {
search<std::memory_order_relaxed>({m.param1, m.param1Len}, latestRoot,
latestVersion, iter);
insert({m.param1, m.param1Len}, {{nullptr, -1}}, iter);
const bool engulfLeft = mm.base[iter.backNode()].entry->clearTo();
move<std::memory_order_relaxed, true>(iter, latestVersion);
const auto *next = iter.searchPathSize() > 0
? mm.base[iter.backNode()].entry
: nullptr;
if (engulfLeft && next && next->clearTo()) {
insert({next->getKey(), next->keyLen}, {}, iter);
move<std::memory_order_relaxed, false>(iter, latestVersion);
remove(iter);
}
} else {
search<std::memory_order_relaxed>({m.param1, m.param1Len}, latestRoot,
latestVersion, iter);
insert({m.param1, m.param1Len}, {{nullptr, -1}}, iter);
// Check if we can engulf on the left
{
const auto *entry = mm.base[iter.backNode()].entry;
if (entry->clearTo()) {
remove(iter);
}
}
move<std::memory_order_relaxed, true>(iter, latestVersion);
while (iter.searchPathSize() > 0 &&
mm.base[iter.backNode()] < Key{m.param2, m.param2Len}) {
@@ -898,6 +940,20 @@ struct __attribute__((__visibility__("hidden"))) VersionedMap::Impl {
search<std::memory_order_relaxed>({m.param2, m.param2Len}, latestRoot,
latestVersion, iter);
insert({m.param2, m.param2Len}, {}, iter);
// Check if we can engulf on the right
{
const auto *entry = mm.base[iter.backNode()].entry;
move<std::memory_order_relaxed, true>(iter, latestVersion);
const auto *next = iter.searchPathSize() > 0
? mm.base[iter.backNode()].entry
: nullptr;
if (entry->pointClear() && next && next->clearTo()) {
insert({next->getKey(), next->keyLen}, {}, iter);
move<std::memory_order_relaxed, false>(iter, latestVersion);
remove(iter);
}
}
}
} break;
default: // GCOVR_EXCL_LINE
@@ -1066,17 +1122,14 @@ void materializeMutations(VersionedMap::Iterator::Impl *impl, const Entry *prev,
impl->mutations[impl->mutationCount++] = {
prev->getKey(),
entry.getKey(),
prev->pointClear() && prev->pointVersion == entry.rangeVersion
? prev->keyLen
: prev->keyLen + 1,
prev->pointClear() ? prev->keyLen : prev->keyLen + 1,
entry.keyLen,
VersionedMap::Clear,
entry.rangeVersion};
}
if (entry.pointMutation()) {
if (entry.valLen < 0 /* pointClear */) {
if (next == nullptr ||
!(next->clearTo() && next->rangeVersion == entry.pointVersion)) {
if (next == nullptr || !next->clearTo()) {
impl->mutations[impl->mutationCount++] = {
entry.getKey(), nullptr, entry.keyLen, 0,
VersionedMap::Clear, entry.pointVersion};
@@ -1176,8 +1229,18 @@ bool VersionedMap::Iterator::operator==(const Iterator &other) const {
return impl->equals(*other.impl);
}
void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
Iterator *iterator, int count) const {
bool geq(const VersionedMap::Iterator::VersionedMutation &m,
const VersionedMap::Key &k) {
if (m.type == VersionedMap::Set || m.param2Len == 0) {
return VersionedMap::Key{m.param1, m.param1Len} >= k;
} else {
return VersionedMap::Key{m.param2, m.param2Len} > k;
}
}
void VersionedMap::Impl::firstGeq(const weaselab::VersionedMap::Key *key,
const int64_t *version, Iterator *iterator,
int count) const {
// TODO ILP!
auto handle = roots.getThreadSafeHandle();
for (int i = 0; i < count; ++i) {
@@ -1197,17 +1260,11 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
Finger &finger = iterator[i].impl->finger;
search<std::memory_order_acquire>(key[i], root, version[i], finger);
bool exact;
if (finger.searchPathSize() == 0) {
exact = false;
} else if (finger.backNode() == 0) {
exact = false;
if (finger.searchPathSize() > 0 && finger.backNode() == 0) {
move<std::memory_order_acquire, true>(finger, version[i]);
if (finger.searchPathSize() > 0) {
assert(finger.backNode() != 0);
}
} else {
exact = true;
}
iterator[i].impl->version = version[i];
@@ -1227,10 +1284,18 @@ void VersionedMap::Impl::firstGeq(const Key *key, const int64_t *version,
iterator[i].impl->map->move<std::memory_order_acquire, true>(
finger, iterator[i].impl->version);
}
if (exact) {
iterator[i].impl->mutationIndex = iterator[i].impl->mutationCount - 1;
if (iterator[i].impl->mutationCount == 0) {
assert(finger.searchPathSize() == 0);
} else {
iterator[i].impl->mutationIndex = 0;
[[maybe_unused]] bool match = false;
for (int j = 0; j < iterator[i].impl->mutationCount; ++j) {
if (geq(iterator[i].impl->mutations[j], key[i])) {
iterator[i].impl->mutationIndex = j;
match = true;
break;
}
}
assert(match);
}
}
}