Bug 3389 - Scheduling time adaptation calculated per device
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / statistics / StatisticsManagerImpl.java
index 6e99aa76540234515686d309b530fc60f59858cb..178e0656daa34a04831d770e514469e60fe3b31b 100644 (file)
@@ -16,6 +16,7 @@ import io.netty.util.Timeout;
 import io.netty.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
@@ -34,9 +35,8 @@ public class StatisticsManagerImpl implements StatisticsManager {
 
     private HashedWheelTimer hashedWheelTimer;
 
-    private ConcurrentHashMap<DeviceContext, StatisticsContext> contexts = new ConcurrentHashMap();
+    private final ConcurrentHashMap<DeviceContext, StatisticsContext> contexts = new ConcurrentHashMap<>();
 
-    private final TimeCounter timeCounter = new TimeCounter();
 
     private static final long basicTimerDelay = 3000;
     private static long currentTimerDelay = basicTimerDelay;
@@ -53,7 +53,6 @@ public class StatisticsManagerImpl implements StatisticsManager {
         if (null == hashedWheelTimer) {
             LOG.trace("This is first device that delivered timer. Starting statistics polling immediately.");
             hashedWheelTimer = deviceContext.getTimer();
-            pollStatistics();
         }
 
         final StatisticsContext statisticsContext = new StatisticsContextImpl(deviceContext);
@@ -65,6 +64,8 @@ public class StatisticsManagerImpl implements StatisticsManager {
                 if (statisticsGathered.booleanValue()) {
                     //there are some statistics on device worth gathering
                     contexts.put(deviceContext, statisticsContext);
+                    final TimeCounter timeCounter = new TimeCounter();
+                    pollStatistics(deviceContext, statisticsContext, timeCounter);
                 }
                 LOG.trace("Device dynamic info collecting done. Going to announce raise to next level.");
                 deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
@@ -83,42 +84,48 @@ public class StatisticsManagerImpl implements StatisticsManager {
         });
     }
 
-    private void pollStatistics() {
-        try {
-            timeCounter.markStart();
-            for (final StatisticsContext statisticsContext : contexts.values()) {
-                ListenableFuture deviceStatisticsCollectionFuture = statisticsContext.gatherDynamicData();
-                Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback() {
-                    @Override
-                    public void onSuccess(final Object o) {
-                        timeCounter.addTimeMark();
-                    }
-
-                    @Override
-                    public void onFailure(final Throwable throwable) {
-                        timeCounter.addTimeMark();
-                        LOG.info("Statistics gathering for single node was not successful: {}", throwable.getMessage());
-                        LOG.debug("Statistics gathering for single node was not successful.. ", throwable);
-                    }
-                });
+    private void pollStatistics(final DeviceContext deviceContext,
+                                final StatisticsContext statisticsContext,
+                                final TimeCounter timeCounter) {
+        timeCounter.markStart();
+        ListenableFuture<Boolean> deviceStatisticsCollectionFuture = statisticsContext.gatherDynamicData();
+        Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback<Boolean>() {
+            @Override
+            public void onSuccess(final Boolean o) {
+                timeCounter.addTimeMark();
+                calculateTimerDelay(timeCounter);
+                scheduleNextPolling(deviceContext, statisticsContext, timeCounter);
             }
-        } finally {
-            calculateTimerDelay();
-            if (null != hashedWheelTimer) {
-                hashedWheelTimer.newTimeout(new TimerTask() {
-                    @Override
-                    public void run(final Timeout timeout) throws Exception {
-                        pollStatistics();
-                    }
-                }, currentTimerDelay, TimeUnit.MILLISECONDS);
+
+            @Override
+            public void onFailure(final Throwable throwable) {
+                timeCounter.addTimeMark();
+                LOG.info("Statistics gathering for single node was not successful: {}", throwable.getMessage());
+                LOG.debug("Statistics gathering for single node was not successful.. ", throwable);
+                if (ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
+                    calculateTimerDelay(timeCounter);
+                    scheduleNextPolling(deviceContext, statisticsContext, timeCounter);
+                }
             }
+        });
+    }
+
+    private void scheduleNextPolling(final DeviceContext deviceContext,
+                                     final StatisticsContext statisticsContext,
+                                     final TimeCounter timeCounter) {
+        if (null != hashedWheelTimer) {
+            hashedWheelTimer.newTimeout(new TimerTask() {
+                @Override
+                public void run(final Timeout timeout) throws Exception {
+                    pollStatistics(deviceContext, statisticsContext, timeCounter);
+                }
+            }, currentTimerDelay, TimeUnit.MILLISECONDS);
         }
     }
 
-    private void calculateTimerDelay() {
+    private void calculateTimerDelay(final TimeCounter timeCounter) {
         long averageStatisticsGatheringTime = timeCounter.getAverageTimeBetweenMarks();
-        int numberOfDevices = contexts.size();
-        if ((averageStatisticsGatheringTime * numberOfDevices) > currentTimerDelay) {
+        if (averageStatisticsGatheringTime > currentTimerDelay) {
             currentTimerDelay *= 2;
             if (currentTimerDelay > maximumTimerDelay) {
                 currentTimerDelay = maximumTimerDelay;
@@ -126,16 +133,17 @@ public class StatisticsManagerImpl implements StatisticsManager {
         } else {
             if (currentTimerDelay > basicTimerDelay) {
                 currentTimerDelay /= 2;
+            } else {
+                currentTimerDelay = basicTimerDelay;
             }
         }
     }
 
     @Override
     public void onDeviceContextClosed(final DeviceContext deviceContext) {
-        if (contexts.containsKey(deviceContext)) {
+        StatisticsContext statisticsContext = contexts.remove(deviceContext);
+        if (null != statisticsContext) {
             LOG.trace("Removing device context from stack. No more statistics gathering for node {}", deviceContext.getDeviceState().getNodeId());
-            contexts.remove(deviceContext);
-            StatisticsContext statisticsContext = contexts.remove(deviceContext);
             try {
                 statisticsContext.close();
             } catch (Exception e) {
@@ -150,13 +158,13 @@ public class StatisticsManagerImpl implements StatisticsManager {
         private int marksCount = 0;
 
         public void markStart() {
-            beginningOfTime = System.currentTimeMillis();
+            beginningOfTime = System.nanoTime();
             delta = 0;
             marksCount = 0;
         }
 
         public void addTimeMark() {
-            delta += System.currentTimeMillis() - beginningOfTime;
+            delta += System.nanoTime() - beginningOfTime;
             marksCount++;
         }
 
@@ -165,7 +173,7 @@ public class StatisticsManagerImpl implements StatisticsManager {
             if (marksCount > 0) {
                 average = delta / marksCount;
             }
-            return average;
+            return TimeUnit.NANOSECONDS.toMillis(average);
         }
 
     }