Split out statistics tracking into separate classes 12/5312/4
authorRobert Varga <rovarga@cisco.com>
Thu, 13 Feb 2014 18:45:13 +0000 (19:45 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 15 Feb 2014 02:10:09 +0000 (02:10 +0000)
- FlowStats
- FlowTableStats
- GroupDescStats
- GroupStats
- MeterConfigStats
- MeterStats
- NodeConnectorStats
- QueueStats

are all now tracked by dedicated classes. Also create a dedicated
QueueStatsEntry and FlowStatsEntry class.

Furthermore the flow walking code is modified to stop searching as soon
as it finds a matching flow.

Change-Id: Ia2bacb12f9c0af6520c115c161388b72a846b062
Signed-off-by: Robert Varga <rovarga@cisco.com>
13 files changed:
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeStatisticsHandler.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java [new file with mode: 0644]
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/StatisticsProvider.java

diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/AbstractStatsTracker.java
new file mode 100644 (file)
index 0000000..aa7720c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+
+import com.google.common.base.Preconditions;
+
+abstract class AbstractStatsTracker<I, K> {
+    private final Map<K, Long> trackedItems = new HashMap<>();
+    private final InstanceIdentifier<Node> nodeIdentifier;
+    private final DataProviderService dps;
+    private final long lifetimeNanos;
+
+    protected AbstractStatsTracker(final InstanceIdentifier<Node> nodeIdentifier, final DataProviderService dps, long lifetimeNanos) {
+        this.nodeIdentifier = Preconditions.checkNotNull(nodeIdentifier);
+        this.dps = Preconditions.checkNotNull(dps);
+        this.lifetimeNanos = lifetimeNanos;
+    }
+
+    protected final InstanceIdentifierBuilder<Node> getNodeIdentifierBuilder() {
+        return InstanceIdentifier.builder(nodeIdentifier);
+    }
+
+    final synchronized void updateStats(List<I> list) {
+        final Long expiryTime = System.nanoTime() + lifetimeNanos;
+        final DataModificationTransaction trans = dps.beginTransaction();
+
+        for (final I item : list) {
+            trackedItems.put(updateSingleStat(trans, item), expiryTime);
+        }
+
+        trans.commit();
+    }
+
+
+    final synchronized void cleanup(final DataModificationTransaction trans, long now) {
+        for (Iterator<Entry<K, Long>> it = trackedItems.entrySet().iterator();it.hasNext();){
+            Entry<K, Long> e = it.next();
+            if (now > e.getValue()) {
+                cleanupSingleStat(trans, e.getKey());
+                it.remove();
+            }
+        }
+    }
+
+    protected abstract void cleanupSingleStat(DataModificationTransaction trans, K item);
+    protected abstract K updateSingleStat(DataModificationTransaction trans, I item);
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsEntry.java
new file mode 100644 (file)
index 0000000..b5b39d9
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+
+final class FlowStatsEntry {
+    private final Short tableId;
+    private final Flow flow;
+
+    public FlowStatsEntry(Short tableId, Flow flow){
+        this.tableId = tableId;
+        this.flow = flow;
+    }
+
+    public Short getTableId() {
+        return tableId;
+    }
+
+    public Flow getFlow() {
+        return flow;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((flow == null) ? 0 : flow.hashCode());
+        result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        FlowStatsEntry other = (FlowStatsEntry) obj;
+        if (flow == null) {
+            if (other.flow != null)
+                return false;
+        } else if (!flow.equals(other.flow))
+            return false;
+        if (tableId == null) {
+            if (other.tableId != null)
+                return false;
+        } else if (!tableId.equals(other.tableId))
+            return false;
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java
new file mode 100644 (file)
index 0000000..e185437
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class FlowStatsTracker extends AbstractStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
+    private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
+    private int unaccountedFlowsCounter = 1;
+
+    FlowStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, FlowStatsEntry item) {
+        InstanceIdentifier<?> flowRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Table.class, new TableKey(item.getTableId()))
+                            .child(Flow.class,item.getFlow().getKey())
+                            .augmentation(FlowStatisticsData.class).toInstance();
+        trans.removeOperationalData(flowRef);
+    }
+
+    @Override
+    protected FlowStatsEntry updateSingleStat(DataModificationTransaction trans, FlowAndStatisticsMapList map) {
+        short tableId = map.getTableId();
+
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
+
+        FlowBuilder flow = new FlowBuilder();
+        flow.setContainerName(map.getContainerName());
+        flow.setBufferId(map.getBufferId());
+        flow.setCookie(map.getCookie());
+        flow.setCookieMask(map.getCookieMask());
+        flow.setFlags(map.getFlags());
+        flow.setFlowName(map.getFlowName());
+        flow.setHardTimeout(map.getHardTimeout());
+        if(map.getFlowId() != null)
+            flow.setId(new FlowId(map.getFlowId().getValue()));
+        flow.setIdleTimeout(map.getIdleTimeout());
+        flow.setInstallHw(map.isInstallHw());
+        flow.setInstructions(map.getInstructions());
+        if(map.getFlowId()!= null)
+            flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+        flow.setMatch(map.getMatch());
+        flow.setOutGroup(map.getOutGroup());
+        flow.setOutPort(map.getOutPort());
+        flow.setPriority(map.getPriority());
+        flow.setStrict(map.isStrict());
+        flow.setTableId(tableId);
+
+        Flow flowRule = flow.build();
+
+        FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
+        stats.setByteCount(map.getByteCount());
+        stats.setPacketCount(map.getPacketCount());
+        stats.setDuration(map.getDuration());
+
+        GenericStatistics flowStats = stats.build();
+
+        //Augment the data to the flow node
+
+        FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
+        flowStatistics.setByteCount(flowStats.getByteCount());
+        flowStatistics.setPacketCount(flowStats.getPacketCount());
+        flowStatistics.setDuration(flowStats.getDuration());
+        flowStatistics.setContainerName(map.getContainerName());
+        flowStatistics.setBufferId(map.getBufferId());
+        flowStatistics.setCookie(map.getCookie());
+        flowStatistics.setCookieMask(map.getCookieMask());
+        flowStatistics.setFlags(map.getFlags());
+        flowStatistics.setFlowName(map.getFlowName());
+        flowStatistics.setHardTimeout(map.getHardTimeout());
+        flowStatistics.setIdleTimeout(map.getIdleTimeout());
+        flowStatistics.setInstallHw(map.isInstallHw());
+        flowStatistics.setInstructions(map.getInstructions());
+        flowStatistics.setMatch(map.getMatch());
+        flowStatistics.setOutGroup(map.getOutGroup());
+        flowStatistics.setOutPort(map.getOutPort());
+        flowStatistics.setPriority(map.getPriority());
+        flowStatistics.setStrict(map.isStrict());
+        flowStatistics.setTableId(tableId);
+
+        flowStatisticsData.setFlowStatistics(flowStatistics.build());
+
+        logger.debug("Flow : {}",flowRule.toString());
+        logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+
+        InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
+
+        //TODO: Not a good way to do it, need to figure out better way.
+        //TODO: major issue in any alternate approach is that flow key is incrementally assigned
+        //to the flows stored in data store.
+        // Augment same statistics to all the matching masked flow
+        Table table= (Table)trans.readConfigurationData(tableRef);
+        if(table != null){
+            for(Flow existingFlow : table.getFlow()){
+                logger.debug("Existing flow in data store : {}",existingFlow.toString());
+                if(FlowComparator.flowEquals(flowRule,existingFlow)){
+                    InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Table.class, new TableKey(tableId))
+                            .child(Flow.class,existingFlow.getKey()).toInstance();
+                    flowBuilder.setKey(existingFlow.getKey());
+                    flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                    logger.debug("Found matching flow in the datastore, augmenting statistics");
+                    // Update entry with timestamp of latest response
+                    flow.setKey(existingFlow.getKey());
+                    FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+                    trans.putOperationalData(flowRef, flowBuilder.build());
+                    return flowStatsEntry;
+                }
+            }
+        }
+
+        table = (Table)trans.readOperationalData(tableRef);
+        if(table != null){
+            for(Flow existingFlow : table.getFlow()){
+                FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
+                if(augmentedflowStatisticsData != null){
+                    FlowBuilder existingOperationalFlow = new FlowBuilder();
+                    existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
+                    logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
+                    if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
+                        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+                                .augmentation(FlowCapableNode.class)
+                                .child(Table.class, new TableKey(tableId))
+                                .child(Flow.class,existingFlow.getKey()).toInstance();
+                        flowBuilder.setKey(existingFlow.getKey());
+                        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+                        logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
+                        // Update entry with timestamp of latest response
+                        flow.setKey(existingFlow.getKey());
+                        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+                        trans.putOperationalData(flowRef, flowBuilder.build());
+                        return flowStatsEntry;
+                    }
+                }
+            }
+        }
+
+        String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
+        this.unaccountedFlowsCounter++;
+        FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
+        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                    .child(Table.class, new TableKey(tableId))
+                    .child(Flow.class,newFlowKey).toInstance();
+        flowBuilder.setKey(newFlowKey);
+        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
+        logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
+                    flowBuilder.build());
+
+        // Update entry with timestamp of latest response
+        flow.setKey(newFlowKey);
+        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
+        trans.putOperationalData(flowRef, flowBuilder.build());
+        return flowStatsEntry;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowTableStatsTracker.java
new file mode 100644 (file)
index 0000000..2544d55
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class FlowTableStatsTracker extends AbstractStatsTracker<FlowTableAndStatisticsMap, FlowTableAndStatisticsMap> {
+    private final Set<TableKey> privateTables = new ConcurrentSkipListSet<>();
+    private final Set<TableKey> tables = Collections.unmodifiableSet(privateTables);
+
+    FlowTableStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    Set<TableKey> getTables() {
+        return tables;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+        // TODO: do we want to do this?
+    }
+
+    @Override
+    protected FlowTableAndStatisticsMap updateSingleStat(DataModificationTransaction trans, FlowTableAndStatisticsMap item) {
+
+        InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(item.getTableId().getValue())).build();
+
+        FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
+        final FlowTableStatistics stats = new FlowTableStatisticsBuilder(item).build();
+        statisticsDataBuilder.setFlowTableStatistics(stats);
+
+        TableBuilder tableBuilder = new TableBuilder();
+        tableBuilder.setKey(new TableKey(item.getTableId().getValue()));
+        tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
+        trans.putOperationalData(tableRef, tableBuilder.build());
+        return item;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupDescStatsTracker.java
new file mode 100644 (file)
index 0000000..928bf4e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class GroupDescStatsTracker extends AbstractStatsTracker<GroupDescStats, GroupDescStats> {
+    public GroupDescStatsTracker(final InstanceIdentifier<Node> targetNodeIdentifier, final DataProviderService dps, final long lifetimeNanos) {
+        super(targetNodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected GroupDescStats updateSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+        GroupBuilder groupBuilder = new GroupBuilder();
+        GroupKey groupKey = new GroupKey(item.getGroupId());
+        groupBuilder.setKey(groupKey);
+
+        InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Group.class,groupKey).build();
+
+        NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
+        groupDesc.setGroupDesc(new GroupDescBuilder(item).build());
+
+        //Update augmented data
+        groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
+
+        trans.putOperationalData(groupRef, groupBuilder.build());
+        return item;
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, GroupDescStats item) {
+        InstanceIdentifier<NodeGroupDescStats> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupDescStats.class).build();
+        trans.removeOperationalData(groupRef);
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/GroupStatsTracker.java
new file mode 100644 (file)
index 0000000..a5498f5
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class GroupStatsTracker extends AbstractStatsTracker<GroupStats, GroupStats> {
+
+    GroupStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, GroupStats item) {
+        InstanceIdentifier<NodeGroupStatistics> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class, new GroupKey(item.getGroupId())).augmentation(NodeGroupStatistics.class).build();
+        trans.removeOperationalData(groupRef);
+    }
+
+    @Override
+    protected GroupStats updateSingleStat(DataModificationTransaction trans,
+            GroupStats item) {
+        GroupBuilder groupBuilder = new GroupBuilder();
+        GroupKey groupKey = new GroupKey(item.getGroupId());
+        groupBuilder.setKey(groupKey);
+
+        InstanceIdentifier<Group> groupRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Group.class,groupKey).build();
+
+        NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
+        groupStatisticsBuilder.setGroupStatistics(new GroupStatisticsBuilder(item).build());
+
+        //Update augmented data
+        groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
+        trans.putOperationalData(groupRef, groupBuilder.build());
+        return item;
+    }
+
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterConfigStatsTracker.java
new file mode 100644 (file)
index 0000000..dcb0b40
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class MeterConfigStatsTracker extends AbstractStatsTracker<MeterConfigStats, MeterConfigStats> {
+    protected MeterConfigStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+        InstanceIdentifier<NodeMeterConfigStats> meterRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Meter.class, new MeterKey(item.getMeterId()))
+                            .augmentation(NodeMeterConfigStats.class).build();
+        trans.removeOperationalData(meterRef);
+    }
+
+    @Override
+    protected MeterConfigStats updateSingleStat(DataModificationTransaction trans, MeterConfigStats item) {
+        MeterBuilder meterBuilder = new MeterBuilder();
+        MeterKey meterKey = new MeterKey(item.getMeterId());
+        meterBuilder.setKey(meterKey);
+
+        InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
+                .child(Meter.class,meterKey).toInstance();
+
+        NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder();
+        meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(item).build());
+
+        //Update augmented data
+        meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
+
+        trans.putOperationalData(meterRef, meterBuilder.build());
+        return item;
+    }
+
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MeterStatsTracker.java
new file mode 100644 (file)
index 0000000..381db8a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+final class MeterStatsTracker extends AbstractStatsTracker<MeterStats, MeterStats> {
+
+    MeterStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, MeterStats item) {
+        InstanceIdentifier<NodeMeterStatistics> meterRef = getNodeIdentifierBuilder()
+                            .augmentation(FlowCapableNode.class)
+                            .child(Meter.class,new MeterKey(item.getMeterId()))
+                            .augmentation(NodeMeterStatistics.class).build();
+        trans.removeOperationalData(meterRef);
+    }
+
+    @Override
+    protected MeterStats updateSingleStat(DataModificationTransaction trans, MeterStats item) {
+        MeterBuilder meterBuilder = new MeterBuilder();
+        MeterKey meterKey = new MeterKey(item.getMeterId());
+        meterBuilder.setKey(meterKey);
+
+        InstanceIdentifier<Meter> meterRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class).child(Meter.class,meterKey).build();
+
+        NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
+        meterStatsBuilder.setMeterStatistics(new MeterStatisticsBuilder(item).build());
+
+        //Update augmented data
+        meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
+        trans.putOperationalData(meterRef, meterBuilder.build());
+        return item;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/NodeConnectorStatsTracker.java
new file mode 100644 (file)
index 0000000..2a8b180
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class NodeConnectorStatsTracker extends AbstractStatsTracker<NodeConnectorStatisticsAndPortNumberMap, NodeConnectorStatisticsAndPortNumberMap> {
+    private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsTracker.class);
+
+    NodeConnectorStatsTracker(InstanceIdentifier<Node> nodeIdentifier, DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    protected NodeConnectorStatisticsAndPortNumberMap updateSingleStat(DataModificationTransaction trans, NodeConnectorStatisticsAndPortNumberMap item) {
+        FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
+                                        = new FlowCapableNodeConnectorStatisticsBuilder();
+        statisticsBuilder.setBytes(item.getBytes());
+        statisticsBuilder.setCollisionCount(item.getCollisionCount());
+        statisticsBuilder.setDuration(item.getDuration());
+        statisticsBuilder.setPackets(item.getPackets());
+        statisticsBuilder.setReceiveCrcError(item.getReceiveCrcError());
+        statisticsBuilder.setReceiveDrops(item.getReceiveDrops());
+        statisticsBuilder.setReceiveErrors(item.getReceiveErrors());
+        statisticsBuilder.setReceiveFrameError(item.getReceiveFrameError());
+        statisticsBuilder.setReceiveOverRunError(item.getReceiveOverRunError());
+        statisticsBuilder.setTransmitDrops(item.getTransmitDrops());
+        statisticsBuilder.setTransmitErrors(item.getTransmitErrors());
+
+        //Augment data to the node-connector
+        FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
+                new FlowCapableNodeConnectorStatisticsDataBuilder();
+
+        statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
+
+        InstanceIdentifier<NodeConnector> nodeConnectorRef = getNodeIdentifierBuilder()
+                .child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId())).build();
+
+        // FIXME: can we bypass this read?
+        NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
+        if(nodeConnector != null){
+            final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
+            logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
+            NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
+            nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
+            trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
+        }
+
+        return item;
+    }
+}
index 326da07..17f1ce2 100644 (file)
@@ -8,95 +8,41 @@
 package org.opendaylight.controller.md.statistics.manager;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.AggregateFlowStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -113,122 +59,34 @@ public final class NodeStatisticsHandler implements AutoCloseable {
     private static final Logger logger = LoggerFactory.getLogger(NodeStatisticsHandler.class);
     private static final int NUMBER_OF_WAIT_CYCLES = 2;
 
-    private final Map<GroupDescStats,Long> groupDescStatsUpdate = new HashMap<>();
-    private final Map<MeterConfigStats,Long> meterConfigStatsUpdate = new HashMap<>();
-    private final Map<FlowEntry,Long> flowStatsUpdate = new HashMap<>();
-    private final Map<QueueEntry,Long> queuesStatsUpdate = new HashMap<>();
     private final InstanceIdentifier<Node> targetNodeIdentifier;
+    private final FlowStatsTracker flowStats;
+    private final FlowTableStatsTracker flowTableStats;
+    private final GroupDescStatsTracker groupDescStats;
+    private final GroupStatsTracker groupStats;
+    private final MeterConfigStatsTracker meterConfigStats;
+    private final MeterStatsTracker meterStats;
+    private final NodeConnectorStatsTracker nodeConnectorStats;
+    private final QueueStatsTracker queueStats;
     private final DataProviderService dps;
     private final NodeRef targetNodeRef;
     private final NodeKey targetNodeKey;
-    private Collection<TableKey> knownTables = Collections.emptySet();
-    private int unaccountedFlowsCounter = 1;
 
     public NodeStatisticsHandler(final DataProviderService dps, final NodeKey nodeKey) {
         this.dps = Preconditions.checkNotNull(dps);
         this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
         this.targetNodeIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey).build();
         this.targetNodeRef = new NodeRef(targetNodeIdentifier);
-    }
-
-    private static class FlowEntry {
-        private final Short tableId;
-        private final Flow flow;
-
-        public FlowEntry(Short tableId, Flow flow){
-            this.tableId = tableId;
-            this.flow = flow;
-        }
-
-        public Short getTableId() {
-            return tableId;
-        }
-
-        public Flow getFlow() {
-            return flow;
-        }
 
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((flow == null) ? 0 : flow.hashCode());
-            result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            FlowEntry other = (FlowEntry) obj;
-            if (flow == null) {
-                if (other.flow != null)
-                    return false;
-            } else if (!flow.equals(other.flow))
-                return false;
-            if (tableId == null) {
-                if (other.tableId != null)
-                    return false;
-            } else if (!tableId.equals(other.tableId))
-                return false;
-            return true;
-        }
-    }
-
-    private static final class QueueEntry {
-        private final NodeConnectorId nodeConnectorId;
-        private final QueueId queueId;
-        public QueueEntry(NodeConnectorId ncId, QueueId queueId){
-            this.nodeConnectorId = ncId;
-            this.queueId = queueId;
-        }
-        public NodeConnectorId getNodeConnectorId() {
-            return nodeConnectorId;
-        }
-        public QueueId getQueueId() {
-            return queueId;
-        }
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
-            result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
-            return result;
-        }
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (!(obj instanceof QueueEntry)) {
-                return false;
-            }
-            QueueEntry other = (QueueEntry) obj;
-            if (nodeConnectorId == null) {
-                if (other.nodeConnectorId != null) {
-                    return false;
-                }
-            } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
-                return false;
-            }
-            if (queueId == null) {
-                if (other.queueId != null) {
-                    return false;
-                }
-            } else if (!queueId.equals(other.queueId)) {
-                return false;
-            }
-            return true;
-        }
+        final long lifetimeNanos = TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
+        flowStats = new FlowStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        flowTableStats = new FlowTableStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        groupDescStats = new GroupDescStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        groupStats = new GroupStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        meterConfigStats = new MeterConfigStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        meterStats = new MeterStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        nodeConnectorStats = new NodeConnectorStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
+        queueStats = new QueueStatsTracker(targetNodeIdentifier, dps, lifetimeNanos);
     }
 
     public NodeKey getTargetNodeKey() {
@@ -236,7 +94,7 @@ public final class NodeStatisticsHandler implements AutoCloseable {
     }
 
     public Collection<TableKey> getKnownTables() {
-        return knownTables;
+        return flowTableStats.getTables();
     }
 
     public InstanceIdentifier<Node> getTargetNodeIdentifier() {
@@ -247,235 +105,38 @@ public final class NodeStatisticsHandler implements AutoCloseable {
         return targetNodeRef;
     }
 
-    public synchronized void updateGroupDescStats(List<GroupDescStats> list){
-        final Long expiryTime = getExpiryTime();
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for (GroupDescStats groupDescStats : list) {
-            GroupBuilder groupBuilder = new GroupBuilder();
-            GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
-            groupBuilder.setKey(groupKey);
-
-            InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Group.class,groupKey).toInstance();
-
-            NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
-            GroupDescBuilder stats = new GroupDescBuilder();
-            stats.fieldsFrom(groupDescStats);
-            groupDesc.setGroupDesc(stats.build());
-
-            //Update augmented data
-            groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
-
-            trans.putOperationalData(groupRef, groupBuilder.build());
-            this.groupDescStatsUpdate.put(groupDescStats, expiryTime);
-        }
-
-        trans.commit();
+    public synchronized void updateGroupDescStats(List<GroupDescStats> list) {
+        groupDescStats.updateStats(list);
     }
 
     public synchronized void updateGroupStats(List<GroupStats> list) {
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for(GroupStats groupStats : list) {
-            GroupBuilder groupBuilder = new GroupBuilder();
-            GroupKey groupKey = new GroupKey(groupStats.getGroupId());
-            groupBuilder.setKey(groupKey);
-
-            InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Group.class,groupKey).toInstance();
-
-            NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
-            GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
-            stats.fieldsFrom(groupStats);
-            groupStatisticsBuilder.setGroupStatistics(stats.build());
-
-            //Update augmented data
-            groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
-            trans.putOperationalData(groupRef, groupBuilder.build());
-
-            // FIXME: should we be tracking this data?
-        }
-
-        trans.commit();
+        groupStats.updateStats(list);
     }
 
     public synchronized void updateMeterConfigStats(List<MeterConfigStats> list) {
-        final Long expiryTime = getExpiryTime();
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for(MeterConfigStats meterConfigStats : list) {
-            MeterBuilder meterBuilder = new MeterBuilder();
-            MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
-            meterBuilder.setKey(meterKey);
-
-            InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Meter.class,meterKey).toInstance();
-
-            NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
-            MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
-            stats.fieldsFrom(meterConfigStats);
-            meterConfig.setMeterConfigStats(stats.build());
-
-            //Update augmented data
-            meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
-
-            trans.putOperationalData(meterRef, meterBuilder.build());
-            this.meterConfigStatsUpdate.put(meterConfigStats, expiryTime);
-        }
-
-        trans.commit();
+        meterConfigStats.updateStats(list);
     }
 
