X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=applications%2Fforwardingrules-sync%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fapplications%2Ffrsync%2Fimpl%2FSimplifiedOperationalListener.java;h=f7f51b4753f41a1bf76af834a868543fa3706938;hb=137e4d7d86e8f402f3d52fd0fa162792f9ff60eb;hp=eb70f5d4931a61acb897a1799ebabefd6b8063c1;hpb=9ecd75a2cd929871d62695b950f153ce0aa3f0f7;p=openflowplugin.git diff --git a/applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListener.java b/applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListener.java index eb70f5d493..f7f51b4753 100644 --- a/applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListener.java +++ b/applications/forwardingrules-sync/src/main/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListener.java @@ -15,8 +15,9 @@ import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Objects; +import javax.annotation.Nonnull; import org.opendaylight.controller.md.sal.binding.api.DataObjectModification; -import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType; import org.opendaylight.controller.md.sal.binding.api.DataTreeModification; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.openflowplugin.applications.frsync.SyncReactor; @@ -40,12 +41,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Listens to operational new nodes and delegates add/remove/update/barrier to {@link SyncReactor}. + * Listens to operational changes and starts reconciliation through {@link SyncReactor} when necessary. */ public class SimplifiedOperationalListener extends AbstractFrmSyncListener { + private static final Logger LOG = LoggerFactory.getLogger(SimplifiedOperationalListener.class); public static final String DATE_AND_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; - private final SyncReactor reactor; private final FlowCapableNodeSnapshotDao operationalSnapshot; private final FlowCapableNodeDao configDao; @@ -65,116 +66,94 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener } @Override - public void onDataTreeChanged(Collection> modifications) { - LOG.trace("Operational changes: {}", modifications.size()); + public void onDataTreeChanged(@Nonnull final Collection> modifications) { super.onDataTreeChanged(modifications); } /** - * This method behaves like this: - *
    - *
  • If node is added to operational store then reconciliation.
  • - *
  • Node is deleted from operational cache is removed.
  • - *
  • Skip this event otherwise.
  • - *
- * - * @throws InterruptedException from syncup + * Update cache, register for device mastership when device connected and start reconciliation if device + * is registered and actual modification is consistent.Skip the event otherwise. */ + @Override protected Optional> processNodeModification( - DataTreeModification modification) throws InterruptedException { + final DataTreeModification modification) { + Optional> result; final NodeId nodeId = ModificationUtil.nodeId(modification); - updateCache(modification); + final DataObjectModification nodeModification = modification.getRootNode(); - if (isAdd(modification) || isAddLogical(modification)) { - deviceMastershipManager.onDeviceConnected(nodeId); - } - - if (isRegisteredAndConsistentForReconcile(modification)) { - return reconciliation(modification); - } else { - return skipModification(modification); - } - } - - /** - * Remove if delete. Update only if FlowCapableNode Augmentation modified. - * - * @param modification Datastore modification - */ - private void updateCache(DataTreeModification modification) { - NodeId nodeId = ModificationUtil.nodeId(modification); - if (isDelete(modification) || isDeleteLogical(modification)) { + if (isDelete(nodeModification) || isDeleteLogical(nodeModification)) { operationalSnapshot.updateCache(nodeId, Optional.absent()); deviceMastershipManager.onDeviceDisconnected(nodeId); - return; + result = skipModification(modification); + } else { + operationalSnapshot.updateCache(nodeId, Optional.fromNullable( + ModificationUtil.flowCapableNodeAfter(modification))); + + final boolean isAdd = isAdd(nodeModification) || isAddLogical(nodeModification); + + if (isAdd) { + deviceMastershipManager.onDeviceConnected(nodeId); + } + + // if node is registered for reconcile we need consistent data from operational DS (skip partial + // collections) but we can accept first modification since all statistics are intentionally collected in + // one step on startup + if (reconciliationRegistry.isRegistered(nodeId) && (isAdd || isConsistentForReconcile(modification))) { + result = reconciliation(modification); + } else { + result = skipModification(modification); + } } - operationalSnapshot.updateCache(nodeId, Optional.fromNullable(ModificationUtil.flowCapableNodeAfter(modification))); + return result; } - private Optional> skipModification(DataTreeModification modification) { - LOG.trace("Skipping operational modification: {}, before {}, after {}", - ModificationUtil.nodeIdValue(modification), - modification.getRootNode().getDataBefore() == null ? "null" : "nonnull", - modification.getRootNode().getDataAfter() == null ? "null" : "nonnull"); + private Optional> skipModification(final DataTreeModification modification) { + if (LOG.isTraceEnabled()) { + LOG.trace("Skipping operational modification: {}, before {}, after {}", + ModificationUtil.nodeIdValue(modification), + modification.getRootNode().getDataBefore() == null ? "null" : "nonnull", + modification.getRootNode().getDataAfter() == null ? "null" : "nonnull"); + } return Optional.absent(); } - /** - * ModificationType.DELETE. - */ - private boolean isDelete(DataTreeModification modification) { - if (ModificationType.DELETE == modification.getRootNode().getModificationType()) { - LOG.trace("Delete {} (physical)", ModificationUtil.nodeIdValue(modification)); - return true; - } - - return false; + private boolean isDelete(final DataObjectModification nodeModification) { + return Objects.nonNull(nodeModification.getDataBefore()) && Objects.isNull(nodeModification.getDataAfter()); } /** * All connectors disappeared from operational store (logical delete). */ - private boolean isDeleteLogical(DataTreeModification modification) { - final DataObjectModification rootNode = modification.getRootNode(); - if (!safeConnectorsEmpty(rootNode.getDataBefore()) && safeConnectorsEmpty(rootNode.getDataAfter())) { - LOG.trace("Delete {} (logical)", ModificationUtil.nodeIdValue(modification)); - return true; - } + private boolean isDeleteLogical(final DataObjectModification nodeModification) { + return !safeConnectorsEmpty(nodeModification.getDataBefore()) + && safeConnectorsEmpty(nodeModification.getDataAfter()); - return false; } - private boolean isAdd(DataTreeModification modification) { - final DataObjectModification rootNode = modification.getRootNode(); - final Node dataAfter = rootNode.getDataAfter(); - final Node dataBefore = rootNode.getDataBefore(); - - final boolean nodeAppearedInOperational = dataBefore == null && dataAfter != null; - if (nodeAppearedInOperational) { - LOG.trace("Add {} (physical)", ModificationUtil.nodeIdValue(modification)); - } - return nodeAppearedInOperational; + private boolean isAdd(final DataObjectModification nodeModification) { + return Objects.isNull(nodeModification.getDataBefore()) && Objects.nonNull(nodeModification.getDataAfter()); } /** * All connectors appeared in operational store (logical add). */ - private boolean isAddLogical(DataTreeModification modification) { - final DataObjectModification rootNode = modification.getRootNode(); - if (safeConnectorsEmpty(rootNode.getDataBefore()) && !safeConnectorsEmpty(rootNode.getDataAfter())) { - LOG.trace("Add {} (logical)", ModificationUtil.nodeIdValue(modification)); - return true; - } - - return false; + private boolean isAddLogical(final DataObjectModification nodeModification) { + return safeConnectorsEmpty(nodeModification.getDataBefore()) + && !safeConnectorsEmpty(nodeModification.getDataAfter()); } - private Optional> reconciliation(DataTreeModification modification) throws InterruptedException { + /** + * If node is present in config DS diff between wanted configuration (in config DS) and actual device + * configuration (coming from operational) should be calculated and sent to device. + * @param modification from DS + * @return optional syncup future + */ + private Optional> reconciliation(final DataTreeModification modification) { final NodeId nodeId = ModificationUtil.nodeId(modification); final Optional nodeConfiguration = configDao.loadByNodeId(nodeId); if (nodeConfiguration.isPresent()) { - LOG.debug("Reconciliation: {}", nodeId.getValue()); + LOG.debug("Reconciliation {}: {}", dsType(), nodeId.getValue()); final InstanceIdentifier nodePath = InstanceIdentifier.create(Nodes.class) .child(Node.class, new NodeKey(ModificationUtil.nodeId(modification))) .augmentation(FlowCapableNode.class); @@ -184,19 +163,21 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener return Optional.of(reactor.syncup(nodePath, syncupEntry)); } else { LOG.debug("Config not present for reconciliation: {}", nodeId.getValue()); + reconciliationRegistry.unregisterIfRegistered(nodeId); return skipModification(modification); } } - private boolean isRegisteredAndConsistentForReconcile(DataTreeModification modification) { + /** + * Check if modification is consistent for reconciliation. We need fresh data, which means that current statistics + * were collected after registration for reconcile and whole bunch of statistics was collected successfully. + * @param modification from DS + * @return status of modification + */ + private boolean isConsistentForReconcile(final DataTreeModification modification) { final NodeId nodeId = PathUtil.digNodeId(modification.getRootPath().getRootIdentifier()); - - if (!reconciliationRegistry.isRegistered(nodeId)) { - return false; - } - final FlowCapableStatisticsGatheringStatus gatheringStatus = modification.getRootNode().getDataAfter() - .getAugmentation(FlowCapableStatisticsGatheringStatus.class); + .augmentation(FlowCapableStatisticsGatheringStatus.class); if (gatheringStatus == null) { LOG.trace("Statistics gathering never started: {}", nodeId.getValue()); @@ -224,19 +205,17 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener return true; } } catch (ParseException e) { - LOG.error("Timestamp parsing error {}", e); + LOG.warn("Timestamp parsing error {}", e); } LOG.debug("Fresh operational not present: {}", nodeId.getValue()); return false; } - private static boolean safeConnectorsEmpty(Node node) { + private static boolean safeConnectorsEmpty(final Node node) { if (node == null) { return true; } - final List nodeConnectors = node.getNodeConnector(); - return nodeConnectors == null || nodeConnectors.isEmpty(); } @@ -244,5 +223,4 @@ public class SimplifiedOperationalListener extends AbstractFrmSyncListener public LogicalDatastoreType dsType() { return LogicalDatastoreType.OPERATIONAL; } - }