Skip to content

Commit

Permalink
Refactor CRDT and Urkel integration; add benchmarking tool
Browse files Browse the repository at this point in the history
- Updated `verifyConsistency` to allow mutable access to CRDT data.
- Enhanced `MapLike` concept to include `insert_or_assign`.
- Refactored CRDT templates to align with the updated `MapLike` concept.
- Improved `UrkelMap` with full transaction handling, proof generation, root hash validation, and iterator implementation.
- Added a comprehensive benchmarking tool `urkel_benchmark.cpp` to test insert, update, delete, and sync operations with performance metrics.
- Introduced handling for directory creation and cleanup in the benchmark.
- Ensured compatibility with hash-based RecordId and custom CRDT setup.
- Added error handling for `UrkelMap` initialization and transactions.
  • Loading branch information
sinkingsugar committed Nov 24, 2024
1 parent 445bf83 commit 7496d29
Show file tree
Hide file tree
Showing 4 changed files with 650 additions and 102 deletions.
9 changes: 5 additions & 4 deletions benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ class CrdtBenchmark {
RecordId rid = record_ids[index];

int field_num = field_dist(rng);
node1.insert_or_update(rid, std::make_pair("field" + std::to_string(field_num), "updated_value_" + std::to_string(updates)));
node1.insert_or_update(rid,
std::make_pair("field" + std::to_string(field_num), "updated_value_" + std::to_string(updates)));
updates++;
}

Expand Down Expand Up @@ -121,11 +122,11 @@ class CrdtBenchmark {
verifyConsistency();
}

void verifyConsistency() const {
void verifyConsistency() {
std::cout << "Verifying consistency between nodes..." << std::endl;

const auto &data1 = node1.get_data();
const auto &data2 = node2.get_data();
auto &data1 = node1.get_data();
auto &data2 = node2.get_data();

bool consistent = (data1.size() == data2.size());

Expand Down
55 changes: 26 additions & 29 deletions crdt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,32 +221,28 @@ template <typename V> constexpr bool operator==(const Record<V> &lhs, const Reco
}

// Concept for map-like containers
template<typename Container, typename Key, typename Value>
template <typename Container, typename Key, typename Value>
concept MapLike = requires(Container c, Key k, Value v) {
typename Container::key_type;
typename Container::mapped_type;
typename Container::value_type;
{ c[k] } -> std::convertible_to<Value&>;
{ c.find(k) } -> std::convertible_to<typename Container::iterator>;
{ c.emplace(k, v) };
{ c.try_emplace(k, v) } -> std::same_as<std::pair<typename Container::iterator, bool>>;
{ c.clear() } -> std::same_as<void>;
{ c.erase(k) };
typename Container::key_type;
typename Container::mapped_type;
typename Container::value_type;
typename Container::iterator;
{ c[k] } -> std::convertible_to<Value &>;
{ c.find(k) } -> std::convertible_to<typename Container::iterator>;
{ c.emplace(k, v) };
{ c.try_emplace(k, v) } -> std::same_as<std::pair<typename Container::iterator, bool>>;
{ c.insert_or_assign(k, v) } -> std::same_as<std::pair<typename Container::iterator, bool>>;
{ c.clear() } -> std::same_as<void>;
{ c.erase(k) };
};

/// Represents the CRDT structure, generic over key (`K`) and value (`V`) types.
template <
typename K,
typename V,
typename MergeContext = void,
MergeRule<K, V, MergeContext> MergeRuleType = DefaultMergeRule<K, V, MergeContext>,
ChangeComparator<K, V> ChangeComparatorType = DefaultChangeComparator<K, V>,
typename SortFunctionType = DefaultSort,
MapLike<K, Record<V>> MapType = CrdtMap<K, Record<V>>
>
template <typename K, typename V, typename MergeContext = void,
MergeRule<K, V, MergeContext> MergeRuleType = DefaultMergeRule<K, V, MergeContext>,
ChangeComparator<K, V> ChangeComparatorType = DefaultChangeComparator<K, V>, typename SortFunctionType = DefaultSort,
MapLike<K, Record<V>> MapType = CrdtMap<K, Record<V>>>
class CRDT : public std::enable_shared_from_this<
CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType>
> {
CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType>> {
public:
// Create a new empty CRDT
// Complexity: O(1)
Expand Down Expand Up @@ -769,7 +765,7 @@ class CRDT : public std::enable_shared_from_this<
return combined_data;
}

constexpr CrdtMap<K, Record<V>> &get_data() { return data_; }
constexpr auto &get_data() { return data_; }

/// Retrieves a pointer to a record if it exists, or nullptr if it doesn't.
///
Expand Down Expand Up @@ -955,7 +951,7 @@ class CRDT : public std::enable_shared_from_this<

// Notice that this will not check if the record is tombstoned! Such check should be done by the caller
constexpr Record<V> &get_or_create_record_unchecked(const K &record_id, bool ignore_parent = false) {
auto [it, inserted] = data_.try_emplace(record_id);
auto [it, inserted] = data_.try_emplace(record_id, Record<V>());
if (inserted && parent_ && !ignore_parent) {
if (auto parent_record = parent_->get_record_ptr(record_id)) {
it->second = *parent_record;
Expand Down Expand Up @@ -998,9 +994,9 @@ class CRDT : public std::enable_shared_from_this<
/// # Returns
///
/// A vector of inverse `Change` objects.
CrdtVector<Change<K, V>>
invert_changes(const CrdtVector<Change<K, V>> &changes,
const CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType> &reference_crdt) const {
CrdtVector<Change<K, V>> invert_changes(
const CrdtVector<Change<K, V>> &changes,
const CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType> &reference_crdt) const {
CrdtVector<Change<K, V>> inverse_changes;

for (const auto &change : changes) {
Expand Down Expand Up @@ -1174,9 +1170,10 @@ class CRDT : public std::enable_shared_from_this<
/// and m is the complexity of merge_changes
template <typename K, typename V, typename MergeContext = void,
MergeRule<K, V, MergeContext> MergeRuleType = DefaultMergeRule<K, V, MergeContext>,
ChangeComparator<K, V> ChangeComparatorType = DefaultChangeComparator<K, V>, typename SortFunctionType = DefaultSort>
constexpr void sync_nodes(CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType> &source,
CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType> &target,
ChangeComparator<K, V> ChangeComparatorType = DefaultChangeComparator<K, V>, typename SortFunctionType = DefaultSort,
MapLike<K, Record<V>> MapType = CrdtMap<K, Record<V>>>
constexpr void sync_nodes(CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType> &source,
CRDT<K, V, MergeContext, MergeRuleType, ChangeComparatorType, SortFunctionType, MapType> &target,
uint64_t &last_db_version) {
auto changes = source.get_changes_since(last_db_version);

Expand Down
Loading

0 comments on commit 7496d29

Please sign in to comment.