Files
natsdotnet/src/NATS.Server/Raft/RaftLog.cs

63 lines
1.8 KiB
C#

namespace NATS.Server.Raft;
public sealed class RaftLog
{
private readonly List<RaftLogEntry> _entries = [];
private long _baseIndex;
public IReadOnlyList<RaftLogEntry> Entries => _entries;
public RaftLogEntry Append(int term, string command)
{
var entry = new RaftLogEntry(_baseIndex + _entries.Count + 1, term, command);
_entries.Add(entry);
return entry;
}
public void AppendReplicated(RaftLogEntry entry)
{
if (_entries.Any(e => e.Index == entry.Index))
return;
_entries.Add(entry);
}
public void ReplaceWithSnapshot(RaftSnapshot snapshot)
{
_entries.Clear();
_baseIndex = snapshot.LastIncludedIndex;
}
public async Task PersistAsync(string path, CancellationToken ct)
{
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
var model = new PersistedLog
{
BaseIndex = _baseIndex,
Entries = [.. _entries],
};
await File.WriteAllTextAsync(path, System.Text.Json.JsonSerializer.Serialize(model), ct);
}
public static async Task<RaftLog> LoadAsync(string path, CancellationToken ct)
{
var log = new RaftLog();
if (!File.Exists(path))
return log;
var json = await File.ReadAllTextAsync(path, ct);
var model = System.Text.Json.JsonSerializer.Deserialize<PersistedLog>(json) ?? new PersistedLog();
log._baseIndex = model.BaseIndex;
log._entries.AddRange(model.Entries);
return log;
}
private sealed class PersistedLog
{
public long BaseIndex { get; set; }
public List<RaftLogEntry> Entries { get; set; } = [];
}
}
public sealed record RaftLogEntry(long Index, int Term, string Command);