-
     public synchronized void updateMeterStats(List<MeterStats> list) {
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for(MeterStats meterStats : list) {
-            MeterBuilder meterBuilder = new MeterBuilder();
-            MeterKey meterKey = new MeterKey(meterStats.getMeterId());
-            meterBuilder.setKey(meterKey);
-
-            InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                                                                        .augmentation(FlowCapableNode.class)
-                                                                                        .child(Meter.class,meterKey).toInstance();
-
-            NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
-            MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
-            stats.fieldsFrom(meterStats);
-            meterStatsBuilder.setMeterStatistics(stats.build());
-
-            //Update augmented data
-            meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
-            trans.putOperationalData(meterRef, meterBuilder.build());
-
-            // FIXME: should we be tracking this data?
-        }
-
-        trans.commit();
+        meterStats.updateStats(list);
     }
 
     public synchronized void updateQueueStats(List<QueueIdAndStatisticsMap> list) {
-        final Long expiryTime = getExpiryTime();
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for (QueueIdAndStatisticsMap swQueueStats : list) {
-
-            QueueEntry queueEntry = new QueueEntry(swQueueStats.getNodeConnectorId(),swQueueStats.getQueueId());
-
-            FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
-
-            FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
-
-            queueStatisticsBuilder.fieldsFrom(swQueueStats);
-
-            queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
-
-            InstanceIdentifier<Queue> queueRef
-                    = InstanceIdentifier.builder(Nodes.class)
-                                        .child(Node.class, targetNodeKey)
-                                        .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
-                                        .augmentation(FlowCapableNodeConnector.class)
-                                        .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
-
-            QueueBuilder queueBuilder = new QueueBuilder();
-            FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
-            queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
-            queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
-
-            logger.debug("Augmenting queue statistics {} of queue {} to port {}",
-                                        qsd,
-                                        swQueueStats.getQueueId(),
-                                        swQueueStats.getNodeConnectorId());
-
-            trans.putOperationalData(queueRef, queueBuilder.build());
-            this.queuesStatsUpdate.put(queueEntry, expiryTime);
-        }
-
-        trans.commit();
+        queueStats.updateStats(list);
     }
 
     public synchronized void updateFlowTableStats(List<FlowTableAndStatisticsMap> list) {
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        final Set<TableKey> knownTables = new HashSet<>(list.size());
-        for (FlowTableAndStatisticsMap ftStats : list) {
-
-            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
-
-            FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
-            final FlowTableStatistics stats = new FlowTableStatisticsBuilder(ftStats).build();
-            statisticsDataBuilder.setFlowTableStatistics(stats);
-
-            logger.debug("Augment flow table statistics: {} for table {} on Node {}",
-                    stats,ftStats.getTableId(), targetNodeKey);
-
-            TableBuilder tableBuilder = new TableBuilder();
-            tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
-            tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
-            trans.putOperationalData(tableRef, tableBuilder.build());
-
-            knownTables.add(tableBuilder.getKey());
-        }
-
-        this.knownTables = Collections.unmodifiableCollection(knownTables);
-        trans.commit();
+        flowTableStats.updateStats(list);
     }
 
     public synchronized void updateNodeConnectorStats(List<NodeConnectorStatisticsAndPortNumberMap> list) {
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for(NodeConnectorStatisticsAndPortNumberMap portStats : list) {
-
-            FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder
-                                            = new FlowCapableNodeConnectorStatisticsBuilder();
-            statisticsBuilder.setBytes(portStats.getBytes());
-            statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
-            statisticsBuilder.setDuration(portStats.getDuration());
-            statisticsBuilder.setPackets(portStats.getPackets());
-            statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
-            statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
-            statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
-            statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
-            statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
-            statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
-            statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
-
-            //Augment data to the node-connector
-            FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder =
-                    new FlowCapableNodeConnectorStatisticsDataBuilder();
-
-            statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
-
-            InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class)
-                    .child(Node.class, targetNodeKey)
-                    .child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
-
-            // FIXME: can we bypass this read?
-            NodeConnector nodeConnector = (NodeConnector)trans.readOperationalData(nodeConnectorRef);
-            if(nodeConnector != null){
-                final FlowCapableNodeConnectorStatisticsData stats = statisticsDataBuilder.build();
-                logger.debug("Augmenting port statistics {} to port {}",stats,nodeConnectorRef.toString());
-                NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
-                nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, stats);
-                trans.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
-            }
-
-            // FIXME: should we be tracking this data?
-        }
-
-        trans.commit();
+        nodeConnectorStats.updateStats(list);
     }
 
     public synchronized void updateAggregateFlowStats(Short tableId, AggregateFlowStatistics flowStats) {
         if (tableId != null) {
             final DataModificationTransaction trans = dps.beginTransaction();
 
-
             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
 
@@ -534,256 +195,24 @@ public final class NodeStatisticsHandler implements AutoCloseable {
     }
 
     public synchronized void updateFlowStats(List<FlowAndStatisticsMapList> list) {
-        final Long expiryTime = getExpiryTime();
-        final DataModificationTransaction trans = dps.beginTransaction();
-
-        for(FlowAndStatisticsMapList map : list) {
-            short tableId = map.getTableId();
-            boolean foundOriginalFlow = false;
-
-            FlowBuilder flowBuilder = new FlowBuilder();
-
-            FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
-
-            FlowBuilder flow = new FlowBuilder();
-            flow.setContainerName(map.getContainerName());
-            flow.setBufferId(map.getBufferId());
-            flow.setCookie(map.getCookie());
-            flow.setCookieMask(map.getCookieMask());
-            flow.setFlags(map.getFlags());
-            flow.setFlowName(map.getFlowName());
-            flow.setHardTimeout(map.getHardTimeout());
-            if(map.getFlowId() != null)
-                flow.setId(new FlowId(map.getFlowId().getValue()));
-            flow.setIdleTimeout(map.getIdleTimeout());
-            flow.setInstallHw(map.isInstallHw());
-            flow.setInstructions(map.getInstructions());
-            if(map.getFlowId()!= null)
-                flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
-            flow.setMatch(map.getMatch());
-            flow.setOutGroup(map.getOutGroup());
-            flow.setOutPort(map.getOutPort());
-            flow.setPriority(map.getPriority());
-            flow.setStrict(map.isStrict());
-            flow.setTableId(tableId);
-
-            Flow flowRule = flow.build();
-
-            FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
-            stats.setByteCount(map.getByteCount());
-            stats.setPacketCount(map.getPacketCount());
-            stats.setDuration(map.getDuration());
-
-            GenericStatistics flowStats = stats.build();
-
-            //Augment the data to the flow node
-
-            FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
-            flowStatistics.setByteCount(flowStats.getByteCount());
-            flowStatistics.setPacketCount(flowStats.getPacketCount());
-            flowStatistics.setDuration(flowStats.getDuration());
-            flowStatistics.setContainerName(map.getContainerName());
-            flowStatistics.setBufferId(map.getBufferId());
-            flowStatistics.setCookie(map.getCookie());
-            flowStatistics.setCookieMask(map.getCookieMask());
-            flowStatistics.setFlags(map.getFlags());
-            flowStatistics.setFlowName(map.getFlowName());
-            flowStatistics.setHardTimeout(map.getHardTimeout());
-            flowStatistics.setIdleTimeout(map.getIdleTimeout());
-            flowStatistics.setInstallHw(map.isInstallHw());
-            flowStatistics.setInstructions(map.getInstructions());
-            flowStatistics.setMatch(map.getMatch());
-            flowStatistics.setOutGroup(map.getOutGroup());
-            flowStatistics.setOutPort(map.getOutPort());
-            flowStatistics.setPriority(map.getPriority());
-            flowStatistics.setStrict(map.isStrict());
-            flowStatistics.setTableId(tableId);
-
-            flowStatisticsData.setFlowStatistics(flowStatistics.build());
-
-            logger.debug("Flow : {}",flowRule.toString());
-            logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
-
-            InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                    .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-
-            Table table= (Table)trans.readConfigurationData(tableRef);
-
-            //TODO: Not a good way to do it, need to figure out better way.
-            //TODO: major issue in any alternate approach is that flow key is incrementally assigned
-            //to the flows stored in data store.
-            // Augment same statistics to all the matching masked flow
-            if(table != null){
-
-                for(Flow existingFlow : table.getFlow()){
-                    logger.debug("Existing flow in data store : {}",existingFlow.toString());
-                    if(FlowComparator.flowEquals(flowRule,existingFlow)){
-                        InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                .augmentation(FlowCapableNode.class)
-                                .child(Table.class, new TableKey(tableId))
-                                .child(Flow.class,existingFlow.getKey()).toInstance();
-                        flowBuilder.setKey(existingFlow.getKey());
-                        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                        logger.debug("Found matching flow in the datastore, augmenting statistics");
-                        foundOriginalFlow = true;
-                        // Update entry with timestamp of latest response
-                        flow.setKey(existingFlow.getKey());
-                        FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
-                        flowStatsUpdate.put(flowStatsEntry, expiryTime);
-
-                        trans.putOperationalData(flowRef, flowBuilder.build());
-                    }
-                }
-            }
-
-            table = (Table)trans.readOperationalData(tableRef);
-            if(!foundOriginalFlow && table != null){
-
-                for(Flow existingFlow : table.getFlow()){
-                    FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
-                    if(augmentedflowStatisticsData != null){
-                        FlowBuilder existingOperationalFlow = new FlowBuilder();
-                        existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
-                        logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
-                        if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
-                            InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                                    .augmentation(FlowCapableNode.class)
-                                    .child(Table.class, new TableKey(tableId))
-                                    .child(Flow.class,existingFlow.getKey()).toInstance();
-                            flowBuilder.setKey(existingFlow.getKey());
-                            flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                            logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
-                            foundOriginalFlow = true;
-
-                            // Update entry with timestamp of latest response
-                            flow.setKey(existingFlow.getKey());
-                            FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
-                            flowStatsUpdate.put(flowStatsEntry, expiryTime);
-                            trans.putOperationalData(flowRef, flowBuilder.build());
-                            break;
-                        }
-                    }
-                }
-            }
-            if(!foundOriginalFlow){
-                String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
-                this.unaccountedFlowsCounter++;
-                FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
-                InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, targetNodeKey)
-                        .augmentation(FlowCapableNode.class)
-                        .child(Table.class, new TableKey(tableId))
-                        .child(Flow.class,newFlowKey).toInstance();
-                flowBuilder.setKey(newFlowKey);
-                flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
-                        flowBuilder.build());
-
-                // Update entry with timestamp of latest response
-                flow.setKey(newFlowKey);
-                FlowEntry flowStatsEntry = new FlowEntry(tableId,flow.build());
-                flowStatsUpdate.put(flowStatsEntry, expiryTime);
-                trans.putOperationalData(flowRef, flowBuilder.build());
-            }
-        }
-
-        trans.commit();
+        flowStats.updateStats(list);
     }
 
