Use a single Timer instead of two threads 00/5300/4
authorRobert Varga <rovarga@cisco.com>
Thu, 13 Feb 2014 07:45:36 +0000 (08:45 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Sat, 15 Feb 2014 02:09:52 +0000 (02:09 +0000)
It turns out that we really want to have the aging and collection bound
to a common timeline, so let's combine them. This will give us the
opportunity to perform mark&sweep in future.

Furthermore we use the threads only for periodic tasks, so let's convert
to a Timer with TimerTasks. This will allow us more flexibility going
forward, for example allowing NodeStatisticsHandlers to manage how often
they wish to collect individual statistics.

Change-Id: Ie2cd0e4e7391e1175a8927773f85278b80f16c48
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/MultipartMessageManager.java
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/StatisticsProvider.java

index 02b397e78f15875d3ce6cd18ba62a86219d77ebf..2201cb3930e43427cdec6a1921a27f57538fdb04 100644 (file)
@@ -129,7 +129,7 @@ public class MultipartMessageManager {
 
     private static Long getExpiryTime(){
         return System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(
-                StatisticsProvider.STATS_THREAD_EXECUTION_TIME*NUMBER_OF_WAIT_CYCLES);
+                StatisticsProvider.STATS_COLLECTION_MILLIS*NUMBER_OF_WAIT_CYCLES);
     }
 
     public enum StatsRequestType{
index 5ef4b36563173815af981977e542f88a956e948b..326da07c7321e388ac0aa615a73729f85c9a4e53 100644 (file)
@@ -691,7 +691,7 @@ public final class NodeStatisticsHandler implements AutoCloseable {
 
     private static Long getExpiryTime(){
         final long now = System.nanoTime();
-        return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_THREAD_EXECUTION_TIME * NUMBER_OF_WAIT_CYCLES);
+        return now + TimeUnit.MILLISECONDS.toNanos(StatisticsProvider.STATS_COLLECTION_MILLIS * NUMBER_OF_WAIT_CYCLES);
     }
 
     public synchronized void cleanStaleStatistics(){
index 3b9b4dc39e29ebaabb7d0bae2b944dbf0624abba..7432db74eb175fc1e35f1736fe2ea5cd1ae0b2e4 100644 (file)
@@ -8,10 +8,13 @@
 package org.opendaylight.controller.md.statistics.manager;
 
 import java.util.Collection;
+import java.util.Timer;
+import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
 
 import org.opendaylight.controller.md.statistics.manager.MultipartMessageManager.StatsRequestType;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
@@ -88,12 +91,13 @@ import com.google.common.base.Preconditions;
  *
  */
 public class StatisticsProvider implements AutoCloseable {
-    public static final int STATS_THREAD_EXECUTION_TIME= 15000;
+    public static final long STATS_COLLECTION_MILLIS = TimeUnit.SECONDS.toMillis(15);
 
     private static final Logger spLogger = LoggerFactory.getLogger(StatisticsProvider.class);
 
     private final ConcurrentMap<NodeId, NodeStatisticsHandler> handlers = new ConcurrentHashMap<>();
     private final MultipartMessageManager multipartMessageManager = new MultipartMessageManager();
+    private final Timer timer = new Timer("statistics-manager", true);
     private final DataProviderService dps;
 
     private OpendaylightGroupStatisticsService groupStatsService;
@@ -110,11 +114,6 @@ public class StatisticsProvider implements AutoCloseable {
 
     private StatisticsUpdateHandler statsUpdateHandler;
 
-    private Thread statisticsRequesterThread;
-
-    private Thread statisticsAgerThread;
-
-
     public StatisticsProvider(final DataProviderService dataService) {
         this.dps = Preconditions.checkNotNull(dataService);
     }
@@ -152,49 +151,26 @@ public class StatisticsProvider implements AutoCloseable {
         statsUpdateHandler = new StatisticsUpdateHandler(StatisticsProvider.this);
         registerDataStoreUpdateListener(dbs);
 
-        statisticsRequesterThread = new Thread( new Runnable(){
-
+        timer.schedule(new TimerTask() {
             @Override
             public void run() {
-                while(true){
-                    try {
-                        statsRequestSender();
+                try {
+                    // Send stats requests
+                    statsRequestSender();
 
-                        Thread.sleep(STATS_THREAD_EXECUTION_TIME);
-                    }catch (Exception e){
-                        spLogger.error("Exception occurred while sending stats request : {}",e);
+                    // Perform cleanup
+                    for(NodeStatisticsHandler nodeStatisticsAger : handlers.values()){
+                        nodeStatisticsAger.cleanStaleStatistics();
                     }
-                }
-            }
-        });
-
-        spLogger.debug("Statistics requester thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
 
-        statisticsRequesterThread.start();
-
-        statisticsAgerThread = new Thread( new Runnable(){
-
-            @Override
-            public void run() {
-                while(true){
-                    try {
-                        for(NodeStatisticsHandler nodeStatisticsAger : handlers.values()){
-                            nodeStatisticsAger.cleanStaleStatistics();
-                        }
-                        multipartMessageManager.cleanStaleTransactionIds();
-
-                        Thread.sleep(STATS_THREAD_EXECUTION_TIME);
-                    }catch (Exception e){
-                        spLogger.error("Exception occurred while sending stats request : {}",e);
-                    }
+                    multipartMessageManager.cleanStaleTransactionIds();
+                } catch (RuntimeException e) {
+                    spLogger.warn("Failed to request statistics", e);
                 }
             }
-        });
-
-        spLogger.debug("Statistics ager thread started with timer interval : {}",STATS_THREAD_EXECUTION_TIME);
-
-        statisticsAgerThread.start();
+        }, 0, STATS_COLLECTION_MILLIS);
 
+        spLogger.debug("Statistics timer task with timer interval : {}ms", STATS_COLLECTION_MILLIS);
         spLogger.info("Statistics Provider started.");
     }
 
@@ -465,13 +441,13 @@ public class StatisticsProvider implements AutoCloseable {
         try {
             if (this.listenerRegistration != null) {
                 this.listenerRegistration.close();
-                this.statisticsRequesterThread.destroy();
-                this.statisticsAgerThread.destroy();
+                this.listenerRegistration = null;
             }
             if (this.flowCapableTrackerRegistration != null) {
                 this.flowCapableTrackerRegistration.close();
                 this.flowCapableTrackerRegistration = null;
             }
+            timer.cancel();
         } catch (Exception e) {
             spLogger.warn("Failed to stop Statistics Provider completely", e);
         } finally {