From 6842a017d5c7b89742152ce7ea37a11a776ad559 Mon Sep 17 00:00:00 2001 From: Tomas Cere Date: Wed, 2 Jun 2021 14:08:25 +0200 Subject: [PATCH] Remove failed cache entries We need to remove these from the cache once their corresponding future fails, otherwise these would not be recomputed. JIRA: YANGTOOLS-1293 Change-Id: Ic1c58392e7948f4a5fb144df6e8782ea0ffcab11 Signed-off-by: Tomas Cere Signed-off-by: Robert Varga --- .../SharedEffectiveModelContextFactory.java | 4 ++ ...haredEffectiveModelContextFactoryTest.java | 54 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/parser/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactory.java b/parser/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactory.java index 7c7ff28884..a3f70814c6 100644 --- a/parser/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactory.java +++ b/parser/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactory.java @@ -218,6 +218,10 @@ final class SharedEffectiveModelContextFactory implements EffectiveModelContextF public void onFailure(final Throwable cause) { LOG.debug("Failed assembly of {} in {}", sources, sw, cause); entry.getFuture().setException(cause); + + // remove failed result from the cache so it can be recomputed, as this might have been a transient + // problem. + cache.remove(sources, entry); } }, MoreExecutors.directExecutor()); } diff --git a/parser/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactoryTest.java b/parser/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactoryTest.java index 6e88c41d85..bcbaa6ee85 100644 --- a/parser/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactoryTest.java +++ b/parser/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedEffectiveModelContextFactoryTest.java @@ -7,7 +7,12 @@ */ package org.opendaylight.yangtools.yang.parser.repo; +import static java.util.Objects.requireNonNull; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture; import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture; import com.google.common.util.concurrent.ListenableFuture; @@ -18,11 +23,13 @@ import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.yangtools.yang.common.Revision; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider; import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource; import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToIRTransformer; @@ -85,4 +92,51 @@ public class SharedEffectiveModelContextFactoryTest { sharedSchemaContextFactory.createEffectiveModelContext(sIdWithoutRevision, provider.getId()); assertNotNull(schemaContext.get()); } + + @Test + public void testTransientFailureWhilreRetrievingSchemaSource() throws Exception { + final RevisionSourceIdentifier s3 = + RevisionSourceIdentifier.create("network-topology", Revision.of("2013-10-21")); + + repository.registerSchemaSource(new TransientFailureProvider( + YangTextSchemaSource.forResource("/ietf/network-topology@2013-10-21.yang")), + PotentialSchemaSource.create(s3, YangTextSchemaSource.class, 1)); + + final SharedEffectiveModelContextFactory sharedSchemaContextFactory = + new SharedEffectiveModelContextFactory(repository, config); + + ListenableFuture schemaContext = + sharedSchemaContextFactory.createEffectiveModelContext(s1, s3); + + final ExecutionException exception = assertThrows(ExecutionException.class, schemaContext::get); + assertThat(exception.getCause(), instanceOf(MissingSchemaSourceException.class)); + + // check if future is invalidated and resolution of source is retried after failure + schemaContext = sharedSchemaContextFactory.createEffectiveModelContext(s1, s3); + assertNotNull(schemaContext.get()); + } + + /** + * Schema source provider that fails on first attempt of getSource() and succeeds on every subsequent call + * to simulate transient failures of source retrieval. + */ + private static final class TransientFailureProvider implements SchemaSourceProvider { + + private final YangTextSchemaSource schemaSource; + private boolean shouldFail = true; + + private TransientFailureProvider(final YangTextSchemaSource schemaSource) { + this.schemaSource = requireNonNull(schemaSource); + } + + @Override + public ListenableFuture getSource(final SourceIdentifier sourceIdentifier) { + if (shouldFail) { + shouldFail = false; + return immediateFailedFluentFuture(new Exception("Transient test failure.")); + } + + return immediateFluentFuture(schemaSource); + } + } } -- 2.36.6