ascherbakoff commented on code in PR #6779:
URL: https://github.com/apache/ignite-3/pull/6779#discussion_r2533000577


##########
modules/client/src/main/java/org/apache/ignite/internal/client/table/ClientTable.java:
##########
@@ -839,25 +868,202 @@ <E> CompletableFuture<List<E>> split(
                         idx++;
                     }
 
-                    List<CompletableFuture<List<E>>> res = new 
ArrayList<>(aff.size());
-                    List<Batch<E>> batches = new ArrayList<>();
+                    CompletableFuture<List<E>> resFut = new 
CompletableFuture<>();
+                    mapAndRetry(fun, keys, txns, mapped, new long[1], resFut, 
log);
+                    return resFut;
+                });
+    }
+
+    private static <R, E> void mapAndRetry(
+            MapFunction<E, R> mapFun,
+            @Nullable R initialValue, Reducer<R> reducer,
+            List<Transaction> txns,
+            Map<Integer, List<E>> mapped,
+            long[] startTs,
+            CompletableFuture<R> resFut,
+            IgniteLogger log
+    ) {
+        if (startTs[0] == 0) {
+            startTs[0] = System.nanoTime();
+        }
+
+        List<CompletableFuture<R>> res = new ArrayList<>();
+
+        for (Entry<Integer, List<E>> entry : mapped.entrySet()) {
+            res.add(mapFun.apply(entry.getValue(), 
PartitionAwarenessProvider.of(entry.getKey()), mapped.size() > 1));
+        }
+
+        CompletableFutures.allOf(res).handle((ignored, err) -> {
+            List<CompletableFuture<Void>> waitCommitFuts = List.of();
+            if (!txns.isEmpty()) {
+                boolean allRetryableExceptions = true;
+
+                for (int i = 0; i < res.size(); i++) {
+                    CompletableFuture<R> fut0 = res.get(i);
+                    if (fut0.isCompletedExceptionally()) {
+                        try {
+                            fut0.join();
+                        } catch (CompletionException e) {
+                            allRetryableExceptions = 
ExceptionUtils.matchAny(unwrapCause(e), ACQUIRE_LOCK_ERR);
+                        }
+                    }
+                    Transaction tx0 = txns.get(i);
+                    tx0.rollbackAsync().whenComplete((r, e) -> {
+                        if (e != null) {
+                            log.error("Failed to rollback a transactional 
batch: [tx=" + tx0 + ']', e);
+                        }
+                    });
+                }
+
+                if (err != null) {
+                    // Check if we can retry.
+                    long nowRelative = System.nanoTime();
+                    if (allRetryableExceptions && nowRelative - startTs[0] < 
DEFAULT_IMPLICIT_GET_ALL_TIMEOUT_NANOS) {
+                        startTs[0] = nowRelative;
+                        txns.clear(); // This collection is re-filled on next 
map attempt.
+
+                        mapAndRetry(mapFun, initialValue, reducer, txns, 
mapped, startTs, resFut, log);
 
-                    for (Entry<Integer, Batch<E>> entry : mapped.entrySet()) {
-                        res.add(fun.apply(entry.getValue().batch, 
PartitionAwarenessProvider.of(entry.getKey())));
-                        batches.add(entry.getValue());
+                        return null;
                     }
 
-                    return CompletableFuture.allOf(res.toArray(new 
CompletableFuture[0])).thenApply(ignored -> {
-                        var in = new 
ArrayList<E>(Collections.nCopies(keys.size(), null));
+                    resFut.completeExceptionally(err);
+
+                    return null;
+                }
+
+                waitCommitFuts = unlockFragments(txns, log);
+            } else {
+                if (err != null) {
+                    resFut.completeExceptionally(err);
+
+                    return null;
+                }
+            }
+
+            R in = initialValue;
+
+            for (CompletableFuture<R> val : res) {
+                in = reducer.reduce(in, val.getNow(null));
+            }
+
+            if (waitCommitFuts.isEmpty()) {
+                resFut.complete(in);
+            } else {
+                R finalIn = in;
+                CompletableFutures.allOf(waitCommitFuts).whenComplete((r, e) 
-> {
+                    // Ignore errors.
+                    resFut.complete(finalIn);
+                });
+            }
 
-                        for (int i = 0; i < res.size(); i++) {
-                            CompletableFuture<List<E>> f = res.get(i);
-                            reduceWithKeepOrder(in, f.getNow(null), 
batches.get(i).originalIndices);
+            return null;
+        });
+    }
+
+    private static <E> void mapAndRetry(
+            MapFunction<E, List<E>> mapFun,
+            Collection<E> keys,
+            List<Transaction> txns,
+            Map<Integer, Batch<E>> mapped,
+            long[] startTs,
+            CompletableFuture<List<E>> resFut,
+            IgniteLogger log
+    ) {
+        if (startTs[0] == 0) {
+            startTs[0] = System.nanoTime();
+        }
+
+        List<CompletableFuture<List<E>>> res = new ArrayList<>(mapped.size());
+        List<Batch<E>> batches = new ArrayList<>();
+
+        for (Entry<Integer, Batch<E>> entry : mapped.entrySet()) {
+            res.add(mapFun.apply(entry.getValue().batch, 
PartitionAwarenessProvider.of(entry.getKey()), mapped.size() > 1));
+            batches.add(entry.getValue());
+        }
+
+        CompletableFutures.allOf(res).handle((ignored, err) -> {
+            // TODO remove copy paste
+            List<CompletableFuture<Void>> waitCommitFuts = List.of();
+            if (!txns.isEmpty()) {
+                boolean allRetryableExceptions = true;
+
+                for (int i = 0; i < res.size(); i++) {
+                    CompletableFuture<?> fut0 = res.get(i);
+                    if (fut0.isCompletedExceptionally()) {
+                        try {
+                            fut0.join();
+                        } catch (CompletionException e) {
+                            allRetryableExceptions = 
ExceptionUtils.matchAny(unwrapCause(e), ACQUIRE_LOCK_ERR);
                         }
+                    }
+                    txns.get(i).rollbackAsync();
+                }
 
-                        return in;
-                    });
+                if (err != null) {
+                    // Check if we can retry.
+                    long nowRelative = System.nanoTime();
+                    if (allRetryableExceptions && nowRelative - startTs[0] < 
DEFAULT_IMPLICIT_GET_ALL_TIMEOUT_NANOS) {
+                        startTs[0] = nowRelative;
+                        txns.clear(); // This collection is re-filled on next 
map attempt.
+
+                        mapAndRetry(mapFun, keys, txns, mapped, startTs, 
resFut, log);
+
+                        return null;
+                    }
+
+                    resFut.completeExceptionally(err);
+
+                    return null;
+                }
+
+                waitCommitFuts = unlockFragments(txns, log);
+            } else {
+                if (err != null) {
+                    resFut.completeExceptionally(err);
+
+                    return null;
+                }
+            }
+
+            var in = new ArrayList<E>(Collections.nCopies(keys.size(), null));
+
+            for (int i = 0; i < res.size(); i++) {
+                CompletableFuture<List<E>> f = res.get(i);
+                reduceWithKeepOrder(in, f.getNow(null), 
batches.get(i).originalIndices);
+            }
+
+            if (waitCommitFuts.isEmpty()) {
+                resFut.complete(in);
+            } else {
+                CompletableFutures.allOf(waitCommitFuts).whenComplete((r, e) 
-> {
+                    // Ignore errors.
+                    resFut.complete(in);
                 });
+            }
+
+            return null;
+        });
+    }
+
+    @NotNull
+    private static List<CompletableFuture<Void>> 
unlockFragments(List<Transaction> txns, IgniteLogger log) {
+        List<CompletableFuture<Void>> waitCommitFuts = new ArrayList<>();
+
+        for (Transaction txn : txns) {
+            // ClientTransaction tx0 = (ClientTransaction) txn; TODO FIXME 
investigate error handling

Review Comment:
   Temporary TODO removed, no ticket needed



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

Reply via email to