1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.executor;
21
22 import java.util.concurrent.atomic.AtomicInteger;
23
24 import org.apache.mina.core.session.IoEvent;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28
29
30
31
32
33 public class IoEventQueueThrottle implements IoEventQueueHandler {
34
35 private final static Logger LOGGER = LoggerFactory.getLogger(IoEventQueueThrottle.class);
36
37
38 private final IoEventSizeEstimator eventSizeEstimator;
39
40 private volatile int threshold;
41
42 private final Object lock = new Object();
43
44 private final AtomicInteger counter = new AtomicInteger();
45
46 private int waiters;
47
48 public IoEventQueueThrottle() {
49 this(new DefaultIoEventSizeEstimator(), 65536);
50 }
51
52 public IoEventQueueThrottle(int threshold) {
53 this(new DefaultIoEventSizeEstimator(), threshold);
54 }
55
56 public IoEventQueueThrottle(IoEventSizeEstimator eventSizeEstimator, int threshold) {
57 if (eventSizeEstimator == null) {
58 throw new IllegalArgumentException("eventSizeEstimator");
59 }
60 this.eventSizeEstimator = eventSizeEstimator;
61
62 setThreshold(threshold);
63 }
64
65 public IoEventSizeEstimator getEventSizeEstimator() {
66 return eventSizeEstimator;
67 }
68
69 public int getThreshold() {
70 return threshold;
71 }
72
73 public int getCounter() {
74 return counter.get();
75 }
76
77 public void setThreshold(int threshold) {
78 if (threshold <= 0) {
79 throw new IllegalArgumentException("threshold: " + threshold);
80 }
81 this.threshold = threshold;
82 }
83
84 public boolean accept(Object source, IoEvent event) {
85 return true;
86 }
87
88 public void offered(Object source, IoEvent event) {
89 int eventSize = estimateSize(event);
90 int currentCounter = counter.addAndGet(eventSize);
91 logState();
92
93 if (currentCounter >= threshold) {
94 block();
95 }
96 }
97
98 public void polled(Object source, IoEvent event) {
99 int eventSize = estimateSize(event);
100 int currentCounter = counter.addAndGet(-eventSize);
101
102 logState();
103
104 if (currentCounter < threshold) {
105 unblock();
106 }
107 }
108
109 private int estimateSize(IoEvent event) {
110 int size = getEventSizeEstimator().estimateSize(event);
111 if (size < 0) {
112 throw new IllegalStateException(IoEventSizeEstimator.class.getSimpleName() + " returned "
113 + "a negative value (" + size + "): " + event);
114 }
115 return size;
116 }
117
118 private void logState() {
119 if (LOGGER.isDebugEnabled()) {
120 LOGGER.debug(Thread.currentThread().getName() + " state: " + counter.get() + " / " + getThreshold());
121 }
122 }
123
124 protected void block() {
125 if (LOGGER.isDebugEnabled()) {
126 LOGGER.debug(Thread.currentThread().getName() + " blocked: " + counter.get() + " >= " + threshold);
127 }
128
129 synchronized (lock) {
130 while (counter.get() >= threshold) {
131 waiters++;
132 try {
133 lock.wait();
134 } catch (InterruptedException e) {
135
136 } finally {
137 waiters--;
138 }
139 }
140 }
141
142 if (LOGGER.isDebugEnabled()) {
143 LOGGER.debug(Thread.currentThread().getName() + " unblocked: " + counter.get() + " < " + threshold);
144 }
145 }
146
147 protected void unblock() {
148 synchronized (lock) {
149 if (waiters > 0) {
150 lock.notify();
151 }
152 }
153 }
154 }