// Copyright 2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/jetstream_batching.go in the NATS server Go source.
namespace ZB.MOM.NatsNet.Server;
// ---------------------------------------------------------------------------
// Batching types
// ---------------------------------------------------------------------------
///
/// Tracks in-progress atomic publish batch groups for a stream.
/// Mirrors the batching struct in server/jetstream_batching.go.
///
internal sealed class Batching
{
private readonly Lock _mu = new();
private readonly Dictionary _group = new(StringComparer.Ordinal);
public Lock Mu => _mu;
public Dictionary Group => _group;
}
///
/// A single in-progress atomic batch: its temporary store and cleanup timer.
/// Mirrors batchGroup in server/jetstream_batching.go.
///
internal sealed class BatchGroup
{
/// Last proposed stream sequence for this batch.
public ulong LastSeq { get; set; }
/// Temporary backing store for the batch's messages.
public object? Store { get; set; } // IStreamStore — session 20
/// Timer that abandons the batch after the configured timeout.
public Timer? BatchTimer { get; set; }
///
/// Stops the cleanup timer and flushes pending writes so the batch is
/// ready to be committed.
/// Mirrors batchGroup.readyForCommit.
///
public bool ReadyForCommit()
{
// Stub — full implementation requires IStreamStore.FlushAllPending (session 20).
return BatchTimer?.Change(Timeout.Infinite, Timeout.Infinite) != null;
}
}
///
/// Stages consistency-check data for a single atomic batch before it is committed.
/// Mirrors batchStagedDiff in server/jetstream_batching.go.
///
internal sealed class BatchStagedDiff
{
/// Message IDs seen in this batch, for duplicate detection.
public Dictionary? MsgIds { get; set; }
/// Running counter totals, keyed by subject.
public Dictionary? Counter { get; set; } // map[string]*msgCounterRunningTotal
/// Inflight subject byte/op totals for DiscardNew checks.
public Dictionary? Inflight { get; set; } // map[string]*inflightSubjectRunningTotal
/// Expected-last-seq-per-subject checks staged in this batch.
public Dictionary? ExpectedPerSubject { get; set; }
}
///
/// Cached expected-last-sequence-per-subject result for a single subject within a batch.
/// Mirrors batchExpectedPerSubject in server/jetstream_batching.go.
///
internal sealed class BatchExpectedPerSubject
{
/// Stream sequence of the last message on this subject at proposal time.
public ulong SSeq { get; set; }
/// Clustered proposal sequence at which this check was computed.
public ulong ClSeq { get; set; }
}
///
/// Tracks the in-progress application of a committed batch on the Raft apply path.
/// Mirrors batchApply in server/jetstream_batching.go.
///
internal sealed class BatchApply
{
private readonly Lock _mu = new();
/// ID of the current batch.
public string Id { get; set; } = string.Empty;
/// Number of entries expected in the batch (for consistency checks).
public ulong Count { get; set; }
/// Raft committed entries that make up this batch.
public List