Files
conflict-set/HashTable.cpp
Andrew Noyes 2b1c710953
All checks were successful
Tests / Clang total: 1533, passed: 1533
Clang |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Debug total: 1531, passed: 1531
Tests / SIMD fallback total: 1533, passed: 1533
Tests / Release [gcc] total: 1533, passed: 1533
GNU C Compiler (gcc) |Total|New|Outstanding|Fixed|Trend |:-:|:-:|:-:|:-:|:-: |0|0|0|0|:clap:
Tests / Release [gcc,aarch64] total: 1144, passed: 1144
Tests / Coverage total: 1151, passed: 1151
Code Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 98.81% (1739/1760) * Branch Coverage: 64.01% (1526/2384) * Complexity Density: 0.00 * Lines of Code: 1760 #### Quality Gates Summary Output truncated.
weaselab/conflict-set/pipeline/head This commit looks good
Add noop getMetricsV1 to HashTable.cpp
2024-07-19 11:25:12 -07:00

162 lines
4.8 KiB
C++

#include "ConflictSet.h"
#include "Internal.h"
#include <functional>
#include <string>
#include <unordered_map>
// This implementation isn't correct for range queries :). It's just intended as
// a reference for performance comparison with point queries.
// struct is from "https://www.cppstories.com/2021/heterogeneous-access-cpp20/"
struct string_hash {
using is_transparent = void;
[[nodiscard]] size_t operator()(std::string_view txt) const {
return std::hash<std::string_view>{}(txt);
}
[[nodiscard]] size_t operator()(const std::string &txt) const {
return std::hash<std::string>{}(txt);
}
};
struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
Impl(int64_t oldestVersion) : oldestVersion(oldestVersion) {}
void check(const ConflictSet::ReadRange *reads, ConflictSet::Result *results,
int count) const {
for (int i = 0; i < count; ++i) {
auto key =
std::string_view((const char *)reads[i].begin.p, reads[i].begin.len);
auto version = reads[i].readVersion;
if (version < oldestVersion) {
results[i] = TooOld;
continue;
}
auto iter = map.find(key);
results[i] =
iter == map.end() || iter->second <= version ? Commit : Conflict;
}
}
void addWrites(const ConflictSet::WriteRange *writes, int count,
int64_t writeVersion) {
for (int i = 0; i < count; ++i) {
auto &max = map[std::string((const char *)writes[i].begin.p,
writes[i].begin.len)];
assert(writeVersion >= max);
max = writeVersion;
keyUpdates += 2;
}
}
void setOldestVersion(int64_t oldestVersion) {
if (oldestVersion <= this->oldestVersion) {
return;
}
this->oldestVersion = oldestVersion;
if (keyUpdates < 100) {
return;
}
auto iter = map.find(removalKey);
while (keyUpdates > 0) {
if (iter == map.end()) {
iter = map.begin();
}
for (; iter != map.end(); --keyUpdates) {
if (iter->second <= oldestVersion) {
iter = map.erase(iter);
} else {
++iter;
}
}
}
if (iter == map.end()) {
removalKey.clear();
} else {
removalKey = iter->first;
}
}
private:
int64_t keyUpdates = 0;
int64_t oldestVersion;
std::unordered_map<std::string, int64_t, string_hash, std::equal_to<>> map;
std::string removalKey;
};
void ConflictSet::check(const ReadRange *reads, Result *results,
int count) const {
return impl->check(reads, results, count);
}
void ConflictSet::addWrites(const WriteRange *writes, int count,
int64_t writeVersion) {
return impl->addWrites(writes, count, writeVersion);
}
void ConflictSet::setOldestVersion(int64_t oldestVersion) {
return impl->setOldestVersion(oldestVersion);
}
int64_t ConflictSet::getBytes() const { return -1; }
void ConflictSet::getMetricsV1(MetricsV1 **metrics, int *count) const {
*metrics = nullptr;
*count = 0;
}
double ConflictSet::MetricsV1::getValue() const { return 0; }
ConflictSet::ConflictSet(int64_t oldestVersion)
: impl(new(safe_malloc(sizeof(Impl))) Impl{oldestVersion}) {}
ConflictSet::~ConflictSet() {
if (impl) {
impl->~Impl();
safe_free(impl, sizeof(Impl));
}
}
ConflictSet::ConflictSet(ConflictSet &&other) noexcept
: impl(std::exchange(other.impl, nullptr)) {}
ConflictSet &ConflictSet::operator=(ConflictSet &&other) noexcept {
impl = std::exchange(other.impl, nullptr);
return *this;
}
using ConflictSet_Result = ConflictSet::Result;
using ConflictSet_Key = ConflictSet::Key;
using ConflictSet_ReadRange = ConflictSet::ReadRange;
using ConflictSet_WriteRange = ConflictSet::WriteRange;
extern "C" {
__attribute__((__visibility__("default"))) void
ConflictSet_check(void *cs, const ConflictSet_ReadRange *reads,
ConflictSet_Result *results, int count) {
((ConflictSet::Impl *)cs)->check(reads, results, count);
}
__attribute__((__visibility__("default"))) void
ConflictSet_addWrites(void *cs, const ConflictSet_WriteRange *writes, int count,
int64_t writeVersion) {
((ConflictSet::Impl *)cs)->addWrites(writes, count, writeVersion);
}
__attribute__((__visibility__("default"))) void
ConflictSet_setOldestVersion(void *cs, int64_t oldestVersion) {
((ConflictSet::Impl *)cs)->setOldestVersion(oldestVersion);
}
__attribute__((__visibility__("default"))) void *
ConflictSet_create(int64_t oldestVersion) {
return new (safe_malloc(sizeof(ConflictSet::Impl)))
ConflictSet::Impl{oldestVersion};
}
__attribute__((__visibility__("default"))) void ConflictSet_destroy(void *cs) {
using Impl = ConflictSet::Impl;
((Impl *)cs)->~Impl();
safe_free(cs, sizeof(Impl));
}
__attribute__((__visibility__("default"))) int64_t
ConflictSet_getBytes(void *cs) {
using Impl = ConflictSet::Impl;
return -1;
}
}