docs(xmldoc): fill missing XML docs + strip tracking-ID comments across src
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>/<param>/<returns>/<inheritdoc> where missing and removes project bookkeeping IDs (task/tracking refs) from shipped code comments, so the docs read cleanly and CommentChecker is quiet except for known false positives (PLC/protocol terms, event/IEqualityComparer inheritdoc). Doc/comment-only; no logic changed; solution builds clean.
This commit is contained in:
@@ -3,7 +3,7 @@ using LiteDB;
|
||||
namespace ZB.MOM.WW.OtOpcUa.Configuration.LocalCache;
|
||||
|
||||
/// <summary>
|
||||
/// Generation-sealed LiteDB cache per <c>docs/v2/plan.md</c> decision #148 and Phase 6.1
|
||||
/// Generation-sealed LiteDB cache per <c>docs/v2/plan.md</c> and Phase 6.1
|
||||
/// Stream D.1. Each published generation writes one <b>read-only</b> LiteDB file under
|
||||
/// <c><cache-root>/<clusterId>/<generationId>.db</c>. A per-cluster
|
||||
/// <c>CURRENT</c> text file holds the currently-active generation id; it is updated
|
||||
@@ -32,7 +32,7 @@ public sealed class GenerationSealedCache
|
||||
// BsonMapper.Global is a process-wide singleton whose lazy per-type member registration is
|
||||
// not thread-safe across concurrently-constructed LiteDatabase instances; a seal racing a
|
||||
// read (or this cache racing LiteDbConfigCache) corrupts the global mapper, surfacing as
|
||||
// "Member … not found on BsonMapper" or a bogus duplicate-_id insert — Configuration-012.
|
||||
// "Member … not found on BsonMapper" or a bogus duplicate-_id insert.
|
||||
private static BsonMapper BuildMapper()
|
||||
{
|
||||
var mapper = new BsonMapper();
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace ZB.MOM.WW.OtOpcUa.Configuration.LocalCache;
|
||||
|
||||
/// <summary>
|
||||
/// Per-node local cache of the most-recently-applied generation(s). Used to bootstrap the
|
||||
/// address space when the central DB is unreachable (decision #79 — degraded-but-running).
|
||||
/// address space when the central DB is unreachable (degraded-but-running).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para><b>Concurrency contract:</b> implementations must serialize writes — specifically,
|
||||
@@ -21,10 +21,12 @@ public interface ILocalConfigCache
|
||||
/// <summary>Stores a generation snapshot in the local cache.</summary>
|
||||
/// <param name="snapshot">The generation snapshot to store.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task PutAsync(GenerationSnapshot snapshot, CancellationToken ct = default);
|
||||
/// <summary>Removes old generations, keeping only the most recent N.</summary>
|
||||
/// <param name="clusterId">The cluster identifier.</param>
|
||||
/// <param name="keepLatest">The number of latest generations to keep.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task PruneOldGenerationsAsync(string clusterId, int keepLatest = 10, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ZB.MOM.WW.OtOpcUa.Configuration.LocalCache;
|
||||
/// LiteDB-backed <see cref="ILocalConfigCache"/>. One file per node (default
|
||||
/// <c>config_cache.db</c>), one collection per snapshot. Corruption surfaces as
|
||||
/// <see cref="LocalConfigCacheCorruptException"/> on construction or read — callers should
|
||||
/// delete and re-fetch from the central DB (decision #80).
|
||||
/// delete and re-fetch from the central DB.
|
||||
/// </summary>
|
||||
public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
{
|
||||
@@ -17,7 +17,7 @@ public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
// instances. When several caches (this one + GenerationSealedCache) initialise in parallel
|
||||
// the global mapper races, surfacing as "Member ClusterId not found on BsonMapper" or a
|
||||
// bogus "duplicate key _id = 0" (the int auto-id mapping was lost so Insert writes a literal
|
||||
// 0 twice) — Configuration-012. Give each database a private, pre-registered mapper so member
|
||||
// 0 twice). Give each database a private, pre-registered mapper so member
|
||||
// resolution happens once, single-threaded, at construction and never touches the global.
|
||||
private static BsonMapper BuildMapper()
|
||||
{
|
||||
@@ -30,7 +30,7 @@ public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
private readonly ILiteCollection<GenerationSnapshot> _col;
|
||||
// PutAsync is a find-then-insert/update; without serialization, two concurrent puts for the
|
||||
// same (ClusterId, GenerationId) can both observe `existing is null` and both Insert,
|
||||
// producing duplicate rows (Configuration-005). Serialize writes through this semaphore so
|
||||
// producing duplicate rows. Serialize writes through this semaphore so
|
||||
// the read-modify-write block is atomic for a given instance. LiteDB itself only locks the
|
||||
// page-level write, not the find-then-insert window.
|
||||
private readonly SemaphoreSlim _writeGate = new(initialCount: 1, maxCount: 1);
|
||||
@@ -60,9 +60,7 @@ public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the most recent snapshot for the specified cluster.</summary>
|
||||
/// <param name="clusterId">The cluster ID.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public Task<GenerationSnapshot?> GetMostRecentAsync(string clusterId, CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
@@ -73,15 +71,13 @@ public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
return Task.FromResult<GenerationSnapshot?>(snapshot);
|
||||
}
|
||||
|
||||
/// <summary>Stores a snapshot in the cache.</summary>
|
||||
/// <param name="snapshot">The snapshot to store.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public async Task PutAsync(GenerationSnapshot snapshot, CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
// Serialize the find-then-insert/update so concurrent callers do not observe a stale
|
||||
// `existing is null` and both Insert (Configuration-005). LiteDB's per-call lock is
|
||||
// not enough — the read and the write are independent calls.
|
||||
// `existing is null` and both Insert. LiteDB's per-call lock is not enough — the
|
||||
// read and the write are independent calls.
|
||||
await _writeGate.WaitAsync(ct).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
@@ -104,10 +100,7 @@ public sealed class LiteDbConfigCache : ILocalConfigCache, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Removes old generation snapshots, keeping only the latest ones.</summary>
|
||||
/// <param name="clusterId">The cluster ID.</param>
|
||||
/// <param name="keepLatest">Number of latest generations to keep.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public Task PruneOldGenerationsAsync(string clusterId, int keepLatest = 10, CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -69,7 +69,7 @@ public sealed class ResilientConfigReader
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration-010: redact connection-string fragments (Password, User Id, Pwd, etc.)
|
||||
/// Redacts connection-string fragments (Password, User Id, Pwd, etc.)
|
||||
/// that a caller's exception message could carry. Conservative regex pass — anything
|
||||
/// matching <c>Key=Value</c> with a known credential key gets its value replaced.
|
||||
/// </summary>
|
||||
@@ -120,7 +120,7 @@ public sealed class ResilientConfigReader
|
||||
// that case, not propagate. Only rethrow if the caller actually requested cancellation.
|
||||
catch (Exception ex) when (ex is not OperationCanceledException || !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
// Configuration-010: do NOT pass the raw exception object — it carries the stack
|
||||
// Do NOT pass the raw exception object — it carries the stack
|
||||
// and inner-exception chain, and SqlException/wrapping delegates can surface
|
||||
// connection-string fragments (Password=…, User Id=…) embedded in messages.
|
||||
// Log only the exception type and a scrubbed message so secrets stay out of logs.
|
||||
|
||||
Reference in New Issue
Block a user