Merge "OPNFLWPLUG-1076 Migrate lldp-speaker, forwardingrules-sync and arbitratorrecon...
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / SimpleRatelimiter.java
1 /*
2  * Copyright (c) 2015 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.openflowplugin.impl.device;
9
10 import com.google.common.base.Preconditions;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import javax.annotation.concurrent.GuardedBy;
13
14 abstract class SimpleRatelimiter {
15     private final AtomicInteger counter = new AtomicInteger();
16     private final Object counterLock = new Object();
17     @GuardedBy("counterLock")
18     private int lowWatermark;
19     private volatile int lowWatermarkEffective;
20     private volatile int highWatermark;
21     @GuardedBy("counterLock")
22     private volatile boolean limited;
23
24     SimpleRatelimiter(final int lowWatermark, final int highWatermark) {
25         Preconditions.checkArgument(lowWatermark >= 0);
26         Preconditions.checkArgument(highWatermark >= 0);
27         Preconditions.checkArgument(lowWatermark <= highWatermark);
28
29         this.lowWatermark = lowWatermark;
30         this.highWatermark = highWatermark;
31         lowWatermarkEffective = lowWatermark;
32     }
33
34     protected final boolean isLimited() {
35         return limited;
36     }
37
38     protected abstract void disableFlow();
39
40     protected abstract void enableFlow();
41
42     boolean acquirePermit() {
43         final int cnt = counter.incrementAndGet();
44         if (cnt > highWatermark) {
45             synchronized (counterLock) {
46                 final int recheck = counter.decrementAndGet();
47                 if (recheck >= highWatermark && !limited) {
48                     disableFlow();
49                     limited = true;
50                 }
51             }
52             return false;
53         }
54
55         return true;
56     }
57
58     void releasePermit() {
59         final int cnt = counter.decrementAndGet();
60         if (cnt <= lowWatermarkEffective) {
61             synchronized (counterLock) {
62                 final int recheck = counter.get();
63                 if (recheck <= lowWatermarkEffective && limited) {
64                     enableFlow();
65                     limited = false;
66                     resetLowWaterMark();
67                 }
68             }
69         }
70     }
71
72     @GuardedBy("counterLock")
73     private void resetLowWaterMark() {
74         lowWatermarkEffective = lowWatermark;
75     }
76
77     void adaptLowWaterMarkAndDisableFlow(int temporaryLowWaterMark) {
78         if (temporaryLowWaterMark < highWatermark) {
79             synchronized (counterLock) {
80                 lowWatermarkEffective = temporaryLowWaterMark;
81                 if (!limited) {
82                     disableFlow();
83                     limited = true;
84                 }
85             }
86         }
87     }
88
89     int getOccupiedPermits() {
90         return counter.get();
91     }
92
93     void changeWaterMarks(final int newLowWatermark, final int newHighWatermark) {
94         synchronized (counterLock) {
95             lowWatermark = newLowWatermark;
96             highWatermark = newHighWatermark;
97             resetLowWaterMark();
98         }
99     }
100 }