From 87b99506882331057cd6e83da9adf617317bffae Mon Sep 17 00:00:00 2001 From: han Date: Sun, 30 Sep 2018 16:49:54 +0800 Subject: [PATCH] Fix up release old producers to avoid memory leak - It should close all correlative old 'InMemoryDOMDataTreeShardProducer' when close a 'ShardedDOMDataTreeProducer', or a memory leak happens for repeatly creating and closing the same producer as well as in the case of attach/detach subshards. JIRA: MDSAL-386 Change-Id: I9c6ad6b63de4dfc7b75a315fce23a5da3be9d06d Signed-off-by: Jie Han Signed-off-by: Robert Varga --- .../mdsal/dom/broker/ProducerLayout.java | 12 +- .../broker/ShardedDOMDataTreeProducer.java | 2 +- ...rdedDOMDataTreeProducerMultiShardTest.java | 129 ++++++++++++++++++ ...dedDOMDataTreeProducerSingleShardTest.java | 1 + .../ShardedDOMDataWriteTransactionTest.java | 2 + .../inmemory/InMemoryDOMDataTreeShard.java | 14 +- .../InMemoryDOMDataTreeShardProducer.java | 19 +++ .../InMemoryShardDataModificationFactory.java | 6 + .../InMemoryDOMDataTreeShardTest.java | 7 +- .../mdsal/dom/store/inmemory/TestUtils.java | 9 +- .../spi/shard/DOMDataTreeShardProducer.java | 13 +- .../ForeignShardModificationContext.java | 4 + 12 files changed, 203 insertions(+), 15 deletions(-) diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ProducerLayout.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ProducerLayout.java index e383d5be6a..6b5a0a531b 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ProducerLayout.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ProducerLayout.java @@ -7,6 +7,8 @@ */ package org.opendaylight.mdsal.dom.broker; +import static java.util.Objects.requireNonNull; + import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; @@ -42,8 +44,8 @@ final class ProducerLayout { final BiMap idToProducer, final Map children) { this.shardMap = ImmutableMap.copyOf(shardMap); - this.idToProducer = Preconditions.checkNotNull(idToProducer); - this.children = Preconditions.checkNotNull(children); + this.idToProducer = requireNonNull(idToProducer); + this.children = requireNonNull(children); } static ProducerLayout create(final Map shardMap) { @@ -87,6 +89,7 @@ final class ProducerLayout { } ProducerLayout reshard(final Map newShardMap) { + close(); return new ProducerLayout(newShardMap, mapIdsToProducer(newShardMap), children); } @@ -134,4 +137,9 @@ final class ProducerLayout { "Cannot create transaction since the producer is not mapped to any shard"); return Maps.transformValues(idToProducer, DOMDataTreeShardProducer::createTransaction); } + + void close() { + idToProducer.values().forEach(DOMDataTreeShardProducer::close); + } + } diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java index e842e433fd..f377c9322f 100644 --- a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java +++ b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducer.java @@ -79,7 +79,6 @@ class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { void subshardAdded(final Map shardMap) { checkIdle(); - layout = layout.reshard(shardMap); } @@ -195,6 +194,7 @@ class ShardedDOMDataTreeProducer implements DOMDataTreeProducer { if (CLOSED_UPDATER.compareAndSet(this, 0, 1)) { synchronized (this) { dataTree.destroyProducer(this); + layout.close(); } } } diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerMultiShardTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerMultiShardTest.java index cd2ed50643..a497ffff6f 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerMultiShardTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerMultiShardTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import com.google.common.collect.Iterables; import com.google.common.util.concurrent.Futures; import java.util.Collection; import java.util.Collections; @@ -252,6 +253,134 @@ public class ShardedDOMDataTreeProducerMultiShardTest { verifyNoMoreInteractions(mockedDataTreeListener); } + @Test + public void testMultipleShardsProducerClose() throws Exception { + final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1); + innerShard.onGlobalContextUpdated(SCHEMA_CONTEXT); + + assertTrue(rootShard.getProducers().isEmpty()); + + final DOMDataTreeProducer innerShardRegProducer = + dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID)); + assertTrue(rootShard.getProducers().size() == 1); + final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers()); + assertEquals(rootShardProducer.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + + dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer); + + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().size() == 1); + final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers()); + assertEquals(innerShardProducer.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + + innerShardRegProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().isEmpty()); + + final DOMDataTreeProducer testProducer = + dataTreeService.createProducer(Collections.singletonList(TEST_ID)); + assertTrue(rootShard.getProducers().size() == 1); + final DOMDataTreeShardProducer rootShardProducer2 = Iterables.getOnlyElement(rootShard.getProducers()); + assertEquals(rootShardProducer2.getPrefixes().toString(), + Collections.singletonList(TEST_ID).toString()); + + assertTrue(innerShard.getProducers().size() == 1); + final DOMDataTreeShardProducer innerShardProducer2 = Iterables.getOnlyElement(innerShard.getProducers()); + assertEquals(innerShardProducer2.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + + testProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().isEmpty()); + } + + @Test + public void testMultipleShardsChildProducerClose() throws Exception { + final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1); + innerShard.onGlobalContextUpdated(SCHEMA_CONTEXT); + + final DOMDataTreeProducer innerShardRegProducer = + dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID)); + dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer); + innerShardRegProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().isEmpty()); + + final DOMDataTreeProducer testProducer = + dataTreeService.createProducer(Collections.singletonList(TEST_ID)); + final DOMDataTreeProducer testChildProducer = testProducer.createProducer( + Collections.singletonList(INNER_CONTAINER_ID)); + assertTrue(rootShard.getProducers().size() == 1); + assertTrue(innerShard.getProducers().size() == 2); + + final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers()); + assertEquals(rootShardProducer.getPrefixes().toString(), + Collections.singletonList(TEST_ID).toString()); + + for (DOMDataTreeShardProducer producer : innerShard.getProducers()) { + assertEquals(producer.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + } + + testProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().size() == 1); + final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers()); + assertEquals(innerShardProducer.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + + testChildProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().isEmpty()); + } + + @Test + public void testMultipleShardsProducerCloseForSubshardAttached() throws Exception { + final InMemoryDOMDataTreeShard innerShard = InMemoryDOMDataTreeShard.create(INNER_CONTAINER_ID, executor, 1); + innerShard.onGlobalContextUpdated(SCHEMA_CONTEXT); + + final DOMDataTreeProducer innerShardRegProducer = + dataTreeService.createProducer(Collections.singletonList(INNER_CONTAINER_ID)); + dataTreeService.registerDataTreeShard(INNER_CONTAINER_ID, innerShard, innerShardRegProducer); + innerShardRegProducer.close(); + assertTrue(rootShard.getProducers().isEmpty()); + assertTrue(innerShard.getProducers().isEmpty()); + + final DOMDataTreeProducer testProducer = + dataTreeService.createProducer(Collections.singletonList(TEST_ID)); + assertTrue(rootShard.getProducers().size() == 1); + assertTrue(innerShard.getProducers().size() == 1); + + final DOMDataTreeShardProducer rootShardProducer = Iterables.getOnlyElement(rootShard.getProducers()); + assertEquals(rootShardProducer.getPrefixes().toString(), + Collections.singletonList(TEST_ID).toString()); + + final DOMDataTreeShardProducer innerShardProducer = Iterables.getOnlyElement(innerShard.getProducers()); + assertEquals(innerShardProducer.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + + final InMemoryDOMDataTreeShard test2Shard = InMemoryDOMDataTreeShard.create(TEST2_ID, executor, 1); + innerShard.onGlobalContextUpdated(SCHEMA_CONTEXT); + + final DOMDataTreeProducer test2ShardRegProducer = + dataTreeService.createProducer(Collections.singletonList(TEST2_ID)); + dataTreeService.registerDataTreeShard(TEST2_ID, test2Shard, test2ShardRegProducer); + test2ShardRegProducer.close(); + + assertTrue(rootShard.getProducers().size() == 1); + assertTrue(innerShard.getProducers().size() == 1); + + final DOMDataTreeShardProducer rootShardProducer2 = Iterables.getOnlyElement(rootShard.getProducers()); + assertEquals(rootShardProducer2.getPrefixes().toString(), + Collections.singletonList(TEST_ID).toString()); + + final DOMDataTreeShardProducer innerShardProducer2 = Iterables.getOnlyElement(innerShard.getProducers()); + assertEquals(innerShardProducer2.getPrefixes().toString(), + Collections.singletonList(INNER_CONTAINER_ID).toString()); + } + @Test public void testMultipleWritesIntoSingleShard() throws Exception { final DOMDataTreeListener mockedDataTreeListener = mock(DOMDataTreeListener.class); diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerSingleShardTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerSingleShardTest.java index cd1558642b..0809cec4f4 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerSingleShardTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataTreeProducerSingleShardTest.java @@ -87,6 +87,7 @@ public class ShardedDOMDataTreeProducerSingleShardTest { doReturn("rootShard").when(rootShard).toString(); doReturn(producerMock).when(rootShard).createProducer(any(Collection.class)); doReturn(shardTxMock).when(producerMock).createTransaction(); + doNothing().when(producerMock).close(); doNothing().when(shardTxMock).ready(); doReturn(Futures.immediateFuture(null)).when(shardTxMock).submit(); diff --git a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataWriteTransactionTest.java b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataWriteTransactionTest.java index b277ea92a6..035acaca99 100644 --- a/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataWriteTransactionTest.java +++ b/dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/ShardedDOMDataWriteTransactionTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.MockitoAnnotations.initMocks; @@ -59,6 +60,7 @@ public class ShardedDOMDataWriteTransactionTest { doReturn(new TestDOMShardWriteTransaction()).when(mockedProducer).createTransaction(); doReturn(mockedProducer).when(rootShard).createProducer(any(Collection.class)); + doNothing().when(mockedProducer).close(); final ShardedDOMDataTree shardedDOMDataTree = new ShardedDOMDataTree(); diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShard.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShard.java index 393e1cd2ef..e03795b214 100644 --- a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShard.java +++ b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShard.java @@ -117,6 +117,7 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha public void onChildDetached(final DOMDataTreeIdentifier childPrefix, final DOMDataTreeShard child) { childShards.remove(childPrefix); childShardsTable.remove(childPrefix); + //FIXME: Producers not being affected could be skipped over. updateProducers(); } @@ -165,7 +166,7 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha @Override public InMemoryDOMDataTreeShardProducer createProducer(final Collection prefixes) { for (final DOMDataTreeIdentifier prodPrefix : prefixes) { - checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shart root", prodPrefix, + checkArgument(prefix.contains(prodPrefix), "Prefix %s is not contained under shard root", prodPrefix, prefix); } @@ -176,8 +177,10 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha } void closeProducer(final InMemoryDOMDataTreeShardProducer producer) { - if (!producers.remove(producer)) { - LOG.warn("Producer {} not found in shard {}", producer, this); + synchronized (this) { + if (!producers.remove(producer)) { + LOG.warn("Producer {} not found in shard {}", producer, this); + } } } @@ -249,4 +252,9 @@ public class InMemoryDOMDataTreeShard implements ReadableWriteableDOMDataTreeSha producer.getModificationFactory().createModification((CursorAwareDataTreeSnapshot) snapshot), dataTree, shardChangePublisher, executor); } + + @VisibleForTesting + public Collection getProducers() { + return producers; + } } diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducer.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducer.java index 17e062464a..a91362d232 100644 --- a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducer.java +++ b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardProducer.java @@ -14,6 +14,7 @@ import com.google.common.collect.ImmutableSet; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardProducer; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; @@ -130,6 +131,19 @@ class InMemoryDOMDataTreeShardProducer implements DOMDataTreeShardProducer { return ret; } + @Override + public void close() { + final Shutdown shutdown = new Shutdown("Producer closed"); + if (!STATE_UPDATER.compareAndSet(this, idleState, shutdown)) { + throw new IllegalStateException("Producer " + this + " in unexpected state " + state); + } + + // FIXME: This call is ugly, it's better to clean up all by exposing only one entrance, + // 'closeProducer' of shard or this 'close'. + getParentShard().closeProducer(this); + getModificationFactory().close(); + } + void transactionReady(final InmemoryDOMDataTreeShardWriteTransaction tx, final DataTreeModification modification) { final State localState = state; LOG.debug("Transaction was readied {}, current state {}", tx.getIdentifier(), localState); @@ -204,11 +218,16 @@ class InMemoryDOMDataTreeShardProducer implements DOMDataTreeShardProducer { return prefixes; } + @NonNull InMemoryDOMDataTreeShard getParentShard() { + return parentShard; + } + InMemoryShardDataModificationFactory getModificationFactory() { return modificationFactory; } void setModificationFactory(final InMemoryShardDataModificationFactory modificationFactory) { + this.getModificationFactory().close(); this.modificationFactory = requireNonNull(modificationFactory); } } diff --git a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryShardDataModificationFactory.java b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryShardDataModificationFactory.java index ffb487b15d..c772ee90ed 100644 --- a/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryShardDataModificationFactory.java +++ b/dom/mdsal-dom-inmemory-datastore/src/main/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryShardDataModificationFactory.java @@ -12,6 +12,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import java.util.Map; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardProducer; import org.opendaylight.mdsal.dom.spi.shard.ForeignShardModificationContext; import org.opendaylight.mdsal.dom.spi.shard.WriteableModificationNode; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; @@ -44,4 +45,9 @@ final class InMemoryShardDataModificationFactory { ShardDataModification createModification(final CursorAwareDataTreeSnapshot snapshot) { return new ShardDataModification(new ShardRootModificationContext(root, snapshot), children, childShards); } + + void close() { + childShards.values().stream().map(ForeignShardModificationContext::getProducer) + .forEach(DOMDataTreeShardProducer::close); + } } diff --git a/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardTest.java b/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardTest.java index 181043d2af..28488bcba7 100644 --- a/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardTest.java +++ b/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/InMemoryDOMDataTreeShardTest.java @@ -29,7 +29,6 @@ import org.junit.Test; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; -import org.opendaylight.mdsal.dom.spi.shard.ReadableWriteableDOMDataTreeShard; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -48,9 +47,11 @@ public class InMemoryDOMDataTreeShardTest { new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of(QName.create("", "Test"))); - final ReadableWriteableDOMDataTreeShard domDataTreeShard = mock(ReadableWriteableDOMDataTreeShard.class); + final InMemoryDOMDataTreeShard domDataTreeShard = mock(InMemoryDOMDataTreeShard.class); doReturn("testReadableWriteableDOMDataTreeShard").when(domDataTreeShard).toString(); doReturn(DOM_DATA_TREE_SHARD_PRODUCER).when(domDataTreeShard).createProducer(any()); + doReturn(domDataTreeShard).when(DOM_DATA_TREE_SHARD_PRODUCER).getParentShard(); + doNothing().when(DOM_DATA_TREE_SHARD_PRODUCER).close(); assertFalse(inMemoryDOMDataTreeShard.getChildShards().containsValue(domDataTreeShard)); inMemoryDOMDataTreeShard.onChildAttached(DOM_DATA_TREE_IDENTIFIER, domDataTreeShard); @@ -63,7 +64,7 @@ public class InMemoryDOMDataTreeShardTest { final InMemoryDOMDataTreeShardProducer mockProducer = mock(InMemoryDOMDataTreeShardProducer.class); doReturn(prefixes).when(mockProducer).getPrefixes(); doReturn(inMemoryDOMDataTreeShard.createModificationFactory(prefixes)) - .when(mockProducer).getModificationFactory(); + .when(mockProducer).getModificationFactory(); inMemoryDOMDataTreeShard.onGlobalContextUpdated(createTestContext()); inMemoryDOMDataTreeShard.createTransaction("", mockProducer, mock(CursorAwareDataTreeSnapshot.class)); diff --git a/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/TestUtils.java b/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/TestUtils.java index 3af5bfa469..768eaba4f4 100644 --- a/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/TestUtils.java +++ b/dom/mdsal-dom-inmemory-datastore/src/test/java/org/opendaylight/mdsal/dom/store/inmemory/TestUtils.java @@ -17,8 +17,6 @@ import java.util.Map; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteCursor; -import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardProducer; -import org.opendaylight.mdsal.dom.spi.shard.DOMDataTreeShardWriteTransaction; import org.opendaylight.mdsal.dom.spi.shard.ForeignShardModificationContext; import org.opendaylight.mdsal.dom.spi.shard.WriteCursorStrategy; import org.opendaylight.mdsal.dom.spi.shard.WriteableModificationNode; @@ -54,10 +52,11 @@ final class TestUtils { static final WriteCursorStrategy WRITE_CURSOR_STRATEGY = mock(WriteCursorStrategy.class); - static final DOMDataTreeShardProducer DOM_DATA_TREE_SHARD_PRODUCER = mock(DOMDataTreeShardProducer.class); + static final InMemoryDOMDataTreeShardProducer DOM_DATA_TREE_SHARD_PRODUCER = + mock(InMemoryDOMDataTreeShardProducer.class); - static final DOMDataTreeShardWriteTransaction DOM_DATA_TREE_SHARD_WRITE_TRANSACTION = - mock(DOMDataTreeShardWriteTransaction.class); + static final InmemoryDOMDataTreeShardWriteTransaction DOM_DATA_TREE_SHARD_WRITE_TRANSACTION = + mock(InmemoryDOMDataTreeShardWriteTransaction.class); static final DataTree DATA_TREE = mock(DataTree.class); diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/DOMDataTreeShardProducer.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/DOMDataTreeShardProducer.java index cb1f2b1c80..0ae5876c67 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/DOMDataTreeShardProducer.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/DOMDataTreeShardProducer.java @@ -11,9 +11,10 @@ import com.google.common.annotations.Beta; import java.util.Collection; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; +import org.opendaylight.yangtools.concepts.Registration; @Beta -public interface DOMDataTreeShardProducer { +public interface DOMDataTreeShardProducer extends Registration { /** * Return the collection of tree identifiers to which this producer is bound. This collection * is constant during the lifetime of a producer. @@ -30,4 +31,14 @@ public interface DOMDataTreeShardProducer { * @throws IllegalStateException if a previous transaction has not been closed */ @NonNull DOMDataTreeShardWriteTransaction createTransaction(); + + /** + * Close this producer, releasing all resources. Default implementation does nothing, implementations should provide + * an implementation. + */ + // FIXME: 4.0.0: make this method non-default + @Override + default void close() { + + } } diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/ForeignShardModificationContext.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/ForeignShardModificationContext.java index bf14d73996..ed7d00f62c 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/ForeignShardModificationContext.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/shard/ForeignShardModificationContext.java @@ -79,6 +79,10 @@ public final class ForeignShardModificationContext implements Identifiable validate() { return tx.validate(); } -- 2.36.6