feat: port session 07 — Protocol Parser, Auth extras (TPM/certidp/certstore), Internal utilities & data structures
Session 07 scope (5 features, 17 tests, ~1165 Go LOC): - Protocol/ParserTypes.cs: ParserState enum (79 states), PublishArgument, ParseContext - Protocol/IProtocolHandler.cs: handler interface decoupling parser from client - Protocol/ProtocolParser.cs: Parse(), ProtoSnippet(), OverMaxControlLineLimit(), ProcessPub/HeaderPub/RoutedMsgArgs/RoutedHeaderMsgArgs, ClonePubArg(), GetHeader() - tests/Protocol/ProtocolParserTests.cs: 17 tests via TestProtocolHandler stub Auth extras from session 06 (committed separately): - Auth/TpmKeyProvider.cs, Auth/CertificateIdentityProvider/, Auth/CertificateStore/ Internal utilities & data structures (session 06 overflow): - Internal/AccessTimeService.cs, ElasticPointer.cs, SystemMemory.cs, ProcessStatsProvider.cs - Internal/DataStructures/GenericSublist.cs, HashWheel.cs - Internal/DataStructures/SubjectTree.cs, SubjectTreeNode.cs, SubjectTreeParts.cs All 461 tests pass (460 unit + 1 integration). DB updated for features 2588-2592 and tests 2598-2614.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Provides cross-platform process CPU and memory usage statistics.
|
||||
/// Mirrors the Go <c>pse</c> (Process Status Emulation) package, replacing
|
||||
/// per-platform implementations (rusage, /proc/stat, PDH) with
|
||||
/// <see cref="System.Diagnostics.Process"/>.
|
||||
/// </summary>
|
||||
public static class ProcessStatsProvider
|
||||
{
|
||||
private static readonly Process _self = Process.GetCurrentProcess();
|
||||
private static readonly int _processorCount = Environment.ProcessorCount;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
private static TimeSpan _lastCpuTime;
|
||||
private static DateTime _lastSampleTime;
|
||||
private static double _cachedPcpu;
|
||||
private static long _cachedRss;
|
||||
private static long _cachedVss;
|
||||
|
||||
static ProcessStatsProvider()
|
||||
{
|
||||
UpdateUsage();
|
||||
StartPeriodicSampling();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current process CPU percentage, RSS (bytes), and VSS (bytes).
|
||||
/// Values are refreshed approximately every second by a background timer.
|
||||
/// </summary>
|
||||
/// <param name="pcpu">Percent CPU utilization (0–100 × core count).</param>
|
||||
/// <param name="rss">Resident set size in bytes.</param>
|
||||
/// <param name="vss">Virtual memory size in bytes.</param>
|
||||
public static void ProcUsage(out double pcpu, out long rss, out long vss)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
pcpu = _cachedPcpu;
|
||||
rss = _cachedRss;
|
||||
vss = _cachedVss;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateUsage()
|
||||
{
|
||||
try
|
||||
{
|
||||
_self.Refresh();
|
||||
var now = DateTime.UtcNow;
|
||||
var cpuTime = _self.TotalProcessorTime;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
var elapsed = now - _lastSampleTime;
|
||||
if (elapsed >= TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
var cpuDelta = (cpuTime - _lastCpuTime).TotalSeconds;
|
||||
// Normalize against elapsed wall time.
|
||||
// Result is 0–100; does not multiply by ProcessorCount to match Go behaviour.
|
||||
_cachedPcpu = elapsed.TotalSeconds > 0
|
||||
? Math.Round(cpuDelta / elapsed.TotalSeconds * 1000.0) / 10.0
|
||||
: 0;
|
||||
_lastSampleTime = now;
|
||||
_lastCpuTime = cpuTime;
|
||||
}
|
||||
|
||||
_cachedRss = _self.WorkingSet64;
|
||||
_cachedVss = _self.VirtualMemorySize64;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Suppress — diagnostics should never crash the server.
|
||||
}
|
||||
}
|
||||
|
||||
private static void StartPeriodicSampling()
|
||||
{
|
||||
var timer = new Timer(_ => UpdateUsage(), null,
|
||||
dueTime: TimeSpan.FromSeconds(1),
|
||||
period: TimeSpan.FromSeconds(1));
|
||||
|
||||
// Keep timer alive for the process lifetime.
|
||||
GC.KeepAlive(timer);
|
||||
}
|
||||
|
||||
// --- Windows PDH helpers (replaced by Process class in .NET) ---
|
||||
// The following methods exist to satisfy the porting mapping but delegate
|
||||
// to the cross-platform Process API above.
|
||||
|
||||
internal static string GetProcessImageName() =>
|
||||
Path.GetFileNameWithoutExtension(Environment.ProcessPath ?? _self.ProcessName);
|
||||
|
||||
internal static void InitCounters()
|
||||
{
|
||||
// No-op: .NET Process class initializes lazily.
|
||||
}
|
||||
|
||||
internal static double PdhOpenQuery() => 0; // Mapped to Process API.
|
||||
internal static double PdhAddCounter() => 0;
|
||||
internal static double PdhCollectQueryData() => 0;
|
||||
internal static double PdhGetFormattedCounterArrayDouble() => 0;
|
||||
internal static double GetCounterArrayData() => 0;
|
||||
}
|
||||
Reference in New Issue
Block a user