X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FInMemoryDOMDataStore.java;h=00df6580effda8da33e80a648653935049010c47;hp=9bbba1e24d8600f196f23df145105d1b787e9c6e;hb=617941ac35b64881556f7311a8a296f4b60b2935;hpb=84248dac9ed8aa37e996e39429c8aa8ece473eaf diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java index 9bbba1e24d..00df6580ef 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java @@ -9,19 +9,20 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static org.opendaylight.controller.md.sal.dom.store.impl.StoreUtils.increase; import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeSnapshot; import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; -import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.InMemoryDataTreeFactory; import org.opendaylight.controller.sal.core.spi.data.DOMStore; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; @@ -32,9 +33,7 @@ import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeUtils; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; @@ -44,33 +43,21 @@ import com.google.common.base.Objects; import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Optional; import com.google.common.base.Preconditions; -import com.google.common.primitives.UnsignedLong; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; public class InMemoryDOMDataStore implements DOMStore, Identifiable, SchemaContextListener { - private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class); - private static final InstanceIdentifier PUBLIC_ROOT_PATH = InstanceIdentifier.builder().build(); - - + private final DataTree dataTree = InMemoryDataTreeFactory.getInstance().create(); + private final ListenerTree listenerTree = ListenerTree.create(); + private final AtomicLong txCounter = new AtomicLong(0); private final ListeningExecutorService executor; private final String name; - private final AtomicLong txCounter = new AtomicLong(0); - private final ListenerTree listenerTree; - private final AtomicReference snapshot; - - private ModificationApplyOperation operationTree; - - private SchemaContext schemaContext; public InMemoryDOMDataStore(final String name, final ListeningExecutorService executor) { this.name = Preconditions.checkNotNull(name); this.executor = Preconditions.checkNotNull(executor); - this.listenerTree = ListenerTree.create(); - this.snapshot = new AtomicReference(DataAndMetadataSnapshot.createEmpty()); - this.operationTree = new AlwaysFailOperation(); } @Override @@ -80,23 +67,22 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public DOMStoreReadTransaction newReadOnlyTransaction() { - return new SnapshotBackedReadTransaction(nextIdentifier(), snapshot.get()); + return new SnapshotBackedReadTransaction(nextIdentifier(), dataTree.takeSnapshot()); } @Override public DOMStoreReadWriteTransaction newReadWriteTransaction() { - return new SnapshotBackedReadWriteTransaction(nextIdentifier(), snapshot.get(), this, operationTree); + return new SnapshotBackedReadWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this); } @Override public DOMStoreWriteTransaction newWriteOnlyTransaction() { - return new SnaphostBackedWriteTransaction(nextIdentifier(), snapshot.get(), this, operationTree); + return new SnapshotBackedWriteTransaction(nextIdentifier(), dataTree.takeSnapshot(), this); } @Override public synchronized void onGlobalContextUpdated(final SchemaContext ctx) { - operationTree = SchemaAwareApplyOperationRoot.from(ctx); - schemaContext = ctx; + dataTree.setSchemaContext(ctx); } @Override @@ -104,21 +90,21 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch final InstanceIdentifier path, final L listener, final DataChangeScope scope) { /* - * Make sure commit is not occurring right now. Listener has to be registered and its - * state capture enqueued at a consistent point. + * Make sure commit is not occurring right now. Listener has to be + * registered and its state capture enqueued at a consistent point. * - * FIXME: improve this to read-write lock, such that multiple listener registrations - * can occur simultaneously + * FIXME: improve this to read-write lock, such that multiple listener + * registrations can occur simultaneously */ final DataChangeListenerRegistration reg; synchronized (this) { - LOG.debug("{}: Registering data change listener {} for {}",name,listener,path); + LOG.debug("{}: Registering data change listener {} for {}", name, listener, path); reg = listenerTree.registerDataChangeListener(path, listener, scope); - Optional currentState = snapshot.get().read(path); + Optional> currentState = dataTree.takeSnapshot().readNode(path); if (currentState.isPresent()) { - final NormalizedNode data = currentState.get().getData(); + final NormalizedNode data = currentState.get(); final DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE) // .setAfter(data) // @@ -138,9 +124,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch }; } - private synchronized DOMStoreThreePhaseCommitCohort submit( - final SnaphostBackedWriteTransaction writeTx) { - LOG.debug("Tx: {} is submitted. Modifications: {}",writeTx.getIdentifier(),writeTx.getMutatedView()); + private synchronized DOMStoreThreePhaseCommitCohort submit(final SnapshotBackedWriteTransaction writeTx) { + LOG.debug("Tx: {} is submitted. Modifications: {}", writeTx.getIdentifier(), writeTx.getMutatedView()); return new ThreePhaseCommitImpl(writeTx); } @@ -148,33 +133,6 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch return name + "-" + txCounter.getAndIncrement(); } - private void commit(final DataAndMetadataSnapshot currentSnapshot, - final StoreMetadataNode newDataTree, final ResolveDataChangeEventsTask listenerResolver) { - LOG.debug("Updating Store snaphot version: {} with version:{}",currentSnapshot.getMetadataTree().getSubtreeVersion(),newDataTree.getSubtreeVersion()); - - if(LOG.isTraceEnabled()) { - LOG.trace("Data Tree is {}",StoreUtils.toStringTree(newDataTree)); - } - - final DataAndMetadataSnapshot newSnapshot = DataAndMetadataSnapshot.builder() // - .setMetadataTree(newDataTree) // - .setSchemaContext(schemaContext) // - .build(); - - /* - * The commit has to occur atomically with regard to listener registrations. - */ - synchronized (this) { - final boolean success = snapshot.compareAndSet(currentSnapshot, newSnapshot); - checkState(success, "Store snapshot and transaction snapshot differ. This should never happen."); - - for (ChangeListenerNotifyTask task : listenerResolver.call()) { - LOG.trace("Scheduling invocation of listeners: {}",task); - executor.submit(task); - } - } - } - private static abstract class AbstractDOMStoreTransaction implements DOMStoreTransaction { private final Object identifier; @@ -195,7 +153,8 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch /** * Add class-specific toString attributes. * - * @param toStringHelper ToStringHelper instance + * @param toStringHelper + * ToStringHelper instance * @return ToStringHelper instance which was passed in */ protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { @@ -203,13 +162,14 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch } } - private static class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements DOMStoreReadTransaction { - private DataAndMetadataSnapshot stableSnapshot; + private static final class SnapshotBackedReadTransaction extends AbstractDOMStoreTransaction implements + DOMStoreReadTransaction { + private DataTreeSnapshot stableSnapshot; - public SnapshotBackedReadTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot) { + public SnapshotBackedReadTransaction(final Object identifier, final DataTreeSnapshot snapshot) { super(identifier); this.stableSnapshot = Preconditions.checkNotNull(snapshot); - LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot.getMetadataTree().getSubtreeVersion()); + LOG.debug("ReadOnly Tx: {} allocated with snapshot {}", identifier, snapshot); } @Override @@ -222,21 +182,22 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public ListenableFuture>> read(final InstanceIdentifier path) { checkNotNull(path, "Path must not be null."); checkState(stableSnapshot != null, "Transaction is closed"); - return Futures.immediateFuture(NormalizedNodeUtils.findNode(stableSnapshot.getDataTree(), path)); + return Futures.immediateFuture(stableSnapshot.readNode(path)); } } - private static class SnaphostBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction { - private MutableDataTree mutableTree; + private static class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements + DOMStoreWriteTransaction { + private DataTreeModification mutableTree; private InMemoryDOMDataStore store; private boolean ready = false; - public SnaphostBackedWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot, - final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) { + public SnapshotBackedWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, + final InMemoryDOMDataStore store) { super(identifier); - mutableTree = MutableDataTree.from(snapshot, applyOper); + mutableTree = snapshot.newModification(); this.store = store; - LOG.debug("Write Tx: {} allocated with snapshot {}",identifier,snapshot.getMetadataTree().getSubtreeVersion()); + LOG.debug("Write Tx: {} allocated with snapshot {}", identifier, snapshot); } @Override @@ -250,11 +211,11 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public void write(final InstanceIdentifier path, final NormalizedNode data) { checkNotReady(); try { - LOG.trace("Tx: {} Write: {}:{}",getIdentifier(),path,data); + LOG.trace("Tx: {} Write: {}:{}", getIdentifier(), path, data); mutableTree.write(path, data); - // FIXME: Add checked exception + // 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, mutableTree, e); } } @@ -262,11 +223,11 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public void merge(final InstanceIdentifier path, final NormalizedNode data) { checkNotReady(); try { - LOG.trace("Tx: {} Merge: {}:{}",getIdentifier(),path,data); + LOG.trace("Tx: {} Merge: {}:{}", getIdentifier(), path, data); mutableTree.merge(path, data); - // FIXME: Add checked exception + // 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, mutableTree, e); } } @@ -274,11 +235,11 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch public void delete(final InstanceIdentifier path) { checkNotReady(); try { - LOG.trace("Tx: {} Delete: {}",getIdentifier(),path); + LOG.trace("Tx: {} Delete: {}", getIdentifier(), path); mutableTree.delete(path); - // FIXME: Add checked exception + // 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, mutableTree, e); } } @@ -300,7 +261,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch return store.submit(this); } - protected MutableDataTree getMutatedView() { + protected DataTreeModification getMutatedView() { return mutableTree; } @@ -310,21 +271,21 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch } } - private static class SnapshotBackedReadWriteTransaction extends SnaphostBackedWriteTransaction implements - DOMStoreReadWriteTransaction { + private static class SnapshotBackedReadWriteTransaction extends SnapshotBackedWriteTransaction implements + DOMStoreReadWriteTransaction { - protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataAndMetadataSnapshot snapshot, - final InMemoryDOMDataStore store, final ModificationApplyOperation applyOper) { - super(identifier, snapshot, store, applyOper); + protected SnapshotBackedReadWriteTransaction(final Object identifier, final DataTreeSnapshot snapshot, + final InMemoryDOMDataStore store) { + super(identifier, snapshot, store); } @Override public ListenableFuture>> read(final InstanceIdentifier path) { - LOG.trace("Tx: {} Read: {}",getIdentifier(),path); + LOG.trace("Tx: {} Read: {}", getIdentifier(), path); try { - return Futures.immediateFuture(getMutatedView().read(path)); + return Futures.immediateFuture(getMutatedView().readNode(path)); } catch (Exception e) { - LOG.error("Tx: {} Failed Read of {}",getIdentifier(),path,e); + LOG.error("Tx: {} Failed Read of {}", getIdentifier(), path, e); throw e; } } @@ -332,59 +293,41 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch private class ThreePhaseCommitImpl implements DOMStoreThreePhaseCommitCohort { - private final SnaphostBackedWriteTransaction transaction; - private final NodeModification modification; + private final SnapshotBackedWriteTransaction transaction; + private final DataTreeModification modification; - private DataAndMetadataSnapshot storeSnapshot; - private Optional proposedSubtree; private ResolveDataChangeEventsTask listenerResolver; + private DataTreeCandidate candidate; - public ThreePhaseCommitImpl(final SnaphostBackedWriteTransaction writeTransaction) { + public ThreePhaseCommitImpl(final SnapshotBackedWriteTransaction writeTransaction) { this.transaction = writeTransaction; - this.modification = transaction.getMutatedView().getRootModification(); + this.modification = transaction.getMutatedView(); } @Override public ListenableFuture canCommit() { - final DataAndMetadataSnapshot snapshotCapture = snapshot.get(); - final ModificationApplyOperation snapshotOperation = operationTree; - return executor.submit(new Callable() { - @Override - public Boolean call() throws Exception { - boolean applicable = snapshotOperation.isApplicable(modification, - Optional.of(snapshotCapture.getMetadataTree())); - LOG.debug("Store Transcation: {} : canCommit : {}", transaction.getIdentifier(), applicable); - return applicable; + public Boolean call() { + try { + dataTree.validate(modification); + LOG.debug("Store Transaction: {} can be committed", transaction.getIdentifier()); + return true; + } catch (DataPreconditionFailedException e) { + LOG.warn("Store Tx: {} Data Precondition failed for {}.",transaction.getIdentifier(),e.getPath(),e); + return false; + } } }); } @Override public ListenableFuture preCommit() { - storeSnapshot = snapshot.get(); - if(modification.getModificationType() == ModificationType.UNMODIFIED) { - return Futures.immediateFuture(null); - } return executor.submit(new Callable() { - - - @Override - public Void call() throws Exception { - StoreMetadataNode metadataTree = storeSnapshot.getMetadataTree(); - - proposedSubtree = operationTree.apply(modification, Optional.of(metadataTree), - increase(metadataTree.getSubtreeVersion())); - - listenerResolver = ResolveDataChangeEventsTask.create() // - .setRootPath(PUBLIC_ROOT_PATH) // - .setBeforeRoot(Optional.of(metadataTree)) // - .setAfterRoot(proposedSubtree) // - .setModificationRoot(modification) // - .setListenerRoot(listenerTree); - + public Void call() { + candidate = dataTree.prepare(modification); + listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree); return null; } }); @@ -392,48 +335,28 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable, Sch @Override public ListenableFuture abort() { - storeSnapshot = null; - proposedSubtree = null; - return Futures. immediateFuture(null); + candidate = null; + return Futures.immediateFuture(null); } @Override public ListenableFuture commit() { - if(modification.getModificationType() == ModificationType.UNMODIFIED) { - return Futures.immediateFuture(null); + checkState(candidate != null, "Proposed subtree must be computed"); + + /* + * The commit has to occur atomically with regard to listener + * registrations. + */ + synchronized (this) { + dataTree.commit(candidate); + + for (ChangeListenerNotifyTask task : listenerResolver.call()) { + LOG.trace("Scheduling invocation of listeners: {}", task); + executor.submit(task); + } } - checkState(proposedSubtree != null,"Proposed subtree must be computed"); - checkState(storeSnapshot != null,"Proposed subtree must be computed"); - // return ImmediateFuture<>; - InMemoryDOMDataStore.this.commit(storeSnapshot, proposedSubtree.get(),listenerResolver); - return Futures. immediateFuture(null); - } - - } - - private static final class AlwaysFailOperation implements ModificationApplyOperation { - - @Override - public Optional apply(final NodeModification modification, - final Optional storeMeta, final UnsignedLong subtreeVersion) { - throw new IllegalStateException("Schema Context is not available."); - } - - @Override - public boolean isApplicable(final NodeModification modification, final Optional storeMetadata) { - throw new IllegalStateException("Schema Context is not available."); + return Futures.immediateFuture(null); } - - @Override - public Optional getChild(final PathArgument child) { - throw new IllegalStateException("Schema Context is not available."); - } - - @Override - public void verifyStructure(final NodeModification modification) throws IllegalArgumentException { - throw new IllegalStateException("Schema Context is not available."); - } - } }