| 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.util.List; | |
| 19 | import java.util.concurrent.Executor; | |
| 20 | import java.util.function.UnaryOperator; | |
| 21 | ||
| 22 | /** | |
| 23 | * Fluent configuration builder for collectors that <em>collect</em> all results (i.e. non-streaming). | |
| 24 | * <p> | |
| 25 | * Instances of this class are used internally to accumulate configuration options that are later | |
| 26 | * interpreted by {@link ConfigProcessor}. | |
| 27 | */ | |
| 28 | public final class CollectingConfigurer { | |
| 29 | ||
| 30 | private final ConfigurerState state = new ConfigurerState(); | |
| 31 | ||
| 32 | CollectingConfigurer() { | |
| 33 | } | |
| 34 | ||
| 35 | /** | |
| 36 | * Enables batching of work submitted to workers. | |
| 37 | * <p> | |
| 38 | * When enabled, each worker thread receives a batch of input items and processes them in one go, | |
| 39 | * instead of scheduling one task per item. This reduces the number of tasks created and typically | |
| 40 | * decreases contention on the underlying worker queue. | |
| 41 | * | |
| 42 | * <p><b>Note:</b> Depending on batch sizing and workload skew, batching may reduce load balancing and | |
| 43 | * can lead to thread starvation (some workers become idle while others remain overloaded). | |
| 44 | * | |
| 45 | * @return this configurer instance for fluent chaining | |
| 46 | */ | |
| 47 | public CollectingConfigurer batching() { | |
| 48 |
1
1. batching : removed call to com/pivovarit/collectors/ConfigurerState::batching → KILLED |
state.batching(); |
| 49 |
1
1. batching : replaced return value with null for com/pivovarit/collectors/CollectingConfigurer::batching → KILLED |
return this; |
| 50 | } | |
| 51 | ||
| 52 | /** | |
| 53 | * Sets the maximum level of parallelism. | |
| 54 | * <p> | |
| 55 | * This limits the number of tasks submitted to the worker queue at once, effectively bounding | |
| 56 | * the amount of in-flight work and the maximum concurrency used by the collector. | |
| 57 | * | |
| 58 | * @param parallelism the desired parallelism level (must be positive) | |
| 59 | * | |
| 60 | * @return this configurer instance for fluent chaining | |
| 61 | */ | |
| 62 | public CollectingConfigurer parallelism(int parallelism) { | |
| 63 |
1
1. parallelism : removed call to com/pivovarit/collectors/ConfigurerState::parallelism → KILLED |
state.parallelism(parallelism); |
| 64 |
1
1. parallelism : replaced return value with null for com/pivovarit/collectors/CollectingConfigurer::parallelism → KILLED |
return this; |
| 65 | } | |
| 66 | ||
| 67 | /** | |
| 68 | * Sets the {@link Executor} used for running tasks. | |
| 69 | * | |
| 70 | * <p><b>Note:</b> The provided executor must not <em>drop</em> tasks on rejection (e.g. using a | |
| 71 | * {@code RejectedExecutionHandler} that discards submitted work). Dropping tasks will cause the | |
| 72 | * collector to wait for results that will never be produced, which can lead to deadlocks. | |
| 73 | * | |
| 74 | * @param executor the executor to use | |
| 75 | * | |
| 76 | * @return this configurer instance for fluent chaining | |
| 77 | */ | |
| 78 | public CollectingConfigurer executor(Executor executor) { | |
| 79 |
1
1. executor : removed call to com/pivovarit/collectors/ConfigurerState::executor → KILLED |
state.executor(executor); |
| 80 |
1
1. executor : replaced return value with null for com/pivovarit/collectors/CollectingConfigurer::executor → KILLED |
return this; |
| 81 | } | |
| 82 | ||
| 83 | /** | |
| 84 | * Decorates the executor used for running tasks. | |
| 85 | * <p> | |
| 86 | * The decorator receives the resolved executor (either the default virtual-thread executor or | |
| 87 | * the one provided via {@link #executor(Executor)}) and returns a wrapped replacement. | |
| 88 | * This is useful for augmenting the executor with cross-cutting concerns such as context | |
| 89 | * propagation (MDC, OpenTelemetry spans, etc.) or monitoring, without replacing the executor entirely. | |
| 90 | * | |
| 91 | * <p><b>Note:</b> The executor returned by the decorator must not <em>drop</em> tasks on rejection. | |
| 92 | * Dropping tasks will cause the collector to wait for results that will never be produced, | |
| 93 | * which can lead to deadlocks. | |
| 94 | * | |
| 95 | * @param decorator a function that wraps the resolved executor | |
| 96 | * | |
| 97 | * @return this configurer instance for fluent chaining | |
| 98 | */ | |
| 99 | public CollectingConfigurer executorDecorator(UnaryOperator<Executor> decorator) { | |
| 100 |
1
1. executorDecorator : removed call to com/pivovarit/collectors/ConfigurerState::executorDecorator → KILLED |
state.executorDecorator(decorator); |
| 101 |
1
1. executorDecorator : replaced return value with null for com/pivovarit/collectors/CollectingConfigurer::executorDecorator → KILLED |
return this; |
| 102 | } | |
| 103 | ||
| 104 | /** | |
| 105 | * Decorates each individual task before it is submitted to the executor. | |
| 106 | * <p> | |
| 107 | * The decorator receives the {@link Runnable} representing a single unit of work and returns a | |
| 108 | * wrapped replacement that runs in its place. This is useful for propagating thread-local context | |
| 109 | * (e.g. MDC entries, OpenTelemetry spans, {@code SecurityContext}) into worker threads, or for | |
| 110 | * per-task instrumentation, without replacing the executor entirely. | |
| 111 | * | |
| 112 | * <p>Unlike {@link #executorDecorator(UnaryOperator)}, which wraps the executor as a whole, | |
| 113 | * this decorator is applied to each task individually and runs on the worker thread. | |
| 114 | * | |
| 115 | * @param decorator a function that wraps each submitted task | |
| 116 | * | |
| 117 | * @return this configurer instance for fluent chaining | |
| 118 | */ | |
| 119 | public CollectingConfigurer taskDecorator(UnaryOperator<Runnable> decorator) { | |
| 120 |
1
1. taskDecorator : removed call to com/pivovarit/collectors/ConfigurerState::taskDecorator → KILLED |
state.taskDecorator(decorator); |
| 121 |
1
1. taskDecorator : replaced return value with null for com/pivovarit/collectors/CollectingConfigurer::taskDecorator → KILLED |
return this; |
| 122 | } | |
| 123 | ||
| 124 | List<ConfigProcessor.Option> getConfig() { | |
| 125 |
1
1. getConfig : replaced return value with Collections.emptyList for com/pivovarit/collectors/CollectingConfigurer::getConfig → KILLED |
return state.getConfig(); |
| 126 | } | |
| 127 | ||
| 128 | void validate() { | |
| 129 |
1
1. validate : removed call to com/pivovarit/collectors/ConfigurerState::validate → KILLED |
state.validate(); |
| 130 | } | |
| 131 | } | |
Mutations | ||
| 48 |
1.1 |
|
| 49 |
1.1 |
|
| 63 |
1.1 |
|
| 64 |
1.1 |
|
| 79 |
1.1 |
|
| 80 |
1.1 |
|
| 100 |
1.1 |
|
| 101 |
1.1 |
|
| 120 |
1.1 |
|
| 121 |
1.1 |
|
| 125 |
1.1 |
|
| 129 |
1.1 |