Merge branch 'master' of ../controller
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / ConcurrentDurationStatisticsTracker.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.yangtools.util;
9
10 import com.google.common.primitives.UnsignedLong;
11 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
12 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
13
14 /**
15  * Concurrent version of {@link DurationStatisticsTracker}.
16  */
17 // TODO: once DurationStatsTracker is gone make this class final
18 class ConcurrentDurationStatisticsTracker extends DurationStatisticsTracker {
19
20     private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime>
21         LONGEST_UPDATER = AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class,
22                 DurationWithTime.class, "longest");
23
24     private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime>
25         SHORTEST_UPDATER = AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class,
26                 DurationWithTime.class, "shortest");
27
28     private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> COUNT_UPDATER =
29             AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "count");
30     private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> SUM_UPDATER =
31             AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "sum");
32
33     private volatile long sum = 0;
34     private volatile long count = 0;
35     private volatile DurationWithTime longest = null;
36     private volatile DurationWithTime shortest = null;
37
38     ConcurrentDurationStatisticsTracker() {
39         // Hidden on purpose
40     }
41
42     @Override
43     public final void addDuration(final long duration) {
44         // First update the quick stats
45         SUM_UPDATER.addAndGet(this, duration);
46         COUNT_UPDATER.incrementAndGet(this);
47
48         /*
49          * Now the hairy 'min/max' things. The notion of "now" we cache,
50          * so the first time we use it, we do not call it twice. We populate
51          * it lazily, though.
52          *
53          * The longest/shortest stats both are encapsulated in an object,
54          * so we update them atomically and we minimize the number of volatile
55          * operations.
56          */
57         DurationWithTime current = shortest;
58         if (current == null || duration < current.getDuration()) {
59             final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
60             while (!SHORTEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
61                 current = shortest;
62                 if (current != null && duration >= current.getDuration()) {
63                     break;
64                 }
65             }
66         }
67
68         current = longest;
69         if (current == null || duration > current.getDuration()) {
70             final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
71             while (!LONGEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
72                 current = longest;
73                 if (current != null && duration <= current.getDuration()) {
74                     break;
75                 }
76             }
77         }
78     }
79
80     @Override
81     public final long getTotalDurations() {
82         return count;
83     }
84
85     @Override
86     public final double getAverageDuration() {
87         final long myCount = count;
88         return myCount == 0 ? 0 : UnsignedLong.fromLongBits(sum).doubleValue() / myCount;
89     }
90
91     @Override
92     public final synchronized void reset() {
93         // Synchronized is just to make sure we do not have concurrent resets :)
94         longest = null;
95         shortest = null;
96         count = 0;
97         sum = 0;
98     }
99
100     @Override
101     protected final DurationWithTime getLongest() {
102         return longest;
103     }
104
105     @Override
106     protected final DurationWithTime getShortest() {
107         return shortest;
108     }
109 }