AsyncParallelStreamingCollector.java

1
/*
2
 * Copyright 2014-2026 Grzegorz Piwowarek, https://4comprehension.com/
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.pivovarit.collectors;
17
18
import java.time.Duration;
19
import java.util.ArrayList;
20
import java.util.Collection;
21
import java.util.List;
22
import java.util.Set;
23
import java.util.concurrent.CompletableFuture;
24
import java.util.concurrent.CompletionException;
25
import java.util.concurrent.ExecutionException;
26
import java.util.concurrent.Executor;
27
import java.util.concurrent.TimeUnit;
28
import java.util.concurrent.TimeoutException;
29
import java.util.function.BiConsumer;
30
import java.util.function.BinaryOperator;
31
import java.util.function.Function;
32
import java.util.function.Supplier;
33
import java.util.stream.Collector;
34
import java.util.stream.Stream;
35
import java.util.stream.StreamSupport;
36
37
import static com.pivovarit.collectors.BatchingSpliterator.batching;
38
import static com.pivovarit.collectors.BatchingSpliterator.partitioned;
39
import static java.util.Collections.emptySet;
40
41
/**
42
 * @author Grzegorz Piwowarek
43
 */
44
final class AsyncParallelStreamingCollector<T, R> extends AbstractParallelCollector<T, R, Stream<R>> {
45
46
    private static final Set<Characteristics> UNORDERED_CHARACTERISTICS = Set.of(Characteristics.UNORDERED);
47
48
    private final CompletionStrategy completionStrategy;
49
    private final Duration timeout;
50
51
    AsyncParallelStreamingCollector(Function<? super T, ? extends R> task, Dispatcher<R> dispatcher, boolean ordered, Duration timeout) {
52
        super(task, dispatcher);
53 1 1. <init> : negated conditional → KILLED
        this.completionStrategy = ordered ? CompletionStrategy.ORDERED : CompletionStrategy.UNORDERED;
54
        this.timeout = timeout;
55
    }
56
57
    @Override
58
    public Function<List<CompletableFuture<R>>, Stream<R>> finalizer() {
59 2 1. finalizer : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::finalizer → KILLED
2. lambda$finalizer$0 : replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$finalizer$0 → KILLED
        return acc -> switch (completionStrategy) {
60
            case ORDERED -> orderedStream(acc);
61
            case UNORDERED -> StreamSupport.stream(
62 1 1. lambda$finalizer$0 : negated conditional → KILLED
              new CompletionOrderSpliterator<>(acc, timeout == null ? null : new Deadline(timeout.toNanos())), false);
63
        };
64
    }
65
66
    private Stream<R> orderedStream(List<CompletableFuture<R>> acc) {
67 1 1. orderedStream : negated conditional → KILLED
        if (timeout == null) {
68 2 1. lambda$orderedStream$0 : replaced boolean return with false for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$0 → KILLED
2. orderedStream : replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::orderedStream → KILLED
            return acc.stream().map(AsyncParallelStreamingCollector::joinInterruptibly).filter(__ -> true);
69
        }
70
        var deadline = new Deadline(timeout.toNanos());
71 3 1. lambda$orderedStream$1 : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$1 → KILLED
2. orderedStream : replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::orderedStream → KILLED
3. lambda$orderedStream$2 : replaced boolean return with false for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$2 → KILLED
        return acc.stream().map(future -> joinWithin(future, deadline)).filter(__ -> true);
72
    }
73
74
    private static <R> R joinInterruptibly(CompletableFuture<R> future) {
75
        try {
76 1 1. joinInterruptibly : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::joinInterruptibly → KILLED
            return future.get();
77
        } catch (ExecutionException e) {
78
            throw new CompletionException(e.getCause());
79
        } catch (InterruptedException e) {
80 1 1. joinInterruptibly : removed call to java/lang/Thread::interrupt → KILLED
            Thread.currentThread().interrupt();
81
            throw new CompletionException(e);
82
        }
83
    }
84
85
    private static <R> R joinWithin(CompletableFuture<R> future, Deadline deadline) {
86
        try {
87 1 1. joinWithin : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::joinWithin → KILLED
            return future.get(deadline.remainingNanos(), TimeUnit.NANOSECONDS);
88
        } catch (TimeoutException e) {
89
            throw new CompletionException(new TimeoutException("Timeout while streaming results"));
90
        } catch (ExecutionException e) {
91
            throw new CompletionException(e.getCause());
92
        } catch (InterruptedException e) {
93 1 1. joinWithin : removed call to java/lang/Thread::interrupt → KILLED
            Thread.currentThread().interrupt();
94
            throw new CompletionException(e);
95
        }
96
    }
97
98
    @Override
99
    public Set<Characteristics> characteristics() {
100 1 1. characteristics : replaced return value with Collections.emptySet for com/pivovarit/collectors/AsyncParallelStreamingCollector::characteristics → KILLED
        return switch (completionStrategy) {
101
            case ORDERED -> emptySet();
102
            case UNORDERED -> UNORDERED_CHARACTERISTICS;
103
        };
104
    }
105
106
    record BatchingCollector<T, R>(Function<? super T, ? extends R> task, Executor executor, int parallelism, boolean ordered, Duration timeout)
107
      implements Collector<T, ArrayList<T>, Stream<R>> {
108
109
        @Override
110
        public Supplier<ArrayList<T>> supplier() {
111 1 1. supplier : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::supplier → KILLED
            return ArrayList::new;
112
        }
113
114
        @Override
115
        public BiConsumer<ArrayList<T>, T> accumulator() {
116 1 1. accumulator : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::accumulator → KILLED
            return ArrayList::add;
117
        }
118
119
        @Override
120
        public BinaryOperator<ArrayList<T>> combiner() {
121 1 1. combiner : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::combiner → KILLED
            return (left, right) -> {
122
                throw new UnsupportedOperationException("using parallel stream with parallel collectors is not supported");
123
            };
124
        }
125
126
        @Override
127
        public Function<ArrayList<T>, Stream<R>> finisher() {
128 1 1. finisher : replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::finisher → KILLED
            return items -> {
129 1 1. lambda$finisher$0 : negated conditional → KILLED
                if (items.size() == parallelism) {
130 1 1. lambda$finisher$0 : replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::lambda$finisher$0 → KILLED
                    return items.stream()
131
                      .collect(new AsyncParallelStreamingCollector<>(task, new Dispatcher<>(executor, parallelism), ordered, timeout));
132
                } else {
133 1 1. lambda$finisher$0 : replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::lambda$finisher$0 → KILLED
                    return partitioned(items, parallelism)
134
                      .collect(new AsyncParallelStreamingCollector<>(batching(task), new Dispatcher<>(executor, parallelism), ordered, timeout))
135
                      .flatMap(Collection::stream);
136
                }
137
            };
138
        }
139
140
        @Override
141
        public Set<Characteristics> characteristics() {
142
            return emptySet();
143
        }
144
    }
145
}

