X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-inmemory-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FResolveDataChangeState.java;fp=opendaylight%2Fmd-sal%2Fsal-inmemory-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FResolveDataChangeState.java;h=0000000000000000000000000000000000000000;hb=402dbc040ddb5dfc488320356b5a36c66d59c36e;hp=c9a842070f2b26cfb41a555fb367bc343157cfd9;hpb=bd11e415d86b815a30e3559e199f1ad4637bd02b;p=controller.git diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java deleted file mode 100644 index c9a842070f..0000000000 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.md.sal.dom.store.impl; - -import com.google.common.base.Preconditions; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; -import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder; -import org.opendaylight.controller.sal.core.compat.DataChangeListenerRegistration; -import org.opendaylight.mdsal.dom.spi.RegistrationTreeNode; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue; -import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Recursion state used in {@link ResolveDataChangeEventsTask}. Instances of this - * method track which listeners are affected by a particular change node. It takes - * care of properly inheriting SUB/ONE listeners and also provides a means to - * understand when actual processing need not occur. - */ -final class ResolveDataChangeState { - private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeState.class); - - /** - * Inherited from all parents. - */ - private final Iterable inheritedSub; - - /** - * Inherited from immediate parent. - */ - private final Collection inheritedOne; - private final YangInstanceIdentifier nodeId; - private final Collection>> nodes; - - private final Map, Builder> subBuilders; - private final Map, Builder> oneBuilders; - private final Map, Builder> baseBuilders; - - private ResolveDataChangeState(final YangInstanceIdentifier nodeId, - final Iterable inheritedSub, final Collection inheritedOne, - final Collection>> nodes) { - this.nodeId = Preconditions.checkNotNull(nodeId); - this.nodes = Preconditions.checkNotNull(nodes); - this.inheritedSub = Preconditions.checkNotNull(inheritedSub); - this.inheritedOne = Preconditions.checkNotNull(inheritedOne); - - /* - * Collect the nodes which need to be propagated from us to the child. - */ - final Map, Builder> sub = new HashMap<>(); - final Map, Builder> one = new HashMap<>(); - final Map, Builder> base = new HashMap<>(); - for (RegistrationTreeNode> n : nodes) { - for (DataChangeListenerRegistration l : n.getRegistrations()) { - final Builder b = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE); - switch (l.getScope()) { - case BASE: - base.put(l, b); - break; - case ONE: - one.put(l, b); - break; - case SUBTREE: - sub.put(l, b); - break; - default: - break; - } - } - } - - baseBuilders = maybeEmpty(base); - oneBuilders = maybeEmpty(one); - subBuilders = maybeEmpty(sub); - } - - private static Map maybeEmpty(final Map map) { - if (map.isEmpty()) { - return Collections.emptyMap(); - } - return map; - } - - /** - * Create an initial state handle at a particular root node. - * - * @param rootId root instance identifier - * @param registrationTreeNode root node - */ - public static ResolveDataChangeState initial(final YangInstanceIdentifier rootId, - final RegistrationTreeNode> registrationTreeNode) { - return new ResolveDataChangeState(rootId, Collections.emptyList(), - Collections.emptyList(), Collections.singletonList(registrationTreeNode)); - } - - /** - * Create a state handle for iterating over a particular child. - * - * @param childId ID of the child - * @return State handle - */ - public ResolveDataChangeState child(final PathArgument childId) { - /* - * We instantiate a concatenation only when needed: - * - * 1) If our collection is empty, we reuse the parent's. This is typically the case - * for intermediate node, which should be the vast majority. - * 2) If the parent's iterable is a Collection and it is empty, reuse our collection. - * This is the case for the first node which defines a subtree listener in a - * particular subtree. - * 3) Concatenate the two collections. This happens when we already have some - * subtree listeners and we encounter a node which adds a few more. - * - * This allows us to lower number of objects allocated and also - * speeds up Iterables.isEmpty() in needsProcessing(). - * - * Note that the check for Collection in 2) relies on precisely this logic, which - * ensures that we simply cannot see an empty concatenation, but rather start off with - * an empty collection, then switch to a non-empty collection and finally switch to - * a concatenation. This saves us from instantiating iterators, which a trivial - * Iterables.isEmpty() would do as soon as we cross case 3). - */ - final Iterable sb; - if (!subBuilders.isEmpty()) { - if (inheritedSub instanceof Collection && ((Collection) inheritedSub).isEmpty()) { - sb = subBuilders.values(); - } else { - sb = Iterables.concat(inheritedSub, subBuilders.values()); - } - } else { - sb = inheritedSub; - } - - return new ResolveDataChangeState(nodeId.node(childId), sb, - oneBuilders.values(), getListenerChildrenWildcarded(nodes, childId)); - } - - /** - * Get the current path. - * - * @return Current path. - */ - public YangInstanceIdentifier getPath() { - return nodeId; - } - - /** - * Check if this child needs processing. - * - * @return True if processing needs to occur, false otherwise. - */ - public boolean needsProcessing() { - // May have underlying listeners, so we need to process - if (!nodes.isEmpty()) { - return true; - } - // Have ONE listeners - if (!inheritedOne.isEmpty()) { - return true; - } - - /* - * Have SUBTREE listeners - * - * This is slightly magical replacement for !Iterables.isEmpty(inheritedSub). - * It relies on the logic in child(), which gives us the guarantee that when - * inheritedSub is not a Collection, it is guaranteed to be non-empty (which - * means we need to process). If it is a collection, we still need to check - * it for emptiness. - * - * Unlike Iterables.isEmpty() this code does not instantiate any temporary - * objects and is thus more efficient. - */ - if (inheritedSub instanceof Collection) { - return !((Collection) inheritedSub).isEmpty(); - } - - // Non-Collection => non-empty => have to process - return true; - } - - /** - * Add an event to all current listeners. - */ - public void addEvent(final DOMImmutableDataChangeEvent event) { - // Subtree builders get always notified - for (Builder b : subBuilders.values()) { - b.merge(event); - } - for (Builder b : inheritedSub) { - b.merge(event); - } - - if (event.getScope() == DataChangeScope.ONE || event.getScope() == DataChangeScope.BASE) { - for (Builder b : oneBuilders.values()) { - b.merge(event); - } - } - - if (event.getScope() == DataChangeScope.BASE) { - for (Builder b : inheritedOne) { - b.merge(event); - } - for (Builder b : baseBuilders.values()) { - b.merge(event); - } - } - } - - /** - * Gather all non-empty events into the provided map. - * - * @param before before-image - * @param after after-image - * @param map target map - */ - public void collectEvents(final NormalizedNode before, final NormalizedNode after, - final Multimap, DOMImmutableDataChangeEvent> map) { - for (Entry, Builder> e : baseBuilders.entrySet()) { - final Builder b = e.getValue(); - if (!b.isEmpty()) { - map.put(e.getKey(), b.setBefore(before).setAfter(after).build()); - } - } - for (Entry, Builder> e : oneBuilders.entrySet()) { - final Builder b = e.getValue(); - if (!b.isEmpty()) { - map.put(e.getKey(), b.setBefore(before).setAfter(after).build()); - } - } - for (Entry, Builder> e : subBuilders.entrySet()) { - final Builder b = e.getValue(); - if (!b.isEmpty()) { - map.put(e.getKey(), b.setBefore(before).setAfter(after).build()); - } - } - - LOG.trace("Collected events {}", map); - } - - private static Collection>> getListenerChildrenWildcarded( - final Collection>> parentNodes, - final PathArgument child) { - if (parentNodes.isEmpty()) { - return Collections.emptyList(); - } - - final List>> result = new ArrayList<>(); - if (child instanceof NodeWithValue || child instanceof NodeIdentifierWithPredicates) { - NodeIdentifier wildcardedIdentifier = new NodeIdentifier(child.getNodeType()); - addChildNodes(result, parentNodes, wildcardedIdentifier); - } - addChildNodes(result, parentNodes, child); - return result; - } - - private static void addChildNodes(final List>> result, - final Collection>> parentNodes, - final PathArgument childIdentifier) { - for (RegistrationTreeNode> node : parentNodes) { - RegistrationTreeNode> child = node.getExactChild(childIdentifier); - if (child != null) { - result.add(child); - } - } - } -}