fix(abcip): budget expected reply size in RequestScheduler.TakeBatch (#582); private lock + struct-handle check across read fragments (#567)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-07 22:53:10 -04:00
parent 04b6563286
commit 9641cefe2e
8 changed files with 187 additions and 16 deletions
@@ -122,7 +122,7 @@ internal sealed class NativeAbCipTagRuntime : IAbCipTagRuntime
var path = Path();
try
{
var (type, handle, data) = await client.ReadAsync(path,_elements, cancellationToken).ConfigureAwait(false);
var (type, handle, data) = await client.ReadAsync(path, _elements, cancellationToken, ExpectedElementBytes(_p.AuthoredType)).ConfigureAwait(false);
_data = data;
_typeCode = type;
_structHandle = handle;
@@ -136,6 +136,21 @@ internal sealed class NativeAbCipTagRuntime : IAbCipTagRuntime
}
}
/// <summary>
/// Upper bound on one element's wire bytes for the scheduler's reply budget (#582); 0 when the
/// authored type is unknown or a structure, which sends the read alone rather than guess.
/// BOOL counts 4 (a packed BOOL array reads back as DWORDs).
/// </summary>
internal static int ExpectedElementBytes(AbCipDataType? type) => type switch
{
AbCipDataType.Bool or AbCipDataType.DInt or AbCipDataType.UDInt or AbCipDataType.Real or AbCipDataType.Dt => 4,
AbCipDataType.SInt or AbCipDataType.USInt => 1,
AbCipDataType.Int or AbCipDataType.UInt => 2,
AbCipDataType.LInt or AbCipDataType.ULInt or AbCipDataType.LReal => 8,
AbCipDataType.String => LogixTypeCode.StringElementBytes,
_ => 0,
};
/// <inheritdoc />
public async Task WriteAsync(CancellationToken cancellationToken)
{