Mutations

53

1.1
Location : <init>
Killed by : com.pivovarit.collectors.test.StreamingConfigurerTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.StreamingConfigurerTest]/[test-factory:shouldReportUnorderedCharacteristic()]/[dynamic-test:#1]
negated conditional → KILLED

59

1.1
Location : finalizer
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessEmpty()]/[dynamic-test:#29]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::finalizer → KILLED

2.2
Location : lambda$finalizer$0
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElements()]/[dynamic-test:#38]
replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$finalizer$0 → KILLED

62

1.1
Location : lambda$finalizer$0
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessEmpty()]/[dynamic-test:#29]
negated conditional → KILLED

67

1.1
Location : orderedStream
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessEmpty()]/[dynamic-test:#38]
negated conditional → KILLED

68

1.1
Location : lambda$orderedStream$0
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElements()]/[dynamic-test:#38]
replaced boolean return with false for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$0 → KILLED

2.2
Location : orderedStream
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElements()]/[dynamic-test:#38]
replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::orderedStream → KILLED

71

1.1
Location : lambda$orderedStream$1
Killed by : com.pivovarit.collectors.test.TimeoutStreamingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.TimeoutStreamingTest]/[method:shouldNotTimeoutOrderedWhenFastEnough()]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$1 → KILLED

