- // TODO: can we ditch this synchronized block?
- private synchronized DataContainerCodecPrototype<?> cacheMismatched(final Class<?> childClass,
- final DataContainerCodecPrototype<?> prototype) {
- // Original access was unsynchronized, we need to perform additional checking
- final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> local = mismatchedAugmented;
- final DataContainerCodecPrototype<?> existing = local.get(childClass);
- if (existing != null) {
- return existing;
- }
-
- final Builder<Class<?>, DataContainerCodecPrototype<?>> builder = ImmutableMap.builderWithExpectedSize(
- local.size() + 1);
- builder.putAll(local);
- builder.put(childClass, prototype);
+ private @NonNull DataContainerCodecPrototype<?> cacheMismatched(
+ final @NonNull ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> oldMismatched,
+ final @NonNull Class<?> childClass, final @NonNull DataContainerCodecPrototype<?> prototype) {
+
+ ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> expected = oldMismatched;
+ while (true) {
+ final Map<Class<?>, DataContainerCodecPrototype<?>> newMismatched =
+ ImmutableMap.<Class<?>, DataContainerCodecPrototype<?>>builderWithExpectedSize(expected.size() + 1)
+ .putAll(expected)
+ .put(childClass, prototype)
+ .build();
+
+ final Object witness = MISMATCHED_AUGMENTED.compareAndExchangeRelease(this, expected, newMismatched);
+ if (witness == expected) {
+ LOG.trace("Cached mismatched augmentation {} -> {} in {}", childClass, prototype, this);
+ return prototype;
+ }