diff --git a/CRDT.cs b/CRDT.cs
index 98926d3..061c3f1 100644
--- a/CRDT.cs
+++ b/CRDT.cs
@@ -4,6 +4,8 @@
#nullable enable
+using CrdtNodeId = ulong;
+
// Namespace for CRDT implementation
namespace ForSync.CRDT {
///
@@ -52,10 +54,10 @@ public void SetTime(ulong t) {
public struct ColumnVersion {
public ulong ColVersion { get; set; }
public ulong DbVersion { get; set; }
- public ulong NodeId { get; set; }
+ public CrdtNodeId NodeId { get; set; }
public ulong LocalDbVersion { get; set; }
- public ColumnVersion(ulong c, ulong d, ulong n, ulong ldbVer = 0) {
+ public ColumnVersion(ulong c, ulong d, CrdtNodeId n, ulong ldbVer = 0) {
ColVersion = c;
DbVersion = d;
NodeId = n;
@@ -151,14 +153,15 @@ public class Change {
public V? Value { get; set; } // null represents deletion of the column, not the record
public ulong ColVersion { get; set; }
public ulong DbVersion { get; set; }
- public ulong NodeId { get; set; }
+ public CrdtNodeId NodeId { get; set; }
public ulong LocalDbVersion { get; set; }
public Change() {
RecordId = default!;
+ Value = default!;
}
- public Change(K recordId, ColName? colName, V? value, ulong colVersion, ulong dbVersion, ulong nodeId, ulong localDbVersion = 0) {
+ public Change(K recordId, ColName? colName, V? value, ulong colVersion, ulong dbVersion, CrdtNodeId nodeId, ulong localDbVersion = 0) {
RecordId = recordId;
ColName = colName;
Value = value;
@@ -200,7 +203,7 @@ public int Compare(Change? a, Change? b) {
return a.DbVersion > b.DbVersion ? -1 : 1;
if (a.NodeId != b.NodeId)
- return a.NodeId > b.NodeId ? -1 : 1;
+ return a.NodeId.CompareTo(b.NodeId);
return 0; // Consider equal if all fields match
}
@@ -210,7 +213,7 @@ public int Compare(Change? a, Change? b) {
/// Represents the CRDT structure, generic over key (K) and value (V) types.
///
public class CRDT {
- private ulong _nodeId;
+ private CrdtNodeId _nodeId;
private LogicalClock _clock;
private Dictionary> _data;
private HashSet _tombstones;
@@ -218,11 +221,11 @@ public class CRDT {
private CRDT? _parent;
private ulong _baseVersion;
- public ulong NodeId => _nodeId;
+ public CrdtNodeId NodeId => _nodeId;
public ulong Clock => _clock.CurrentTime;
public ulong BaseVersion => _baseVersion;
- public CRDT(ulong nodeId, CRDT? parent = null) {
+ public CRDT(CrdtNodeId nodeId, CRDT? parent = null) {
_nodeId = nodeId;
_clock = new LogicalClock();
_data = new Dictionary>();
@@ -245,7 +248,7 @@ public CRDT(ulong nodeId, CRDT? parent = null) {
///
/// Creates a CRDT from a list of changes (e.g., loaded from disk).
///
- public CRDT(ulong nodeId, List> changes) {
+ public CRDT(CrdtNodeId nodeId, List> changes) {
_nodeId = nodeId;
_clock = new LogicalClock();
_data = new Dictionary>();
@@ -278,7 +281,7 @@ public List> InvertChanges(List> changes, bool usePare
if (colName == null) {
// The change was a record deletion (tombstone)
- Record? recordPtr = useParent ? GetRecordPtr(recordId, true) : GetRecordPtr(recordId);
+ Record? recordPtr = useParent ? GetRecord(recordId, true) : GetRecord(recordId);
if (recordPtr != null) {
// Restore all fields from the record
@@ -304,7 +307,7 @@ public List> InvertChanges(List> changes, bool usePare
} else {
// The change was an insertion or update of a column
ColName col = colName.Value;
- Record? recordPtr = useParent ? GetRecordPtr(recordId, true) : GetRecordPtr(recordId);
+ Record? recordPtr = useParent ? GetRecord(recordId, true) : GetRecord(recordId);
if (recordPtr != null) {
if (recordPtr.Fields.TryGetValue(col, out V existingValue)) {
@@ -497,14 +500,14 @@ public List> MergeChanges(List> changes, bool ignorePa
ColName? colName = change.ColName;
ulong remoteColVersion = change.ColVersion;
ulong remoteDbVersion = change.DbVersion;
- ulong remoteNodeId = change.NodeId;
+ CrdtNodeId remoteNodeId = change.NodeId;
V? remoteValue = change.Value;
// Update the logical clock
ulong newLocalDbVersion = _clock.Update(remoteDbVersion);
// Retrieve local column version information
- Record? recordPtr = GetRecordPtr(recordId, ignoreParent);
+ Record? recordPtr = GetRecord(recordId, ignoreParent);
ColumnVersion? localColInfo = null;
if (recordPtr != null) {
@@ -535,7 +538,7 @@ public List> MergeChanges(List> changes, bool ignorePa
shouldAccept = false;
} else {
// db_version is equal; use node_id for final tiebreaking
- shouldAccept = remoteNodeId > localColInfo.Value.NodeId;
+ shouldAccept = remoteNodeId.CompareTo(localColInfo.Value.NodeId) > 0;
}
}
}
@@ -704,7 +707,7 @@ private void ApplyChanges(List> changes) {
ColName? colName = change.ColName;
ulong remoteColVersion = change.ColVersion;
ulong remoteDbVersion = change.DbVersion;
- ulong remoteNodeId = change.NodeId;
+ CrdtNodeId remoteNodeId = change.NodeId;
ulong remoteLocalDbVersion = change.LocalDbVersion;
V? remoteValue = change.Value;
@@ -757,12 +760,12 @@ private bool IsRecordTombstoned(K recordId, bool ignoreParent = false) {
///
/// Retrieves a record pointer.
///
- private Record? GetRecordPtr(K recordId, bool ignoreParent = false) {
+ public Record? GetRecord(K recordId, bool ignoreParent = false) {
if (_data.TryGetValue(recordId, out Record? record))
return record;
if (_parent != null && !ignoreParent)
- return _parent.GetRecordPtr(recordId);
+ return _parent.GetRecord(recordId);
return null;
}
@@ -775,7 +778,7 @@ private Record GetOrCreateRecordUnchecked(K recordId, bool ignoreParent =
_data[recordId] = new Record();
if (_parent != null && !ignoreParent) {
- Record? parentRecord = _parent.GetRecordPtr(recordId);
+ Record? parentRecord = _parent.GetRecord(recordId);
if (parentRecord != null)
_data[recordId] = new Record(new Dictionary, V>(parentRecord.Fields),
new Dictionary, ColumnVersion>(parentRecord.ColumnVersions));