task6: implement batch38 group E state snapshot and wait queue
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
using System.Text.Json;
|
||||
using System.Text;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server;
|
||||
|
||||
internal sealed partial class NatsConsumer
|
||||
{
|
||||
private static readonly TimeSpan DefaultGatewayInterestInterval = TimeSpan.FromSeconds(1);
|
||||
private ConsumerInfo? _initialInfo;
|
||||
|
||||
internal bool UpdateDeliveryInterest(bool localInterest)
|
||||
{
|
||||
@@ -582,4 +584,158 @@ internal sealed partial class NatsConsumer
|
||||
_mu.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyState(ConsumerState state)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(state);
|
||||
_mu.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_state = new ConsumerState
|
||||
{
|
||||
Delivered = new SequencePair
|
||||
{
|
||||
Consumer = state.Delivered.Consumer,
|
||||
Stream = state.Delivered.Stream,
|
||||
},
|
||||
AckFloor = new SequencePair
|
||||
{
|
||||
Consumer = state.AckFloor.Consumer,
|
||||
Stream = state.AckFloor.Stream,
|
||||
},
|
||||
Pending = state.Pending is null ? null : new Dictionary<ulong, Pending>(state.Pending),
|
||||
Redelivered = state.Redelivered is null ? null : new Dictionary<ulong, ulong>(state.Redelivered),
|
||||
};
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mu.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetStoreState(ConsumerState state) => ApplyState(state);
|
||||
|
||||
internal ConsumerState WriteStoreState()
|
||||
{
|
||||
_mu.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
return WriteStoreStateUnlocked();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mu.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal ConsumerState WriteStoreStateUnlocked() => GetConsumerState();
|
||||
|
||||
internal ConsumerInfo InitialInfo()
|
||||
{
|
||||
_mu.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_initialInfo ??= GetInfo();
|
||||
return _initialInfo;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mu.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal void ClearInitialInfo()
|
||||
{
|
||||
_mu.EnterWriteLock();
|
||||
try
|
||||
{
|
||||
_initialInfo = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mu.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal ConsumerInfo Info() => GetInfo();
|
||||
|
||||
internal ConsumerInfo InfoWithSnap(ConsumerState? snapshot = null)
|
||||
{
|
||||
if (snapshot is null)
|
||||
return GetInfo();
|
||||
|
||||
var info = GetInfo();
|
||||
info.Delivered = new SequenceInfo { Consumer = snapshot.Delivered.Consumer, Stream = snapshot.Delivered.Stream };
|
||||
info.AckFloor = new SequenceInfo { Consumer = snapshot.AckFloor.Consumer, Stream = snapshot.AckFloor.Stream };
|
||||
return info;
|
||||
}
|
||||
|
||||
internal (ConsumerInfo Info, string ReplySubject) InfoWithSnapAndReply(string replySubject, ConsumerState? snapshot = null) =>
|
||||
(InfoWithSnap(snapshot), replySubject);
|
||||
|
||||
internal void SignalNewMessages() => _updateChannel.Writer.TryWrite(true);
|
||||
|
||||
internal bool ShouldSample()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Config.SampleFrequency))
|
||||
return false;
|
||||
|
||||
var token = Config.SampleFrequency!.Trim().TrimEnd('%');
|
||||
if (!int.TryParse(token, out var percent))
|
||||
return false;
|
||||
|
||||
return percent > 0;
|
||||
}
|
||||
|
||||
internal bool SampleAck(string ackReply)
|
||||
{
|
||||
if (!ShouldSample())
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ackReply))
|
||||
return false;
|
||||
|
||||
AddAckReply((ulong)ackReply.Length, ackReply);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal bool IsFiltered(string subject)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(subject))
|
||||
return false;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Config.FilterSubject))
|
||||
return Internal.DataStructures.SubscriptionIndex.SubjectIsSubsetMatch(subject, Config.FilterSubject!);
|
||||
|
||||
if (Config.FilterSubjects is not { Length: > 0 })
|
||||
return false;
|
||||
|
||||
return Config.FilterSubjects.Any(filter => Internal.DataStructures.SubscriptionIndex.SubjectIsSubsetMatch(subject, filter));
|
||||
}
|
||||
|
||||
internal bool NeedAck() => Config.AckPolicy != AckPolicy.AckNone;
|
||||
|
||||
internal static (JsApiConsumerGetNextRequest? Request, Exception? Error) NextReqFromMsg(ReadOnlySpan<byte> message)
|
||||
{
|
||||
if (message.Length == 0)
|
||||
return (new JsApiConsumerGetNextRequest { Batch = 1 }, null);
|
||||
|
||||
try
|
||||
{
|
||||
var text = Encoding.UTF8.GetString(message);
|
||||
if (int.TryParse(text, out var batch))
|
||||
return (new JsApiConsumerGetNextRequest { Batch = Math.Max(1, batch) }, null);
|
||||
|
||||
var req = JsonSerializer.Deserialize<JsApiConsumerGetNextRequest>(text);
|
||||
if (req is null)
|
||||
return (null, new InvalidOperationException("invalid request"));
|
||||
if (req.Batch <= 0)
|
||||
req.Batch = 1;
|
||||
return (req, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user