From 11d13dee3de89651199e942c4b8265b93ebdef76 Mon Sep 17 00:00:00 2001 From: Ryan Goulding Date: Fri, 24 Jun 2016 11:50:00 -0400 Subject: [PATCH] Add option to enable/disable basic DCL and/or DTCL The cars stress test is a very appropriate place to measure the effects of DCL and DTCL on a very long list. This change adds a few RPC implementations in order to do the following: 1) enable DCL 2) disable DCL 3) enable DTCL 4) disable DTCL This change includes very basic DCL/DTCL implementations, which just log a message at trace level (off by default but there for ensuring the onData*Changed(...) method is actually called. The existing clustering-test-app behavior doesn't change at all; these new RPC(s) do not need to be used, and the added Listener implementations are not registered listeners by default. Change-Id: I6fcec6cd8c0a082e815561e88b325a55022ad2af Signed-off-by: Ryan Goulding (cherry picked from commit 7a53dd074428ce5c4be767a51c509b1b8cf0f05e) --- .../model/src/main/yang/car.yang | 18 +++++ .../it/provider/CarDataChangeListener.java | 49 +++++++++++++ .../provider/CarDataTreeChangeListener.java | 66 +++++++++++++++++ .../clustering/it/provider/CarProvider.java | 72 +++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataChangeListener.java create mode 100644 opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataTreeChangeListener.java diff --git a/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/car.yang b/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/car.yang index f8c2f5b88c..f279949b5e 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/car.yang +++ b/opendaylight/md-sal/samples/clustering-test-app/model/src/main/yang/car.yang @@ -98,4 +98,22 @@ module car { } } } + + rpc register-logging-dcl { + description "Registers a basic logging DCL on the cars container. This is useful + for analyzing effects of DCL on a long, flat list."; + } + + rpc unregister-logging-dcls { + description "Unregisters the logging DCL(s) for the cars container."; + } + + rpc register-logging-dtcl { + description "Registers a basic logging DTCL on the cars container. This is useful + for analyzing the effects of DTCL on a long, flat list."; + } + + rpc unregister-logging-dtcls { + description "Unregisters the logging DTCL(s) for the cars container."; + } } \ No newline at end of file diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataChangeListener.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataChangeListener.java new file mode 100644 index 0000000000..ac5c368927 --- /dev/null +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataChangeListener.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 Brocade Communications 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.clustering.it.provider; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides a basic DCL implementation for performance testing reasons. Emits a summary + * of the changes that occurred. + * + * @author Ryan Goulding (ryandgoulding@gmail.com) + */ +public class CarDataChangeListener implements DataChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(CarDataChangeListener.class); + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { + if (LOG.isTraceEnabled()) { + LOG.trace("onDataChanged invoked"); + outputChanges(change); + } + } + + private void outputChanges(final AsyncDataChangeEvent, DataObject> change) { + final Map, DataObject> originalData = change.getOriginalData() != null ? + change.getOriginalData(): Collections., DataObject>emptyMap(); + final Map, DataObject> updatedData = change.getUpdatedData() != null ? + change.getUpdatedData(): Collections., DataObject>emptyMap(); + final Map, DataObject> createdData = change.getCreatedData() != null ? + change.getCreatedData(): Collections., DataObject>emptyMap(); + final Set> removedPaths = change.getRemovedPaths() != null ? + change.getRemovedPaths(): Collections.>emptySet(); + LOG.trace("AsyncDataChangeEvent - originalData={} updatedData={} createdData={} removedPaths={}", + originalData, updatedData, createdData, removedPaths); + } +} diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataTreeChangeListener.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataTreeChangeListener.java new file mode 100644 index 0000000000..c157b6cd89 --- /dev/null +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarDataTreeChangeListener.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016 Brocade Communications 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.clustering.it.provider; + +import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; +import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE; +import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.SUBTREE_MODIFIED; +import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE; + +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.sal.clustering.it.car.rev140818.Cars; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provides a basic DTCL implementation for performance testing reasons. Emits a rudimentary + * summary of the changes that occurred. + * + * @author Ryan Goulding (ryandgoulding@gmail.com) + */ +public class CarDataTreeChangeListener implements DataTreeChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(CarDataTreeChangeListener.class); + + @java.lang.Override + public void onDataTreeChanged(@Nonnull java.util.Collection> changes) { + if (LOG.isTraceEnabled()) { + for (DataTreeModification change : changes) { + ouputChanges(change); + } + } + } + + private void ouputChanges(final DataTreeModification change) { + final DataObjectModification rootNode = change.getRootNode(); + final ModificationType modificationType = rootNode.getModificationType(); + final InstanceIdentifier rootIdentifier = change.getRootPath().getRootIdentifier(); + switch (modificationType) { + case WRITE: + case SUBTREE_MODIFIED: { + final Cars dataBefore = rootNode.getDataBefore(); + final Cars dataAfter = rootNode.getDataAfter(); + LOG.trace("onDataTreeChanged - Cars config with path {} was added or changed from {} to {}", + rootIdentifier, dataBefore, dataAfter); + break; + } + case DELETE: { + LOG.trace("onDataTreeChanged - Cars config with path {} was deleted", rootIdentifier); + break; + } + default: { + LOG.trace("onDataTreeChanged called with unknown modificationType: {}", modificationType); + break; + } + } + } +} diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarProvider.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarProvider.java index 1ab7f5e901..2dfb32b421 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarProvider.java +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/CarProvider.java @@ -8,19 +8,24 @@ package org.opendaylight.controller.clustering.it.provider; import com.google.common.base.Stopwatch; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; +import java.util.Collection; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException; import org.opendaylight.controller.md.sal.common.api.clustering.Entity; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.sal.clustering.it.car.rev140818.CarId; @@ -32,6 +37,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.sal.clustering.it.car.rev140818.UnregisterOwnershipInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.sal.clustering.it.car.rev140818.cars.CarEntry; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.sal.clustering.it.car.rev140818.cars.CarEntryBuilder; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -57,6 +63,15 @@ public class CarProvider implements CarService { private volatile Thread testThread; private volatile boolean stopThread; + private static final InstanceIdentifier CARS_IID = InstanceIdentifier.builder(Cars.class).build(); + private static final DataTreeIdentifier CARS_DTID = new DataTreeIdentifier<>( + LogicalDatastoreType.CONFIGURATION, CARS_IID); + + private Collection> carsDclRegistrations = + Sets.newConcurrentHashSet(); + private Collection> carsDtclRegistrations = + Sets.newConcurrentHashSet(); + public CarProvider(DataBroker dataProvider, EntityOwnershipService ownershipService) { this.dataProvider = dataProvider; this.ownershipService = ownershipService; @@ -183,4 +198,61 @@ public class CarProvider implements CarService { LOG.info("ownershipChanged: {}", ownershipChange); } } + + @Override + public Future> registerLoggingDcl() { + LOG.info("Registering a new CarDataChangeListener"); + final ListenerRegistration carsDclRegistration = dataProvider.registerDataChangeListener( + LogicalDatastoreType.CONFIGURATION, CARS_IID, new CarDataChangeListener(), + AsyncDataBroker.DataChangeScope.SUBTREE); + + if (carsDclRegistration != null) { + carsDclRegistrations.add(carsDclRegistration); + return RpcResultBuilder.success().buildFuture(); + } + return RpcResultBuilder.failed().buildFuture(); + } + + @Override + public Future> registerLoggingDtcl() { + LOG.info("Registering a new CarDataTreeChangeListener"); + final ListenerRegistration carsDtclRegistration = + dataProvider.registerDataTreeChangeListener(CARS_DTID, new CarDataTreeChangeListener()); + + if (carsDtclRegistration != null) { + carsDtclRegistrations.add(carsDtclRegistration); + return RpcResultBuilder.success().buildFuture(); + } + return RpcResultBuilder.failed().buildFuture(); + } + + @Override + public Future> unregisterLoggingDcls() { + LOG.info("Unregistering the CarDataChangeListener(s)"); + synchronized (carsDclRegistrations) { + int numListeners = 0; + for (ListenerRegistration carsDclRegistration : carsDclRegistrations) { + carsDclRegistration.close(); + numListeners++; + } + carsDclRegistrations.clear(); + LOG.info("Unregistered {} CarDataChangeListener(s)", numListeners); + } + return RpcResultBuilder.success().buildFuture(); + } + + @Override + public Future> unregisterLoggingDtcls() { + LOG.info("Unregistering the CarDataTreeChangeListener(s)"); + synchronized (carsDtclRegistrations) { + int numListeners = 0; + for (ListenerRegistration carsDtclRegistration : carsDtclRegistrations) { + carsDtclRegistration.close(); + numListeners++; + } + carsDtclRegistrations.clear(); + LOG.info("Unregistered {} CaraDataTreeChangeListener(s)", numListeners); + } + return RpcResultBuilder.success().buildFuture(); + } } -- 2.36.6