X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-inmemory-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FSnapshotBackedWriteTransaction.java;h=faddbae850ce50753dc7ca1e7298bdc6e77c0f21;hp=6129df74787b2fdb8b2da30d9cc2c78f04b288bc;hb=3997099eb61b0f2adc47f7a85952c324e9de223f;hpb=35f74293edf98402e2b622e060185f7874d10857 diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java index 6129df7478..faddbae850 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SnapshotBackedWriteTransaction.java @@ -8,11 +8,11 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkState; - -import com.google.common.base.Objects.ToStringHelper; +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; - +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -29,11 +29,16 @@ import org.slf4j.LoggerFactory; * */ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction { - private static final Logger LOG = LoggerFactory.getLogger(SnapshotBackedWriteTransaction.class); - private DataTreeModification mutableTree; - private boolean ready = false; - private TransactionReadyPrototype readyImpl; + private static final AtomicReferenceFieldUpdater READY_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(SnapshotBackedWriteTransaction.class, TransactionReadyPrototype.class, "readyImpl"); + private static final AtomicReferenceFieldUpdater TREE_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(SnapshotBackedWriteTransaction.class, DataTreeModification.class, "mutableTree"); + + // non-null when not ready + private volatile TransactionReadyPrototype readyImpl; + // non-null when not committed/closed + private volatile DataTreeModification mutableTree; /** * Creates new write-only transaction. @@ -48,27 +53,23 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme public SnapshotBackedWriteTransaction(final Object identifier, final boolean debug, final DataTreeSnapshot snapshot, final TransactionReadyPrototype readyImpl) { super(identifier, debug); - mutableTree = snapshot.newModification(); this.readyImpl = Preconditions.checkNotNull(readyImpl, "readyImpl must not be null."); + mutableTree = snapshot.newModification(); LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot); } - @Override - public void close() { - LOG.debug("Store transaction: {} : Closed", getIdentifier()); - this.mutableTree = null; - this.readyImpl = null; - } - @Override public void write(final YangInstanceIdentifier path, final NormalizedNode data) { checkNotReady(); + + final DataTreeModification tree = mutableTree; + LOG.debug("Tx: {} Write: {}:{}", getIdentifier(), path, data); + try { - LOG.debug("Tx: {} Write: {}:{}", getIdentifier(), path, data); - mutableTree.write(path, data); + tree.write(path, data); // FIXME: Add checked exception } catch (Exception e) { - LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, tree, e); // Rethrow original ones if they are subclasses of RuntimeException // or Error Throwables.propagateIfPossible(e); @@ -80,12 +81,15 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme @Override public void merge(final YangInstanceIdentifier path, final NormalizedNode data) { checkNotReady(); + + final DataTreeModification tree = mutableTree; + LOG.debug("Tx: {} Merge: {}:{}", getIdentifier(), path, data); + try { - LOG.debug("Tx: {} Merge: {}:{}", getIdentifier(), path, data); - mutableTree.merge(path, data); + tree.merge(path, data); // FIXME: Add checked exception } catch (Exception e) { - LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, mutableTree, e); + LOG.error("Tx: {}, failed to write {}:{} in {}", getIdentifier(), path, data, tree, e); // Rethrow original ones if they are subclasses of RuntimeException // or Error Throwables.propagateIfPossible(e); @@ -97,12 +101,15 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme @Override public void delete(final YangInstanceIdentifier path) { checkNotReady(); + + final DataTreeModification tree = mutableTree; + LOG.debug("Tx: {} Delete: {}", getIdentifier(), path); + try { - LOG.debug("Tx: {} Delete: {}", getIdentifier(), path); - mutableTree.delete(path); + tree.delete(path); // FIXME: Add checked exception } catch (Exception e) { - LOG.error("Tx: {}, failed to delete {} in {}", getIdentifier(), path, mutableTree, e); + LOG.error("Tx: {}, failed to delete {} in {}", getIdentifier(), path, tree, e); // Rethrow original ones if they are subclasses of RuntimeException // or Error Throwables.propagateIfPossible(e); @@ -111,30 +118,49 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme } } - protected final boolean isReady() { - return ready; + /** + * Exposed for {@link SnapshotBackedReadWriteTransaction}'s sake only. The contract does + * not allow data access after the transaction has been closed or readied. + * + * @param path Path to read + * @return null if the the transaction has been closed; + */ + protected final Optional> readSnapshotNode(final YangInstanceIdentifier path) { + return readyImpl == null ? null : mutableTree.readNode(path); } - protected final void checkNotReady() { - checkState(!ready, "Transaction %s is ready. No further modifications allowed.", getIdentifier()); + private final void checkNotReady() { + checkState(readyImpl != null, "Transaction %s is no longer open. No further modifications allowed.", getIdentifier()); } @Override - public synchronized DOMStoreThreePhaseCommitCohort ready() { - checkState(!ready, "Transaction %s is already ready.", getIdentifier()); - ready = true; + public DOMStoreThreePhaseCommitCohort ready() { + final TransactionReadyPrototype wasReady = READY_UPDATER.getAndSet(this, null); + checkState(wasReady != null, "Transaction %s is no longer open", getIdentifier()); + LOG.debug("Store transaction: {} : Ready", getIdentifier()); - mutableTree.ready(); - return readyImpl.ready(this); + + final DataTreeModification tree = mutableTree; + TREE_UPDATER.lazySet(this, null); + tree.ready(); + return wasReady.transactionReady(this, tree); } - protected DataTreeModification getMutatedView() { - return mutableTree; + @Override + public void close() { + final TransactionReadyPrototype wasReady = READY_UPDATER.getAndSet(this, null); + if (wasReady != null) { + LOG.debug("Store transaction: {} : Closed", getIdentifier()); + TREE_UPDATER.lazySet(this, null); + wasReady.transactionAborted(this); + } else { + LOG.debug("Store transaction: {} : Closed after submit", getIdentifier()); + } } @Override protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { - return toStringHelper.add("ready", isReady()); + return toStringHelper.add("ready", readyImpl == null); } /** @@ -146,7 +172,14 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme * providing underlying logic for applying implementation. * */ - public static interface TransactionReadyPrototype { + abstract static class TransactionReadyPrototype { + /** + * Called when a transaction is closed without being readied. This is not invoked for + * transactions which are ready. + * + * @param tx Transaction which got aborted. + */ + protected abstract void transactionAborted(final SnapshotBackedWriteTransaction tx); /** * Returns a commit coordinator associated with supplied transactions. @@ -155,8 +188,10 @@ class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction impleme * * @param tx * Transaction on which ready was invoked. + * @param tree + * Modified data tree which has been constructed. * @return DOMStoreThreePhaseCommitCohort associated with transaction */ - DOMStoreThreePhaseCommitCohort ready(SnapshotBackedWriteTransaction tx); + protected abstract DOMStoreThreePhaseCommitCohort transactionReady(SnapshotBackedWriteTransaction tx, DataTreeModification tree); } } \ No newline at end of file