OPNFLWPLUG-983 Group and flow removal stats are not reported in order
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / statistics / StatisticsPollingService.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowplugin.impl.statistics;
9
10 import com.google.common.util.concurrent.AbstractScheduledService;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import com.google.common.util.concurrent.Service;
16 import com.google.common.util.concurrent.SettableFuture;
17 import java.util.concurrent.CancellationException;
18 import java.util.concurrent.CompletableFuture;
19 import java.util.concurrent.TimeUnit;
20 import java.util.function.Supplier;
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import org.opendaylight.openflowplugin.api.ConnectionException;
24
25 public class StatisticsPollingService extends AbstractScheduledService {
26     private static final long DEFAULT_STATS_TIMEOUT = 50000;
27
28     private final TimeCounter counter;
29     private final long pollingInterval;
30     private final long maximumTimerDelay;
31     private final Supplier<ListenableFuture<Boolean>> gatheringSupplier;
32     private final SettableFuture<Void> future = SettableFuture.create();
33
34     StatisticsPollingService(@Nonnull final TimeCounter counter,
35                              final long pollingInterval,
36                              final long maximumTimerDelay,
37                              @Nonnull final Supplier<ListenableFuture<Boolean>> gatheringSupplier) {
38         this.counter = counter;
39         this.pollingInterval = pollingInterval;
40         this.maximumTimerDelay = maximumTimerDelay;
41         this.gatheringSupplier = gatheringSupplier;
42         this.addListener(new StatisticsPollingServiceListener(), MoreExecutors.directExecutor());
43     }
44
45     ListenableFuture<Void> stop() {
46         stopAsync();
47         return future;
48     }
49
50     @Override
51     protected void startUp() throws Exception {
52         counter.markStart();
53     }
54
55     @Override
56     protected void runOneIteration() throws Exception {
57         final long averageTime = counter.getAverageTimeBetweenMarks();
58         final long statsTimeout = averageTime > 0 ? 3 * averageTime : DEFAULT_STATS_TIMEOUT;
59         final CompletableFuture<Boolean> waitFuture = new CompletableFuture<>();
60
61         Futures.addCallback(gatheringSupplier.get(), new FutureCallback<Boolean>() {
62             @Override
63             public void onSuccess(@Nullable final Boolean result) {
64                 waitFuture.complete(result);
65             }
66
67             @Override
68             public void onFailure(@Nonnull final Throwable throwable) {
69                 waitFuture.completeExceptionally(throwable);
70             }
71         }, MoreExecutors.directExecutor());
72
73         try {
74             waitFuture.get(statsTimeout, TimeUnit.MILLISECONDS);
75         } finally {
76             counter.addTimeMark();
77         }
78     }
79
80     @Override
81     protected Scheduler scheduler() {
82         final long averageStatisticsGatheringTime = counter.getAverageTimeBetweenMarks();
83         long currentTimerDelay = pollingInterval;
84
85         if (averageStatisticsGatheringTime > currentTimerDelay) {
86             currentTimerDelay = averageStatisticsGatheringTime;
87
88             if (currentTimerDelay > maximumTimerDelay) {
89                 currentTimerDelay = maximumTimerDelay;
90             }
91         }
92
93         return Scheduler.newFixedDelaySchedule(currentTimerDelay, currentTimerDelay, TimeUnit.MILLISECONDS);
94     }
95
96     private final class StatisticsPollingServiceListener extends Service.Listener {
97         @Override
98         public void terminated(final Service.State from) {
99             super.terminated(from);
100             future.set(null);
101         }
102
103         @Override
104         public void failed(final Service.State from, final Throwable failure) {
105             super.failed(from, failure);
106             if (!(failure instanceof CancellationException) && !(failure instanceof ConnectionException)) {
107                 future.setException(failure);
108             } else {
109                 future.set(null);
110             }
111         }
112     }
113 }