7404ecdb0e
- Add cached state properties (LastSeq, MessageCount, TotalBytes, FirstSeq) to IStreamStore/FileStore/MemStore — eliminates GetStateAsync on publish path - Add Capture(StreamHandle, ...) overload to StreamManager — eliminates double FindBySubject lookup (once in JetStreamPublisher, once in Capture) - Remove _messageIndexes dictionary from FileStore write path — all lookups now use _messages directly, saving ~48B allocation per message - Add JetStreamPubAckFormatter for hand-rolled UTF-8 success ack formatting — avoids JsonSerializer overhead on the hot publish path - Switch flush loop to exponential backoff (1→2→4→8ms) matching Go server
180 lines
9.9 KiB
C#
180 lines
9.9 KiB
C#
using NATS.Server.JetStream.Models;
|
|
|
|
// Alias for the full Go-parity StreamState in this namespace.
|
|
using StorageStreamState = NATS.Server.JetStream.Storage.StreamState;
|
|
|
|
namespace NATS.Server.JetStream.Storage;
|
|
|
|
// Go: server/store.go:91
|
|
/// <summary>
|
|
/// Abstraction over a single stream's message store.
|
|
/// The async methods (AppendAsync, LoadAsync, …) are used by the current
|
|
/// high-level JetStream layer. The sync methods (StoreMsg, LoadMsg, State, …)
|
|
/// mirror Go's StreamStore interface exactly and will be the primary surface
|
|
/// once the block-engine FileStore implementation lands.
|
|
/// </summary>
|
|
public interface IStreamStore
|
|
{
|
|
// -------------------------------------------------------------------------
|
|
// Async helpers — used by the current JetStream layer
|
|
// -------------------------------------------------------------------------
|
|
|
|
ValueTask<ulong> AppendAsync(string subject, ReadOnlyMemory<byte> payload, CancellationToken ct);
|
|
ValueTask<StoredMessage?> LoadAsync(ulong sequence, CancellationToken ct);
|
|
ValueTask<StoredMessage?> LoadLastBySubjectAsync(string subject, CancellationToken ct);
|
|
ValueTask<IReadOnlyList<StoredMessage>> ListAsync(CancellationToken ct);
|
|
ValueTask<bool> RemoveAsync(ulong sequence, CancellationToken ct);
|
|
ValueTask PurgeAsync(CancellationToken ct);
|
|
ValueTask<byte[]> CreateSnapshotAsync(CancellationToken ct);
|
|
ValueTask RestoreSnapshotAsync(ReadOnlyMemory<byte> snapshot, CancellationToken ct);
|
|
|
|
// Returns Models.StreamState for API-layer JSON serialisation compatibility.
|
|
// Existing MemStore/FileStore implementations return this type.
|
|
ValueTask<ApiStreamState> GetStateAsync(CancellationToken ct);
|
|
|
|
// Cached state properties — avoid GetStateAsync on the publish hot path.
|
|
// These are maintained incrementally by FileStore/MemStore and are O(1).
|
|
ulong LastSeq => throw new NotSupportedException("LastSeq not implemented.");
|
|
ulong MessageCount => throw new NotSupportedException("MessageCount not implemented.");
|
|
ulong TotalBytes => throw new NotSupportedException("TotalBytes not implemented.");
|
|
ulong FirstSeq => throw new NotSupportedException("FirstSeq not implemented.");
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Go-parity sync interface — mirrors server/store.go StreamStore
|
|
// Default implementations throw NotSupportedException so existing
|
|
// MemStore / FileStore implementations continue to compile while the
|
|
// block-engine port is in progress.
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Go: StreamStore.StoreMsg — append a message; returns (seq, timestamp)
|
|
(ulong Seq, long Ts) StoreMsg(string subject, byte[]? hdr, byte[] msg, long ttl)
|
|
=> throw new NotSupportedException("Block-engine StoreMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.StoreRawMsg — store a raw message at a specified sequence
|
|
void StoreRawMsg(string subject, byte[]? hdr, byte[] msg, ulong seq, long ts, long ttl, bool discardNewCheck)
|
|
=> throw new NotSupportedException("Block-engine StoreRawMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.SkipMsg — reserve a sequence without storing a message
|
|
ulong SkipMsg(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine SkipMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.SkipMsgs — reserve a range of sequences
|
|
void SkipMsgs(ulong seq, ulong num)
|
|
=> throw new NotSupportedException("Block-engine SkipMsgs not yet implemented.");
|
|
|
|
// Go: StreamStore.FlushAllPending — flush any buffered writes to backing storage
|
|
Task FlushAllPending()
|
|
=> throw new NotSupportedException("Block-engine FlushAllPending not yet implemented.");
|
|
|
|
// Go: StreamStore.LoadMsg — load message by exact sequence; sm is an optional reusable buffer
|
|
StoreMsg LoadMsg(ulong seq, StoreMsg? sm)
|
|
=> throw new NotSupportedException("Block-engine LoadMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.LoadNextMsg — load next message at or after start matching filter;
|
|
// returns the message and the number of sequences skipped
|
|
(StoreMsg Msg, ulong Skip) LoadNextMsg(string filter, bool wc, ulong start, StoreMsg? sm)
|
|
=> throw new NotSupportedException("Block-engine LoadNextMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.LoadLastMsg — load the most recent message on a given subject
|
|
StoreMsg LoadLastMsg(string subject, StoreMsg? sm)
|
|
=> throw new NotSupportedException("Block-engine LoadLastMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.LoadPrevMsg — load message before start sequence
|
|
StoreMsg LoadPrevMsg(ulong start, StoreMsg? sm)
|
|
=> throw new NotSupportedException("Block-engine LoadPrevMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.RemoveMsg — soft-delete a message by sequence; returns true if found
|
|
bool RemoveMsg(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine RemoveMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.EraseMsg — overwrite a message with random bytes before removing it
|
|
bool EraseMsg(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine EraseMsg not yet implemented.");
|
|
|
|
// Go: StreamStore.Purge — remove all messages; returns count purged
|
|
ulong Purge()
|
|
=> throw new NotSupportedException("Block-engine Purge not yet implemented.");
|
|
|
|
// Go: StreamStore.PurgeEx — purge messages on subject up to seq keeping keep newest
|
|
ulong PurgeEx(string subject, ulong seq, ulong keep)
|
|
=> throw new NotSupportedException("Block-engine PurgeEx not yet implemented.");
|
|
|
|
// Go: StreamStore.Compact — remove all messages with seq < given sequence
|
|
ulong Compact(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine Compact not yet implemented.");
|
|
|
|
// Go: StreamStore.Truncate — remove all messages with seq > given sequence
|
|
void Truncate(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine Truncate not yet implemented.");
|
|
|
|
// Go: StreamStore.GetSeqFromTime — return first sequence at or after wall-clock time t
|
|
ulong GetSeqFromTime(DateTime t)
|
|
=> throw new NotSupportedException("Block-engine GetSeqFromTime not yet implemented.");
|
|
|
|
// Go: StreamStore.FilteredState — compact state for messages matching subject at or after seq
|
|
SimpleState FilteredState(ulong seq, string subject)
|
|
=> throw new NotSupportedException("Block-engine FilteredState not yet implemented.");
|
|
|
|
// Go: StreamStore.SubjectsState — per-subject SimpleState for all subjects matching filter
|
|
Dictionary<string, SimpleState> SubjectsState(string filterSubject)
|
|
=> throw new NotSupportedException("Block-engine SubjectsState not yet implemented.");
|
|
|
|
// Go: StreamStore.SubjectsTotals — per-subject message count for subjects matching filter
|
|
Dictionary<string, ulong> SubjectsTotals(string filterSubject)
|
|
=> throw new NotSupportedException("Block-engine SubjectsTotals not yet implemented.");
|
|
|
|
// Go: StreamStore.AllLastSeqs — last sequence for every subject in the stream
|
|
ulong[] AllLastSeqs()
|
|
=> throw new NotSupportedException("Block-engine AllLastSeqs not yet implemented.");
|
|
|
|
// Go: StreamStore.MultiLastSeqs — last sequences for subjects matching filters, up to maxSeq
|
|
ulong[] MultiLastSeqs(string[] filters, ulong maxSeq, int maxAllowed)
|
|
=> throw new NotSupportedException("Block-engine MultiLastSeqs not yet implemented.");
|
|
|
|
// Go: StreamStore.SubjectForSeq — return the subject stored at the given sequence
|
|
string SubjectForSeq(ulong seq)
|
|
=> throw new NotSupportedException("Block-engine SubjectForSeq not yet implemented.");
|
|
|
|
// Go: StreamStore.NumPending — count messages pending from sseq on filter subject;
|
|
// lastPerSubject restricts to one-per-subject semantics
|
|
(ulong Total, ulong ValidThrough) NumPending(ulong sseq, string filter, bool lastPerSubject)
|
|
=> throw new NotSupportedException("Block-engine NumPending not yet implemented.");
|
|
|
|
// Go: StreamStore.State — return full stream state (Go-parity, with deleted sets)
|
|
StorageStreamState State()
|
|
=> throw new NotSupportedException("Block-engine State not yet implemented.");
|
|
|
|
// Go: StreamStore.FastState — populate a pre-allocated StreamState with the minimum
|
|
// fields needed for replication without allocating a new struct
|
|
void FastState(ref StorageStreamState state)
|
|
=> throw new NotSupportedException("Block-engine FastState not yet implemented.");
|
|
|
|
// Go: StreamStore.EncodedStreamState — binary-encode stream state for NRG replication
|
|
byte[] EncodedStreamState(ulong failed)
|
|
=> throw new NotSupportedException("Block-engine EncodedStreamState not yet implemented.");
|
|
|
|
// Go: StreamStore.Type — the storage type (File or Memory)
|
|
StorageType Type()
|
|
=> throw new NotSupportedException("Block-engine Type not yet implemented.");
|
|
|
|
// Go: StreamStore.UpdateConfig — apply a new StreamConfig without restarting the store
|
|
void UpdateConfig(StreamConfig cfg)
|
|
=> throw new NotSupportedException("Block-engine UpdateConfig not yet implemented.");
|
|
|
|
// Go: StreamStore.Delete — stop and delete all data; inline=true means synchronous deletion
|
|
void Delete(bool inline)
|
|
=> throw new NotSupportedException("Block-engine Delete not yet implemented.");
|
|
|
|
// Go: StreamStore.Stop — flush and stop without deleting data
|
|
void Stop()
|
|
=> throw new NotSupportedException("Block-engine Stop not yet implemented.");
|
|
|
|
// Go: StreamStore.ConsumerStore — create or open a consumer store for the named consumer
|
|
IConsumerStore ConsumerStore(string name, DateTime created, ConsumerConfig cfg)
|
|
=> throw new NotSupportedException("Block-engine ConsumerStore not yet implemented.");
|
|
|
|
// Go: StreamStore.ResetState — reset internal state caches (used after NRG catchup)
|
|
void ResetState()
|
|
=> throw new NotSupportedException("Block-engine ResetState not yet implemented.");
|
|
}
|