Committed by
Gerrit Code Review
Drop unused onlab-nio module
Change-Id: I52141335643ad5b62b2a9cebe4d79faf0762e3e0
Showing
23 changed files
with
0 additions
and
2143 deletions
utils/nio/pom.xml
deleted
100644 → 0
1 | -<?xml version="1.0" encoding="UTF-8"?> | ||
2 | -<!-- | ||
3 | - ~ Copyright 2014 Open Networking Laboratory | ||
4 | - ~ | ||
5 | - ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | - ~ you may not use this file except in compliance with the License. | ||
7 | - ~ You may obtain a copy of the License at | ||
8 | - ~ | ||
9 | - ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | - ~ | ||
11 | - ~ Unless required by applicable law or agreed to in writing, software | ||
12 | - ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | - ~ See the License for the specific language governing permissions and | ||
15 | - ~ limitations under the License. | ||
16 | - --> | ||
17 | -<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
18 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
20 | - <modelVersion>4.0.0</modelVersion> | ||
21 | - | ||
22 | - <parent> | ||
23 | - <groupId>org.onosproject</groupId> | ||
24 | - <artifactId>onlab-utils</artifactId> | ||
25 | - <version>1.5.0-SNAPSHOT</version> | ||
26 | - <relativePath>../pom.xml</relativePath> | ||
27 | - </parent> | ||
28 | - | ||
29 | - <artifactId>onlab-nio</artifactId> | ||
30 | - <packaging>bundle</packaging> | ||
31 | - | ||
32 | - <description>Fast network I/O using Java NIO</description> | ||
33 | - | ||
34 | - <dependencies> | ||
35 | - <dependency> | ||
36 | - <groupId>com.google.guava</groupId> | ||
37 | - <artifactId>guava-testlib</artifactId> | ||
38 | - <scope>test</scope> | ||
39 | - </dependency> | ||
40 | - <dependency> | ||
41 | - <groupId>commons-pool</groupId> | ||
42 | - <artifactId>commons-pool</artifactId> | ||
43 | - </dependency> | ||
44 | - <dependency> | ||
45 | - <groupId>org.onosproject</groupId> | ||
46 | - <artifactId>onos-api</artifactId> | ||
47 | - </dependency> | ||
48 | - <dependency> | ||
49 | - <groupId>org.onosproject</groupId> | ||
50 | - <artifactId>onlab-misc</artifactId> | ||
51 | - </dependency> | ||
52 | - <dependency> | ||
53 | - <groupId>org.onosproject</groupId> | ||
54 | - <artifactId>onlab-junit</artifactId> | ||
55 | - <scope>test</scope> | ||
56 | - </dependency> | ||
57 | - </dependencies> | ||
58 | -</project> |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -/** | ||
19 | - * Base {@link Message} implementation. | ||
20 | - */ | ||
21 | -public abstract class AbstractMessage implements Message { | ||
22 | - | ||
23 | - protected int length; | ||
24 | - | ||
25 | - @Override | ||
26 | - public int length() { | ||
27 | - return length; | ||
28 | - } | ||
29 | - | ||
30 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | -import java.net.SocketAddress; | ||
20 | -import java.net.StandardSocketOptions; | ||
21 | -import java.nio.channels.SelectionKey; | ||
22 | -import java.nio.channels.ServerSocketChannel; | ||
23 | -import java.util.Iterator; | ||
24 | - | ||
25 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
26 | - | ||
27 | -/** | ||
28 | - * Selector loop derivative tailored to acceptConnection inbound connections. | ||
29 | - */ | ||
30 | -public abstract class AcceptorLoop extends SelectorLoop { | ||
31 | - | ||
32 | - private SocketAddress listenAddress; | ||
33 | - private ServerSocketChannel socketChannel; | ||
34 | - | ||
35 | - /** | ||
36 | - * Creates an acceptor loop with the specified selection timeout and | ||
37 | - * accepting connections on the the given address. | ||
38 | - * | ||
39 | - * @param selectTimeout selection timeout; specified in millis | ||
40 | - * @param listenAddress socket address where to listen for connections | ||
41 | - * @throws IOException if the backing selector cannot be opened | ||
42 | - */ | ||
43 | - public AcceptorLoop(long selectTimeout, SocketAddress listenAddress) | ||
44 | - throws IOException { | ||
45 | - super(selectTimeout); | ||
46 | - this.listenAddress = checkNotNull(listenAddress, "Address cannot be null"); | ||
47 | - } | ||
48 | - | ||
49 | - /** | ||
50 | - * Hook to accept an inbound connection on the specified socket channel. | ||
51 | - * | ||
52 | - * @param channel socketChannel where an accept operation awaits | ||
53 | - * @throws IOException if the accept operation cannot be processed | ||
54 | - */ | ||
55 | - protected abstract void acceptConnection(ServerSocketChannel channel) throws IOException; | ||
56 | - | ||
57 | - /** | ||
58 | - * Opens a new server socket channel configured in non-blocking mode and | ||
59 | - * bound to the loop's listen address. | ||
60 | - * | ||
61 | - * @throws IOException if unable to open or configure the socket channel | ||
62 | - */ | ||
63 | - protected synchronized void openChannel() throws IOException { | ||
64 | - socketChannel = ServerSocketChannel.open(); | ||
65 | - socketChannel.configureBlocking(false); | ||
66 | - socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); | ||
67 | - socketChannel.register(selector, SelectionKey.OP_ACCEPT); | ||
68 | - socketChannel.bind(listenAddress); | ||
69 | - } | ||
70 | - | ||
71 | - /** | ||
72 | - * Closes the server socket channel. | ||
73 | - * | ||
74 | - * @throws IOException if unable to close the socketChannel | ||
75 | - */ | ||
76 | - protected synchronized void closechannel() throws IOException { | ||
77 | - if (socketChannel != null) { | ||
78 | - socketChannel.close(); | ||
79 | - socketChannel = null; | ||
80 | - } | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public void shutdown() { | ||
85 | - try { | ||
86 | - closechannel(); | ||
87 | - } catch (IOException e) { | ||
88 | - log.warn("Unable to close the socketChannel", e); | ||
89 | - } | ||
90 | - super.shutdown(); | ||
91 | - } | ||
92 | - | ||
93 | - @Override | ||
94 | - protected void loop() throws IOException { | ||
95 | - openChannel(); | ||
96 | - notifyReady(); | ||
97 | - | ||
98 | - // Keep looping until told otherwise. | ||
99 | - while (isRunning()) { | ||
100 | - // Attempt a selection; if no operations selected or if signalled | ||
101 | - // to shutdown, spin through. | ||
102 | - int count = selector.select(selectTimeout); | ||
103 | - if (count == 0 || !isRunning()) { | ||
104 | - continue; | ||
105 | - } | ||
106 | - | ||
107 | - // Iterate over all keys selected for an operation and process them. | ||
108 | - Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); | ||
109 | - while (keys.hasNext()) { | ||
110 | - // Fetch the key and remove it from the pending list. | ||
111 | - SelectionKey key = keys.next(); | ||
112 | - keys.remove(); | ||
113 | - | ||
114 | - // If the key has a pending acceptConnection operation, process it. | ||
115 | - if (key.isAcceptable()) { | ||
116 | - acceptConnection((ServerSocketChannel) key.channel()); | ||
117 | - } | ||
118 | - } | ||
119 | - } | ||
120 | - } | ||
121 | - | ||
122 | -} | ||
123 | - |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | -import java.nio.channels.ByteChannel; | ||
20 | -import java.nio.channels.CancelledKeyException; | ||
21 | -import java.nio.channels.ClosedChannelException; | ||
22 | -import java.nio.channels.SelectableChannel; | ||
23 | -import java.nio.channels.SelectionKey; | ||
24 | -import java.nio.channels.SocketChannel; | ||
25 | -import java.util.Iterator; | ||
26 | -import java.util.List; | ||
27 | -import java.util.Queue; | ||
28 | -import java.util.Set; | ||
29 | -import java.util.concurrent.ConcurrentLinkedQueue; | ||
30 | -import java.util.concurrent.CopyOnWriteArraySet; | ||
31 | - | ||
32 | -/** | ||
33 | - * I/O loop for driving inbound & outbound {@link Message} transfer via | ||
34 | - * {@link MessageStream}. | ||
35 | - * | ||
36 | - * @param <M> message type | ||
37 | - * @param <S> message stream type | ||
38 | - */ | ||
39 | -public abstract class IOLoop<M extends Message, S extends MessageStream<M>> | ||
40 | - extends SelectorLoop { | ||
41 | - | ||
42 | - // Queue of requests for new message streams to enter the IO loop processing. | ||
43 | - private final Queue<NewStreamRequest> newStreamRequests = new ConcurrentLinkedQueue<>(); | ||
44 | - | ||
45 | - // Carries information required for admitting a new message stream. | ||
46 | - private class NewStreamRequest { | ||
47 | - private final S stream; | ||
48 | - private final SelectableChannel channel; | ||
49 | - private final int op; | ||
50 | - | ||
51 | - public NewStreamRequest(S stream, SelectableChannel channel, int op) { | ||
52 | - this.stream = stream; | ||
53 | - this.channel = channel; | ||
54 | - this.op = op; | ||
55 | - } | ||
56 | - } | ||
57 | - | ||
58 | - // Set of message streams currently admitted into the IO loop. | ||
59 | - private final Set<MessageStream<M>> streams = new CopyOnWriteArraySet<>(); | ||
60 | - | ||
61 | - /** | ||
62 | - * Creates an IO loop with the given selection timeout. | ||
63 | - * | ||
64 | - * @param timeout selection timeout in milliseconds | ||
65 | - * @throws IOException if the backing selector cannot be opened | ||
66 | - */ | ||
67 | - public IOLoop(long timeout) throws IOException { | ||
68 | - super(timeout); | ||
69 | - } | ||
70 | - | ||
71 | - /** | ||
72 | - * Returns the number of message stream in custody of the loop. | ||
73 | - * | ||
74 | - * @return number of message streams | ||
75 | - */ | ||
76 | - public int streamCount() { | ||
77 | - return streams.size(); | ||
78 | - } | ||
79 | - | ||
80 | - /** | ||
81 | - * Creates a new message stream backed by the specified socket channel. | ||
82 | - * | ||
83 | - * @param byteChannel backing byte channel | ||
84 | - * @return newly created message stream | ||
85 | - */ | ||
86 | - protected abstract S createStream(ByteChannel byteChannel); | ||
87 | - | ||
88 | - /** | ||
89 | - * Removes the specified message stream from the IO loop. | ||
90 | - * | ||
91 | - * @param stream message stream to remove | ||
92 | - */ | ||
93 | - protected void removeStream(MessageStream<M> stream) { | ||
94 | - streams.remove(stream); | ||
95 | - } | ||
96 | - | ||
97 | - /** | ||
98 | - * Processes the list of messages extracted from the specified message | ||
99 | - * stream. | ||
100 | - * | ||
101 | - * @param messages non-empty list of received messages | ||
102 | - * @param stream message stream from which the messages were extracted | ||
103 | - */ | ||
104 | - protected abstract void processMessages(List<M> messages, MessageStream<M> stream); | ||
105 | - | ||
106 | - /** | ||
107 | - * Completes connection request pending on the given selection key. | ||
108 | - * | ||
109 | - * @param key selection key holding the pending connect operation. | ||
110 | - * @throws IOException when I/O exception of some sort has occurred | ||
111 | - */ | ||
112 | - protected void connect(SelectionKey key) throws IOException { | ||
113 | - SocketChannel ch = (SocketChannel) key.channel(); | ||
114 | - ch.finishConnect(); | ||
115 | - if (key.isValid()) { | ||
116 | - key.interestOps(SelectionKey.OP_READ); | ||
117 | - } | ||
118 | - } | ||
119 | - | ||
120 | - /** | ||
121 | - * Processes an IO operation pending on the specified key. | ||
122 | - * | ||
123 | - * @param key selection key holding the pending I/O operation. | ||
124 | - */ | ||
125 | - protected void processKeyOperation(SelectionKey key) { | ||
126 | - @SuppressWarnings("unchecked") | ||
127 | - S stream = (S) key.attachment(); | ||
128 | - | ||
129 | - try { | ||
130 | - // If the key is not valid, bail out. | ||
131 | - if (!key.isValid()) { | ||
132 | - stream.close(); | ||
133 | - return; | ||
134 | - } | ||
135 | - | ||
136 | - // If there is a pending connect operation, complete it. | ||
137 | - if (key.isConnectable()) { | ||
138 | - try { | ||
139 | - connect(key); | ||
140 | - } catch (IOException | IllegalStateException e) { | ||
141 | - log.warn("Unable to complete connection", e); | ||
142 | - } | ||
143 | - } | ||
144 | - | ||
145 | - // If there is a read operation, slurp as much data as possible. | ||
146 | - if (key.isReadable()) { | ||
147 | - List<M> messages = stream.read(); | ||
148 | - | ||
149 | - // No messages or failed flush imply disconnect; bail. | ||
150 | - if (messages == null || stream.hadError()) { | ||
151 | - stream.close(); | ||
152 | - return; | ||
153 | - } | ||
154 | - | ||
155 | - // If there were any messages read, process them. | ||
156 | - if (!messages.isEmpty()) { | ||
157 | - try { | ||
158 | - processMessages(messages, stream); | ||
159 | - } catch (RuntimeException e) { | ||
160 | - onError(stream, e); | ||
161 | - } | ||
162 | - } | ||
163 | - } | ||
164 | - | ||
165 | - // If there are pending writes, flush them | ||
166 | - if (key.isWritable()) { | ||
167 | - stream.flushIfPossible(); | ||
168 | - } | ||
169 | - | ||
170 | - // If there were any issued flushing, close the stream. | ||
171 | - if (stream.hadError()) { | ||
172 | - stream.close(); | ||
173 | - } | ||
174 | - | ||
175 | - } catch (CancelledKeyException e) { | ||
176 | - // Key was cancelled, so silently close the stream | ||
177 | - stream.close(); | ||
178 | - } catch (IOException e) { | ||
179 | - if (!stream.isClosed() && !isResetByPeer(e)) { | ||
180 | - log.warn("Unable to process IO", e); | ||
181 | - } | ||
182 | - stream.close(); | ||
183 | - } | ||
184 | - } | ||
185 | - | ||
186 | - // Indicates whether or not this exception is caused by 'reset by peer'. | ||
187 | - private boolean isResetByPeer(IOException e) { | ||
188 | - Throwable cause = e.getCause(); | ||
189 | - return cause != null && cause instanceof IOException && | ||
190 | - cause.getMessage().contains("reset by peer"); | ||
191 | - } | ||
192 | - | ||
193 | - /** | ||
194 | - * Hook to allow intercept of any errors caused during message processing. | ||
195 | - * Default behaviour is to rethrow the error. | ||
196 | - * | ||
197 | - * @param stream message stream involved in the error | ||
198 | - * @param error the runtime exception | ||
199 | - */ | ||
200 | - protected void onError(S stream, RuntimeException error) { | ||
201 | - throw error; | ||
202 | - } | ||
203 | - | ||
204 | - /** | ||
205 | - * Admits a new message stream backed by the specified socket channel | ||
206 | - * with a pending accept operation. | ||
207 | - * | ||
208 | - * @param channel backing socket channel | ||
209 | - * @return newly accepted message stream | ||
210 | - */ | ||
211 | - public S acceptStream(SocketChannel channel) { | ||
212 | - return createAndAdmit(channel, SelectionKey.OP_READ); | ||
213 | - } | ||
214 | - | ||
215 | - | ||
216 | - /** | ||
217 | - * Admits a new message stream backed by the specified socket channel | ||
218 | - * with a pending connect operation. | ||
219 | - * | ||
220 | - * @param channel backing socket channel | ||
221 | - * @return newly connected message stream | ||
222 | - */ | ||
223 | - public S connectStream(SocketChannel channel) { | ||
224 | - return createAndAdmit(channel, SelectionKey.OP_CONNECT); | ||
225 | - } | ||
226 | - | ||
227 | - /** | ||
228 | - * Creates a new message stream backed by the specified socket channel | ||
229 | - * and admits it into the IO loop. | ||
230 | - * | ||
231 | - * @param channel socket channel | ||
232 | - * @param op pending operations mask to be applied to the selection | ||
233 | - * key as a set of initial interestedOps | ||
234 | - * @return newly created message stream | ||
235 | - */ | ||
236 | - private synchronized S createAndAdmit(SocketChannel channel, int op) { | ||
237 | - S stream = createStream(channel); | ||
238 | - streams.add(stream); | ||
239 | - newStreamRequests.add(new NewStreamRequest(stream, channel, op)); | ||
240 | - selector.wakeup(); | ||
241 | - return stream; | ||
242 | - } | ||
243 | - | ||
244 | - /** | ||
245 | - * Safely admits new streams into the IO loop. | ||
246 | - */ | ||
247 | - private void admitNewStreams() { | ||
248 | - Iterator<NewStreamRequest> it = newStreamRequests.iterator(); | ||
249 | - while (isRunning() && it.hasNext()) { | ||
250 | - try { | ||
251 | - NewStreamRequest request = it.next(); | ||
252 | - it.remove(); | ||
253 | - SelectionKey key = request.channel.register(selector, request.op, | ||
254 | - request.stream); | ||
255 | - request.stream.setKey(key); | ||
256 | - } catch (ClosedChannelException e) { | ||
257 | - log.warn("Unable to admit new message stream", e); | ||
258 | - } | ||
259 | - } | ||
260 | - } | ||
261 | - | ||
262 | - @Override | ||
263 | - protected void loop() throws IOException { | ||
264 | - notifyReady(); | ||
265 | - | ||
266 | - // Keep going until told otherwise. | ||
267 | - while (isRunning()) { | ||
268 | - admitNewStreams(); | ||
269 | - | ||
270 | - // Process flushes & write selects on all streams | ||
271 | - for (MessageStream<M> stream : streams) { | ||
272 | - stream.flushIfWriteNotPending(); | ||
273 | - } | ||
274 | - | ||
275 | - // Select keys and process them. | ||
276 | - int count = selector.select(selectTimeout); | ||
277 | - if (count > 0 && isRunning()) { | ||
278 | - Iterator<SelectionKey> it = selector.selectedKeys().iterator(); | ||
279 | - while (it.hasNext()) { | ||
280 | - SelectionKey key = it.next(); | ||
281 | - it.remove(); | ||
282 | - processKeyOperation(key); | ||
283 | - } | ||
284 | - } | ||
285 | - } | ||
286 | - } | ||
287 | - | ||
288 | - /** | ||
289 | - * Prunes the registered streams by discarding any stale ones. | ||
290 | - * | ||
291 | - * @return number of remaining streams | ||
292 | - */ | ||
293 | - public synchronized int pruneStaleStreams() { | ||
294 | - for (MessageStream<M> stream : streams) { | ||
295 | - if (stream.isStale()) { | ||
296 | - stream.close(); | ||
297 | - } | ||
298 | - } | ||
299 | - return streams.size(); | ||
300 | - } | ||
301 | - | ||
302 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -/** | ||
19 | - * Representation of a message transferred via {@link MessageStream}. | ||
20 | - */ | ||
21 | -public interface Message { | ||
22 | - | ||
23 | - /** | ||
24 | - * Gets the message length in bytes. | ||
25 | - * | ||
26 | - * @return number of bytes | ||
27 | - */ | ||
28 | - int length(); | ||
29 | - | ||
30 | -} |
This diff is collapsed. Click to expand it.
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import org.slf4j.Logger; | ||
19 | -import org.slf4j.LoggerFactory; | ||
20 | - | ||
21 | -import java.io.IOException; | ||
22 | -import java.nio.channels.Selector; | ||
23 | - | ||
24 | -import static com.google.common.base.Preconditions.checkArgument; | ||
25 | -import static java.lang.System.currentTimeMillis; | ||
26 | - | ||
27 | -/** | ||
28 | - * Abstraction of an I/O processing loop based on an NIO selector. | ||
29 | - */ | ||
30 | -public abstract class SelectorLoop implements Runnable { | ||
31 | - | ||
32 | - protected final Logger log = LoggerFactory.getLogger(getClass()); | ||
33 | - | ||
34 | - /** | ||
35 | - * Selector used by this loop to pace the I/O operations. | ||
36 | - */ | ||
37 | - protected final Selector selector; | ||
38 | - | ||
39 | - /** | ||
40 | - * Selection operations timeout; specified in millis. | ||
41 | - */ | ||
42 | - protected long selectTimeout; | ||
43 | - | ||
44 | - /** | ||
45 | - * Retains the error that caused the loop to exit prematurely. | ||
46 | - */ | ||
47 | - private Throwable error; | ||
48 | - | ||
49 | - // State indicator | ||
50 | - private enum State { STARTING, STARTED, STOPPING, STOPPED }; | ||
51 | - private volatile State state = State.STOPPED; | ||
52 | - | ||
53 | - /** | ||
54 | - * Creates a new selector loop with the given selection timeout. | ||
55 | - * | ||
56 | - * @param selectTimeout selection timeout; specified in millis | ||
57 | - * @throws IOException if the backing selector cannot be opened | ||
58 | - */ | ||
59 | - public SelectorLoop(long selectTimeout) throws IOException { | ||
60 | - checkArgument(selectTimeout > 0, "Timeout must be positive"); | ||
61 | - this.selectTimeout = selectTimeout; | ||
62 | - this.selector = openSelector(); | ||
63 | - } | ||
64 | - | ||
65 | - /** | ||
66 | - * Opens a new selector for the use by the loop. | ||
67 | - * | ||
68 | - * @return newly open selector | ||
69 | - * @throws IOException if the backing selector cannot be opened | ||
70 | - */ | ||
71 | - protected Selector openSelector() throws IOException { | ||
72 | - return Selector.open(); | ||
73 | - } | ||
74 | - | ||
75 | - /** | ||
76 | - * Indicates that the loop is marked to run. | ||
77 | - * @return true if the loop is marked to run | ||
78 | - */ | ||
79 | - protected boolean isRunning() { | ||
80 | - return state == State.STARTED || state == State.STARTING; | ||
81 | - } | ||
82 | - | ||
83 | - /** | ||
84 | - * Returns the error, if there was one, that caused the loop to terminate | ||
85 | - * prematurely. | ||
86 | - * | ||
87 | - * @return error or null if there was none | ||
88 | - */ | ||
89 | - public Throwable getError() { | ||
90 | - return error; | ||
91 | - } | ||
92 | - | ||
93 | - /** | ||
94 | - * Contains the body of the I/O selector loop. | ||
95 | - * | ||
96 | - * @throws IOException if an error is encountered while selecting I/O | ||
97 | - */ | ||
98 | - protected abstract void loop() throws IOException; | ||
99 | - | ||
100 | - @Override | ||
101 | - public void run() { | ||
102 | - error = null; | ||
103 | - state = State.STARTING; | ||
104 | - try { | ||
105 | - loop(); | ||
106 | - } catch (Exception e) { | ||
107 | - error = e; | ||
108 | - log.error("Loop aborted", e); | ||
109 | - } | ||
110 | - notifyDone(); | ||
111 | - } | ||
112 | - | ||
113 | - /** | ||
114 | - * Notifies observers waiting for loop to become ready. | ||
115 | - */ | ||
116 | - protected synchronized void notifyReady() { | ||
117 | - state = State.STARTED; | ||
118 | - notifyAll(); | ||
119 | - } | ||
120 | - | ||
121 | - /** | ||
122 | - * Triggers loop shutdown. | ||
123 | - */ | ||
124 | - public void shutdown() { | ||
125 | - // Mark the loop as no longer running and wake up the selector. | ||
126 | - state = State.STOPPING; | ||
127 | - selector.wakeup(); | ||
128 | - } | ||
129 | - | ||
130 | - /** | ||
131 | - * Notifies observers waiting for loop to fully stop. | ||
132 | - */ | ||
133 | - private synchronized void notifyDone() { | ||
134 | - state = State.STOPPED; | ||
135 | - notifyAll(); | ||
136 | - } | ||
137 | - | ||
138 | - /** | ||
139 | - * Waits for the loop execution to start. | ||
140 | - * | ||
141 | - * @param timeout number of milliseconds to wait | ||
142 | - * @return true if loop started in time | ||
143 | - */ | ||
144 | - public final synchronized boolean awaitStart(long timeout) { | ||
145 | - long max = currentTimeMillis() + timeout; | ||
146 | - while (state != State.STARTED && (currentTimeMillis() < max)) { | ||
147 | - try { | ||
148 | - wait(timeout); | ||
149 | - } catch (InterruptedException e) { | ||
150 | - throw new RuntimeException("Interrupted", e); | ||
151 | - } | ||
152 | - } | ||
153 | - return state == State.STARTED; | ||
154 | - } | ||
155 | - | ||
156 | - /** | ||
157 | - * Waits for the loop execution to stop. | ||
158 | - * | ||
159 | - * @param timeout number of milliseconds to wait | ||
160 | - * @return true if loop finished in time | ||
161 | - */ | ||
162 | - public final synchronized boolean awaitStop(long timeout) { | ||
163 | - long max = currentTimeMillis() + timeout; | ||
164 | - while (state != State.STOPPED && (currentTimeMillis() < max)) { | ||
165 | - try { | ||
166 | - wait(timeout); | ||
167 | - } catch (InterruptedException e) { | ||
168 | - throw new RuntimeException("Interrupted", e); | ||
169 | - } | ||
170 | - } | ||
171 | - return state == State.STOPPED; | ||
172 | - } | ||
173 | - | ||
174 | - | ||
175 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/** | ||
18 | - * Mechanism to transfer messages over network using IO loop and | ||
19 | - * message stream, backed by NIO byte buffers. | ||
20 | - */ | ||
21 | -package org.onlab.nio; |
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio.service; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | -import java.nio.channels.ByteChannel; | ||
20 | -import java.nio.channels.SelectionKey; | ||
21 | -import java.util.List; | ||
22 | -import java.util.function.Consumer; | ||
23 | - | ||
24 | -import org.onlab.nio.IOLoop; | ||
25 | -import org.onlab.nio.MessageStream; | ||
26 | - | ||
27 | -/** | ||
28 | - * IOLoop for transporting DefaultMessages. | ||
29 | - */ | ||
30 | -public class DefaultIOLoop extends IOLoop<DefaultMessage, DefaultMessageStream> { | ||
31 | - | ||
32 | - public static final int SELECT_TIMEOUT_MILLIS = 500; | ||
33 | - private static final int MAX_IDLE_TIMEOUT_MILLIS = 1000; | ||
34 | - private static final int BUFFER_SIZE = 1024 * 1024; | ||
35 | - private final Consumer<DefaultMessage> consumer; | ||
36 | - | ||
37 | - public DefaultIOLoop(Consumer<DefaultMessage> consumer) throws IOException { | ||
38 | - this(SELECT_TIMEOUT_MILLIS, consumer); | ||
39 | - } | ||
40 | - | ||
41 | - public DefaultIOLoop(long timeout, Consumer<DefaultMessage> consumer) throws IOException { | ||
42 | - super(timeout); | ||
43 | - this.consumer = consumer; | ||
44 | - } | ||
45 | - | ||
46 | - @Override | ||
47 | - protected DefaultMessageStream createStream(ByteChannel byteChannel) { | ||
48 | - return new DefaultMessageStream(this, byteChannel, BUFFER_SIZE, MAX_IDLE_TIMEOUT_MILLIS); | ||
49 | - } | ||
50 | - | ||
51 | - @Override | ||
52 | - protected void processMessages(List<DefaultMessage> messages, MessageStream<DefaultMessage> stream) { | ||
53 | - messages.forEach(consumer); | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | - protected void connect(SelectionKey key) throws IOException { | ||
58 | - DefaultMessageStream stream = (DefaultMessageStream) key.attachment(); | ||
59 | - try { | ||
60 | - super.connect(key); | ||
61 | - stream.connected(); | ||
62 | - } catch (Exception e) { | ||
63 | - stream.connectFailed(e); | ||
64 | - } | ||
65 | - } | ||
66 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio.service; | ||
17 | - | ||
18 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
19 | - | ||
20 | -import org.onlab.nio.AbstractMessage; | ||
21 | -import org.onlab.packet.IpAddress; | ||
22 | -import org.onlab.util.ByteArraySizeHashPrinter; | ||
23 | -import org.onosproject.store.cluster.messaging.Endpoint; | ||
24 | - | ||
25 | -import com.google.common.base.Charsets; | ||
26 | -import com.google.common.base.MoreObjects; | ||
27 | - | ||
28 | -/** | ||
29 | - * Default message. | ||
30 | - */ | ||
31 | -public class DefaultMessage extends AbstractMessage { | ||
32 | - | ||
33 | - private long id; | ||
34 | - private Endpoint sender; | ||
35 | - private String type; | ||
36 | - private byte[] payload; | ||
37 | - | ||
38 | - /** | ||
39 | - * Creates a new message with the specified data. | ||
40 | - * | ||
41 | - * @param id message id | ||
42 | - * @param type message type | ||
43 | - * @param sender sender endpoint | ||
44 | - * @param payload message payload | ||
45 | - */ | ||
46 | - DefaultMessage(long id, Endpoint sender, String type, byte[] payload) { | ||
47 | - this.id = id; | ||
48 | - this.type = checkNotNull(type, "Type cannot be null"); | ||
49 | - this.sender = checkNotNull(sender, "Sender cannot be null"); | ||
50 | - this.payload = checkNotNull(payload, "Payload cannot be null"); | ||
51 | - | ||
52 | - byte[] messageTypeBytes = type.getBytes(Charsets.UTF_8); | ||
53 | - IpAddress senderIp = sender.host(); | ||
54 | - byte[] ipOctets = senderIp.toOctets(); | ||
55 | - | ||
56 | - length = 25 + ipOctets.length + messageTypeBytes.length + payload.length; | ||
57 | - } | ||
58 | - | ||
59 | - /** | ||
60 | - * Returns message id. | ||
61 | - * | ||
62 | - * @return message id | ||
63 | - */ | ||
64 | - public long id() { | ||
65 | - return id; | ||
66 | - } | ||
67 | - | ||
68 | - /** | ||
69 | - * Returns message sender. | ||
70 | - * | ||
71 | - * @return message sender | ||
72 | - */ | ||
73 | - public Endpoint sender() { | ||
74 | - return sender; | ||
75 | - } | ||
76 | - | ||
77 | - /** | ||
78 | - * Returns message type. | ||
79 | - * | ||
80 | - * @return message type | ||
81 | - */ | ||
82 | - public String type() { | ||
83 | - return type; | ||
84 | - } | ||
85 | - | ||
86 | - /** | ||
87 | - * Returns message payload. | ||
88 | - * | ||
89 | - * @return payload | ||
90 | - */ | ||
91 | - public byte[] payload() { | ||
92 | - return payload; | ||
93 | - } | ||
94 | - | ||
95 | - @Override | ||
96 | - public String toString() { | ||
97 | - return MoreObjects.toStringHelper(this) | ||
98 | - .add("id", id) | ||
99 | - .add("type", type) | ||
100 | - .add("sender", sender) | ||
101 | - .add("payload", ByteArraySizeHashPrinter.of(payload)) | ||
102 | - .toString(); | ||
103 | - } | ||
104 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio.service; | ||
17 | - | ||
18 | -import java.nio.ByteBuffer; | ||
19 | -import java.nio.channels.ByteChannel; | ||
20 | -import java.util.concurrent.CompletableFuture; | ||
21 | -import java.util.concurrent.atomic.AtomicInteger; | ||
22 | - | ||
23 | -import org.onlab.nio.IOLoop; | ||
24 | -import org.onlab.nio.MessageStream; | ||
25 | -import org.onlab.packet.IpAddress; | ||
26 | -import org.onlab.packet.IpAddress.Version; | ||
27 | -import org.onosproject.store.cluster.messaging.Endpoint; | ||
28 | - | ||
29 | -import com.google.common.base.Charsets; | ||
30 | - | ||
31 | -/** | ||
32 | - * Default bi-directional message stream for transferring messages to & from the | ||
33 | - * network via two byte buffers. | ||
34 | - */ | ||
35 | -public class DefaultMessageStream extends MessageStream<DefaultMessage> { | ||
36 | - | ||
37 | - private final CompletableFuture<Void> connectFuture = new CompletableFuture<>(); | ||
38 | - | ||
39 | - public DefaultMessageStream( | ||
40 | - IOLoop<DefaultMessage, ?> loop, | ||
41 | - ByteChannel byteChannel, | ||
42 | - int bufferSize, | ||
43 | - int maxIdleMillis) { | ||
44 | - super(loop, byteChannel, bufferSize, maxIdleMillis); | ||
45 | - } | ||
46 | - | ||
47 | - public CompletableFuture<DefaultMessageStream> connectedFuture() { | ||
48 | - return connectFuture.thenApply(v -> this); | ||
49 | - } | ||
50 | - | ||
51 | - private final AtomicInteger messageLength = new AtomicInteger(-1); | ||
52 | - | ||
53 | - @Override | ||
54 | - protected DefaultMessage read(ByteBuffer buffer) { | ||
55 | - if (messageLength.get() == -1) { | ||
56 | - // check if we can read the message length. | ||
57 | - if (buffer.remaining() < Integer.BYTES) { | ||
58 | - return null; | ||
59 | - } else { | ||
60 | - messageLength.set(buffer.getInt()); | ||
61 | - } | ||
62 | - } | ||
63 | - | ||
64 | - if (buffer.remaining() < messageLength.get()) { | ||
65 | - return null; | ||
66 | - } | ||
67 | - | ||
68 | - long id = buffer.getLong(); | ||
69 | - Version ipVersion = buffer.get() == 0x0 ? Version.INET : Version.INET6; | ||
70 | - byte[] octects = new byte[IpAddress.byteLength(ipVersion)]; | ||
71 | - buffer.get(octects); | ||
72 | - IpAddress senderIp = IpAddress.valueOf(ipVersion, octects); | ||
73 | - int senderPort = buffer.getInt(); | ||
74 | - int messageTypeByteLength = buffer.getInt(); | ||
75 | - byte[] messageTypeBytes = new byte[messageTypeByteLength]; | ||
76 | - buffer.get(messageTypeBytes); | ||
77 | - String messageType = new String(messageTypeBytes, Charsets.UTF_8); | ||
78 | - int payloadLength = buffer.getInt(); | ||
79 | - byte[] payloadBytes = new byte[payloadLength]; | ||
80 | - buffer.get(payloadBytes); | ||
81 | - | ||
82 | - // reset for next message | ||
83 | - messageLength.set(-1); | ||
84 | - | ||
85 | - return new DefaultMessage(id, new Endpoint(senderIp, senderPort), messageType, payloadBytes); | ||
86 | - } | ||
87 | - | ||
88 | - @Override | ||
89 | - protected void write(DefaultMessage message, ByteBuffer buffer) { | ||
90 | - Endpoint sender = message.sender(); | ||
91 | - byte[] messageTypeBytes = message.type().getBytes(Charsets.UTF_8); | ||
92 | - IpAddress senderIp = sender.host(); | ||
93 | - byte[] ipOctets = senderIp.toOctets(); | ||
94 | - byte[] payload = message.payload(); | ||
95 | - | ||
96 | - int messageLength = 21 + ipOctets.length + messageTypeBytes.length + payload.length; | ||
97 | - | ||
98 | - buffer.putInt(messageLength); | ||
99 | - | ||
100 | - buffer.putLong(message.id()); | ||
101 | - | ||
102 | - if (senderIp.version() == Version.INET) { | ||
103 | - buffer.put((byte) 0x0); | ||
104 | - } else { | ||
105 | - buffer.put((byte) 0x1); | ||
106 | - } | ||
107 | - buffer.put(ipOctets); | ||
108 | - | ||
109 | - // write sender port | ||
110 | - buffer.putInt(sender.port()); | ||
111 | - | ||
112 | - // write length of message type | ||
113 | - buffer.putInt(messageTypeBytes.length); | ||
114 | - | ||
115 | - // write message type bytes | ||
116 | - buffer.put(messageTypeBytes); | ||
117 | - | ||
118 | - // write payload length | ||
119 | - buffer.putInt(payload.length); | ||
120 | - | ||
121 | - // write payload. | ||
122 | - buffer.put(payload); | ||
123 | - } | ||
124 | - | ||
125 | - /** | ||
126 | - * Callback invoked when the stream is successfully connected. | ||
127 | - */ | ||
128 | - public void connected() { | ||
129 | - connectFuture.complete(null); | ||
130 | - } | ||
131 | - | ||
132 | - /** | ||
133 | - * Callback invoked when the stream fails to connect. | ||
134 | - * @param cause failure cause | ||
135 | - */ | ||
136 | - public void connectFailed(Throwable cause) { | ||
137 | - connectFuture.completeExceptionally(cause); | ||
138 | - } | ||
139 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
This diff is collapsed. Click to expand it.
1 | -/* | ||
2 | - * Copyright 2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/** | ||
18 | - * Assembly for sending and receiving messages using the I/O loop mechanism. | ||
19 | - */ | ||
20 | -package org.onlab.nio.service; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import org.junit.Before; | ||
19 | - | ||
20 | -import java.util.concurrent.CountDownLatch; | ||
21 | -import java.util.concurrent.ExecutorService; | ||
22 | -import java.util.concurrent.TimeUnit; | ||
23 | - | ||
24 | -import static java.util.concurrent.Executors.newSingleThreadExecutor; | ||
25 | -import static org.junit.Assert.fail; | ||
26 | -import static org.onlab.util.Tools.namedThreads; | ||
27 | - | ||
28 | -/** | ||
29 | - * Base class for various NIO loop unit tests. | ||
30 | - */ | ||
31 | -public abstract class AbstractLoopTest { | ||
32 | - | ||
33 | - protected static final long MAX_MS_WAIT = 1500; | ||
34 | - | ||
35 | - /** Block on specified countdown latch. Return when countdown reaches | ||
36 | - * zero, or fail the test if the {@value #MAX_MS_WAIT} ms timeout expires. | ||
37 | - * | ||
38 | - * @param latch the latch | ||
39 | - * @param label an identifying label | ||
40 | - */ | ||
41 | - protected void waitForLatch(CountDownLatch latch, String label) { | ||
42 | - try { | ||
43 | - boolean ok = latch.await(MAX_MS_WAIT, TimeUnit.MILLISECONDS); | ||
44 | - if (!ok) { | ||
45 | - fail("Latch await timeout! [" + label + "]"); | ||
46 | - } | ||
47 | - } catch (InterruptedException e) { | ||
48 | - System.out.println("Latch interrupt [" + label + "] : " + e); | ||
49 | - fail("Unexpected interrupt"); | ||
50 | - } | ||
51 | - } | ||
52 | - | ||
53 | - protected ExecutorService exec; | ||
54 | - | ||
55 | - @Before | ||
56 | - public void setUp() { | ||
57 | - exec = newSingleThreadExecutor(namedThreads("test")); | ||
58 | - } | ||
59 | - | ||
60 | -} |
1 | -/* | ||
2 | - * Copyright 2014-2015 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import org.junit.Test; | ||
19 | - | ||
20 | -import java.io.IOException; | ||
21 | -import java.net.InetSocketAddress; | ||
22 | -import java.net.SocketAddress; | ||
23 | -import java.nio.channels.ServerSocketChannel; | ||
24 | -import java.util.concurrent.CountDownLatch; | ||
25 | - | ||
26 | -import static org.junit.Assert.assertEquals; | ||
27 | -import static org.onlab.junit.TestTools.delay; | ||
28 | - | ||
29 | -/** | ||
30 | - * Unit tests for AcceptLoop. | ||
31 | - */ | ||
32 | -public class AcceptorLoopTest extends AbstractLoopTest { | ||
33 | - | ||
34 | - private static final int PICK_EPHEMERAL = 0; | ||
35 | - | ||
36 | - private static final SocketAddress SOCK_ADDR = new InetSocketAddress("127.0.0.1", PICK_EPHEMERAL); | ||
37 | - | ||
38 | - private static class MyAcceptLoop extends AcceptorLoop { | ||
39 | - private final CountDownLatch loopStarted = new CountDownLatch(1); | ||
40 | - private final CountDownLatch loopFinished = new CountDownLatch(1); | ||
41 | - private final CountDownLatch runDone = new CountDownLatch(1); | ||
42 | - private final CountDownLatch ceaseLatch = new CountDownLatch(1); | ||
43 | - | ||
44 | - private int acceptCount = 0; | ||
45 | - | ||
46 | - MyAcceptLoop() throws IOException { | ||
47 | - super(500, SOCK_ADDR); | ||
48 | - } | ||
49 | - | ||
50 | - @Override | ||
51 | - protected void acceptConnection(ServerSocketChannel ssc) throws IOException { | ||
52 | - acceptCount++; | ||
53 | - } | ||
54 | - | ||
55 | - @Override | ||
56 | - public void loop() throws IOException { | ||
57 | - loopStarted.countDown(); | ||
58 | - super.loop(); | ||
59 | - loopFinished.countDown(); | ||
60 | - } | ||
61 | - | ||
62 | - @Override | ||
63 | - public void run() { | ||
64 | - super.run(); | ||
65 | - runDone.countDown(); | ||
66 | - } | ||
67 | - | ||
68 | - @Override | ||
69 | - public void shutdown() { | ||
70 | - super.shutdown(); | ||
71 | - ceaseLatch.countDown(); | ||
72 | - } | ||
73 | - } | ||
74 | - | ||
75 | - @Test | ||
76 | - public void basic() throws IOException { | ||
77 | - MyAcceptLoop myAccLoop = new MyAcceptLoop(); | ||
78 | - AcceptorLoop accLoop = myAccLoop; | ||
79 | - exec.execute(accLoop); | ||
80 | - waitForLatch(myAccLoop.loopStarted, "loopStarted"); | ||
81 | - delay(200); // take a quick nap | ||
82 | - accLoop.shutdown(); | ||
83 | - waitForLatch(myAccLoop.loopFinished, "loopFinished"); | ||
84 | - waitForLatch(myAccLoop.runDone, "runDone"); | ||
85 | - assertEquals(0, myAccLoop.acceptCount); | ||
86 | - } | ||
87 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import org.junit.Before; | ||
19 | -import org.junit.Ignore; | ||
20 | -import org.junit.Test; | ||
21 | - | ||
22 | -import java.net.InetAddress; | ||
23 | -import java.util.Random; | ||
24 | -import java.util.logging.Level; | ||
25 | -import java.util.logging.Logger; | ||
26 | - | ||
27 | -import static org.onlab.junit.TestTools.delay; | ||
28 | - | ||
29 | -/** | ||
30 | - * Integration test for the select, accept and IO loops. | ||
31 | - */ | ||
32 | -public class IOLoopIntegrationTest { | ||
33 | - | ||
34 | - private static final int THREADS = 6; | ||
35 | - private static final int TIMEOUT = 60; | ||
36 | - private static final int MESSAGE_LENGTH = 128; | ||
37 | - | ||
38 | - private static final int MILLION = 1000000; | ||
39 | - private static final int MSG_COUNT = 40 * MILLION; | ||
40 | - | ||
41 | - @Before | ||
42 | - public void warmUp() throws Exception { | ||
43 | - Logger.getLogger("").setLevel(Level.SEVERE); | ||
44 | - try { | ||
45 | - runTest(MILLION, MESSAGE_LENGTH, 15); | ||
46 | - } catch (Throwable e) { | ||
47 | - System.err.println("Failed warmup but moving on."); | ||
48 | - e.printStackTrace(); | ||
49 | - } | ||
50 | - } | ||
51 | - | ||
52 | - // TODO: this test can not pass in some environments, need to be improved | ||
53 | - @Ignore | ||
54 | - @Test | ||
55 | - public void basic() throws Exception { | ||
56 | - runTest(MILLION, MESSAGE_LENGTH, TIMEOUT); | ||
57 | - } | ||
58 | - | ||
59 | - public void longHaul() throws Exception { | ||
60 | - runTest(MSG_COUNT, MESSAGE_LENGTH, TIMEOUT); | ||
61 | - } | ||
62 | - | ||
63 | - private void runTest(int count, int size, int timeout) throws Exception { | ||
64 | - // Use a random port to prevent conflicts. | ||
65 | - int port = IOLoopTestServer.PORT + new Random().nextInt(100); | ||
66 | - | ||
67 | - InetAddress ip = InetAddress.getLoopbackAddress(); | ||
68 | - IOLoopTestServer server = new IOLoopTestServer(ip, THREADS, size, port); | ||
69 | - IOLoopTestClient client = new IOLoopTestClient(ip, THREADS, count, size, port); | ||
70 | - | ||
71 | - server.start(); | ||
72 | - client.start(); | ||
73 | - delay(100); // Pause to allow loops to get going | ||
74 | - | ||
75 | - client.await(timeout); | ||
76 | - client.report(); | ||
77 | - | ||
78 | - server.stop(); | ||
79 | - server.report(); | ||
80 | - } | ||
81 | - | ||
82 | -} |
This diff is collapsed. Click to expand it.
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import com.google.common.collect.Lists; | ||
19 | -import org.onlab.util.Counter; | ||
20 | -import org.slf4j.Logger; | ||
21 | -import org.slf4j.LoggerFactory; | ||
22 | - | ||
23 | -import java.io.IOException; | ||
24 | -import java.net.InetAddress; | ||
25 | -import java.net.InetSocketAddress; | ||
26 | -import java.net.Socket; | ||
27 | -import java.net.SocketAddress; | ||
28 | -import java.nio.channels.ByteChannel; | ||
29 | -import java.nio.channels.ServerSocketChannel; | ||
30 | -import java.nio.channels.SocketChannel; | ||
31 | -import java.text.DecimalFormat; | ||
32 | -import java.util.ArrayList; | ||
33 | -import java.util.List; | ||
34 | -import java.util.concurrent.ExecutorService; | ||
35 | -import java.util.concurrent.Executors; | ||
36 | - | ||
37 | -import static java.lang.String.format; | ||
38 | -import static java.lang.System.out; | ||
39 | -import static org.onlab.util.Tools.delay; | ||
40 | -import static org.onlab.util.Tools.namedThreads; | ||
41 | - | ||
42 | -/** | ||
43 | - * Auxiliary test fixture to measure speed of NIO-based channels. | ||
44 | - */ | ||
45 | -public class IOLoopTestServer { | ||
46 | - | ||
47 | - private static Logger log = LoggerFactory.getLogger(IOLoopTestServer.class); | ||
48 | - | ||
49 | - private static final int PRUNE_FREQUENCY = 1000; | ||
50 | - | ||
51 | - static final int PORT = 9876; | ||
52 | - static final long TIMEOUT = 1000; | ||
53 | - | ||
54 | - static final boolean SO_NO_DELAY = false; | ||
55 | - static final int SO_SEND_BUFFER_SIZE = 128 * 1024; | ||
56 | - static final int SO_RCV_BUFFER_SIZE = 128 * 1024; | ||
57 | - | ||
58 | - static final DecimalFormat FORMAT = new DecimalFormat("#,##0"); | ||
59 | - | ||
60 | - private final AcceptorLoop aloop; | ||
61 | - private final ExecutorService apool = Executors.newSingleThreadExecutor(namedThreads("accept")); | ||
62 | - | ||
63 | - private final List<CustomIOLoop> iloops = new ArrayList<>(); | ||
64 | - private final ExecutorService ipool; | ||
65 | - | ||
66 | - private final int workerCount; | ||
67 | - private final int msgLength; | ||
68 | - private int lastWorker = -1; | ||
69 | - | ||
70 | - Counter messages; | ||
71 | - Counter bytes; | ||
72 | - | ||
73 | - /** | ||
74 | - * Main entry point to launch the server. | ||
75 | - * | ||
76 | - * @param args command-line arguments | ||
77 | - * @throws java.io.IOException if unable to crate IO loops | ||
78 | - */ | ||
79 | - public static void main(String[] args) throws IOException { | ||
80 | - startStandalone(args); | ||
81 | - System.exit(0); | ||
82 | - } | ||
83 | - | ||
84 | - /** | ||
85 | - * Starts a standalone IO loop test server. | ||
86 | - * | ||
87 | - * @param args command-line arguments | ||
88 | - */ | ||
89 | - public static void startStandalone(String[] args) throws IOException { | ||
90 | - InetAddress ip = InetAddress.getByName(args.length > 0 ? args[0] : "127.0.0.1"); | ||
91 | - int wc = args.length > 1 ? Integer.parseInt(args[1]) : 6; | ||
92 | - int ml = args.length > 2 ? Integer.parseInt(args[2]) : 128; | ||
93 | - | ||
94 | - log.info("Setting up the server with {} workers, {} byte messages on {}... ", | ||
95 | - wc, ml, ip); | ||
96 | - IOLoopTestServer server = new IOLoopTestServer(ip, wc, ml, PORT); | ||
97 | - server.start(); | ||
98 | - | ||
99 | - // Start pruning clients and keep going until their number goes to 0. | ||
100 | - int remaining = -1; | ||
101 | - while (remaining == -1 || remaining > 0) { | ||
102 | - delay(PRUNE_FREQUENCY); | ||
103 | - int r = server.prune(); | ||
104 | - remaining = remaining == -1 && r == 0 ? remaining : r; | ||
105 | - } | ||
106 | - server.stop(); | ||
107 | - } | ||
108 | - | ||
109 | - /** | ||
110 | - * Creates a speed server. | ||
111 | - * | ||
112 | - * @param ip optional ip of the adapter where to bind | ||
113 | - * @param wc worker count | ||
114 | - * @param ml message length in bytes | ||
115 | - * @param port listen port | ||
116 | - * @throws java.io.IOException if unable to create IO loops | ||
117 | - */ | ||
118 | - public IOLoopTestServer(InetAddress ip, int wc, int ml, int port) throws IOException { | ||
119 | - this.workerCount = wc; | ||
120 | - this.msgLength = ml; | ||
121 | - this.ipool = Executors.newFixedThreadPool(workerCount, namedThreads("io-loop")); | ||
122 | - | ||
123 | - this.aloop = new CustomAcceptLoop(new InetSocketAddress(ip, port)); | ||
124 | - for (int i = 0; i < workerCount; i++) { | ||
125 | - iloops.add(new CustomIOLoop()); | ||
126 | - } | ||
127 | - } | ||
128 | - | ||
129 | - /** | ||
130 | - * Start the server IO loops and kicks off throughput tracking. | ||
131 | - */ | ||
132 | - public void start() { | ||
133 | - messages = new Counter(); | ||
134 | - bytes = new Counter(); | ||
135 | - | ||
136 | - for (CustomIOLoop l : iloops) { | ||
137 | - ipool.execute(l); | ||
138 | - } | ||
139 | - apool.execute(aloop); | ||
140 | - | ||
141 | - for (CustomIOLoop l : iloops) { | ||
142 | - l.awaitStart(TIMEOUT); | ||
143 | - } | ||
144 | - aloop.awaitStart(TIMEOUT); | ||
145 | - } | ||
146 | - | ||
147 | - /** | ||
148 | - * Stop the server IO loops and freezes throughput tracking. | ||
149 | - */ | ||
150 | - public void stop() { | ||
151 | - aloop.shutdown(); | ||
152 | - for (CustomIOLoop l : iloops) { | ||
153 | - l.shutdown(); | ||
154 | - } | ||
155 | - | ||
156 | - for (CustomIOLoop l : iloops) { | ||
157 | - l.awaitStop(TIMEOUT); | ||
158 | - } | ||
159 | - aloop.awaitStop(TIMEOUT); | ||
160 | - | ||
161 | - messages.freeze(); | ||
162 | - bytes.freeze(); | ||
163 | - } | ||
164 | - | ||
165 | - /** | ||
166 | - * Reports on the accumulated throughput and latency. | ||
167 | - */ | ||
168 | - public void report() { | ||
169 | - DecimalFormat f = new DecimalFormat("#,##0"); | ||
170 | - out.println(format("Server: %s messages; %s bytes; %s mps; %s MBs", | ||
171 | - f.format(messages.total()), f.format(bytes.total()), | ||
172 | - f.format(messages.throughput()), | ||
173 | - f.format(bytes.throughput() / (1024 * msgLength)))); | ||
174 | - } | ||
175 | - | ||
176 | - /** | ||
177 | - * Prunes the IO loops of stale message buffers. | ||
178 | - * | ||
179 | - * @return number of remaining IO loops among all workers. | ||
180 | - */ | ||
181 | - public int prune() { | ||
182 | - int count = 0; | ||
183 | - for (CustomIOLoop l : iloops) { | ||
184 | - count += l.pruneStaleStreams(); | ||
185 | - } | ||
186 | - return count; | ||
187 | - } | ||
188 | - | ||
189 | - // Get the next worker to which a client should be assigned | ||
190 | - private synchronized CustomIOLoop nextWorker() { | ||
191 | - lastWorker = (lastWorker + 1) % workerCount; | ||
192 | - return iloops.get(lastWorker); | ||
193 | - } | ||
194 | - | ||
195 | - // Loop for transfer of fixed-length messages | ||
196 | - private class CustomIOLoop extends IOLoop<TestMessage, TestMessageStream> { | ||
197 | - | ||
198 | - public CustomIOLoop() throws IOException { | ||
199 | - super(500); | ||
200 | - } | ||
201 | - | ||
202 | - @Override | ||
203 | - protected TestMessageStream createStream(ByteChannel channel) { | ||
204 | - return new TestMessageStream(msgLength, channel, this); | ||
205 | - } | ||
206 | - | ||
207 | - @Override | ||
208 | - protected void removeStream(MessageStream<TestMessage> stream) { | ||
209 | - super.removeStream(stream); | ||
210 | - messages.add(stream.messagesIn().total()); | ||
211 | - bytes.add(stream.bytesIn().total()); | ||
212 | - } | ||
213 | - | ||
214 | - @Override | ||
215 | - protected void processMessages(List<TestMessage> messages, | ||
216 | - MessageStream<TestMessage> stream) { | ||
217 | - try { | ||
218 | - stream.write(createResponses(messages)); | ||
219 | - } catch (IOException e) { | ||
220 | - log.error("Unable to echo messages", e); | ||
221 | - } | ||
222 | - } | ||
223 | - | ||
224 | - private List<TestMessage> createResponses(List<TestMessage> messages) { | ||
225 | - List<TestMessage> responses = Lists.newArrayListWithCapacity(messages.size()); | ||
226 | - for (TestMessage message : messages) { | ||
227 | - responses.add(new TestMessage(message.length(), message.requestorTime(), | ||
228 | - System.nanoTime(), message.padding())); | ||
229 | - } | ||
230 | - return responses; | ||
231 | - } | ||
232 | - } | ||
233 | - | ||
234 | - // Loop for accepting client connections | ||
235 | - private class CustomAcceptLoop extends AcceptorLoop { | ||
236 | - | ||
237 | - public CustomAcceptLoop(SocketAddress address) throws IOException { | ||
238 | - super(500, address); | ||
239 | - } | ||
240 | - | ||
241 | - @Override | ||
242 | - protected void acceptConnection(ServerSocketChannel channel) throws IOException { | ||
243 | - SocketChannel sc = channel.accept(); | ||
244 | - sc.configureBlocking(false); | ||
245 | - | ||
246 | - Socket so = sc.socket(); | ||
247 | - so.setTcpNoDelay(SO_NO_DELAY); | ||
248 | - so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE); | ||
249 | - so.setSendBufferSize(SO_SEND_BUFFER_SIZE); | ||
250 | - | ||
251 | - nextWorker().acceptStream(sc); | ||
252 | - log.info("Connected client"); | ||
253 | - } | ||
254 | - } | ||
255 | - | ||
256 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import org.junit.After; | ||
19 | -import org.junit.Before; | ||
20 | -import org.junit.Test; | ||
21 | - | ||
22 | -import java.io.IOException; | ||
23 | -import java.nio.ByteBuffer; | ||
24 | -import java.nio.channels.ByteChannel; | ||
25 | -import java.nio.channels.ClosedChannelException; | ||
26 | -import java.nio.channels.SelectableChannel; | ||
27 | -import java.nio.channels.SelectionKey; | ||
28 | -import java.nio.channels.Selector; | ||
29 | -import java.nio.channels.spi.SelectorProvider; | ||
30 | -import java.util.ArrayList; | ||
31 | -import java.util.List; | ||
32 | - | ||
33 | -import static org.junit.Assert.assertEquals; | ||
34 | -import static org.junit.Assert.assertNull; | ||
35 | - | ||
36 | -/** | ||
37 | - * Tests of the message message stream implementation. | ||
38 | - */ | ||
39 | -public class MessageStreamTest { | ||
40 | - | ||
41 | - private static final int SIZE = 64; | ||
42 | - private static final int BIG_SIZE = 32 * 1024; | ||
43 | - | ||
44 | - private TestMessage message; | ||
45 | - | ||
46 | - private TestIOLoop loop; | ||
47 | - private TestByteChannel channel; | ||
48 | - private TestMessageStream stream; | ||
49 | - private TestKey key; | ||
50 | - | ||
51 | - @Before | ||
52 | - public void setUp() throws IOException { | ||
53 | - loop = new TestIOLoop(); | ||
54 | - channel = new TestByteChannel(); | ||
55 | - key = new TestKey(channel); | ||
56 | - stream = loop.createStream(channel); | ||
57 | - stream.setKey(key); | ||
58 | - stream.setNonStrict(); | ||
59 | - message = new TestMessage(SIZE, 0, 0, stream.padding()); | ||
60 | - } | ||
61 | - | ||
62 | - @After | ||
63 | - public void tearDown() { | ||
64 | - loop.shutdown(); | ||
65 | - stream.close(); | ||
66 | - } | ||
67 | - | ||
68 | - // Validates the state of the message stream | ||
69 | - private void validate(boolean wp, boolean fr, int read, int written) { | ||
70 | - assertEquals(wp, stream.isWritePending()); | ||
71 | - assertEquals(fr, stream.isFlushRequired()); | ||
72 | - assertEquals(read, channel.readBytes); | ||
73 | - assertEquals(written, channel.writtenBytes); | ||
74 | - } | ||
75 | - | ||
76 | - @Test | ||
77 | - public void endOfStream() throws IOException { | ||
78 | - channel.close(); | ||
79 | - List<TestMessage> messages = stream.read(); | ||
80 | - assertNull(messages); | ||
81 | - } | ||
82 | - | ||
83 | - @Test | ||
84 | - public void bufferGrowth() throws IOException { | ||
85 | - // Create a stream for big messages and test the growth. | ||
86 | - stream = new TestMessageStream(BIG_SIZE, channel, loop); | ||
87 | - TestMessage bigMessage = new TestMessage(BIG_SIZE, 0, 0, stream.padding()); | ||
88 | - | ||
89 | - stream.write(bigMessage); | ||
90 | - stream.write(bigMessage); | ||
91 | - stream.write(bigMessage); | ||
92 | - stream.write(bigMessage); | ||
93 | - stream.write(bigMessage); | ||
94 | - } | ||
95 | - | ||
96 | - @Test | ||
97 | - public void discardBeforeKey() { | ||
98 | - // Create a stream that does not yet have the key set and discard it. | ||
99 | - stream = loop.createStream(channel); | ||
100 | - assertNull(stream.key()); | ||
101 | - stream.close(); | ||
102 | - // There is not key, so nothing to check; we just expect no problem. | ||
103 | - } | ||
104 | - | ||
105 | - @Test | ||
106 | - public void bufferedRead() throws IOException { | ||
107 | - channel.bytesToRead = SIZE + 4; | ||
108 | - List<TestMessage> messages = stream.read(); | ||
109 | - assertEquals(1, messages.size()); | ||
110 | - validate(false, false, SIZE + 4, 0); | ||
111 | - | ||
112 | - channel.bytesToRead = SIZE - 4; | ||
113 | - messages = stream.read(); | ||
114 | - assertEquals(1, messages.size()); | ||
115 | - validate(false, false, SIZE * 2, 0); | ||
116 | - } | ||
117 | - | ||
118 | - @Test | ||
119 | - public void bufferedWrite() throws IOException { | ||
120 | - validate(false, false, 0, 0); | ||
121 | - | ||
122 | - // First write is immediate... | ||
123 | - stream.write(message); | ||
124 | - validate(false, false, 0, SIZE); | ||
125 | - | ||
126 | - // Second and third get buffered... | ||
127 | - stream.write(message); | ||
128 | - validate(false, true, 0, SIZE); | ||
129 | - stream.write(message); | ||
130 | - validate(false, true, 0, SIZE); | ||
131 | - | ||
132 | - // Reset write, which will flush if needed; the next write is again buffered | ||
133 | - stream.flushIfWriteNotPending(); | ||
134 | - validate(false, false, 0, SIZE * 3); | ||
135 | - stream.write(message); | ||
136 | - validate(false, true, 0, SIZE * 3); | ||
137 | - | ||
138 | - // Select reset, which will flush if needed; the next write is again buffered | ||
139 | - stream.flushIfPossible(); | ||
140 | - validate(false, false, 0, SIZE * 4); | ||
141 | - stream.write(message); | ||
142 | - validate(false, true, 0, SIZE * 4); | ||
143 | - stream.flush(); | ||
144 | - validate(false, true, 0, SIZE * 4); | ||
145 | - } | ||
146 | - | ||
147 | - @Test | ||
148 | - public void bufferedWriteList() throws IOException { | ||
149 | - validate(false, false, 0, 0); | ||
150 | - | ||
151 | - // First write is immediate... | ||
152 | - List<TestMessage> messages = new ArrayList<>(); | ||
153 | - messages.add(message); | ||
154 | - messages.add(message); | ||
155 | - messages.add(message); | ||
156 | - messages.add(message); | ||
157 | - | ||
158 | - stream.write(messages); | ||
159 | - validate(false, false, 0, SIZE * 4); | ||
160 | - | ||
161 | - stream.write(messages); | ||
162 | - validate(false, true, 0, SIZE * 4); | ||
163 | - | ||
164 | - stream.flushIfPossible(); | ||
165 | - validate(false, false, 0, SIZE * 8); | ||
166 | - } | ||
167 | - | ||
168 | - @Test | ||
169 | - public void bufferedPartialWrite() throws IOException { | ||
170 | - validate(false, false, 0, 0); | ||
171 | - | ||
172 | - // First write is immediate... | ||
173 | - stream.write(message); | ||
174 | - validate(false, false, 0, SIZE); | ||
175 | - | ||
176 | - // Tell test channel to accept only half. | ||
177 | - channel.bytesToWrite = SIZE / 2; | ||
178 | - | ||
179 | - // Second and third get buffered... | ||
180 | - stream.write(message); | ||
181 | - validate(false, true, 0, SIZE); | ||
182 | - stream.flushIfPossible(); | ||
183 | - validate(true, true, 0, SIZE + SIZE / 2); | ||
184 | - } | ||
185 | - | ||
186 | - @Test | ||
187 | - public void bufferedPartialWrite2() throws IOException { | ||
188 | - validate(false, false, 0, 0); | ||
189 | - | ||
190 | - // First write is immediate... | ||
191 | - stream.write(message); | ||
192 | - validate(false, false, 0, SIZE); | ||
193 | - | ||
194 | - // Tell test channel to accept only half. | ||
195 | - channel.bytesToWrite = SIZE / 2; | ||
196 | - | ||
197 | - // Second and third get buffered... | ||
198 | - stream.write(message); | ||
199 | - validate(false, true, 0, SIZE); | ||
200 | - stream.flushIfWriteNotPending(); | ||
201 | - validate(true, true, 0, SIZE + SIZE / 2); | ||
202 | - } | ||
203 | - | ||
204 | - @Test | ||
205 | - public void bufferedReadWrite() throws IOException { | ||
206 | - channel.bytesToRead = SIZE + 4; | ||
207 | - List<TestMessage> messages = stream.read(); | ||
208 | - assertEquals(1, messages.size()); | ||
209 | - validate(false, false, SIZE + 4, 0); | ||
210 | - | ||
211 | - stream.write(message); | ||
212 | - validate(false, false, SIZE + 4, SIZE); | ||
213 | - | ||
214 | - channel.bytesToRead = SIZE - 4; | ||
215 | - messages = stream.read(); | ||
216 | - assertEquals(1, messages.size()); | ||
217 | - validate(false, false, SIZE * 2, SIZE); | ||
218 | - } | ||
219 | - | ||
220 | - // Fake IO driver loop | ||
221 | - private static class TestIOLoop extends IOLoop<TestMessage, TestMessageStream> { | ||
222 | - | ||
223 | - public TestIOLoop() throws IOException { | ||
224 | - super(500); | ||
225 | - } | ||
226 | - | ||
227 | - @Override | ||
228 | - protected TestMessageStream createStream(ByteChannel channel) { | ||
229 | - return new TestMessageStream(SIZE, channel, this); | ||
230 | - } | ||
231 | - | ||
232 | - @Override | ||
233 | - protected void processMessages(List<TestMessage> messages, | ||
234 | - MessageStream<TestMessage> stream) { | ||
235 | - } | ||
236 | - | ||
237 | - } | ||
238 | - | ||
239 | - // Byte channel test fixture | ||
240 | - private static class TestByteChannel extends SelectableChannel implements ByteChannel { | ||
241 | - | ||
242 | - private static final int BUFFER_LENGTH = 1024; | ||
243 | - byte[] bytes = new byte[BUFFER_LENGTH]; | ||
244 | - int bytesToWrite = BUFFER_LENGTH; | ||
245 | - int bytesToRead = BUFFER_LENGTH; | ||
246 | - int writtenBytes = 0; | ||
247 | - int readBytes = 0; | ||
248 | - | ||
249 | - @Override | ||
250 | - public int read(ByteBuffer dst) throws IOException { | ||
251 | - int l = Math.min(dst.remaining(), bytesToRead); | ||
252 | - if (bytesToRead > 0) { | ||
253 | - readBytes += l; | ||
254 | - dst.put(bytes, 0, l); | ||
255 | - } | ||
256 | - return l; | ||
257 | - } | ||
258 | - | ||
259 | - @Override | ||
260 | - public int write(ByteBuffer src) throws IOException { | ||
261 | - int l = Math.min(src.remaining(), bytesToWrite); | ||
262 | - writtenBytes += l; | ||
263 | - src.get(bytes, 0, l); | ||
264 | - return l; | ||
265 | - } | ||
266 | - | ||
267 | - @Override | ||
268 | - public Object blockingLock() { | ||
269 | - return null; | ||
270 | - } | ||
271 | - | ||
272 | - @Override | ||
273 | - public SelectableChannel configureBlocking(boolean arg0) throws IOException { | ||
274 | - return null; | ||
275 | - } | ||
276 | - | ||
277 | - @Override | ||
278 | - public boolean isBlocking() { | ||
279 | - return false; | ||
280 | - } | ||
281 | - | ||
282 | - @Override | ||
283 | - public boolean isRegistered() { | ||
284 | - return false; | ||
285 | - } | ||
286 | - | ||
287 | - @Override | ||
288 | - public SelectionKey keyFor(Selector arg0) { | ||
289 | - return null; | ||
290 | - } | ||
291 | - | ||
292 | - @Override | ||
293 | - public SelectorProvider provider() { | ||
294 | - return null; | ||
295 | - } | ||
296 | - | ||
297 | - @Override | ||
298 | - public SelectionKey register(Selector arg0, int arg1, Object arg2) | ||
299 | - throws ClosedChannelException { | ||
300 | - return null; | ||
301 | - } | ||
302 | - | ||
303 | - @Override | ||
304 | - public int validOps() { | ||
305 | - return 0; | ||
306 | - } | ||
307 | - | ||
308 | - @Override | ||
309 | - protected void implCloseChannel() throws IOException { | ||
310 | - bytesToRead = -1; | ||
311 | - } | ||
312 | - | ||
313 | - } | ||
314 | - | ||
315 | - // Selection key text fixture | ||
316 | - private static class TestKey extends SelectionKey { | ||
317 | - | ||
318 | - private SelectableChannel channel; | ||
319 | - | ||
320 | - public TestKey(TestByteChannel channel) { | ||
321 | - this.channel = channel; | ||
322 | - } | ||
323 | - | ||
324 | - @Override | ||
325 | - public void cancel() { | ||
326 | - } | ||
327 | - | ||
328 | - @Override | ||
329 | - public SelectableChannel channel() { | ||
330 | - return channel; | ||
331 | - } | ||
332 | - | ||
333 | - @Override | ||
334 | - public int interestOps() { | ||
335 | - return 0; | ||
336 | - } | ||
337 | - | ||
338 | - @Override | ||
339 | - public SelectionKey interestOps(int ops) { | ||
340 | - return null; | ||
341 | - } | ||
342 | - | ||
343 | - @Override | ||
344 | - public boolean isValid() { | ||
345 | - return true; | ||
346 | - } | ||
347 | - | ||
348 | - @Override | ||
349 | - public int readyOps() { | ||
350 | - return 0; | ||
351 | - } | ||
352 | - | ||
353 | - @Override | ||
354 | - public Selector selector() { | ||
355 | - return null; | ||
356 | - } | ||
357 | - } | ||
358 | - | ||
359 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import java.io.IOException; | ||
19 | -import java.nio.channels.SelectionKey; | ||
20 | -import java.nio.channels.Selector; | ||
21 | -import java.nio.channels.spi.AbstractSelectableChannel; | ||
22 | -import java.nio.channels.spi.AbstractSelector; | ||
23 | -import java.util.Set; | ||
24 | - | ||
25 | -/** | ||
26 | - * A selector instrumented for unit tests. | ||
27 | - */ | ||
28 | -public class MockSelector extends AbstractSelector { | ||
29 | - | ||
30 | - int wakeUpCount = 0; | ||
31 | - | ||
32 | - /** | ||
33 | - * Creates a mock selector, specifying null as the SelectorProvider. | ||
34 | - */ | ||
35 | - public MockSelector() { | ||
36 | - super(null); | ||
37 | - } | ||
38 | - | ||
39 | - @Override | ||
40 | - public String toString() { | ||
41 | - return "{MockSelector: wake=" + wakeUpCount + "}"; | ||
42 | - } | ||
43 | - | ||
44 | - @Override | ||
45 | - protected void implCloseSelector() throws IOException { | ||
46 | - } | ||
47 | - | ||
48 | - @Override | ||
49 | - protected SelectionKey register(AbstractSelectableChannel ch, int ops, | ||
50 | - Object att) { | ||
51 | - return null; | ||
52 | - } | ||
53 | - | ||
54 | - @Override | ||
55 | - public Set<SelectionKey> keys() { | ||
56 | - return null; | ||
57 | - } | ||
58 | - | ||
59 | - @Override | ||
60 | - public Set<SelectionKey> selectedKeys() { | ||
61 | - return null; | ||
62 | - } | ||
63 | - | ||
64 | - @Override | ||
65 | - public int selectNow() throws IOException { | ||
66 | - return 0; | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public int select(long timeout) throws IOException { | ||
71 | - return 0; | ||
72 | - } | ||
73 | - | ||
74 | - @Override | ||
75 | - public int select() throws IOException { | ||
76 | - return 0; | ||
77 | - } | ||
78 | - | ||
79 | - @Override | ||
80 | - public Selector wakeup() { | ||
81 | - wakeUpCount++; | ||
82 | - return null; | ||
83 | - } | ||
84 | - | ||
85 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
19 | - | ||
20 | -/** | ||
21 | - * Test message for measuring rate and round-trip latency. | ||
22 | - */ | ||
23 | -public class TestMessage extends AbstractMessage { | ||
24 | - | ||
25 | - private final byte[] padding; | ||
26 | - | ||
27 | - private final long requestorTime; | ||
28 | - private final long responderTime; | ||
29 | - | ||
30 | - /** | ||
31 | - * Creates a new message with the specified data. | ||
32 | - * | ||
33 | - * @param requestorTime requester time | ||
34 | - * @param responderTime responder time | ||
35 | - * @param padding message padding | ||
36 | - */ | ||
37 | - TestMessage(int length, long requestorTime, long responderTime, byte[] padding) { | ||
38 | - this.length = length; | ||
39 | - this.requestorTime = requestorTime; | ||
40 | - this.responderTime = responderTime; | ||
41 | - this.padding = checkNotNull(padding, "Padding cannot be null"); | ||
42 | - } | ||
43 | - | ||
44 | - public long requestorTime() { | ||
45 | - return requestorTime; | ||
46 | - } | ||
47 | - | ||
48 | - public long responderTime() { | ||
49 | - return responderTime; | ||
50 | - } | ||
51 | - | ||
52 | - public byte[] padding() { | ||
53 | - return padding; | ||
54 | - } | ||
55 | - | ||
56 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.onlab.nio; | ||
17 | - | ||
18 | -import java.nio.ByteBuffer; | ||
19 | -import java.nio.channels.ByteChannel; | ||
20 | - | ||
21 | -import static com.google.common.base.Preconditions.checkArgument; | ||
22 | -import static com.google.common.base.Preconditions.checkState; | ||
23 | - | ||
24 | -/** | ||
25 | - * Fixed-length message transfer buffer. | ||
26 | - */ | ||
27 | -public class TestMessageStream extends MessageStream<TestMessage> { | ||
28 | - | ||
29 | - private static final String E_WRONG_LEN = "Illegal message length: "; | ||
30 | - private static final long START_TAG = 0xfeedcafedeaddeedL; | ||
31 | - private static final long END_TAG = 0xbeadcafedeaddeedL; | ||
32 | - private static final int META_LENGTH = 40; | ||
33 | - | ||
34 | - private final int length; | ||
35 | - private boolean isStrict = true; | ||
36 | - | ||
37 | - public TestMessageStream(int length, ByteChannel ch, IOLoop<TestMessage, ?> loop) { | ||
38 | - super(loop, ch, 64 * 1024, 500); | ||
39 | - checkArgument(length >= META_LENGTH, "Length must be greater than header length of 40"); | ||
40 | - this.length = length; | ||
41 | - } | ||
42 | - | ||
43 | - void setNonStrict() { | ||
44 | - isStrict = false; | ||
45 | - } | ||
46 | - | ||
47 | - @Override | ||
48 | - protected TestMessage read(ByteBuffer rb) { | ||
49 | - if (rb.remaining() < length) { | ||
50 | - return null; | ||
51 | - } | ||
52 | - | ||
53 | - long startTag = rb.getLong(); | ||
54 | - if (isStrict) { | ||
55 | - checkState(startTag == START_TAG, "Incorrect message start"); | ||
56 | - } | ||
57 | - | ||
58 | - long size = rb.getLong(); | ||
59 | - long requestorTime = rb.getLong(); | ||
60 | - long responderTime = rb.getLong(); | ||
61 | - byte[] padding = padding(); | ||
62 | - rb.get(padding); | ||
63 | - | ||
64 | - long endTag = rb.getLong(); | ||
65 | - if (isStrict) { | ||
66 | - checkState(endTag == END_TAG, "Incorrect message end"); | ||
67 | - } | ||
68 | - | ||
69 | - return new TestMessage((int) size, requestorTime, responderTime, padding); | ||
70 | - } | ||
71 | - | ||
72 | - @Override | ||
73 | - protected void write(TestMessage message, ByteBuffer wb) { | ||
74 | - if (message.length() != length) { | ||
75 | - throw new IllegalArgumentException(E_WRONG_LEN + message.length()); | ||
76 | - } | ||
77 | - | ||
78 | - wb.putLong(START_TAG); | ||
79 | - wb.putLong(message.length()); | ||
80 | - wb.putLong(message.requestorTime()); | ||
81 | - wb.putLong(message.responderTime()); | ||
82 | - wb.put(message.padding(), 0, length - META_LENGTH); | ||
83 | - wb.putLong(END_TAG); | ||
84 | - } | ||
85 | - | ||
86 | - public byte[] padding() { | ||
87 | - return new byte[length - META_LENGTH]; | ||
88 | - } | ||
89 | -} |
... | @@ -34,7 +34,6 @@ | ... | @@ -34,7 +34,6 @@ |
34 | <modules> | 34 | <modules> |
35 | <module>junit</module> | 35 | <module>junit</module> |
36 | <module>misc</module> | 36 | <module>misc</module> |
37 | - <module>nio</module> | ||
38 | <module>yangutils</module> | 37 | <module>yangutils</module> |
39 | <module>osgi</module> | 38 | <module>osgi</module> |
40 | <module>rest</module> | 39 | <module>rest</module> | ... | ... |
-
Please register or login to post a comment