From: Robert Varga Date: Tue, 11 Jun 2019 16:53:18 +0000 (+0200) Subject: Deduplicate concurrent SchemaContext loads X-Git-Tag: v3.0.3~32 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=6ee69cdac4289a3ef81c2ab989f40522149b89ce;p=yangtools.git Deduplicate concurrent SchemaContext loads In case we are running concurrent SchemaContext computation, if the result is not cached we will have multiple results. These need to be reconciled with the cache, so that those results will be squashed into a single instance. JIRA: YANGTOOLS-1004 Change-Id: I82df2b32a534d0acc803548579fb8ad138853c68 Signed-off-by: Robert Varga --- diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java index 5f2214444d..10a81fa01e 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java @@ -24,6 +24,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -31,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.ExecutionException; import org.antlr.v4.runtime.ParserRuleContext; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext; @@ -101,20 +103,31 @@ final class SharedSchemaContextFactory implements EffectiveModelContextFactory { final ListenableFuture cf = Futures.transformAsync(sf, assembleSources, MoreExecutors.directExecutor()); - // Populate cache when successful + final SettableFuture rf = SettableFuture.create(); Futures.addCallback(cf, new FutureCallback() { @Override public void onSuccess(final EffectiveModelContext result) { - cache.put(uniqueSourceIdentifiers, result); + // Deduplicate concurrent loads + final EffectiveModelContext existing; + try { + existing = cache.get(uniqueSourceIdentifiers, () -> result); + } catch (ExecutionException e) { + LOG.warn("Failed to recheck result with cache, will use computed value", e); + rf.set(result); + return; + } + + rf.set(existing); } @Override public void onFailure(final Throwable cause) { LOG.debug("Failed to assemble sources", cause); + rf.setException(cause); } }, MoreExecutors.directExecutor()); - return cf; + return rf; } private ListenableFuture requestSource(final @NonNull SourceIdentifier identifier) {