Madan Jampani
Committed by Gerrit Code Review

Drop unused onlab-nio module

Change-Id: I52141335643ad5b62b2a9cebe4d79faf0762e3e0
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 &amp; 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 &amp; 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
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 -}
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>
......