github-actions[bot] commented on code in PR #4547:
URL: https://github.com/apache/iggy/pull/4547#discussion_r4276036264
##########
foreign/csharp/Iggy_SDK/Vsr/VsrConnection.cs:
##########
@@ -341,6 +350,41 @@ private static bool
IsReplayableTransient(IggyInvalidStatusCodeException error,
_ => false
};
}
+
+ /// <summary>
+ /// Whether a refusal of a replay settles the outcome of the original
request. The primary answers a
+ /// same-id replay from its session table, so a result-section
rejection is the cached reply of the
+ /// original, the commit of a request that never entered the pipeline,
or a refusal of a request neither
+ /// the session table nor the pipeline holds. The codes below settle
nothing: most come from the checks
+ /// that run before that lookup, and REQUEST_TOO_OLD means the
original applied and its reply is gone.
+ /// PERSONAL_ACCESS_TOKEN_ALREADY_EXISTS settles even as the refusal
to replay a token the original
+ /// minted: either way the name is taken and the caller holds no
token. Apply can commit INVALID_COMMAND
+ /// too, but nothing tells it apart from the preflight one. The server
never puts HISTORY_UNAVAILABLE in a
+ /// result section, and it stays listed because settling on it would
be wrong if it ever did. The caller
+ /// filters TRANSIENT_NOT_COMMITTED out before asking.
+ /// </summary>
+ private static bool SettlesOutcome(IggyInvalidStatusCodeException error)
+ {
+ return error is
+ {
+ FromResultSection: true,
+ StatusCode: not (VsrError.TRANSIENT_NOT_ACCEPTED or
VsrError.NOT_PRIMARY or VsrError.REQUEST_TOO_OLD
+ or VsrError.INVALID_COMMAND or VsrError.UNAUTHENTICATED or
VsrError.HISTORY_UNAVAILABLE)
+ };
+ }
+
+ /// <summary>
+ /// Whether an unsettled refusal of a replay is final: the primary's
preflight answers every replay of the
+ /// same request id with it again, so replaying until the deadline
only ends in the same unknown outcome.
+ /// </summary>
+ private static bool IsFinalRefusal(IggyInvalidStatusCodeException error)
+ {
+ return error is
+ {
+ FromResultSection: true,
+ StatusCode: VsrError.REQUEST_TOO_OLD or VsrError.INVALID_COMMAND
Review Comment:
nit: The partition plane answers an aged-out replay with `RequestTooOld` on
the status word. `IsFinalRefusal` requires `FromResultSection`, so that shape
replays every 50 ms until the read deadline instead of ending at once. Fix:
match the status-word shape too, because the same request id draws the same
terminal refusal every time.
##########
foreign/csharp/Iggy_SDK/IggyClient/Implementations/TcpMessageStream.PollRouting.cs:
##########
@@ -249,8 +256,25 @@ private async Task<IMemoryOwner<byte>> SendRoutedAsync(int
code, SendTarget targ
catch (OperationCanceledException error) when
(!token.IsCancellationRequested)
{
RemovePartitionRoute(target.Key);
+ // The budget can expire in the backoff or in a read-only control
request that follows it, before the
+ // send call for the request starts again, so the last refusal
still decides the outcome. An expiry
+ // inside that send call reports an unknown outcome even before
the write, which is conservative.
+ if (refusal is not null)
+ {
+ ExceptionDispatchInfo.Throw(refusal);
+ }
+
throw new VsrRequestOutcomeUnknownException(error);
}
+ // The read timer of a route lookup fires at the same deadline as the
budget and turns into a timeout
+ // IOException when it wins. A kept refusal means no send started
since, so it still decides the outcome.
+ catch (IOException) when (refusal is not null
Review Comment:
nit: The new filter catches only `IOException`, so a `SocketException` from
the redial inside `SendPollControlAsync` still escapes the method instead of
the kept refusal. Fix: widen the filter to the connection failures, for example
`SocketException`, because a lookup that fails before any send cannot change
the request outcome.
##########
foreign/csharp/Iggy_SDK/Vsr/VsrError.cs:
##########
@@ -59,11 +60,17 @@ internal static IggyInvalidStatusCodeException
Exception(int code, string messag
}
/// <summary>
- /// A verdict the server reported, on the reply status word, in the
committed result section or in an
- /// eviction frame. Only these may drive retry and failover.
+ /// A verdict the server reported, on the reply status word or in an
eviction frame. Only server verdicts,
Review Comment:
nit: This comment claims that only server verdicts drive retry and failover.
`PollNotAccepted()` raises `TRANSIENT_NOT_ACCEPTED` with `FromServer` false,
and the routed retry acts on it. Fix: name that exception as the client-raised
case, or narrow the claim.
##########
foreign/csharp/Iggy_SDK_Tests/VsrTests/PrimaryPollingTests.cs:
##########
@@ -228,6 +228,37 @@ public async Task
given_only_refusals_when_the_poll_budget_expires_should_report
Assert.All(cluster.Primaries, primary => Assert.Equal(0,
primary.Connections));
}
+ [Fact]
+ public async Task
given_primary_refusal_when_the_budget_expires_in_the_next_route_lookup_should_report_not_accepted()
+ {
+ using var cluster = new PollCluster();
+ var release = new
TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ var lookups = 0;
+ cluster.OnPrimaryPoll = request => Reply(request.Operation, [],
TRANSIENT_NOT_ACCEPTED);
+ cluster.OnCoordinator = request =>
+ {
+ if (request.Code == CommandCodes.GET_PARTITION_ROUTE_CODE &&
Interlocked.Increment(ref lookups) == 2)
+ {
+ release.Task.GetAwaiter().GetResult();
Review Comment:
nit: This test blocks its second route lookup until `VsrRequestTimeoutMs`
(30 s) expires, so one unit test costs half a minute and holds a mock handler
for that time. Fix: make the request budget injectable and set a short value in
this test.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]