@@ -221,7 +221,9 @@ public void close() {
221221 }
222222 var newStoredValue = this .storedValues .compute (compositeKey , //
223223 (__ , oldStoredValue ) -> {
224- if (isPresent (oldStoredValue )) {
224+ // guard against race conditions, repeated from getStoredValue
225+ // this filters out failures inserted by computeIfAbsent
226+ if (isStoredValuePresent (oldStoredValue )) {
225227 return oldStoredValue ;
226228 }
227229 rejectIfClosed ();
@@ -232,6 +234,7 @@ public void close() {
232234 });
233235
234236 if (newStoredValue instanceof StoredValue .DeferredValue value ) {
237+ // Any thread that won the race may run the DeferredSupplier
235238 value .delegate ().run ();
236239 }
237240 return requireNonNull (newStoredValue .evaluate ());
@@ -261,23 +264,31 @@ public <K, V> Object computeIfAbsent(N namespace, K key, Function<? super K, ? e
261264 if (result != null ) {
262265 return result ;
263266 }
267+ Object ownerToken = new Object ();
264268 StoredValue newStoredValue = this .storedValues .compute (compositeKey , (__ , oldStoredValue ) -> {
269+ // guard against race conditions
270+ // computeIfAbsent replaces both null and absent values
265271 if (StoredValue .evaluateIfNotNull (oldStoredValue ) != null ) {
266272 return oldStoredValue ;
267273 }
268274 rejectIfClosed ();
269- return newStoredSuppliedValue (new DeferredSupplier (() -> {
275+ return newStoredSuppliedValue (new DeferredSupplier (ownerToken , () -> {
270276 rejectIfClosed ();
271277 return Preconditions .notNull (defaultCreator .apply (key ), "defaultCreator must not return null" );
272278 }));
273279 });
274280
275281 if (newStoredValue instanceof StoredValue .DeferredOptionalValue value ) {
276282 var delegate = value .delegate ();
277- delegate .run ();
278- return requireNonNull (delegate .getOrThrow ());
283+ if (ownerToken .equals (delegate .ownerToken ())) {
284+ // Only the thread that created the DeferredSupplier may run it
285+ delegate .run ();
286+ // Only the thread that caused the exception may see it
287+ return requireNonNull (delegate .getOrThrow ());
288+ }
279289 }
280- // put or getOrComputeIfAbsent won the race
290+ // Either put, getOrComputeIfAbsent, or another computeIfAbsent call
291+ // won the race
281292 return requireNonNull (newStoredValue .evaluate ());
282293 }
283294
@@ -409,7 +420,7 @@ private StoredValue.DeferredOptionalValue newStoredSuppliedValue(DeferredSupplie
409420
410421 private @ Nullable StoredValue getStoredValue (CompositeKey <N > compositeKey ) {
411422 StoredValue storedValue = this .storedValues .get (compositeKey );
412- if (isPresent (storedValue )) {
423+ if (isStoredValuePresent (storedValue )) {
413424 return storedValue ;
414425 }
415426 if (this .parentStore != null ) {
@@ -418,7 +429,7 @@ private StoredValue.DeferredOptionalValue newStoredSuppliedValue(DeferredSupplie
418429 return null ;
419430 }
420431
421- private static boolean isPresent (@ Nullable StoredValue value ) {
432+ private static boolean isStoredValuePresent (@ Nullable StoredValue value ) {
422433 return value != null && value .isPresent ();
423434 }
424435
@@ -473,6 +484,9 @@ private interface StoredValue {
473484 return value != null ? value .evaluate () : null ;
474485 }
475486
487+ /**
488+ * May contain {@code null} or a value, never an exception.
489+ */
476490 record Value (int order , @ Nullable Object value ) implements StoredValue {
477491
478492 @ Override
@@ -486,6 +500,9 @@ public boolean isPresent() {
486500 }
487501 }
488502
503+ /**
504+ * May eventually contain {@code null} or a value or an exception.
505+ */
489506 record DeferredValue (int order , DeferredSupplier delegate ) implements StoredValue {
490507
491508 @ Override
@@ -499,6 +516,9 @@ public boolean isPresent() {
499516 }
500517 }
501518
519+ /**
520+ * May eventually contain a value or an exception, never {@code null}.
521+ */
502522 record DeferredOptionalValue (int order , DeferredSupplier delegate ) implements StoredValue {
503523
504524 @ Override
@@ -548,11 +568,22 @@ private void close(CloseAction<N> closeAction) throws Throwable {
548568 private static final class DeferredSupplier implements Supplier <@ Nullable Object > {
549569
550570 private final FutureTask <@ Nullable Object > task ;
571+ private final @ Nullable Object ownerToken ;
551572
552573 DeferredSupplier (Supplier <@ Nullable Object > delegate ) {
574+ this (null , delegate );
575+ }
576+
577+ DeferredSupplier (@ Nullable Object ownerToken , Supplier <@ Nullable Object > delegate ) {
578+ this .ownerToken = ownerToken ;
553579 this .task = new FutureTask <>(delegate ::get );
554580 }
555581
582+ @ Nullable
583+ Object ownerToken () {
584+ return ownerToken ;
585+ }
586+
556587 void run () {
557588 this .task .run ();
558589 }
0 commit comments