X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsamples%2Fclustering-test-app%2Fprovider%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fclustering%2Fit%2Fprovider%2Fimpl%2FIdIntsListener.java;h=ed93b380e3f31fc060e1d599e7814879b791f1ee;hb=5d18e15c0dd806791414e069fffdf4cb273688e3;hp=fc3f9adfddf71b2f4759d21875012b04b17fd92a;hpb=64dbc396e21d73a7323b3e9dbf51b31df295cfb5;p=controller.git diff --git a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java index fc3f9adfdd..ed93b380e3 100644 --- a/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java +++ b/opendaylight/md-sal/samples/clustering-test-app/provider/src/main/java/org/opendaylight/controller/clustering/it/provider/impl/IdIntsListener.java @@ -8,23 +8,42 @@ package org.opendaylight.controller.clustering.it.provider.impl; +import static org.opendaylight.controller.clustering.it.provider.impl.AbstractTransactionHandler.ITEM; + import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.SettableFuture; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import javax.annotation.Nonnull; -import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener; +import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; +import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.MapNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; -import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; -import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class IdIntsListener implements DOMDataTreeChangeListener { +public class IdIntsListener implements ClusteredDOMDataTreeChangeListener { private static final Logger LOG = LoggerFactory.getLogger(IdIntsListener.class); + private static final long SECOND_AS_NANO = 1000000000; - private NormalizedNode localCopy = null; + private volatile NormalizedNode localCopy; + private final AtomicLong lastNotifTimestamp = new AtomicLong(0); + private ScheduledExecutorService executorService; + private ScheduledFuture scheduledFuture; + private final AtomicBoolean loggedIgnoredNotificationDiff = new AtomicBoolean(); @Override public void onDataTreeChanged(@Nonnull final Collection changes) { @@ -32,6 +51,8 @@ public class IdIntsListener implements DOMDataTreeChangeListener { // There should only be one candidate reported Preconditions.checkState(changes.size() == 1); + lastNotifTimestamp.set(System.nanoTime()); + // do not log the change into debug, only use trace since it will lead to OOM on default heap settings LOG.debug("Received data tree changed"); @@ -45,7 +66,9 @@ public class IdIntsListener implements DOMDataTreeChangeListener { if (localCopy == null || checkEqual(change.getRootNode().getDataBefore().get())) { localCopy = change.getRootNode().getDataAfter().get(); } else { - LOG.debug("Ignoring notification: {}", change); + LOG.warn("Ignoring notification {}", loggedIgnoredNotificationDiff.compareAndSet(false, true) + ? diffWithLocalCopy(change.getRootNode().getDataBefore().get()) : ""); + LOG.trace("Ignored notification content: {}", change); } } else { LOG.warn("getDataAfter() is missing from notification. change: {}", change); @@ -53,7 +76,82 @@ public class IdIntsListener implements DOMDataTreeChangeListener { }); } + public boolean hasTriggered() { + return localCopy != null; + } + public boolean checkEqual(final NormalizedNode expected) { return localCopy.equals(expected); } + + @SuppressFBWarnings("BC_UNCONFIRMED_CAST") + public String diffWithLocalCopy(final NormalizedNode expected) { + return diffNodes((MapNode)expected, (MapNode)localCopy); + } + + public Future tryFinishProcessing() { + executorService = Executors.newSingleThreadScheduledExecutor(); + final SettableFuture settableFuture = SettableFuture.create(); + + scheduledFuture = executorService.scheduleAtFixedRate(new CheckFinishedTask(settableFuture), + 0, 1, TimeUnit.SECONDS); + return settableFuture; + } + + public static String diffNodes(final MapNode expected, final MapNode actual) { + StringBuilder builder = new StringBuilder("MapNodes diff:"); + + final YangInstanceIdentifier.NodeIdentifier itemNodeId = new YangInstanceIdentifier.NodeIdentifier(ITEM); + + Map expIdIntMap = new HashMap<>(); + expected.getValue().forEach(node -> expIdIntMap.put(node.getIdentifier(), node)); + + actual.getValue().forEach(actIdInt -> { + final MapEntryNode expIdInt = expIdIntMap.remove(actIdInt.getIdentifier()); + if (expIdInt == null) { + builder.append('\n').append(" Unexpected id-int entry for ").append(actIdInt.getIdentifier()); + return; + } + + Map expItemMap = new HashMap<>(); + ((MapNode)expIdInt.getChild(itemNodeId).get()).getValue() + .forEach(node -> expItemMap.put(node.getIdentifier(), node)); + + ((MapNode)actIdInt.getChild(itemNodeId).get()).getValue().forEach(actItem -> { + final MapEntryNode expItem = expItemMap.remove(actItem.getIdentifier()); + if (expItem == null) { + builder.append('\n').append(" Unexpected item entry ").append(actItem.getIdentifier()) + .append(" for id-int entry ").append(actIdInt.getIdentifier()); + } + }); + + expItemMap.values().forEach(node -> builder.append('\n') + .append(" Actual is missing item entry ").append(node.getIdentifier()) + .append(" for id-int entry ").append(actIdInt.getIdentifier())); + }); + + expIdIntMap.values().forEach(node -> builder.append('\n') + .append(" Actual is missing id-int entry for ").append(node.getIdentifier())); + + return builder.toString(); + } + + private class CheckFinishedTask implements Runnable { + + private final SettableFuture future; + + CheckFinishedTask(final SettableFuture future) { + this.future = future; + } + + @Override + public void run() { + if (System.nanoTime() - lastNotifTimestamp.get() > SECOND_AS_NANO * 4) { + scheduledFuture.cancel(false); + future.set(null); + + executorService.shutdown(); + } + } + } }