2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.cluster.datastore;
11 import akka.actor.ActorRef;
12 import akka.actor.PoisonPill;
13 import akka.actor.Status;
14 import com.google.common.base.Preconditions;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.List;
20 import javax.annotation.concurrent.NotThreadSafe;
21 import org.opendaylight.controller.cluster.datastore.DataTreeCohortActor.CanCommit;
22 import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
23 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
24 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeSnapshot;
25 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeCandidate;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
31 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * Registry of user commit cohorts, which is responsible for handling registration and calculation
39 * of affected cohorts based on {@link DataTreeCandidate}.
43 class DataTreeCohortActorRegistry extends AbstractRegistrationTree<ActorRef> {
45 private static final Logger LOG = LoggerFactory.getLogger(DataTreeCohortActorRegistry.class);
47 private final Map<ActorRef, RegistrationTreeNode<ActorRef>> cohortToNode = new HashMap<>();
50 void registerCohort(ActorRef sender, RegisterCohort cohort) {
53 final ActorRef cohortRef = cohort.getCohort();
54 final RegistrationTreeNode<ActorRef> node =
55 findNodeFor(cohort.getPath().getRootIdentifier().getPathArguments());
56 addRegistration(node, cohort.getCohort());
57 cohortToNode.put(cohortRef, node);
58 } catch (final Exception e) {
59 sender.tell(new Status.Failure(e), ActorRef.noSender());
64 sender.tell(new Status.Success(null), ActorRef.noSender());
67 void removeCommitCohort(ActorRef sender, RemoveCohort message) {
68 final ActorRef cohort = message.getCohort();
69 final RegistrationTreeNode<ActorRef> node = cohortToNode.get(cohort);
71 removeRegistration(node, cohort);
72 cohortToNode.remove(cohort);
74 sender.tell(new Status.Success(null), ActorRef.noSender());
75 cohort.tell(PoisonPill.getInstance(), cohort);
78 Collection<DataTreeCohortActor.CanCommit> createCanCommitMessages(String txId, DataTreeCandidate candidate,
79 SchemaContext schema) {
80 try (RegistrationTreeSnapshot<ActorRef> cohorts = takeSnapshot()) {
81 return new CanCommitMessageBuilder(txId, candidate, schema).perform(cohorts.getRootNode());
85 void process(ActorRef sender, CohortRegistryCommand message) {
86 if (message instanceof RegisterCohort) {
87 registerCohort(sender, (RegisterCohort) message);
88 } else if (message instanceof RemoveCohort) {
89 removeCommitCohort(sender, (RemoveCohort) message);
93 static abstract class CohortRegistryCommand {
95 private final ActorRef cohort;
97 CohortRegistryCommand(ActorRef cohort) {
98 this.cohort = Preconditions.checkNotNull(cohort);
101 ActorRef getCohort() {
106 static class RegisterCohort extends CohortRegistryCommand {
108 private final DOMDataTreeIdentifier path;
110 RegisterCohort(DOMDataTreeIdentifier path, ActorRef cohort) {
116 public DOMDataTreeIdentifier getPath() {
122 static class RemoveCohort extends CohortRegistryCommand {
124 RemoveCohort(ActorRef cohort) {
130 private static class CanCommitMessageBuilder {
132 private final String txId;
133 private final DataTreeCandidate candidate;
134 private final SchemaContext schema;
135 private final Collection<DataTreeCohortActor.CanCommit> messages =
138 CanCommitMessageBuilder(String txId, DataTreeCandidate candidate, SchemaContext schema) {
139 this.txId = Preconditions.checkNotNull(txId);
140 this.candidate = Preconditions.checkNotNull(candidate);
141 this.schema = schema;
144 private void lookupAndCreateCanCommits(List<PathArgument> args, int offset,
145 RegistrationTreeNode<ActorRef> node) {
147 if (args.size() != offset) {
148 final PathArgument arg = args.get(offset);
149 final RegistrationTreeNode<ActorRef> exactChild = node.getExactChild(arg);
150 if (exactChild != null) {
151 lookupAndCreateCanCommits(args, offset + 1, exactChild);
153 for (final RegistrationTreeNode<ActorRef> c : node.getInexactChildren(arg)) {
154 lookupAndCreateCanCommits(args, offset + 1, c);
157 lookupAndCreateCanCommits(candidate.getRootPath(), node, candidate.getRootNode());
161 private void lookupAndCreateCanCommits(YangInstanceIdentifier path, RegistrationTreeNode<ActorRef> regNode,
162 DataTreeCandidateNode candNode) {
163 if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
164 LOG.debug("Skipping unmodified candidate {}", path);
167 final Collection<ActorRef> regs = regNode.getRegistrations();
168 if (!regs.isEmpty()) {
169 createCanCommits(regs, path, candNode);
172 for (final DataTreeCandidateNode candChild : candNode.getChildNodes()) {
173 if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
174 final RegistrationTreeNode<ActorRef> regChild =
175 regNode.getExactChild(candChild.getIdentifier());
176 if (regChild != null) {
177 lookupAndCreateCanCommits(path.node(candChild.getIdentifier()), regChild, candChild);
180 for (final RegistrationTreeNode<ActorRef> rc : regNode
181 .getInexactChildren(candChild.getIdentifier())) {
182 lookupAndCreateCanCommits(path.node(candChild.getIdentifier()), rc, candChild);
188 private void createCanCommits(Collection<ActorRef> regs, YangInstanceIdentifier path,
189 DataTreeCandidateNode node) {
190 final DOMDataTreeCandidate candidate = DOMDataTreeCandidateTO.create(treeIdentifier(path), node);
191 for (final ActorRef reg : regs) {
192 final CanCommit message = new DataTreeCohortActor.CanCommit(txId, candidate, schema, reg);
193 messages.add(message);
197 private static DOMDataTreeIdentifier treeIdentifier(YangInstanceIdentifier path) {
198 return new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, path);
201 private Collection<DataTreeCohortActor.CanCommit> perform(RegistrationTreeNode<ActorRef> rootNode) {
202 final List<PathArgument> toLookup = candidate.getRootPath().getPathArguments();
203 lookupAndCreateCanCommits(toLookup, 0, rootNode);