import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nonnull;
+import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
private final Map<TablesKey, ExportPolicyPeerTracker> exportPolicyPeerTrackerMap;
private DOMTransactionChain domChain;
+ @GuardedBy("this")
+ private boolean isServiceInstantiated;
public RIBImpl(final ClusterSingletonServiceProvider provider, final RibId ribId, final AsNumber localAs, final BgpId localBgpId,
final ClusterIdentifier clusterId, final RIBExtensionConsumerContext extensions, final BGPDispatcher dispatcher,
}
@Override
- public void instantiateServiceInstance() {
+ public synchronized void instantiateServiceInstance() {
+ this.isServiceInstantiated = true;
this.domChain = this.domDataBroker.createTransactionChain(this);
if(this.configurationWriter != null) {
this.configurationWriter.apply();
@Override
public synchronized ListenableFuture<Void> closeServiceInstance() {
+ if(!this.isServiceInstantiated) {
+ LOG.trace("RIB Singleton Service {} already closed, RIB {}", getIdentifier().getValue(),
+ this.ribId.getValue());
+ return Futures.immediateFuture(null);
+ }
LOG.info("Close RIB Singleton Service {}, RIB {}", getIdentifier().getValue(), this.ribId.getValue());
+ this.isServiceInstantiated = false;
+
this.txChainToLocRibWriter.values().forEach(LocRibWriter::close);
this.txChainToLocRibWriter.clear();
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Objects;
+import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
}
}
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+ if (this.bgpAppPeerSingletonService != null) {
+ return this.bgpAppPeerSingletonService.closeServiceInstance();
+ }
+
+ return Futures.immediateFuture(null);
+ }
+
@Override
public Boolean containsEqualConfiguration(final Neighbor neighbor) {
return Objects.equals(this.currentConfiguration.getKey(), neighbor.getKey())
private ClusterSingletonServiceRegistration singletonServiceRegistration;
private final ServiceGroupIdentifier serviceGroupIdentifier;
private final WriteConfiguration configurationWriter;
+ @GuardedBy("this")
+ private boolean isServiceInstantiated;
BgpAppPeerSingletonService(final RIB rib, final ApplicationRibId appRibId, final Ipv4Address neighborAddress,
final WriteConfiguration configurationWriter) {
}
@Override
- public void instantiateServiceInstance() {
+ public synchronized void instantiateServiceInstance() {
+ this.isServiceInstantiated = true;
if(this.configurationWriter != null) {
this.configurationWriter.apply();
}
}
@Override
- public ListenableFuture<Void> closeServiceInstance() {
+ public synchronized ListenableFuture<Void> closeServiceInstance() {
+ if(!this.isServiceInstantiated) {
+ LOG.trace("Application Peer Singleton Service {} instance already closed, Application peer {}",
+ getIdentifier().getValue(), this.appRibId.getValue());
+ return Futures.immediateFuture(null);
+ }
LOG.info("Application Peer Singleton Service {} instance closed, Application peer {}",
getIdentifier().getValue(), this.appRibId.getValue());
+ this.isServiceInstantiated = false;
return this.applicationPeer.close();
}
package org.opendaylight.protocol.bgp.rib.impl.config;
+import static com.google.common.util.concurrent.Futures.transform;
import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceIdentifier;
import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceName;
import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getRibInstanceName;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
public synchronized void close() throws Exception {
LOG.info("Closing BGP Deployer.");
this.registration.close();
- this.peers.values().forEach(PeerBean::close);
- this.peers.clear();
- this.ribs.values().forEach(RibImpl::close);
- this.ribs.clear();
this.closed = true;
+
+ final List<ListenableFuture<Void>> futurePeerCloseList = this.peers.values().stream()
+ .map(PeerBean::closeServiceInstance).collect(Collectors.toList());
+ final ListenableFuture<List<Void>> futureOfRelevance = Futures.allAsList(futurePeerCloseList);
+
+ final ListenableFuture<ListenableFuture<List<Void>>> maxRelevanceFuture = transform(futureOfRelevance,
+ (Function<List<Void>, ListenableFuture<List<Void>>>) futurePeersClose -> {
+ this.peers.values().forEach(PeerBean::close);
+ BgpDeployerImpl.this.peers.clear();
+
+ final List<ListenableFuture<Void>> futureRIBCloseList = BgpDeployerImpl.this.ribs.values().stream()
+ .map(RibImpl::closeServiceInstance).collect(Collectors.toList());
+ return Futures.allAsList(futureRIBCloseList);
+ });
+
+ final ListenableFuture<Void> ribFutureClose = transform(maxRelevanceFuture,
+ (Function<ListenableFuture<List<Void>>, Void>) futurePeersClose -> {
+ BgpDeployerImpl.this.ribs.values().forEach(RibImpl::close);
+ this.ribs.clear();
+ return null;
+ });
+
+ ribFutureClose.get();
}
private static CheckedFuture<Void, TransactionCommitFailedException> initializeNetworkInstance(
private synchronized List<PeerBean> closeAllBindedPeers(final InstanceIdentifier<Bgp> rootIdentifier) {
final List<PeerBean> filtered = new ArrayList<>();
this.peers.entrySet().stream().filter(entry -> entry.getKey().firstIdentifierOf(Bgp.class)
- .contains(rootIdentifier)).forEach(entry -> {final PeerBean peer = entry.getValue();
+ .contains(rootIdentifier)).forEach(entry -> {
+ final PeerBean peer = entry.getValue();
+ try {
+ peer.closeServiceInstance().get();
+ } catch (final Exception e) {
+ LOG.error("Peer instance failed to close service instance", e);
+ }
peer.close();
filtered.add(peer);
});
final RibImpl ribImpl, final WriteConfiguration configurationWriter) {
LOG.debug("Modifying RIB instance with configuration: {}", global);
final List<PeerBean> closedPeers = closeAllBindedPeers(rootIdentifier);
+ try {
+ ribImpl.closeServiceInstance().get();
+ } catch (final Exception e) {
+ LOG.error("RIB instance failed to close service instance", e);
+ }
ribImpl.close();
initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
closedPeers.forEach(peer -> peer.restart(ribImpl, this.tableTypeRegistry));
final RibImpl ribImpl = this.ribs.remove(rootIdentifier);
if (ribImpl != null) {
LOG.debug("RIB instance removed {}", ribImpl);
+ closeAllBindedPeers(rootIdentifier);
+ ribImpl.closeServiceInstance();
ribImpl.close();
}
}
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.netty.util.concurrent.Future;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import javax.annotation.concurrent.GuardedBy;
import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeMXBean;
import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpPeerState;
import org.opendaylight.controller.config.yang.bgp.rib.impl.BgpSessionState;
}
}
+ @Override
+ public ListenableFuture<Void> closeServiceInstance() {
+ if (this.bgpPeerSingletonService != null) {
+ return this.bgpPeerSingletonService.closeServiceInstance();
+ }
+ return Futures.immediateFuture(null);
+ }
+
private void closeSingletonService() {
try {
this.bgpPeerSingletonService.close();
private final IpAddress neighborAddress;
private final BGPSessionPreferences prefs;
private Future<Void> connection;
+ @GuardedBy("this")
+ private boolean isServiceInstantiated;
private BgpPeerSingletonService(final RIB rib, final Neighbor neighbor,
final BGPTableTypeRegistryConsumer tableTypeRegistry, final WriteConfiguration configurationWriter) {
}
@Override
- public void instantiateServiceInstance() {
+ public synchronized void instantiateServiceInstance() {
+ this.isServiceInstantiated = true;
if(this.configurationWriter != null) {
this.configurationWriter.apply();
}
}
@Override
- public ListenableFuture<Void> closeServiceInstance() {
+ public synchronized ListenableFuture<Void> closeServiceInstance() {
+ if(!this.isServiceInstantiated) {
+ LOG.info("Peer Singleton Service {} already closed, Peer {}", getIdentifier().getValue(),
+ this.neighborAddress);
+ return Futures.immediateFuture(null);
+ }
LOG.info("Close Peer Singleton Service {}, Peer {}", getIdentifier().getValue(), this.neighborAddress);
+ this.isServiceInstantiated = false;
if (this.connection != null) {
this.connection.cancel(true);
this.connection = null;
package org.opendaylight.protocol.bgp.rib.impl.config;
+import com.google.common.util.concurrent.ListenableFuture;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer.WriteConfiguration;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
@Override
void close();
+ ListenableFuture<Void> closeServiceInstance();
+
Boolean containsEqualConfiguration(Neighbor neighbor);
}
import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.toTableTypes;
import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import java.util.List;
import java.util.Map;
import java.util.Set;
return this.ribImpl.getService();
}
+ public ListenableFuture<Void> closeServiceInstance() {
+ if (this.ribImpl != null) {
+ return this.ribImpl.closeServiceInstance();
+ }
+ return Futures.immediateFuture(null);
+ }
+
@Override
public void close() {
if (this.ribImpl != null) {
verifyPrivate(spyDeployer).invoke("onGlobalCreated", any(InstanceIdentifier.class), any(Global.class),
any(BgpDeployer.WriteConfiguration.class));
verifyPrivate(spyDeployer).invoke("onGlobalUpdated", any(InstanceIdentifier.class), any(Global.class), any(RibImpl.class), any(BgpDeployer.WriteConfiguration.class));
- verifyPrivate(spyDeployer).invoke("closeAllBindedPeers", any(InstanceIdentifier.class));
+ verifyPrivate(spyDeployer, times(2)).invoke("closeAllBindedPeers", any(InstanceIdentifier.class));
verifyPrivate(spyDeployer, times(2)).invoke("initiateRibInstance", any(InstanceIdentifier.class), any(Global.class), any(RibImpl.class), any
(BgpDeployer.WriteConfiguration.class));
verifyPrivate(spyDeployer, times(2)).invoke("registerRibInstance", any(RibImpl.class), anyString());