-    private static Long getExpiryTime(){
-        final long now = System.nanoTime();
-        return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
-    }
-
-    public synchronized void cleanStaleStatistics(){
+    public synchronized void cleanStaleStatistics() {
         final DataModificationTransaction trans = dps.beginTransaction();
         final long now = System.nanoTime();
 
-        //Clean stale statistics related to group
-        for (Iterator<Entry<GroupDescStats, Long>> it = this.groupDescStatsUpdate.entrySet().iterator();it.hasNext();){
-            Entry<GroupDescStats, Long> e = it.next();
-            if (now > e.getValue()) {
-                cleanGroupStatsFromDataStore(trans, e.getKey());
-                it.remove();
-            }
-        }
-
-        //Clean stale statistics related to meter
-        for (Iterator<Entry<MeterConfigStats, Long>> it = this.meterConfigStatsUpdate.entrySet().iterator();it.hasNext();){
-            Entry<MeterConfigStats, Long> e = it.next();
-            if (now > e.getValue()) {
-                cleanMeterStatsFromDataStore(trans, e.getKey());
-                it.remove();
-            }
-        }
-
-        //Clean stale statistics related to flow
-        for (Iterator<Entry<FlowEntry, Long>> it = this.flowStatsUpdate.entrySet().iterator();it.hasNext();){
-            Entry<FlowEntry, Long> e = it.next();
-            if (now > e.getValue()) {
-                cleanFlowStatsFromDataStore(trans, e.getKey());
-                it.remove();
-            }
-        }
-
-        //Clean stale statistics related to queue
-        for (Iterator<Entry<QueueEntry, Long>> it = this.queuesStatsUpdate.entrySet().iterator();it.hasNext();){
-            Entry<QueueEntry, Long> e = it.next();
-            if (now > e.getValue()) {
-                cleanQueueStatsFromDataStore(trans, e.getKey());
-                it.remove();
-            }
-        }
+        flowStats.cleanup(trans, now);
+        groupDescStats.cleanup(trans, now);
+        groupStats.cleanup(trans, now);
+        meterConfigStats.cleanup(trans, now);
+        meterStats.cleanup(trans, now);
+        nodeConnectorStats.cleanup(trans, now);
+        queueStats.cleanup(trans, now);
 
         trans.commit();
     }
 
-    private void cleanQueueStatsFromDataStore(DataModificationTransaction trans, QueueEntry queueEntry) {
-        InstanceIdentifier<?> queueRef
-                        = InstanceIdentifier.builder(Nodes.class)
-                                            .child(Node.class, this.targetNodeKey)
-                                            .child(NodeConnector.class, new NodeConnectorKey(queueEntry.getNodeConnectorId()))
-                                            .augmentation(FlowCapableNodeConnector.class)
-                                            .child(Queue.class, new QueueKey(queueEntry.getQueueId()))
-                                            .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).toInstance();
-        trans.removeOperationalData(queueRef);
-    }
-
-    private void cleanFlowStatsFromDataStore(DataModificationTransaction trans, FlowEntry flowEntry) {
-        InstanceIdentifier<?> flowRef
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class, this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Table.class, new TableKey(flowEntry.getTableId()))
-                                            .child(Flow.class,flowEntry.getFlow().getKey())
-                                            .augmentation(FlowStatisticsData.class).toInstance();
-        trans.removeOperationalData(flowRef);
-    }
-
-    private void cleanMeterStatsFromDataStore(DataModificationTransaction trans, MeterConfigStats meterConfigStats) {
-        InstanceIdentifierBuilder<Meter> meterRef
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Meter.class,new MeterKey(meterConfigStats.getMeterId()));
-
-        InstanceIdentifier<?> nodeMeterConfigStatsAugmentation = meterRef.augmentation(NodeMeterConfigStats.class).toInstance();
-        trans.removeOperationalData(nodeMeterConfigStatsAugmentation);
-
-        InstanceIdentifier<?> nodeMeterStatisticsAugmentation = meterRef.augmentation(NodeMeterStatistics.class).toInstance();
-        trans.removeOperationalData(nodeMeterStatisticsAugmentation);
-    }
-
-    private void cleanGroupStatsFromDataStore(DataModificationTransaction trans, GroupDescStats groupDescStats) {
-        InstanceIdentifierBuilder<Group> groupRef
-                        = InstanceIdentifier.builder(Nodes.class).child(Node.class,this.targetNodeKey)
-                                            .augmentation(FlowCapableNode.class)
-                                            .child(Group.class,new GroupKey(groupDescStats.getGroupId()));
-
-        InstanceIdentifier<?> nodeGroupDescStatsAugmentation = groupRef.augmentation(NodeGroupDescStats.class).toInstance();
-        trans.removeOperationalData(nodeGroupDescStatsAugmentation);
-
-        InstanceIdentifier<?> nodeGroupStatisticsAugmentation = groupRef.augmentation(NodeGroupStatistics.class).toInstance();
-        trans.removeOperationalData(nodeGroupStatisticsAugmentation);
-    }
-
     @Override
     public void close() {
         // FIXME: cleanup any resources we hold (registrations, etc.)
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsEntry.java
new file mode 100644 (file)
index 0000000..d1f2529
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+
+final class QueueStatsEntry {
+    private final NodeConnectorId nodeConnectorId;
+    private final QueueId queueId;
+    public QueueStatsEntry(NodeConnectorId ncId, QueueId queueId){
+        this.nodeConnectorId = ncId;
+        this.queueId = queueId;
+    }
+    public NodeConnectorId getNodeConnectorId() {
+        return nodeConnectorId;
+    }
+    public QueueId getQueueId() {
+        return queueId;
+    }
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((nodeConnectorId == null) ? 0 : nodeConnectorId.hashCode());
+        result = prime * result + ((queueId == null) ? 0 : queueId.hashCode());
+        return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof QueueStatsEntry)) {
+            return false;
+        }
+        QueueStatsEntry other = (QueueStatsEntry) obj;
+        if (nodeConnectorId == null) {
+            if (other.nodeConnectorId != null) {
+                return false;
+            }
+        } else if (!nodeConnectorId.equals(other.nodeConnectorId)) {
+            return false;
+        }
+        if (queueId == null) {
+            if (other.queueId != null) {
+                return false;
+            }
+        } else if (!queueId.equals(other.queueId)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java b/opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/QueueStatsTracker.java
new file mode 100644 (file)
index 0000000..c2bde6a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class QueueStatsTracker extends AbstractStatsTracker<QueueIdAndStatisticsMap, QueueStatsEntry> {
+    private static final Logger logger = LoggerFactory.getLogger(QueueStatsTracker.class);
+
+    QueueStatsTracker(InstanceIdentifier<Node> nodeIdentifier,
+            DataProviderService dps, long lifetimeNanos) {
+        super(nodeIdentifier, dps, lifetimeNanos);
+    }
+
+    @Override
+    protected void cleanupSingleStat(DataModificationTransaction trans, QueueStatsEntry item) {
+        InstanceIdentifier<?> queueRef
+                            = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+                                                .augmentation(FlowCapableNodeConnector.class)
+                                                .child(Queue.class, new QueueKey(item.getQueueId()))
+                                                .augmentation(FlowCapableNodeConnectorQueueStatisticsData.class).build();
+        trans.removeOperationalData(queueRef);
+    }
+
+    @Override
+    protected QueueStatsEntry updateSingleStat(DataModificationTransaction trans, QueueIdAndStatisticsMap item) {
+
+        QueueStatsEntry queueEntry = new QueueStatsEntry(item.getNodeConnectorId(), item.getQueueId());
+
+        FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
+
+        FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
+
+        queueStatisticsBuilder.fieldsFrom(item);
+
+        queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
+
+        InstanceIdentifier<Queue> queueRef = getNodeIdentifierBuilder().child(NodeConnector.class, new NodeConnectorKey(item.getNodeConnectorId()))
+                                    .augmentation(FlowCapableNodeConnector.class)
+                                    .child(Queue.class, new QueueKey(item.getQueueId())).toInstance();
+
+        QueueBuilder queueBuilder = new QueueBuilder();
+        FlowCapableNodeConnectorQueueStatisticsData qsd = queueStatisticsDataBuilder.build();
+        queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, qsd);
+        queueBuilder.setKey(new QueueKey(item.getQueueId()));
+
+        logger.debug("Augmenting queue statistics {} of queue {} to port {}",
+                                    qsd,
+                                    item.getQueueId(),
+                                    item.getNodeConnectorId());
+
+        trans.putOperationalData(queueRef, queueBuilder.build());
+        return queueEntry;
+    }
+}
index d8ee80a..e9d2356 100644 (file)
@@ -156,7 +156,9 @@ public class StatisticsProvider implements AutoCloseable {
             public void run() {
                 try {
                     // Send stats requests
-                    statsRequestSender();
+                    for (NodeStatisticsHandler h : handlers.values()) {
+                        sendStatisticsRequestsToNode(h);
+                    }
 
                     // Perform cleanup
                     for(NodeStatisticsHandler nodeStatisticsAger : handlers.values()){
@@ -209,12 +211,6 @@ public class StatisticsProvider implements AutoCloseable {
         return dps.beginTransaction();
     }
 
-    private void statsRequestSender() {
-        for (NodeStatisticsHandler h : handlers.values()) {
-            sendStatisticsRequestsToNode(h);
-        }
-    }
-
     private void sendStatisticsRequestsToNode(final NodeStatisticsHandler h) {
         NodeKey targetNode = h.getTargetNodeKey();
         spLogger.debug("Send requests for statistics collection to node : {}", targetNode.getId());

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.