X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2FDataTreeChangeListenerSupport.java;h=f5e1d1374b8b8923fee3b785c85d31b3a4778b12;hb=HEAD;hp=afce4df546febce2dd122b1eb431896855503ca8;hpb=8f0395b38dbfdf6b3164cb68b1cba651b1075a07;p=controller.git diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerSupport.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerSupport.java index afce4df546..f5e1d1374b 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerSupport.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataTreeChangeListenerSupport.java @@ -9,86 +9,124 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.ActorSelection; -import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; +import org.opendaylight.controller.cluster.datastore.actors.DataTreeNotificationListenerRegistrationActor; import org.opendaylight.controller.cluster.datastore.messages.EnableNotification; import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListener; -import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListenerReply; -import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeNotificationListenerReply; +import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -final class DataTreeChangeListenerSupport extends LeaderLocalDelegateFactory> { +final class DataTreeChangeListenerSupport extends LeaderLocalDelegateFactory { private static final Logger LOG = LoggerFactory.getLogger(DataTreeChangeListenerSupport.class); - private final ArrayList delayedRegistrations = new ArrayList<>(); - private final Collection actors = new ArrayList<>(); - private final Shard shard; + + private final Collection + delayedDataTreeChangeListenerRegistrations = ConcurrentHashMap.newKeySet(); + private final Collection + delayedListenerOnAllRegistrations = ConcurrentHashMap.newKeySet(); + private final Collection leaderOnlyListenerActors = ConcurrentHashMap.newKeySet(); + private final Collection allListenerActors = ConcurrentHashMap.newKeySet(); DataTreeChangeListenerSupport(final Shard shard) { - this.shard = Preconditions.checkNotNull(shard); + super(shard); + } + + void doRegistration(final RegisterDataTreeChangeListener message, final ActorRef registrationActor) { + final ActorSelection listenerActor = processListenerRegistrationMessage(message); + + final DOMDataTreeChangeListener listener = new ForwardingDataTreeChangeListener(listenerActor, getSelf()); + + LOG.debug("{}: Registering listenerActor {} for path {}", persistenceId(), listenerActor, message.getPath()); + + final ShardDataTree shardDataTree = getShard().getDataStore(); + shardDataTree.registerTreeChangeListener(message.getPath(), + listener, shardDataTree.readCurrentData(), registration -> registrationActor.tell( + new DataTreeNotificationListenerRegistrationActor.SetRegistration(registration, () -> + removeListenerActor(listenerActor)), ActorRef.noSender())); + } + + Collection getListenerActors() { + return new ArrayList<>(allListenerActors); } @Override - void onLeadershipChange(final boolean isLeader) { - if (isLeader) { - for (DelayedDataTreeListenerRegistration reg : delayedRegistrations) { - reg.createDelegate(this); + void onLeadershipChange(final boolean isLeader, final boolean hasLeader) { + LOG.debug("{}: onLeadershipChange, isLeader: {}, hasLeader : {}", persistenceId(), isLeader, hasLeader); + + final EnableNotification msg = new EnableNotification(isLeader, persistenceId()); + for (ActorSelection dataChangeListener : leaderOnlyListenerActors) { + dataChangeListener.tell(msg, getSelf()); + } + + if (hasLeader) { + for (var reg : delayedListenerOnAllRegistrations) { + reg.doRegistration(this); } - delayedRegistrations.clear(); - delayedRegistrations.trimToSize(); + + delayedListenerOnAllRegistrations.clear(); } - final EnableNotification msg = new EnableNotification(isLeader); - for (ActorSelection dataChangeListener : actors) { - dataChangeListener.tell(msg, shard.getSelf()); + if (isLeader) { + for (var reg : delayedDataTreeChangeListenerRegistrations) { + reg.doRegistration(this); + } + + delayedDataTreeChangeListenerRegistrations.clear(); } } @Override - void onMessage(final RegisterDataTreeChangeListener registerTreeChangeListener, final boolean isLeader) { - LOG.debug("{}: registerTreeChangeListener for {}, leader: {}", shard.persistenceId(), registerTreeChangeListener.getPath(), isLeader); + void onMessage(final RegisterDataTreeChangeListener message, final boolean isLeader, final boolean hasLeader) { + LOG.debug("{}: onMessage {}, isLeader: {}, hasLeader: {}", persistenceId(), message, isLeader, hasLeader); - final ListenerRegistration registration; - if (!isLeader) { - LOG.debug("{}: Shard is not the leader - delaying registration", shard.persistenceId()); + final ActorRef registrationActor = createActor(DataTreeNotificationListenerRegistrationActor.props()); - DelayedDataTreeListenerRegistration delayedReg = - new DelayedDataTreeListenerRegistration(registerTreeChangeListener); - delayedRegistrations.add(delayedReg); - registration = delayedReg; + if (hasLeader && message.isRegisterOnAllInstances() || isLeader) { + doRegistration(message, registrationActor); } else { - registration = createDelegate(registerTreeChangeListener); - } + LOG.debug("{}: Shard does not have a leader - delaying registration", persistenceId()); + + final var delayedReg = new DelayedDataTreeChangeListenerRegistration(message, registrationActor); + final Collection delayedRegList; + if (message.isRegisterOnAllInstances()) { + delayedRegList = delayedListenerOnAllRegistrations; + } else { + delayedRegList = delayedDataTreeChangeListenerRegistrations; + } - ActorRef listenerRegistration = shard.getContext().actorOf( - DataTreeChangeListenerRegistrationActor.props(registration)); + delayedRegList.add(delayedReg); + registrationActor.tell(new DataTreeNotificationListenerRegistrationActor.SetRegistration( + delayedReg, () -> delayedRegList.remove(delayedReg)), ActorRef.noSender()); + } - LOG.debug("{}: registerDataChangeListener sending reply, listenerRegistrationPath = {} ", - shard.persistenceId(), listenerRegistration.path()); + LOG.debug("{}: sending RegisterDataTreeNotificationListenerReply, listenerRegistrationPath = {} ", + persistenceId(), registrationActor.path()); - shard.getSender().tell(new RegisterDataTreeChangeListenerReply(listenerRegistration), shard.getSelf()); + tellSender(new RegisterDataTreeNotificationListenerReply(registrationActor)); } - @Override - ListenerRegistration createDelegate(final RegisterDataTreeChangeListener message) { - ActorSelection dataChangeListenerPath = shard.getContext().system().actorSelection( - message.getDataTreeChangeListenerPath().path()); + private ActorSelection processListenerRegistrationMessage(final RegisterDataTreeChangeListener message) { + final ActorSelection listenerActor = selectActor(message.getListenerActorPath()); - // Notify the listener if notifications should be enabled or not - // If this shard is the leader then it will enable notifications else - // it will not - dataChangeListenerPath.tell(new EnableNotification(true), shard.getSelf()); + // We have a leader so enable the listener. + listenerActor.tell(new EnableNotification(true, persistenceId()), getSelf()); - // Now store a reference to the data change listener so it can be notified - // at a later point if notifications should be enabled or disabled - actors.add(dataChangeListenerPath); + if (!message.isRegisterOnAllInstances()) { + // This is a leader-only registration so store a reference to the listener actor so it can be notified + // at a later point if notifications should be enabled or disabled. + leaderOnlyListenerActors.add(listenerActor); + } - DOMDataTreeChangeListener listener = new ForwardingDataTreeChangeListener(dataChangeListenerPath); + allListenerActors.add(listenerActor); - LOG.debug("{}: Registering for path {}", shard.persistenceId(), message.getPath()); + return listenerActor; + } - return shard.getDataStore().registerTreeChangeListener(message.getPath(), listener); + private void removeListenerActor(final ActorSelection listenerActor) { + allListenerActors.remove(listenerActor); + leaderOnlyListenerActors.remove(listenerActor); } }