MCPcopy Create free account
hub / github.com/antlr/codebuff / AggregateFutureState

Class AggregateFutureState

output/java_guava/1.4.17/AggregateFutureState.java:37–161  ·  view source on GitHub ↗

A helper which does some thread-safe operations for aggregate futures, which must be implemented differently in GWT. Namely: Lazily initializes a set of seen exceptions Decrements a counter atomically

Source from the content-addressed store, hash-verified

35
36
37@GwtCompatible(emulated = true)
38abstract class AggregateFutureState {
39 // Lazily initialized the first time we see an exception; not released until all the input futures
40 // & this future completes. Released when the future releases the reference to the running state
41 private volatile Set<Throwable> seenExceptions = null;
42 private volatile int remaining;
43 private static final AtomicHelper ATOMIC_HELPER;
44 private static final Logger log = Logger.getLogger(AggregateFutureState.class.getName());
45
46 static {
47 AtomicHelper helper;
48 try {
49 helper = new SafeAtomicHelper(
50 newUpdater(AggregateFutureState.class, (Class) Set.class, "seenExceptions"),
51 newUpdater(AggregateFutureState.class, "remaining"));
52 } catch (Throwable reflectionFailure) {
53 // Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
54 // getDeclaredField to throw a NoSuchFieldException when the field is definitely there.
55 // For these users fallback to a suboptimal implementation, based on synchronized. This will
56 // be a definite performance hit to those users.
57 log.log(Level.SEVERE, "SafeAtomicHelper is broken!", reflectionFailure);
58 helper = new SynchronizedAtomicHelper();
59 }
60 ATOMIC_HELPER = helper;
61 }
62
63 AggregateFutureState(int remainingFutures) {
64 this.remaining = remainingFutures;
65 }
66
67 final Set<Throwable> getOrInitSeenExceptions() {
68 /*
69 * The initialization of seenExceptions has to be more complicated than we'd like. The simple
70 * approach would be for each caller CAS it from null to a Set populated with its exception. But
71 * there's another race: If the first thread fails with an exception and a second thread
72 * immediately fails with the same exception:
73 *
74 * Thread1: calls setException(), which returns true, context switch before it can CAS
75 * seenExceptions to its exception
76 *
77 * Thread2: calls setException(), which returns false, CASes seenExceptions to its exception,
78 * and wrongly believes that its exception is new (leading it to logging it when it shouldn't)
79 *
80 * Our solution is for threads to CAS seenExceptions from null to a Set population with _the
81 * initial exception_, no matter which thread does the work. This ensures that seenExceptions
82 * always contains not just the current thread's exception but also the initial thread's.
83 */
84 Set<Throwable> seenExceptionsLocal = seenExceptions;
85 if (seenExceptionsLocal == null) {
86 seenExceptionsLocal = newConcurrentHashSet();
87 /*
88 * Other handleException() callers may see this as soon as we publish it. We need to populate
89 * it with the initial failure before we do, or else they may think that the initial failure
90 * has never been seen before.
91 */
92 addInitialException(seenExceptionsLocal);
93 ATOMIC_HELPER.compareAndSetSeenExceptions(this, null, seenExceptionsLocal);
94 /*

Callers

nothing calls this directly

Calls 2

logMethod · 0.80
getNameMethod · 0.45

Tested by

no test coverage detected