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]