From: Robert Varga Date: Tue, 7 May 2019 13:03:57 +0000 (+0200) Subject: Allow SnapshotBackedReadTransaction customization X-Git-Tag: release/fluorine-sr3~5 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=fccad6eeb7f09713bc1037f74c0cf938eb3c380c;p=mdsal.git Allow SnapshotBackedReadTransaction customization In some specific cases we need to customize abort-like handling, which is already implemented for write-like transactions, but is not present for read-only transaction. This patch adds the capability to attach a close() handler and makes sure AbstractSnapshotBackedTransactionChain takes advantage of it. JIRA: CONTROLLER-1879 Change-Id: Ic7027956556b5dd25120ee81613a6151e5dbc501 Signed-off-by: Robert Varga (cherry picked from commit bd73bf5803137b27e25a647ff056da3f59e0a682) --- diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/AbstractSnapshotBackedTransactionChain.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/AbstractSnapshotBackedTransactionChain.java index 4301021eaf..03003ad2ad 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/AbstractSnapshotBackedTransactionChain.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/AbstractSnapshotBackedTransactionChain.java @@ -12,6 +12,7 @@ import com.google.common.base.Preconditions; import java.util.AbstractMap.SimpleEntry; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedReadTransaction.TransactionClosePrototype; import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; @@ -26,7 +27,7 @@ import org.slf4j.LoggerFactory; */ @Beta public abstract class AbstractSnapshotBackedTransactionChain - extends TransactionReadyPrototype implements DOMStoreTransactionChain { + extends TransactionReadyPrototype implements DOMStoreTransactionChain, TransactionClosePrototype { private abstract static class State { /** * Allocate a new snapshot. @@ -131,7 +132,12 @@ public abstract class AbstractSnapshotBackedTransactionChain protected DOMStoreReadTransaction newReadOnlyTransaction(T transactionId) { final Entry entry = getSnapshot(); return SnapshotBackedTransactions.newReadTransaction(transactionId, - getDebugTransactions(), entry.getValue()); + getDebugTransactions(), entry.getValue(), this); + } + + @Override + public void transactionClosed(final SnapshotBackedReadTransaction tx) { + // Defaults to no-op } @Override @@ -178,9 +184,8 @@ public abstract class AbstractSnapshotBackedTransactionChain if (allocated.getTransaction().equals(tx)) { final boolean success = STATE_UPDATER.compareAndSet(this, localState, idleState); if (!success) { - LOG.warn("Transaction {} aborted, but chain {} s" - + "tate already transitioned from {} to {}, very strange", - tx, this, localState, state); + LOG.warn("Transaction {} aborted, but chain {} state already transitioned from {} to {}, " + + "very strange", tx, this, localState, state); } } } diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransaction.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransaction.java index ac754f56f2..1c1b34e30d 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransaction.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransaction.java @@ -13,6 +13,7 @@ import com.google.common.annotations.Beta; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.opendaylight.mdsal.common.api.ReadFailedException; import org.opendaylight.yangtools.util.concurrent.FluentFutures; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -30,8 +31,15 @@ import org.slf4j.LoggerFactory; @Beta public final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements DOMStoreReadTransaction, SnapshotBackedTransaction { - private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedReadTransaction.class); + + @SuppressWarnings("rawtypes") + private static final AtomicReferenceFieldUpdater SNAPSHOT_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(SnapshotBackedReadTransaction.class, DataTreeSnapshot.class, + "stableSnapshot"); + + // Guarded by stableSnapshot CAS, hence it does not need to be volatile + private TransactionClosePrototype closeImpl; private volatile DataTreeSnapshot stableSnapshot; /** @@ -41,16 +49,27 @@ public final class SnapshotBackedReadTransaction extends * @param debug Enable transaction debugging * @param snapshot Snapshot which will be modified. */ - SnapshotBackedReadTransaction(final T identifier, final boolean debug, final DataTreeSnapshot snapshot) { + SnapshotBackedReadTransaction(final T identifier, final boolean debug, final DataTreeSnapshot snapshot, + final TransactionClosePrototype closeImpl) { super(identifier, debug); this.stableSnapshot = requireNonNull(snapshot); + this.closeImpl = closeImpl; LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot); } @Override public void close() { + final DataTreeSnapshot prev = SNAPSHOT_UPDATER.getAndSet(this, null); + if (prev == null) { + LOG.debug("Store transaction: {} : previously closed", getIdentifier()); + return; + } + LOG.debug("Store transaction: {} : Closed", getIdentifier()); - stableSnapshot = null; + if (closeImpl != null) { + closeImpl.transactionClosed(this); + closeImpl = null; + } } @SuppressWarnings("checkstyle:IllegalCatch") @@ -84,4 +103,23 @@ public final class SnapshotBackedReadTransaction extends public java.util.Optional getSnapshot() { return java.util.Optional.ofNullable(stableSnapshot); } + + /** + * Prototype implementation of {@link SnapshotBackedReadTransaction#close()}. + * + *

+ * This class is intended to be implemented by Transaction factories responsible for allocation + * of {@link org.opendaylight.mdsal.dom.spi.store.SnapshotBackedReadTransaction} and + * providing underlying logic for applying implementation. + * + * @param identifier type + */ + public interface TransactionClosePrototype { + /** + * Called when a transaction is closed. This is not invoked at most once for every transaction. + * + * @param tx Transaction which got closed. + */ + void transactionClosed(SnapshotBackedReadTransaction tx); + } } diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedTransactions.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedTransactions.java index ccf1f7884d..e90c7a4745 100644 --- a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedTransactions.java +++ b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedTransactions.java @@ -7,7 +7,11 @@ */ package org.opendaylight.mdsal.dom.spi.store; +import static java.util.Objects.requireNonNull; + import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedReadTransaction.TransactionClosePrototype; import org.opendaylight.mdsal.dom.spi.store.SnapshotBackedWriteTransaction.TransactionReadyPrototype; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; @@ -22,13 +26,29 @@ public final class SnapshotBackedTransactions { /** * Creates a new read-only transaction. + * * @param identifier Transaction Identifier * @param debug Enable transaction debugging * @param snapshot Snapshot which will be modified. + * @return A new read-only transaction */ - public static SnapshotBackedReadTransaction newReadTransaction(final T identifier, + public static @NonNull SnapshotBackedReadTransaction newReadTransaction(final T identifier, final boolean debug, final DataTreeSnapshot snapshot) { - return new SnapshotBackedReadTransaction<>(identifier, debug, snapshot); + return new SnapshotBackedReadTransaction<>(identifier, debug, snapshot, null); + } + + /** + * Creates a new read-only transaction. + * + * @param identifier Transaction Identifier + * @param debug Enable transaction debugging + * @param snapshot Snapshot which will be modified. + * @param closeImpl Implementation of close method + * @return A new read-only transaction + */ + public static @NonNull SnapshotBackedReadTransaction newReadTransaction(final T identifier, + final boolean debug, final DataTreeSnapshot snapshot, final TransactionClosePrototype closeImpl) { + return new SnapshotBackedReadTransaction<>(identifier, debug, snapshot, requireNonNull(closeImpl)); } /** @@ -38,8 +58,9 @@ public final class SnapshotBackedTransactions { * @param debug Enable transaction debugging * @param snapshot Snapshot which will be modified. * @param readyImpl Implementation of ready method. + * @return A new read-write transaction */ - public static SnapshotBackedReadWriteTransaction newReadWriteTransaction(final T identifier, + public static @NonNull SnapshotBackedReadWriteTransaction newReadWriteTransaction(final T identifier, final boolean debug, final DataTreeSnapshot snapshot, final TransactionReadyPrototype readyImpl) { return new SnapshotBackedReadWriteTransaction<>(identifier, debug, snapshot, readyImpl); } @@ -51,8 +72,9 @@ public final class SnapshotBackedTransactions { * @param debug Enable transaction debugging * @param snapshot Snapshot which will be modified. * @param readyImpl Implementation of ready method. + * @return A new write transaction */ - public static SnapshotBackedWriteTransaction newWriteTransaction(final T identifier, + public static @NonNull SnapshotBackedWriteTransaction newWriteTransaction(final T identifier, final boolean debug, final DataTreeSnapshot snapshot, final TransactionReadyPrototype readyImpl) { return new SnapshotBackedWriteTransaction<>(identifier, debug, snapshot, readyImpl); } diff --git a/dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransactionTest.java b/dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransactionTest.java index c137b61ae8..cf1ccb4aaf 100644 --- a/dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransactionTest.java +++ b/dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/store/SnapshotBackedReadTransactionTest.java @@ -29,8 +29,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; public class SnapshotBackedReadTransactionTest { private static final DataTreeSnapshot DATA_TREE_SNAPSHOT = mock(DataTreeSnapshot.class); - private static SnapshotBackedReadTransaction snapshotBackedReadTransaction = - new SnapshotBackedReadTransaction<>(new Object(), false, DATA_TREE_SNAPSHOT); + + private SnapshotBackedReadTransaction snapshotBackedReadTransaction = + new SnapshotBackedReadTransaction<>(new Object(), false, DATA_TREE_SNAPSHOT, null); @Test public void basicTest() throws Exception { @@ -67,7 +68,8 @@ public class SnapshotBackedReadTransactionTest { @Test(expected = ReadFailedException.class) public void readNodeTestWithException() throws Throwable { doThrow(new NullPointerException("no Node")).when(DATA_TREE_SNAPSHOT).readNode(any()); - snapshotBackedReadTransaction = new SnapshotBackedReadTransaction<>(new Object(), false, DATA_TREE_SNAPSHOT); + snapshotBackedReadTransaction = new SnapshotBackedReadTransaction<>(new Object(), false, DATA_TREE_SNAPSHOT, + null); try { snapshotBackedReadTransaction.read(YangInstanceIdentifier.EMPTY).get(); fail("Expected ReadFailedException");