bitflicker64 commented on code in PR #3204:
URL: https://github.com/apache/hugegraph/pull/3204#discussion_r3995474168


##########
hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java:
##########
@@ -373,35 +398,70 @@ boolean ifAnyTrue(Supplier<Stream<HgPair<HgStoreNode, 
NodeTkv>>> nodeStreamSuppl
     }
 
     <T> Optional<T> retryingInvoke(Supplier<T> supplier) {
+        boolean[] deadlineRetried = {false};
         return IntStream.rangeClosed(0, NODE_MAX_RETRYING_TIMES).boxed()
                         .map(
                                 i -> {
+                                    if 
(Thread.currentThread().isInterrupted()) {
+                                        // The caller (e.g. a REST worker 
hitting
+                                        // restserver.request_timeout) gave 
up: stop
+                                        // retrying instead of holding its 
thread.
+                                        // InterruptedException as the root 
cause: the
+                                        // server's task cancel path 
recognises it
+                                        // (HugeException.isInterrupted()).
+                                        throw HgStoreClientException.of(
+                                                "Interrupted before retry " + 
i,
+                                                new InterruptedException());
+                                    }
                                     T buffer = null;
                                     try {
                                         buffer = supplier.get();
                                     } catch (Throwable t) {
-                                        if (i + 1 <= NODE_MAX_RETRYING_TIMES) {
-                                            try {
-                                                int sleepTime;
-                                                // The first three times try 
once every second
-                                                if (i < 3) {
-                                                    sleepTime = 1;
-                                                } else {
-                                                    // Subsequent incremental
-                                                    sleepTime = i - 1;
-                                                }
-                                                log.info("Waiting {} seconds " 
+
-                                                         "for the next try.",
-                                                         sleepTime);
-                                                Thread.sleep(sleepTime * 
1000L);
-                                            } catch (InterruptedException e) {
-                                                log.error("Failed to sleep", 
e);
+                                        Failure failure = classify(t);
+                                        if (failure == Failure.FATAL) {
+                                            // The caller's thread was 
interrupted or the
+                                            // call was cancelled: fail fast.
+                                            log.warn("Not retrying after: {}",
+                                                     t.getMessage(), t);
+                                            throw HgStoreClientException.of(
+                                                    t.getMessage(), t);
+                                        }
+                                        if (failure == Failure.DEADLINE) {
+                                            // One retry: the NOT_WORK notice 
sent for the
+                                            // failed RPC reloads the 
partition leaders, so
+                                            // the next attempt can reach a 
new leader. A
+                                            // second deadline in a row would 
only wait the
+                                            // full deadline again on the same 
stalled store.
+                                            if (deadlineRetried[0]) {
+                                                log.warn("Not retrying a 
second deadline: {}",
+                                                         t.getMessage(), t);
+                                                throw 
HgStoreClientException.of(
+                                                        t.getMessage(), t);
                                             }
-                                        } else {
+                                            deadlineRetried[0] = true;
+                                            log.warn("Deadline exceeded, 
retrying once in " +

Review Comment:
   ⚠️ The PR description still describes the pre-`b588aa88` behaviour, so the 
numbers reviewers and the squash commit message will carry are wrong for this 
head.
   
   Evidence:
   
   - The body says "Do not retry a failure whose cause chain carries 
`Status.Code.DEADLINE_EXCEEDED` … (`isRetryable()`)". At this head a deadline 
**is** retried once (this block, plus the guard four lines down), and 
`isRetryable()` no longer exists: `git grep -n isRetryable 172b2d0 -- 
hugegraph-store` returns nothing — it is `classify()` / `Failure` now.
   - The before/after table's `slowest write | 20.1 s` was measured with 
`grpc.timeout.seconds=20` under the never-retry behaviour, i.e. one deadline. 
With the single retry the worst case is two deadlines plus the 1 s backoff: 
about 41 s in that setup, and about 201 s on the shipped default 
`grpc.timeout.seconds=100`. That is still a large improvement over `11 × 
timeout + 38 s`, but it is twice what the table claims.
   
   Requested change: update the "Main Changes" bullet to describe the 
retry-once classification and rename `isRetryable()` to `classify()`, and 
either re-run the SIGSTOP measurement at `172b2d0` or annotate the table as 
taken at `920bbbdf`.



##########
hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java:
##########
@@ -373,35 +398,70 @@ boolean ifAnyTrue(Supplier<Stream<HgPair<HgStoreNode, 
NodeTkv>>> nodeStreamSuppl
     }
 
     <T> Optional<T> retryingInvoke(Supplier<T> supplier) {
+        boolean[] deadlineRetried = {false};
         return IntStream.rangeClosed(0, NODE_MAX_RETRYING_TIMES).boxed()
                         .map(
                                 i -> {
+                                    if 
(Thread.currentThread().isInterrupted()) {
+                                        // The caller (e.g. a REST worker 
hitting
+                                        // restserver.request_timeout) gave 
up: stop
+                                        // retrying instead of holding its 
thread.
+                                        // InterruptedException as the root 
cause: the
+                                        // server's task cancel path 
recognises it
+                                        // (HugeException.isInterrupted()).
+                                        throw HgStoreClientException.of(
+                                                "Interrupted before retry " + 
i,
+                                                new InterruptedException());
+                                    }
                                     T buffer = null;
                                     try {
                                         buffer = supplier.get();
                                     } catch (Throwable t) {
-                                        if (i + 1 <= NODE_MAX_RETRYING_TIMES) {
-                                            try {
-                                                int sleepTime;
-                                                // The first three times try 
once every second
-                                                if (i < 3) {
-                                                    sleepTime = 1;
-                                                } else {
-                                                    // Subsequent incremental
-                                                    sleepTime = i - 1;
-                                                }
-                                                log.info("Waiting {} seconds " 
+
-                                                         "for the next try.",
-                                                         sleepTime);
-                                                Thread.sleep(sleepTime * 
1000L);
-                                            } catch (InterruptedException e) {
-                                                log.error("Failed to sleep", 
e);
+                                        Failure failure = classify(t);
+                                        if (failure == Failure.FATAL) {
+                                            // The caller's thread was 
interrupted or the
+                                            // call was cancelled: fail fast.
+                                            log.warn("Not retrying after: {}",
+                                                     t.getMessage(), t);
+                                            throw HgStoreClientException.of(
+                                                    t.getMessage(), t);
+                                        }
+                                        if (failure == Failure.DEADLINE) {
+                                            // One retry: the NOT_WORK notice 
sent for the
+                                            // failed RPC reloads the 
partition leaders, so
+                                            // the next attempt can reach a 
new leader. A
+                                            // second deadline in a row would 
only wait the
+                                            // full deadline again on the same 
stalled store.
+                                            if (deadlineRetried[0]) {

Review Comment:
   🧹 The comment and the javadoc say "a second deadline **in a row**", but the 
flag is never reset, so the code means "a second deadline anywhere in this 
invocation".
   
   Evidence:
   
   - `boolean[] deadlineRetried = {false}` (`:401`) is set once at `:441` and 
never cleared, including after an attempt that fails with something else or 
that succeeds partially.
   - Concretely: attempt 0 `DEADLINE_EXCEEDED` (retried), attempts 1-9 
`UNAVAILABLE` (retried, ~38 s of backoff, partition leaders reloaded several 
times over), attempt 10 `DEADLINE_EXCEEDED` — the guard fires and the call 
aborts, even though these two deadlines are not consecutive and the stated 
rationale ("the `NOT_WORK` notice … reloads the partition leaders") applies 
just as much the second time.
   - The same wording is in the `Failure` javadoc at `:478`.
   
   Requested change: pick one. Either reset `deadlineRetried[0] = false` 
whenever an attempt fails with a non-`DEADLINE` classification, which makes the 
code match "in a row"; or reword `:433` and `:478` to "a second deadline in 
this invocation" so the budget is honestly described as one deadline retry per 
call.



##########
hugegraph-store/hg-store-client/src/main/java/org/apache/hugegraph/store/client/NodeTxExecutor.java:
##########
@@ -129,35 +136,7 @@ void doCommit() {
                 if (!allSuccess.get()) {
                     throw HgStoreClientException.of(msg);
                 }
-                AtomicReference<Throwable> throwable = new AtomicReference<>();
-                Collection<HgStoreSession> sessions = this.sessions.values();
-                sessions.parallelStream().forEach(e -> {
-                    if (e.isTx()) {
-                        try {
-                            e.commit();
-                        } catch (Throwable t) {
-                            throwable.compareAndSet(null, t);
-                            allSuccess.set(false);
-                        }
-                    }
-                });
-                if (!allSuccess.get()) {
-                    if (isTx) {
-                        try {
-                            
sessions.stream().forEach(HgStoreSession::rollback);
-                        } catch (Exception e) {
-
-                        }
-                    }
-                    Throwable cause = throwable.get();
-                    if (cause.getCause() != null) {
-                        cause = cause.getCause();
-                    }
-                    if (cause instanceof HgStoreClientException) {
-                        throw (HgStoreClientException) cause;
-                    }
-                    throw HgStoreClientException.of(cause);
-                }
+                this.commitSessions(this.sessions.values());

Review Comment:
   🧹 Extracting `commitSessions()` removed the only writer of `allSuccess`, 
leaving a dead variable and an unreachable branch.
   
   Evidence:
   
   - `AtomicBoolean allSuccess = new AtomicBoolean(true)` (`:131`) is now only 
ever read. The `allSuccess.set(false)` that used to live in the inline 
parallel-commit block moved into `commitSessions()`, which reports through the 
thrown exception instead.
   - So `if (!allSuccess.get()) { throw HgStoreClientException.of(msg); }` 
(`:136-138`) can never fire, and `msg` is referenced only from that unreachable 
throw.
   
   Requested change: delete `:131` and `:136-138` (and the now-unused `msg` 
field, plus the `java.util.concurrent.atomic.AtomicBoolean` import, if nothing 
else uses them). If the gate was meant to catch a `doAction()` that returned 
`false`, wire the loop's return value into it instead of leaving it dead.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to