
alluxio.concurrent.jsr.CountedCompleter Maven / Gradle / Ivy
/*
* Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the
* public domain, as explained at http://creativecommons.alluxio.shaded.client.org.publicdomain/zero/1.0/
*/
package alluxio.concurrent.jsr;
/**
* A {@link ForkJoinTask} with a alluxio.shaded.client.com.letion action performed when triggered and there are no
* remaining pending actions. CountedCompleters are in general more robust in the presence of
* subtask stalls and blockage than are other forms of ForkJoinTasks, but are less intuitive to
* program. Uses of CountedCompleter are similar to those of other alluxio.shaded.client.com.letion based alluxio.shaded.client.com.onents (such
* as {@link java.nio.channels.CompletionHandler}) except that multiple pending alluxio.shaded.client.com.letions
* may be necessary to trigger the alluxio.shaded.client.com.letion action {@link #onCompletion(CountedCompleter)}, not
* just one. Unless initialized otherwise, the {@linkplain #getPendingCount pending count} starts at
* zero, but may be (atomically) changed using methods {@link #setPendingCount},
* {@link #addToPendingCount}, and {@link #alluxio.shaded.client.com.areAndSetPendingCount}. Upon invocation of
* {@link #tryComplete}, if the pending action count is nonzero, it is decremented; otherwise, the
* alluxio.shaded.client.com.letion action is performed, and if this alluxio.shaded.client.com.leter itself has a alluxio.shaded.client.com.leter, the process is
* continued with its alluxio.shaded.client.com.leter. As is the case with related synchronization alluxio.shaded.client.com.onents such as
* {@link java.util.concurrent.Phaser} and {@link java.util.concurrent.Semaphore Semaphore}, these
* methods affect only internal counts; they do not establish any further internal bookkeeping. In
* particular, the identities of pending tasks are not maintained. As illustrated below, you can
* create subclasses that do record some or all pending tasks or their results when needed. As
* illustrated below, utility methods supporting customization of alluxio.shaded.client.com.letion traversals are also
* provided. However, because CountedCompleters provide only basic synchronization mechanisms, it
* may be useful to create further abstract subclasses that maintain linkages, fields, and
* additional support methods appropriate for a set of related usages.
*
*
* A concrete CountedCompleter class must define method {@link #alluxio.shaded.client.com.ute}, that should in most cases
* (as illustrated below), invoke {@code tryComplete()} once before returning. The class may also
* optionally override method {@link #onCompletion(CountedCompleter)} to perform an action upon
* normal alluxio.shaded.client.com.letion, and method {@link #onExceptionalCompletion(Throwable, CountedCompleter)} to
* perform an action upon any exception.
*
*
* CountedCompleters most often do not bear results, in which case they are normally declared as
* {@code CountedCompleter}, and will always return {@code null} as a result value. In other
* cases, you should override method {@link #getRawResult} to provide a result from
* {@code join(), invoke()}, and related methods. In general, this method should return the value of
* a field (or a function of one or more fields) of the CountedCompleter object that holds the
* result upon alluxio.shaded.client.com.letion. Method {@link #setRawResult} by default plays no role in
* CountedCompleters. It is possible, but rarely applicable, to override this method to maintain
* other objects or fields holding result data.
*
*
* A CountedCompleter that does not itself have a alluxio.shaded.client.com.leter (i.e., one for which
* {@link #getCompleter} returns {@code null}) can be used as a regular ForkJoinTask with this added
* functionality. However, any alluxio.shaded.client.com.leter that in turn has another alluxio.shaded.client.com.leter serves only as an
* internal helper for other alluxio.shaded.client.com.utations, so its own task status (as reported in methods such as
* {@link ForkJoinTask#isDone}) is arbitrary; this status changes only upon explicit invocations of
* {@link #alluxio.shaded.client.com.lete}, {@link ForkJoinTask#cancel},
* {@link ForkJoinTask#alluxio.shaded.client.com.leteExceptionally(Throwable)} or upon exceptional alluxio.shaded.client.com.letion of method
* {@code alluxio.shaded.client.com.ute}. Upon any exceptional alluxio.shaded.client.com.letion, the exception may be relayed to a task's
* alluxio.shaded.client.com.leter (and its alluxio.shaded.client.com.leter, and so on), if one exists and it has not otherwise already
* alluxio.shaded.client.com.leted. Similarly, cancelling an internal CountedCompleter has only a local effect on that
* alluxio.shaded.client.com.leter, so is not often useful.
*
*
* Sample Usages.
*
*
* Parallel recursive decomposition. CountedCompleters may be arranged in trees similar to
* those often used with {@link java.util.concurrent.RecursiveAction}s, although the constructions
* involved in setting them up typically vary. Here, the alluxio.shaded.client.com.leter of each task is its parent in the
* alluxio.shaded.client.com.utation tree. Even though they entail a bit more bookkeeping, CountedCompleters may be better
* choices when applying a possibly time-consuming operation (that cannot be further subdivided) to
* each element of an array or collection; especially when the operation takes a significantly
* different amount of time to alluxio.shaded.client.com.lete for some elements than others, either because of intrinsic
* variation (for example I/O) or auxiliary effects such as garbage collection. Because
* CountedCompleters provide their own continuations, other tasks need not block waiting to perform
* them.
*
*
* For example, here is an initial version of a utility method that uses divide-by-two recursive
* decomposition to divide work into single pieces (leaf tasks). Even when work is split into
* individual calls, tree-based techniques are usually preferable to directly forking leaf tasks,
* because they reduce inter-thread alluxio.shaded.client.com.unication and improve load balancing. In the recursive case,
* the second of each pair of subtasks to finish triggers alluxio.shaded.client.com.letion of their parent (because no
* result alluxio.shaded.client.com.ination is performed, the default no-op implementation of method {@code onCompletion}
* is not overridden). The utility method sets up the root task and invokes it (here, implicitly
* using the {@link ForkJoinPool#alluxio.shaded.client.com.onPool()}). It is straightforward and reliable (but not
* optimal) to always set the pending count to the number of child tasks and call {@code
* tryComplete()} immediately before returning.
*
*
* {@code
* public static void forEach(E[] array, Consumer action) {
* class Task extends CountedCompleter {
* final int lo, hi;
* Task(Task parent, int lo, int hi) {
* super(parent); this.lo = lo; this.hi = hi;
* }
*
* public void alluxio.shaded.client.com.ute() {
* if (hi - lo >= 2) {
* int mid = (lo + hi) >>> 1;
* // must set pending count before fork
* setPendingCount(2);
* new Task(this, mid, hi).fork(); // right child
* new Task(this, lo, mid).fork(); // left child
* }
* else if (hi > lo)
* action.accept(array[lo]);
* tryComplete();
* }
* }
* new Task(null, 0, array.length).invoke();
* }}
*
*
* This design can be improved by noticing that in the recursive case, the task has nothing to do
* after forking its right task, so can directly invoke its left task before returning. (This is an
* analog of tail recursion removal.) Also, when the last action in a task is to fork or invoke a
* subtask (a "tail call"), the call to {@code
* tryComplete()} can be optimized away, at the cost of making the pending count look "off by one".
*
*
* {@code
* public void alluxio.shaded.client.com.ute() {
* if (hi - lo >= 2) {
* int mid = (lo + hi) >>> 1;
* setPendingCount(1); // looks off by one, but correct!
* new Task(this, mid, hi).fork(); // right child
* new Task(this, lo, mid).alluxio.shaded.client.com.ute(); // direct invoke
* } else {
* if (hi > lo)
* action.accept(array[lo]);
* tryComplete();
* }
* }}
*
*
* As a further optimization, notice that the left task need not even exist. Instead of creating a
* new one, we can continue using the original task, and add a pending count for each fork.
* Additionally, because no task in this tree implements an {@link #onCompletion(CountedCompleter)}
* method, {@code tryComplete} can be replaced with {@link #propagateCompletion}.
*
*
* {@code
* public void alluxio.shaded.client.com.ute() {
* int n = hi - lo;
* for (; n >= 2; n /= 2) {
* addToPendingCount(1);
* new Task(this, lo + n/2, lo + n).fork();
* }
* if (n > 0)
* action.accept(array[lo]);
* propagateCompletion();
* }}
*
*
* When pending counts can be precomputed, they can be established in the constructor:
*
*
* {@code
* public static void forEach(E[] array, Consumer action) {
* class Task extends CountedCompleter {
* final int lo, hi;
* Task(Task parent, int lo, int hi) {
* super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
* this.lo = lo; this.hi = hi;
* }
*
* public void alluxio.shaded.client.com.ute() {
* for (int n = hi - lo; n >= 2; n /= 2)
* new Task(this, lo + n/2, lo + n).fork();
* action.accept(array[lo]);
* propagateCompletion();
* }
* }
* if (array.length > 0)
* new Task(null, 0, array.length).invoke();
* }}
*
*
* Additional optimizations of such classes might entail specializing classes for leaf steps,
* subdividing by say, four, instead of two per iteration, and using an adaptive threshold instead
* of always subdividing down to single elements.
*
*
* Searching. A tree of CountedCompleters can search for a value or property in different
* parts of a data structure, and report a result in an
* {@link java.util.concurrent.atomic.AtomicReference AtomicReference} as soon as one is found. The
* others can poll the result to avoid unnecessary work. (You could additionally {@linkplain #cancel
* cancel} other tasks, but it is usually simpler and more efficient to just let them notice that
* the result is set and if so skip further processing.) Illustrating again with an array using full
* partitioning (again, in practice, leaf tasks will almost always process more than one element):
*
*
* {@code
* class Searcher extends CountedCompleter {
* final E[] array; final AtomicReference result; final int lo, hi;
* Searcher(CountedCompleter> p, E[] array, AtomicReference result, int lo, int hi) {
* super(p);
* this.array = array; this.result = result; this.lo = lo; this.hi = hi;
* }
* public E getRawResult() { return result.get(); }
* public void alluxio.shaded.client.com.ute() { // similar to ForEach version 3
* int l = lo, h = hi;
* while (result.get() == null && h >= l) {
* if (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
* new Searcher(this, array, result, mid, h).fork();
* h = mid;
* }
* else {
* E x = array[l];
* if (matches(x) && result.alluxio.shaded.client.com.areAndSet(null, x))
* quietlyCompleteRoot(); // root task is now joinable
* break;
* }
* }
* tryComplete(); // normally alluxio.shaded.client.com.lete whether or not found
* }
* boolean matches(E e) { ... } // return true if found
*
* public static E search(E[] array) {
* return new Searcher(null, array, new AtomicReference(), 0, array.length).invoke();
* }
* }}
*
*
* In this example, as well as others in which tasks have no other effects except to
* {@code alluxio.shaded.client.com.areAndSet} a alluxio.shaded.client.com.on result, the trailing unconditional invocation of
* {@code tryComplete} could be made conditional ({@code if (result.get() == null) tryComplete();})
* because no further bookkeeping is required to manage alluxio.shaded.client.com.letions once the root task alluxio.shaded.client.com.letes.
*
*
* Recording subtasks. CountedCompleter tasks that alluxio.shaded.client.com.ine results of multiple subtasks
* usually need to access these results in method {@link #onCompletion(CountedCompleter)}. As
* illustrated in the following class (that performs a simplified form of map-reduce where mappings
* and reductions are all of type {@code E}), one way to do this in divide and conquer designs is to
* have each subtask record its sibling, so that it can be accessed in method {@code onCompletion}.
* This technique applies to reductions in which the order of alluxio.shaded.client.com.ining left and right results does
* not matter; ordered reductions require explicit left/right designations. Variants of other
* streamlinings seen in the above examples may also apply.
*
*
* {@code
* class MyMapper { E apply(E v) { ... } }
* class MyReducer { E apply(E x, E y) { ... } }
* class MapReducer extends CountedCompleter {
* final E[] array; final MyMapper mapper;
* final MyReducer reducer; final int lo, hi;
* MapReducer sibling;
* E result;
* MapReducer(CountedCompleter> p, E[] array, MyMapper mapper,
* MyReducer reducer, int lo, int hi) {
* super(p);
* this.array = array; this.mapper = mapper;
* this.reducer = reducer; this.lo = lo; this.hi = hi;
* }
* public void alluxio.shaded.client.com.ute() {
* if (hi - lo >= 2) {
* int mid = (lo + hi) >>> 1;
* MapReducer left = new MapReducer(this, array, mapper, reducer, lo, mid);
* MapReducer right = new MapReducer(this, array, mapper, reducer, mid, hi);
* left.sibling = right;
* right.sibling = left;
* setPendingCount(1); // only right is pending
* right.fork();
* left.alluxio.shaded.client.com.ute(); // directly execute left
* }
* else {
* if (hi > lo)
* result = mapper.apply(array[lo]);
* tryComplete();
* }
* }
* public void onCompletion(CountedCompleter> caller) {
* if (caller != this) {
* MapReducer child = (MapReducer)caller;
* MapReducer sib = child.sibling;
* if (sib == null || sib.result == null)
* result = child.result;
* else
* result = reducer.apply(child.result, sib.result);
* }
* }
* public E getRawResult() { return result; }
*
* public static E mapReduce(E[] array, MyMapper mapper, MyReducer reducer) {
* return new MapReducer(null, array, mapper, reducer,
* 0, array.length).invoke();
* }
* }}
*
*
* Here, method {@code onCompletion} takes a form alluxio.shaded.client.com.on to many alluxio.shaded.client.com.letion designs that alluxio.shaded.client.com.ine
* results. This callback-style method is triggered once per task, in either of the two different
* contexts in which the pending count is, or becomes, zero: (1) by a task itself, if its pending
* count is zero upon invocation of {@code
* tryComplete}, or (2) by any of its subtasks when they alluxio.shaded.client.com.lete and decrement the pending count to
* zero. The {@code caller} argument distinguishes cases. Most often, when the caller is
* {@code this}, no action is necessary. Otherwise the caller argument can be used (usually via a
* cast) to supply a value (and/or links to other values) to be alluxio.shaded.client.com.ined. Assuming proper use of
* pending counts, the actions inside {@code onCompletion} occur (once) upon alluxio.shaded.client.com.letion of a task
* and its subtasks. No additional synchronization is required within this method to ensure thread
* safety of accesses to fields of this task or other alluxio.shaded.client.com.leted tasks.
*
*
* Completion Traversals. If using {@code onCompletion} to process alluxio.shaded.client.com.letions is
* inapplicable or inconvenient, you can use methods {@link #firstComplete} and
* {@link #nextComplete} to create custom traversals. For example, to define a MapReducer that only
* splits out right-hand tasks in the form of the third ForEach example, the alluxio.shaded.client.com.letions must
* cooperatively reduce along unexhausted subtask links, which can be done as follows:
*
*
* {
* @code
* class MapReducer extends CountedCompleter { // version 2
* final E[] array;
* final MyMapper mapper;
* final MyReducer reducer;
* final int lo, hi;
* MapReducer forks, next; // record subtask forks in list
* E result;
*
* MapReducer(CountedCompleter> p, E[] array, MyMapper mapper, MyReducer reducer,
* int lo, int hi, MapReducer next) {
* super(p);
* this.array = array;
* this.mapper = mapper;
* this.reducer = reducer;
* this.lo = lo;
* this.hi = hi;
* this.next = next;
* }
*
* public void alluxio.shaded.client.com.ute() {
* int l = lo, h = hi;
* while (h - l >= 2) {
* int mid = (l + h) >>> 1;
* addToPendingCount(1);
* (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
* h = mid;
* }
* if (h > l)
* result = mapper.apply(array[l]);
* // process alluxio.shaded.client.com.letions by reducing along and advancing subtask links
* for (CountedCompleter> c = firstComplete(); c != null; c = c.nextComplete()) {
* for (MapReducer t = (MapReducer) c, s = t.forks; s != null; s = t.forks = s.next)
* t.result = reducer.apply(t.result, s.result);
* }
* }
*
* public E getRawResult() {
* return result;
* }
*
* public static E mapReduce(E[] array, MyMapper mapper, MyReducer reducer) {
* return new MapReducer(null, array, mapper, reducer, 0, array.length, null).invoke();
* }
* }
* }
*
*
*
* Triggers. Some CountedCompleters are themselves never forked, but instead serve as bits of
* plumbing in other designs; including those in which the alluxio.shaded.client.com.letion of one or more async tasks
* triggers another async task. For example:
*
*
* {@code
* class HeaderBuilder extends CountedCompleter<...> { ... }
* class BodyBuilder extends CountedCompleter<...> { ... }
* class PacketSender extends CountedCompleter<...> {
* PacketSender(...) { super(null, 1); ... } // trigger on second alluxio.shaded.client.com.letion
* public void alluxio.shaded.client.com.ute() { } // never called
* public void onCompletion(CountedCompleter> caller) { sendPacket(); }
* }
* // sample use:
* PacketSender p = new PacketSender();
* new HeaderBuilder(p, ...).fork();
* new BodyBuilder(p, ...).fork();}
*
*
* @since 1.8
* @author Doug Lea
*/
public abstract class CountedCompleter extends ForkJoinTask {
// CVS rev. 1.64
private static final long serialVersionUID = 5232453752276485070L;
// Unsafe mechanics
private static final sun.misc.Unsafe U = UnsafeAccess.unsafe;
private static final long PENDING;
static {
try {
PENDING = U.objectFieldOffset(CountedCompleter.class.getDeclaredField("pending"));
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
/** This task's alluxio.shaded.client.com.leter, or null if none */
final CountedCompleter> alluxio.shaded.client.com.leter;
/** The number of pending tasks until alluxio.shaded.client.com.letion */
volatile int pending;
/**
* Creates a new CountedCompleter with the given alluxio.shaded.client.com.leter and initial pending count.
*
* @param alluxio.shaded.client.com.leter this task's alluxio.shaded.client.com.leter, or {@code null} if none
* @param initialPendingCount the initial pending count
*/
protected CountedCompleter(CountedCompleter> alluxio.shaded.client.com.leter, int initialPendingCount) {
this.alluxio.shaded.client.com.leter = alluxio.shaded.client.com.leter;
this.pending = initialPendingCount;
}
/**
* Creates a new CountedCompleter with the given alluxio.shaded.client.com.leter and an initial pending count of zero.
*
* @param alluxio.shaded.client.com.leter this task's alluxio.shaded.client.com.leter, or {@code null} if none
*/
protected CountedCompleter(CountedCompleter> alluxio.shaded.client.com.leter) {
this.alluxio.shaded.client.com.leter = alluxio.shaded.client.com.leter;
}
/**
* Creates a new CountedCompleter with no alluxio.shaded.client.com.leter and an initial pending count of zero.
*/
protected CountedCompleter() {
this.alluxio.shaded.client.com.leter = null;
}
/**
* The main alluxio.shaded.client.com.utation performed by this task.
*/
public abstract void alluxio.shaded.client.com.ute();
/**
* Performs an action when method {@link #tryComplete} is invoked and the pending count is zero,
* or when the unconditional method {@link #alluxio.shaded.client.com.lete} is invoked. By default, this method does
* nothing. You can distinguish cases by checking the identity of the given caller argument. If
* not equal to {@code
* this}, then it is typically a subtask that may contain results (and/or links to other results)
* to alluxio.shaded.client.com.ine.
*
* @param caller the task invoking this method (which may be this task itself)
*/
public void onCompletion(CountedCompleter> caller) {}
/**
* Performs an action when method {@link #alluxio.shaded.client.com.leteExceptionally(Throwable)} is invoked or method
* {@link #alluxio.shaded.client.com.ute} throws an exception, and this task has not already otherwise alluxio.shaded.client.com.leted
* normally. On entry to this method, this task {@link ForkJoinTask#isCompletedAbnormally}. The
* return value of this method controls further propagation: If {@code true} and this task has a
* alluxio.shaded.client.com.leter that has not alluxio.shaded.client.com.leted, then that alluxio.shaded.client.com.leter is also alluxio.shaded.client.com.leted exceptionally, with the
* same exception as this alluxio.shaded.client.com.leter. The default implementation of this method does nothing except
* return {@code true}.
*
* @param ex the exception
* @param caller the task invoking this method (which may be this task itself)
* @return {@code true} if this exception should be propagated to this task's alluxio.shaded.client.com.leter, if one
* exists
*/
public boolean onExceptionalCompletion(Throwable ex, CountedCompleter> caller) {
return true;
}
/**
* Returns the alluxio.shaded.client.com.leter established in this task's constructor, or {@code null} if none.
*
* @return the alluxio.shaded.client.com.leter
*/
public final CountedCompleter> getCompleter() {
return alluxio.shaded.client.com.leter;
}
/**
* Returns the current pending count.
*
* @return the current pending count
*/
public final int getPendingCount() {
return pending;
}
/**
* Sets the pending count to the given value.
*
* @param count the count
*/
public final void setPendingCount(int count) {
pending = count;
}
/**
* Adds (atomically) the given value to the pending count.
*
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
int c;
do {
} while (!U.alluxio.shaded.client.com.areAndSwapInt(this, PENDING, c = pending, c + delta));
}
/**
* Sets (atomically) the pending count to the given count only if it currently holds the given
* expected value.
*
* @param expected the expected value
* @param count the new value
* @return {@code true} if successful
*/
public final boolean alluxio.shaded.client.com.areAndSetPendingCount(int expected, int count) {
return U.alluxio.shaded.client.com.areAndSwapInt(this, PENDING, expected, count);
}
/**
* If the pending count is nonzero, (atomically) decrements it.
*
* @return the initial (undecremented) pending count holding on entry to this method
*/
public final int decrementPendingCountUnlessZero() {
int c;
do {
} while ((c = pending) != 0 && !U.alluxio.shaded.client.com.areAndSwapInt(this, PENDING, c, c - 1));
return c;
}
/**
* Returns the root of the current alluxio.shaded.client.com.utation; i.e., this task if it has no alluxio.shaded.client.com.leter, else its
* alluxio.shaded.client.com.leter's root.
*
* @return the root of the current alluxio.shaded.client.com.utation
*/
public final CountedCompleter> getRoot() {
CountedCompleter> a = this, p;
while ((p = a.alluxio.shaded.client.com.leter) != null)
a = p;
return a;
}
/**
* If the pending count is nonzero, decrements the count; otherwise invokes
* {@link #onCompletion(CountedCompleter)} and then similarly tries to alluxio.shaded.client.com.lete this task's
* alluxio.shaded.client.com.leter, if one exists, else marks this task as alluxio.shaded.client.com.lete.
*/
public final void tryComplete() {
CountedCompleter> a = this, s = a;
for (int c;;) {
if ((c = a.pending) == 0) {
a.onCompletion(s);
if ((a = (s = a).alluxio.shaded.client.com.leter) == null) {
s.quietlyComplete();
return;
}
} else if (U.alluxio.shaded.client.com.areAndSwapInt(a, PENDING, c, c - 1))
return;
}
}
/**
* Equivalent to {@link #tryComplete} but does not invoke {@link #onCompletion(CountedCompleter)}
* along the alluxio.shaded.client.com.letion path: If the pending count is nonzero, decrements the count; otherwise,
* similarly tries to alluxio.shaded.client.com.lete this task's alluxio.shaded.client.com.leter, if one exists, else marks this task as
* alluxio.shaded.client.com.lete. This method may be useful in cases where {@code onCompletion} should not, or need
* not, be invoked for each alluxio.shaded.client.com.leter in a alluxio.shaded.client.com.utation.
*/
public final void propagateCompletion() {
CountedCompleter> a = this, s;
for (int c;;) {
if ((c = a.pending) == 0) {
if ((a = (s = a).alluxio.shaded.client.com.leter) == null) {
s.quietlyComplete();
return;
}
} else if (U.alluxio.shaded.client.com.areAndSwapInt(a, PENDING, c, c - 1))
return;
}
}
/**
* Regardless of pending count, invokes {@link #onCompletion(CountedCompleter)}, marks this task
* as alluxio.shaded.client.com.lete and further triggers {@link #tryComplete} on this task's alluxio.shaded.client.com.leter, if one exists.
* The given rawResult is used as an argument to {@link #setRawResult} before invoking
* {@link #onCompletion(CountedCompleter)} or marking this task as alluxio.shaded.client.com.lete; its value is
* meaningful only for classes overriding {@code setRawResult}. This method does not modify the
* pending count.
*
*
* This method may be useful when forcing alluxio.shaded.client.com.letion as soon as any one (versus all) of several
* subtask results are obtained. However, in the alluxio.shaded.client.com.on (and recommended) case in which {@code
* setRawResult} is not overridden, this effect can be obtained more simply using
* {@link #quietlyCompleteRoot()}.
*
* @param rawResult the raw result
*/
public void alluxio.shaded.client.com.lete(T rawResult) {
CountedCompleter> p;
setRawResult(rawResult);
onCompletion(this);
quietlyComplete();
if ((p = alluxio.shaded.client.com.leter) != null)
p.tryComplete();
}
/**
* If this task's pending count is zero, returns this task; otherwise decrements its pending count
* and returns {@code
* null}. This method is designed to be used with {@link #nextComplete} in alluxio.shaded.client.com.letion traversal
* loops.
*
* @return this task, if pending count was zero, else {@code null}
*/
public final CountedCompleter> firstComplete() {
for (int c;;) {
if ((c = pending) == 0)
return this;
else if (U.alluxio.shaded.client.com.areAndSwapInt(this, PENDING, c, c - 1))
return null;
}
}
/**
* If this task does not have a alluxio.shaded.client.com.leter, invokes {@link ForkJoinTask#quietlyComplete} and
* returns {@code null}. Or, if the alluxio.shaded.client.com.leter's pending count is non-zero, decrements that pending
* count and returns {@code null}. Otherwise, returns the alluxio.shaded.client.com.leter. This method can be used as
* part of a alluxio.shaded.client.com.letion traversal loop for homogeneous task hierarchies:
*
*
* {@code
* for (CountedCompleter> c = firstComplete();
* c != null;
* c = c.nextComplete()) {
* // ... process c ...
* }}
*
*
* @return the alluxio.shaded.client.com.leter, or {@code null} if none
*/
public final CountedCompleter> nextComplete() {
CountedCompleter> p;
if ((p = alluxio.shaded.client.com.leter) != null)
return p.firstComplete();
else {
quietlyComplete();
return null;
}
}
/**
* Equivalent to {@code getRoot().quietlyComplete()}.
*/
public final void quietlyCompleteRoot() {
for (CountedCompleter> a = this, p;;) {
if ((p = a.alluxio.shaded.client.com.leter) == null) {
a.quietlyComplete();
return;
}
a = p;
}
}
/**
* If this task has not alluxio.shaded.client.com.leted, attempts to process at most the given number of other
* unprocessed tasks for which this task is on the alluxio.shaded.client.com.letion path, if any are known to exist.
*
* @param maxTasks the maximum number of tasks to process. If less than or equal to zero, then no
* tasks are processed.
*/
public final void helpComplete(int maxTasks) {
Thread t;
ForkJoinWorkerThread wt;
if (maxTasks > 0 && status >= 0) {
if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
(wt = (ForkJoinWorkerThread) t).pool.helpComplete(wt.workQueue, this, maxTasks);
else
ForkJoinPool.alluxio.shaded.client.com.on.externalHelpComplete(this, maxTasks);
}
}
/**
* Supports ForkJoinTask exception propagation.
*/
void internalPropagateException(Throwable ex) {
CountedCompleter> a = this, s = a;
while (a.onExceptionalCompletion(ex, s) && (a = (s = a).alluxio.shaded.client.com.leter) != null && a.status >= 0
&& a.recordExceptionalCompletion(ex) == EXCEPTIONAL);
}
/**
* Implements execution conventions for CountedCompleters.
*/
protected final boolean exec() {
alluxio.shaded.client.com.ute();
return false;
}
/**
* Returns the result of the alluxio.shaded.client.com.utation. By default, returns {@code null}, which is appropriate
* for {@code Void} actions, but in other cases should be overridden, almost always to return a
* field or function of a field that holds the result upon alluxio.shaded.client.com.letion.
*
* @return the result of the alluxio.shaded.client.com.utation
*/
public T getRawResult() {
return null;
}
/**
* A method that result-bearing CountedCompleters may optionally use to help maintain result data.
* By default, does nothing. Overrides are not recommended. However, if this method is overridden
* to update existing objects or fields, then it must in general be defined to be thread-safe.
*/
protected void setRawResult(T t) {}
}