Speed up packetin throttling
[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 int lowWatermark;
17     private int lowWatermarkEffective;
18     private final int highWatermark;
19     @GuardedBy("counter")
20     private volatile boolean limited;
21
22     SimpleRatelimiter(final int lowWatermark, final int highWatermark) {
23         Preconditions.checkArgument(lowWatermark >= 0);
24         Preconditions.checkArgument(highWatermark >= 0);
25         Preconditions.checkArgument(lowWatermark <= highWatermark);
26
27         this.lowWatermark = lowWatermark;
28         this.highWatermark = highWatermark;
29         lowWatermarkEffective = lowWatermark;
30     }
31
32     protected final boolean isLimited() {
33         return limited;
34     }
35
36     protected abstract void disableFlow();
37     protected abstract void enableFlow();
38
39     boolean acquirePermit() {
40         final int cnt = counter.incrementAndGet();
41         if (cnt > highWatermark) {
42             synchronized (counter) {
43                 final int recheck = counter.decrementAndGet();
44                 if (recheck >= highWatermark && !limited) {
45                     disableFlow();
46                     limited = true;
47                 }
48             }
49             return false;
50         }
51
52         return true;
53     }
54
55     void releasePermit() {
56         final int cnt = counter.decrementAndGet();
57         if (cnt <= lowWatermarkEffective) {
58             synchronized (counter) {
59                 final int recheck = counter.get();
60                 if (recheck <= lowWatermarkEffective && limited) {
61                     enableFlow();
62                     limited = false;
63                     resetLowWaterMark();
64                 }
65             }
66         }
67     }
68
69     void resetLowWaterMark() {
70         synchronized (counter) {
71             lowWatermarkEffective = lowWatermark;
72         }
73     }
74
75     void adaptLowWaterMarkAndDisableFlow(int temporaryLowWaterMark) {
76         if (temporaryLowWaterMark < highWatermark) {
77             synchronized (counter) {
78                 lowWatermarkEffective = temporaryLowWaterMark;
79                 if (!limited) {
80                     disableFlow();
81                     limited = true;
82                 }
83             }
84         }
85     }
86
87     int getOccupiedPermits() {
88         return counter.get();
89     }
90 }