|
|
|
@@ -5347,6 +5347,11 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|
|
|
|
gc_iterations_total.add(set_oldest_iterations_accum);
|
|
|
|
|
if (n == nullptr) {
|
|
|
|
|
removalKey = {};
|
|
|
|
|
if (removalBufferSize > kMaxRemovalBufferSize) {
|
|
|
|
|
safe_free(removalBuffer, removalBufferSize);
|
|
|
|
|
removalBufferSize = kMinRemovalBufferSize;
|
|
|
|
|
removalBuffer = (uint8_t *)safe_malloc(removalBufferSize);
|
|
|
|
|
}
|
|
|
|
|
oldestExtantVersion = oldestVersionAtGcBegin;
|
|
|
|
|
oldest_extant_version.set(oldestExtantVersion);
|
|
|
|
|
oldestVersionAtGcBegin = oldestVersionFullPrecision;
|
|
|
|
@@ -5357,12 +5362,47 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|
|
|
|
oldestExtantVersion, oldestVersionAtGcBegin);
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
removalKeyArena = Arena();
|
|
|
|
|
removalKey = getSearchPath(removalKeyArena, n);
|
|
|
|
|
// Store the current search path to resume the scan later
|
|
|
|
|
saveRemovalKey(n);
|
|
|
|
|
}
|
|
|
|
|
return fuel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void saveRemovalKey(Node *n) {
|
|
|
|
|
uint8_t *cursor = removalBuffer + removalBufferSize;
|
|
|
|
|
int size = 0;
|
|
|
|
|
auto reserve = [&](int delta) {
|
|
|
|
|
if (size + delta > removalBufferSize) [[unlikely]] {
|
|
|
|
|
int newBufSize = std::max(removalBufferSize * 2, size + delta);
|
|
|
|
|
uint8_t *newBuf = (uint8_t *)safe_malloc(newBufSize);
|
|
|
|
|
memcpy(newBuf + newBufSize - size, cursor, size);
|
|
|
|
|
safe_free(removalBuffer, removalBufferSize);
|
|
|
|
|
removalBuffer = newBuf;
|
|
|
|
|
removalBufferSize = newBufSize;
|
|
|
|
|
cursor = newBuf + newBufSize - size;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
for (;;) {
|
|
|
|
|
auto partialKey = TrivialSpan{n->partialKey(), n->partialKeyLen};
|
|
|
|
|
reserve(partialKey.size());
|
|
|
|
|
size += partialKey.size();
|
|
|
|
|
cursor -= partialKey.size();
|
|
|
|
|
memcpy(cursor, partialKey.data(), partialKey.size());
|
|
|
|
|
|
|
|
|
|
if (n->parent == nullptr) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reserve(1);
|
|
|
|
|
++size;
|
|
|
|
|
--cursor;
|
|
|
|
|
*cursor = n->parentsIndex;
|
|
|
|
|
|
|
|
|
|
n = n->parent;
|
|
|
|
|
}
|
|
|
|
|
removalKey = {cursor, size};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setOldestVersion(int64_t newOldestVersion) {
|
|
|
|
|
assert(newOldestVersion >= 0);
|
|
|
|
|
assert(newOldestVersion <= newestVersionFullPrecision);
|
|
|
|
@@ -5413,7 +5453,7 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|
|
|
|
writeContext.~WriteContext();
|
|
|
|
|
new (&writeContext) WriteContext();
|
|
|
|
|
|
|
|
|
|
removalKeyArena = Arena{};
|
|
|
|
|
// Leave removalBuffer as is
|
|
|
|
|
removalKey = {};
|
|
|
|
|
keyUpdates = 10;
|
|
|
|
|
|
|
|
|
@@ -5445,11 +5485,16 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
|
|
|
|
~Impl() {
|
|
|
|
|
eraseTree(root, &writeContext);
|
|
|
|
|
safe_free(metrics, metricsCount * sizeof(metrics[0]));
|
|
|
|
|
safe_free(removalBuffer, removalBufferSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteContext writeContext;
|
|
|
|
|
|
|
|
|
|
Arena removalKeyArena;
|
|
|
|
|
static constexpr int kMinRemovalBufferSize = 1 << 10;
|
|
|
|
|
// Eventually downsize if larger than this value
|
|
|
|
|
static constexpr int kMaxRemovalBufferSize = 1 << 16;
|
|
|
|
|
uint8_t *removalBuffer = (uint8_t *)safe_malloc(kMinRemovalBufferSize);
|
|
|
|
|
int removalBufferSize = kMinRemovalBufferSize;
|
|
|
|
|
TrivialSpan removalKey;
|
|
|
|
|
int64_t keyUpdates;
|
|
|
|
|
|
|
|
|
|