32
32
import java .util .Iterator ;
33
33
import java .util .Queue ;
34
34
import java .util .Set ;
35
- import java .util .concurrent .ExecutorService ;
36
- import java .util .concurrent .Executors ;
37
- import java .util .concurrent .LinkedBlockingQueue ;
35
+ import java .util .concurrent .*;
36
+ import java .util .concurrent .atomic .AtomicLong ;
37
+ import java .util .concurrent .locks .Lock ;
38
+ import java .util .concurrent .locks .ReentrantLock ;
38
39
39
40
/**
40
41
*
@@ -46,24 +47,35 @@ public class SocketChannelFrameHandlerFactory extends FrameHandlerFactory {
46
47
private final SelectorState readSelectorState ;
47
48
private final SelectorState writeSelectorState ;
48
49
49
- private final ExecutorService executorService = Executors .newFixedThreadPool (2 );
50
+ private ExecutorService executorService ;
51
+
52
+ private Future <?> readLoop ;
53
+ private Future <?> writeLoop ;
54
+
55
+ private Lock loopsLock = new ReentrantLock ();
56
+
57
+ private final ThreadFactory threadFactory = new ThreadFactory () {
58
+
59
+ AtomicLong counter = new AtomicLong ();
60
+
61
+ @ Override
62
+ public Thread newThread (Runnable r ) {
63
+ return new Thread (r , "rabbitmq-nio-" +counter .getAndIncrement ());
64
+ }
65
+ };
50
66
51
67
public SocketChannelFrameHandlerFactory (int connectionTimeout , SocketFactory factory , SocketConfigurator configurator ,
52
68
boolean ssl ) throws IOException {
53
69
super (connectionTimeout , factory , configurator , ssl );
54
70
this .readSelectorState = new SelectorState (Selector .open ());
55
71
this .writeSelectorState = new SelectorState (Selector .open ());
56
- this .executorService .submit (new ReadLoop (readSelectorState ));
57
- this .executorService .submit (new WriteLoop (writeSelectorState ));
58
72
}
59
73
60
74
public SocketChannelFrameHandlerFactory (int connectionTimeout , SocketFactory factory , SocketConfigurator configurator , boolean ssl ,
61
75
ExecutorService shutdownExecutor ) throws IOException {
62
76
super (connectionTimeout , factory , configurator , ssl , shutdownExecutor );
63
77
this .readSelectorState = new SelectorState (Selector .open ());
64
78
this .writeSelectorState = new SelectorState (Selector .open ());
65
- this .executorService .submit (new ReadLoop (readSelectorState ));
66
- this .executorService .submit (new WriteLoop (writeSelectorState ));
67
79
}
68
80
69
81
@ Override
@@ -79,7 +91,25 @@ public FrameHandler create(Address addr) throws IOException {
79
91
80
92
SocketChannelFrameHandlerState state = new SocketChannelFrameHandlerState (channel , writeSelectorState );
81
93
82
- readSelectorState .registerFrameHandlerState (state , SelectionKey .OP_READ );
94
+ loopsLock .lock ();
95
+ try {
96
+ readSelectorState .registerFrameHandlerState (state , SelectionKey .OP_READ );
97
+
98
+ if (this .executorService == null ) {
99
+
100
+ this .executorService = Executors .newFixedThreadPool (2 , threadFactory );
101
+ }
102
+ if (readLoop == null ) {
103
+ readLoop = this .executorService .submit (new ReadLoop (readSelectorState ));
104
+ }
105
+ if (writeLoop == null ) {
106
+ writeLoop = this .executorService .submit (new WriteLoop (writeSelectorState ));
107
+ }
108
+ } finally {
109
+ loopsLock .unlock ();
110
+ }
111
+
112
+
83
113
84
114
SocketChannelFrameHandler frameHandler = new SocketChannelFrameHandler (state );
85
115
return frameHandler ;
@@ -102,7 +132,28 @@ public void registerFrameHandlerState(SocketChannelFrameHandlerState state, int
102
132
103
133
}
104
134
105
- private static class ReadLoop implements Runnable {
135
+ private boolean cleanLoopsOrKeepRunning () {
136
+ loopsLock .lock ();
137
+ try {
138
+ if (readSelectorState .statesToBeRegistered .isEmpty ()) {
139
+ boolean cancelled = writeLoop .cancel (true );
140
+ if (!cancelled ) {
141
+ LOGGER .warn ("Could not stop write loop" );
142
+ }
143
+ this .writeLoop = null ;
144
+ this .readLoop = null ;
145
+ this .executorService .shutdownNow ();
146
+ return false ;
147
+ } else {
148
+ // looks like someone is trying to connect, keep running
149
+ return true ;
150
+ }
151
+ } finally {
152
+ loopsLock .unlock ();
153
+ }
154
+ }
155
+
156
+ private class ReadLoop implements Runnable {
106
157
107
158
private final SelectorState state ;
108
159
@@ -117,16 +168,45 @@ public void run() {
117
168
ByteBuffer buffer = ByteBuffer .allocate (8192 );
118
169
try {
119
170
while (true ) {
171
+
172
+ // if there's no read key anymore
173
+ boolean someoneIsStillReading = false ;
174
+ for (SelectionKey selectionKey : selector .keys ()) {
175
+ SocketChannelFrameHandlerState state = (SocketChannelFrameHandlerState ) selectionKey .attachment ();
176
+ // FIXME connection should always be here
177
+ if (state .getConnection () != null && state .getConnection ().getHeartbeat () > 0 ) {
178
+ long now = System .currentTimeMillis ();
179
+ if ((now - state .getLastActivity ()) > state .getConnection ().getHeartbeat () * 1000 * 2 ) {
180
+ try {
181
+ state .getConnection ().handleHeartbeatFailure ();
182
+ } catch (Exception e ) {
183
+ LOGGER .warn ("Error after heartbeat failure of connection {}" , state .getConnection ());
184
+ } finally {
185
+ selectionKey .cancel ();
186
+ }
187
+ }
188
+ }
189
+
190
+ if (!selectionKey .channel ().isOpen ()) {
191
+ selectionKey .cancel ();
192
+ } else {
193
+ someoneIsStillReading = true ;
194
+ }
195
+ }
196
+
197
+ if (!someoneIsStillReading && state .statesToBeRegistered .isEmpty ()) {
198
+ boolean keepRunning = cleanLoopsOrKeepRunning ();
199
+ if (!keepRunning ) {
200
+ return ;
201
+ }
202
+ }
203
+
120
204
int select ;
121
205
if (state .statesToBeRegistered .isEmpty ()) {
122
206
// we can block, registration will call Selector.wakeup()
123
-
124
- // FIXME check the number of keys and stop the read and write loops
125
- // if there's no read key anymore
126
-
127
- select = selector .select ();
207
+ select = selector .select (1000 );
128
208
} else {
129
- // we cannot block, we need to select and clean cancelled keys before registration
209
+ // we don't have to block, we need to select and clean cancelled keys before registration
130
210
select = selector .selectNow ();
131
211
}
132
212
@@ -153,11 +233,12 @@ public void run() {
153
233
buffer .flip ();
154
234
while (buffer .hasRemaining ()) {
155
235
Frame frame = Frame .readFrom (channel , buffer );
236
+
156
237
// FIXME the connection may not be there yet (to be checked)
157
238
boolean handled = state .getConnection ().handleReadFrame (frame );
158
239
159
240
// problem during frame processing, the connection triggered shutdown
160
- // we can stop
241
+ // we can stop for this channel
161
242
if (!handled ) {
162
243
break ;
163
244
}
@@ -169,9 +250,10 @@ public void run() {
169
250
}
170
251
171
252
}
172
-
253
+ state . setLastActivity ( System . currentTimeMillis ());
173
254
} catch (Exception e ) {
174
- LOGGER .warn ("Error during reading frames: " +e .getMessage ());
255
+ LOGGER .warn ("Error during reading frames" , e );
256
+ key .cancel ();
175
257
} finally {
176
258
buffer .clear ();
177
259
}
@@ -203,7 +285,7 @@ public void run() {
203
285
ByteBuffer buffer = ByteBuffer .allocate (8192 );
204
286
205
287
try {
206
- while (true ) {
288
+ while (true && ! Thread . currentThread (). isInterrupted () ) {
207
289
int select ;
208
290
if (state .statesToBeRegistered .isEmpty ()) {
209
291
// we can block, registration will call Selector.wakeup()
@@ -228,12 +310,9 @@ public void run() {
228
310
SelectionKey key = iterator .next ();
229
311
iterator .remove ();
230
312
SocketChannel channel = (SocketChannel ) key .channel ();
231
- if (key .isConnectable ()) {
232
- if (!channel .isConnected ()) {
233
- channel .finishConnect ();
234
- }
235
- } else if (key .isWritable ()) {
313
+ if (key .isWritable ()) {
236
314
SocketChannelFrameHandlerState state = (SocketChannelFrameHandlerState ) key .attachment ();
315
+ int toBeWritten = state .getWriteQueue ().size ();
237
316
// FIXME property handle header sending request
238
317
if (state .isSendHeader ()) {
239
318
buffer .put ("AMQP" .getBytes ("US-ASCII" ));
@@ -247,9 +326,11 @@ public void run() {
247
326
state .setSendHeader (false );
248
327
}
249
328
329
+ int written = 0 ;
250
330
Frame frame ;
251
- while ((frame = state .getWriteQueue ().poll ()) != null ) {
331
+ while (written <= toBeWritten && (frame = state .getWriteQueue ().poll ()) != null ) {
252
332
frame .writeTo (channel , buffer );
333
+ written ++;
253
334
}
254
335
Frame .drain (channel , buffer );
255
336
}
0 commit comments