2.2
Location : orderedStream
Killed by : com.pivovarit.collectors.test.TimeoutStreamingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.TimeoutStreamingTest]/[method:shouldNotTimeoutOrderedWhenFastEnough()]
replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector::orderedStream → KILLED

3.3
Location : lambda$orderedStream$2
Killed by : com.pivovarit.collectors.test.TimeoutStreamingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.TimeoutStreamingTest]/[method:shouldNotTimeoutOrderedWhenFastEnough()]
replaced boolean return with false for com/pivovarit/collectors/AsyncParallelStreamingCollector::lambda$orderedStream$2 → KILLED

76

1.1
Location : joinInterruptibly
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElements()]/[dynamic-test:#38]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::joinInterruptibly → KILLED

80

1.1
Location : joinInterruptibly
Killed by : com.pivovarit.collectors.test.StreamingInterruptionTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.StreamingInterruptionTest]/[test-factory:shouldUnblockConsumerOnInterrupt()]/[dynamic-test:#1]
removed call to java/lang/Thread::interrupt → KILLED

87

1.1
Location : joinWithin
Killed by : com.pivovarit.collectors.test.TimeoutStreamingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.TimeoutStreamingTest]/[method:shouldNotTimeoutOrderedWhenFastEnough()]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector::joinWithin → KILLED

93

1.1
Location : joinWithin
Killed by : com.pivovarit.collectors.test.StreamingInterruptionTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.StreamingInterruptionTest]/[test-factory:shouldUnblockConsumerOnInterrupt()]/[dynamic-test:#2]
removed call to java/lang/Thread::interrupt → KILLED

100

1.1
Location : characteristics
Killed by : com.pivovarit.collectors.test.StreamingConfigurerTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.StreamingConfigurerTest]/[test-factory:shouldReportUnorderedCharacteristic()]/[dynamic-test:#1]
replaced return value with Collections.emptySet for com/pivovarit/collectors/AsyncParallelStreamingCollector::characteristics → KILLED

111

1.1
Location : supplier
Killed by : com.pivovarit.collectors.test.ParallelismValidationTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.ParallelismValidationTest]/[test-factory:shouldThrowOnParallelStream()]/[dynamic-test:#22]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::supplier → KILLED

116

1.1
Location : accumulator
Killed by : com.pivovarit.collectors.test.ParallelismValidationTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.ParallelismValidationTest]/[test-factory:shouldThrowOnParallelStream()]/[dynamic-test:#22]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::accumulator → KILLED

121

1.1
Location : combiner
Killed by : com.pivovarit.collectors.test.ParallelismValidationTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.ParallelismValidationTest]/[test-factory:shouldThrowOnParallelStream()]/[dynamic-test:#22]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::combiner → KILLED

128

1.1
Location : finisher
Killed by : com.pivovarit.collectors.test.ParallelismValidationTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.ParallelismValidationTest]/[test-factory:shouldThrowOnParallelStream()]/[dynamic-test:#22]
replaced return value with null for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::finisher → KILLED

129

1.1
Location : lambda$finisher$0
Killed by : com.pivovarit.collectors.test.BatchingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BatchingTest]/[test-factory:shouldProcessOnExactlyNThreads()]/[dynamic-test:#2]
negated conditional → KILLED

130

1.1
Location : lambda$finisher$0
Killed by : com.pivovarit.collectors.test.BasicParallelismTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicParallelismTest]/[test-factory:shouldProcessAllElementsWithMaxParallelism()]/[dynamic-test:#145]
replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::lambda$finisher$0 → KILLED

133

1.1
Location : lambda$finisher$0
Killed by : com.pivovarit.collectors.test.BasicProcessingTest.[engine:junit-jupiter]/[class:com.pivovarit.collectors.test.BasicProcessingTest]/[test-factory:shouldProcessAllElementsInOrder()]/[dynamic-test:#33]
replaced return value with Stream.empty for com/pivovarit/collectors/AsyncParallelStreamingCollector$BatchingCollector::lambda$finisher$0 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.30.0 support