| // Copyright 2026 The Bazel Authors. All rights reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| package com.google.devtools.build.lib.concurrent; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.util.concurrent.FutureCallback; | |
| import com.google.common.util.concurrent.ListenableFuture; | |
| import com.google.devtools.build.lib.concurrent.safeexecutor.SafeExecutor; | |
| import com.google.errorprone.annotations.DoNotCall; | |
| import com.google.errorprone.annotations.ForOverride; | |
| /** | |
| * An abstract base class for futures that accumulate the completion of homogeneous subtask futures | |
| * directly into an aggregated state. | |
| * | |
| * <p>Subclasses implement {@link #accumulateFutureResult} to fold completed subtask results into | |
| * their state and {@link #getValue()} to synthesize the final result upon quiescence. | |
| * | |
| * @param <T> the type of value produced by this future upon quiescence | |
| * @param <V> the type of value produced by subtask futures accumulated by this future | |
| */ | |
| public abstract class AccumulatingQuiescingFuture<T, V> extends QuiescingFuture<T> | |
| implements FutureCallback<V> { | |
| /** | |
| * Constructor. | |
| * | |
| * @param getValueExecutor runner for running {@link #getValue} or {@link #doneWithError}. | |
| */ | |
| protected AccumulatingQuiescingFuture(SafeExecutor getValueExecutor) { | |
| super(getValueExecutor); | |
| } | |
| /** | |
| * Direct constructor. | |
| * | |
| * @param getValueExecutor runner for running {@link #getValue} or {@link #doneWithError}. | |
| * @param taskCount initial task count. | |
| */ | |
| protected AccumulatingQuiescingFuture(SafeExecutor getValueExecutor, int taskCount) { | |
| super(getValueExecutor, taskCount); | |
| } | |
| /** | |
| * Registers a subtask future whose completion is accumulated directly by this instance, | |
| * automatically incrementing {@link #taskCount} and rolling back on submission failure. | |
| * | |
| * @param future {@code future}'s result will be accumulated upon completion | |
| * @param executor runner that executes the accumulation | |
| */ | |
| public final void addFuture(ListenableFuture<? extends V> future, SafeExecutor executor) { | |
| Preconditions.checkNotNull(future, "future"); | |
| Preconditions.checkNotNull(executor, "executor"); | |
| increment(); | |
| try { | |
| executor.addCallback(future, this); | |
| } catch (Throwable t) { | |
| notifyException(t); | |
| } | |
| } | |
| /** | |
| * Accumulates the result of a completed subtask future into the aggregated state. | |
| * | |
| * <p><b>Thread Safety & Commutativity:</b> This method may be called concurrently from multiple | |
| * threads when subtask futures complete in parallel, and results may arrive in arbitrary order. | |
| * Implementations must be thread-safe (e.g. using concurrent collections, atomic operations, or | |
| * synchronization) and commutative. | |
| * | |
| * <p>Decrementing {@link #taskCount} is guaranteed to execute automatically upon return or | |
| * exception. | |
| */ | |
| @ForOverride | |
| protected abstract void accumulateFutureResult(V result); | |
| /** | |
| * Implements {@link FutureCallback#onSuccess}. | |
| * | |
| * @deprecated Do not call directly; only used by {@link SafeExecutor#addCallback} callback | |
| * processing. | |
| */ | |
| @Deprecated | |
| @Override | |
| @DoNotCall("Only for use by SafeExecutor / FutureCallback machinery") | |
| public final void onSuccess(V result) { | |
| try { | |
| accumulateFutureResult(result); | |
| } catch (Throwable t) { | |
| notifyException(t); | |
| return; | |
| } | |
| decrement(); | |
| } | |
| /** | |
| * Implements {@link FutureCallback#onFailure}. | |
| * | |
| * @deprecated Do not call directly; only used by {@link SafeExecutor#addCallback} callback | |
| * processing. | |
| */ | |
| @Deprecated | |
| @Override | |
| @DoNotCall("Only for use by SafeExecutor / FutureCallback machinery") | |
| public final void onFailure(Throwable t) { | |
| notifyException(t); | |
| } | |
| } |