From 6ee69cdac4289a3ef81c2ab989f40522149b89ce Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 11 Jun 2019 18:53:18 +0200 Subject: [PATCH] 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 --- .../repo/SharedSchemaContextFactory.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) 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) { -- 2.36.6