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 -}
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.onlab.util.Counter;
19 -import org.slf4j.Logger;
20 -import org.slf4j.LoggerFactory;
21 -
22 -import java.io.IOException;
23 -import java.nio.ByteBuffer;
24 -import java.nio.channels.ByteChannel;
25 -import java.nio.channels.SelectionKey;
26 -import java.util.ArrayList;
27 -import java.util.List;
28 -import java.util.Objects;
29 -
30 -import static com.google.common.base.Preconditions.checkArgument;
31 -import static com.google.common.base.Preconditions.checkNotNull;
32 -import static java.lang.System.currentTimeMillis;
33 -import static java.nio.ByteBuffer.allocateDirect;
34 -
35 -/**
36 - * Bi-directional message stream for transferring messages to &amp; from the
37 - * network via two byte buffers.
38 - *
39 - * @param <M> message type
40 - */
41 -public abstract class MessageStream<M extends Message> {
42 -
43 - protected Logger log = LoggerFactory.getLogger(getClass());
44 -
45 - private final IOLoop<M, ?> loop;
46 - private final ByteChannel channel;
47 - private final int maxIdleMillis;
48 -
49 - private final ByteBuffer inbound;
50 - private ByteBuffer outbound;
51 - private SelectionKey key;
52 -
53 - private volatile boolean closed = false;
54 - private volatile boolean writePending;
55 - private volatile boolean writeOccurred;
56 -
57 - private Exception ioError;
58 - private long lastActiveTime;
59 -
60 - private final Counter bytesIn = new Counter();
61 - private final Counter messagesIn = new Counter();
62 - private final Counter bytesOut = new Counter();
63 - private final Counter messagesOut = new Counter();
64 -
65 - /**
66 - * Creates a message stream associated with the specified IO loop and
67 - * backed by the given byte channel.
68 - *
69 - * @param loop IO loop
70 - * @param byteChannel backing byte channel
71 - * @param bufferSize size of the backing byte buffers
72 - * @param maxIdleMillis maximum number of millis the stream can be idle
73 - * before it will be closed
74 - */
75 - protected MessageStream(IOLoop<M, ?> loop, ByteChannel byteChannel,
76 - int bufferSize, int maxIdleMillis) {
77 - this.loop = checkNotNull(loop, "Loop cannot be null");
78 - this.channel = checkNotNull(byteChannel, "Byte channel cannot be null");
79 -
80 - checkArgument(maxIdleMillis > 0, "Idle time must be positive");
81 - this.maxIdleMillis = maxIdleMillis;
82 -
83 - inbound = allocateDirect(bufferSize);
84 - outbound = allocateDirect(bufferSize);
85 - }
86 -
87 - /**
88 - * Gets a single message from the specified byte buffer; this is
89 - * to be done without manipulating the buffer via flip, reset or clear.
90 - *
91 - * @param buffer byte buffer
92 - * @return read message or null if there are not enough bytes to read
93 - * a complete message
94 - */
95 - protected abstract M read(ByteBuffer buffer);
96 -
97 - /**
98 - * Puts the specified message into the specified byte buffer; this is
99 - * to be done without manipulating the buffer via flip, reset or clear.
100 - *
101 - * @param message message to be write into the buffer
102 - * @param buffer byte buffer
103 - */
104 - protected abstract void write(M message, ByteBuffer buffer);
105 -
106 - /**
107 - * Closes the message buffer.
108 - */
109 - public void close() {
110 - synchronized (this) {
111 - if (closed) {
112 - return;
113 - }
114 - closed = true;
115 - }
116 -
117 - bytesIn.freeze();
118 - bytesOut.freeze();
119 - messagesIn.freeze();
120 - messagesOut.freeze();
121 -
122 - loop.removeStream(this);
123 - if (key != null) {
124 - try {
125 - key.cancel();
126 - key.channel().close();
127 - } catch (IOException e) {
128 - log.warn("Unable to close stream", e);
129 - }
130 - }
131 - }
132 -
133 - /**
134 - * Indicates whether this buffer has been closed.
135 - *
136 - * @return true if this stream has been closed
137 - */
138 - public synchronized boolean isClosed() {
139 - return closed;
140 - }
141 -
142 - /**
143 - * Returns the stream IO selection key.
144 - *
145 - * @return socket channel registration selection key
146 - */
147 - public SelectionKey key() {
148 - return key;
149 - }
150 -
151 - /**
152 - * Binds the selection key to be used for driving IO operations on the stream.
153 - *
154 - * @param key IO selection key
155 - */
156 - public void setKey(SelectionKey key) {
157 - this.key = key;
158 - this.lastActiveTime = currentTimeMillis();
159 - }
160 -
161 - /**
162 - * Returns the IO loop to which this stream is bound.
163 - *
164 - * @return I/O loop used to drive this stream
165 - */
166 - public IOLoop<M, ?> loop() {
167 - return loop;
168 - }
169 -
170 - /**
171 - * Indicates whether the any prior IO encountered an error.
172 - *
173 - * @return true if a write failed
174 - */
175 - public boolean hadError() {
176 - return ioError != null;
177 - }
178 -
179 - /**
180 - * Gets the prior IO error, if one occurred.
181 - *
182 - * @return IO error; null if none occurred
183 - */
184 - public Exception getError() {
185 - return ioError;
186 - }
187 -
188 - /**
189 - * Reads, without blocking, a list of messages from the stream.
190 - * The list will be empty if there were not messages pending.
191 - *
192 - * @return list of messages or null if backing channel has been closed
193 - * @throws IOException if messages could not be read
194 - */
195 - public List<M> read() throws IOException {
196 - try {
197 - int read = channel.read(inbound);
198 - if (read != -1) {
199 - // Read the messages one-by-one and add them to the list.
200 - List<M> messages = new ArrayList<>();
201 - M message;
202 - inbound.flip();
203 - while ((message = read(inbound)) != null) {
204 - messages.add(message);
205 - messagesIn.add(1);
206 - bytesIn.add(message.length());
207 - }
208 - inbound.compact();
209 -
210 - // Mark the stream with current time to indicate liveness.
211 - lastActiveTime = currentTimeMillis();
212 - return messages;
213 - }
214 - return null;
215 -
216 - } catch (Exception e) {
217 - throw new IOException("Unable to read messages", e);
218 - }
219 - }
220 -
221 - /**
222 - * Writes the specified list of messages to the stream.
223 - *
224 - * @param messages list of messages to write
225 - * @throws IOException if error occurred while writing the data
226 - */
227 - public void write(List<M> messages) throws IOException {
228 - synchronized (this) {
229 - // First write all messages.
230 - for (M m : messages) {
231 - append(m);
232 - }
233 - flushUnlessAlreadyPlanningTo();
234 - }
235 - }
236 -
237 - /**
238 - * Writes the given message to the stream.
239 - *
240 - * @param message message to write
241 - * @throws IOException if error occurred while writing the data
242 - */
243 - public void write(M message) throws IOException {
244 - synchronized (this) {
245 - append(message);
246 - flushUnlessAlreadyPlanningTo();
247 - }
248 - }
249 -
250 - // Appends the specified message into the internal buffer, growing the
251 - // buffer if required.
252 - private void append(M message) {
253 - // If the buffer does not have sufficient length double it.
254 - while (outbound.remaining() < message.length()) {
255 - doubleSize();
256 - }
257 - write(message, outbound);
258 - messagesOut.add(1);
259 - bytesOut.add(message.length());
260 - }
261 -
262 - // Forces a flush, unless one is planned already.
263 - private void flushUnlessAlreadyPlanningTo() throws IOException {
264 - if (!writeOccurred && !writePending) {
265 - flush();
266 - }
267 - }
268 -
269 - /**
270 - * Flushes any pending writes.
271 - *
272 - * @throws IOException if flush failed
273 - */
274 - public void flush() throws IOException {
275 - synchronized (this) {
276 - if (!writeOccurred && !writePending) {
277 - outbound.flip();
278 - try {
279 - channel.write(outbound);
280 - } catch (IOException e) {
281 - if (!closed && !Objects.equals(e.getMessage(), "Broken pipe")) {
282 - log.warn("Unable to write data", e);
283 - ioError = e;
284 - }
285 - }
286 - lastActiveTime = currentTimeMillis();
287 - writeOccurred = true;
288 - writePending = outbound.hasRemaining();
289 - outbound.compact();
290 - }
291 - }
292 - }
293 -
294 - /**
295 - * Indicates whether the stream has bytes to be written to the channel.
296 - *
297 - * @return true if there are bytes to be written
298 - */
299 - boolean isWritePending() {
300 - synchronized (this) {
301 - return writePending;
302 - }
303 - }
304 -
305 -
306 - /**
307 - * Indicates whether data has been written but not flushed yet.
308 - *
309 - * @return true if flush is required
310 - */
311 - boolean isFlushRequired() {
312 - synchronized (this) {
313 - return outbound.position() > 0;
314 - }
315 - }
316 -
317 - /**
318 - * Attempts to flush data, internal stream state and channel availability
319 - * permitting. Invoked by the driver I/O loop during handling of writable
320 - * selection key.
321 - * <p>
322 - * Resets the internal state flags {@code writeOccurred} and
323 - * {@code writePending}.
324 - * </p>
325 - * @throws IOException if implicit flush failed
326 - */
327 - void flushIfPossible() throws IOException {
328 - synchronized (this) {
329 - writePending = false;
330 - writeOccurred = false;
331 - if (outbound.position() > 0) {
332 - flush();
333 - }
334 - }
335 - key.interestOps(SelectionKey.OP_READ);
336 - }
337 -
338 - /**
339 - * Attempts to flush data, internal stream state and channel availability
340 - * permitting and if other writes are not pending. Invoked by the driver
341 - * I/O loop prior to entering select wait. Resets the internal
342 - * {@code writeOccurred} state flag.
343 - *
344 - * @throws IOException if implicit flush failed
345 - */
346 - void flushIfWriteNotPending() throws IOException {
347 - synchronized (this) {
348 - writeOccurred = false;
349 - if (!writePending && outbound.position() > 0) {
350 - flush();
351 - }
352 - }
353 - if (isWritePending()) {
354 - key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
355 - }
356 - }
357 -
358 - /**
359 - * Doubles the size of the outbound buffer.
360 - */
361 - private void doubleSize() {
362 - ByteBuffer newBuffer = allocateDirect(outbound.capacity() * 2);
363 - outbound.flip();
364 - newBuffer.put(outbound);
365 - outbound = newBuffer;
366 - }
367 -
368 - /**
369 - * Returns the maximum number of milliseconds the stream is allowed
370 - * without any read/write operations.
371 - *
372 - * @return number if millis of permissible idle time
373 - */
374 - protected int maxIdleMillis() {
375 - return maxIdleMillis;
376 - }
377 -
378 -
379 - /**
380 - * Returns true if the given stream has gone stale.
381 - *
382 - * @return true if the stream is stale
383 - */
384 - boolean isStale() {
385 - return currentTimeMillis() - lastActiveTime > maxIdleMillis() && key != null;
386 - }
387 -
388 - /**
389 - * Returns the inbound bytes counter.
390 - *
391 - * @return inbound bytes counter
392 - */
393 - public Counter bytesIn() {
394 - return bytesIn;
395 - }
396 -
397 - /**
398 - * Returns the outbound bytes counter.
399 - *
400 - * @return outbound bytes counter
401 - */
402 - public Counter bytesOut() {
403 - return bytesOut;
404 - }
405 -
406 - /**
407 - * Returns the inbound messages counter.
408 - *
409 - * @return inbound messages counter
410 - */
411 - public Counter messagesIn() {
412 - return messagesIn;
413 - }
414 -
415 - /**
416 - * Returns the outbound messages counter.
417 - *
418 - * @return outbound messages counter
419 - */
420 - public Counter messagesOut() {
421 - return messagesOut;
422 - }
423 -
424 -}
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 -package org.onlab.nio.service;
17 -
18 -import static org.onlab.util.Tools.groupedThreads;
19 -
20 -import java.io.IOException;
21 -import java.net.InetSocketAddress;
22 -import java.net.Socket;
23 -import java.net.SocketAddress;
24 -import java.nio.channels.ServerSocketChannel;
25 -import java.nio.channels.SocketChannel;
26 -import java.util.List;
27 -import java.util.concurrent.CompletableFuture;
28 -import java.util.concurrent.ConcurrentHashMap;
29 -import java.util.concurrent.ConcurrentMap;
30 -import java.util.concurrent.Executor;
31 -import java.util.concurrent.ExecutorService;
32 -import java.util.concurrent.Executors;
33 -import java.util.concurrent.TimeoutException;
34 -import java.util.concurrent.atomic.AtomicBoolean;
35 -import java.util.concurrent.atomic.AtomicLong;
36 -import java.util.function.BiConsumer;
37 -import java.util.function.BiFunction;
38 -import java.util.function.Consumer;
39 -
40 -import org.apache.commons.pool.KeyedPoolableObjectFactory;
41 -import org.apache.commons.pool.impl.GenericKeyedObjectPool;
42 -import org.onlab.nio.AcceptorLoop;
43 -import org.onlab.nio.SelectorLoop;
44 -import org.onosproject.store.cluster.messaging.Endpoint;
45 -import org.onosproject.store.cluster.messaging.MessagingService;
46 -import org.slf4j.Logger;
47 -import org.slf4j.LoggerFactory;
48 -
49 -import com.google.common.cache.Cache;
50 -import com.google.common.cache.CacheBuilder;
51 -import com.google.common.cache.RemovalListener;
52 -import com.google.common.cache.RemovalNotification;
53 -import com.google.common.collect.Lists;
54 -import com.google.common.util.concurrent.MoreExecutors;
55 -
56 -/**
57 - * MessagingService implementation based on IOLoop.
58 - */
59 -public class IOLoopMessaging implements MessagingService {
60 -
61 - private final Logger log = LoggerFactory.getLogger(getClass());
62 -
63 - private static final String REPLY_MESSAGE_TYPE = "ONOS_REQUEST_REPLY";
64 -
65 - static final long TIMEOUT = 1000;
66 -
67 - static final boolean SO_NO_DELAY = false;
68 - static final int SO_SEND_BUFFER_SIZE = 128 * 1024;
69 - static final int SO_RCV_BUFFER_SIZE = 128 * 1024;
70 -
71 - private static final int NUM_WORKERS = 8;
72 -
73 - private AcceptorLoop acceptorLoop;
74 - private final ExecutorService acceptorThreadPool =
75 - Executors.newSingleThreadExecutor(groupedThreads("onos/nio/messaging", "acceptor"));
76 - private final ExecutorService ioThreadPool =
77 - Executors.newFixedThreadPool(NUM_WORKERS, groupedThreads("onos/nio/messaging", "io-loop-worker-%d"));
78 -
79 - private final List<DefaultIOLoop> ioLoops = Lists.newArrayList();
80 -
81 - private int lastWorker = -1;
82 -
83 - private final AtomicBoolean started = new AtomicBoolean(false);
84 - private Endpoint localEp;
85 -
86 - private GenericKeyedObjectPool<Endpoint, DefaultMessageStream> streams =
87 - new GenericKeyedObjectPool<>(new DefaultMessageStreamFactory());
88 -
89 - private final ConcurrentMap<String, Consumer<DefaultMessage>> handlers = new ConcurrentHashMap<>();
90 - private final AtomicLong messageIdGenerator = new AtomicLong(0);
91 - private final Cache<Long, Callback> responseFutures = CacheBuilder.newBuilder()
92 - .removalListener(new RemovalListener<Long, Callback>() {
93 - @Override
94 - public void onRemoval(RemovalNotification<Long, Callback> entry) {
95 - if (entry.wasEvicted()) {
96 - entry.getValue().completeExceptionally(new TimeoutException("Timedout waiting for reply"));
97 - }
98 - }
99 - })
100 - .build();
101 -
102 - /**
103 - * Activates IO Loops.
104 - *
105 - * @param localEp local end-point
106 - * @throws IOException is activation fails
107 - */
108 - public void start(Endpoint localEp) throws IOException {
109 - if (started.get()) {
110 - log.warn("IOMessaging is already running at {}", localEp);
111 - return;
112 - }
113 - this.localEp = localEp;
114 - streams.setLifo(false);
115 - this.acceptorLoop = new DefaultAcceptorLoop(new InetSocketAddress(localEp.host().toString(), localEp.port()));
116 -
117 - for (int i = 0; i < NUM_WORKERS; i++) {
118 - ioLoops.add(new DefaultIOLoop(this::dispatchLocally));
119 - }
120 -
121 - ioLoops.forEach(ioThreadPool::execute);
122 - acceptorThreadPool.execute(acceptorLoop);
123 - ioLoops.forEach(loop -> loop.awaitStart(TIMEOUT));
124 - acceptorLoop.awaitStart(TIMEOUT);
125 - started.set(true);
126 - }
127 -
128 - /**
129 - * Shuts down IO loops.
130 - */
131 - public void stop() {
132 - if (started.get()) {
133 - ioLoops.forEach(SelectorLoop::shutdown);
134 - acceptorLoop.shutdown();
135 - ioThreadPool.shutdown();
136 - acceptorThreadPool.shutdown();
137 - started.set(false);
138 - }
139 - }
140 -
141 -
142 - @Override
143 - public CompletableFuture<Void> sendAsync(Endpoint ep, String type, byte[] payload) {
144 - DefaultMessage message = new DefaultMessage(
145 - messageIdGenerator.incrementAndGet(),
146 - localEp,
147 - type,
148 - payload);
149 - return sendAsync(ep, message);
150 - }
151 -
152 - protected CompletableFuture<Void> sendAsync(Endpoint ep, DefaultMessage message) {
153 - CompletableFuture<Void> future = new CompletableFuture<>();
154 - if (ep.equals(localEp)) {
155 - dispatchLocally(message);
156 - future.complete(null);
157 - return future;
158 - }
159 -
160 - DefaultMessageStream stream = null;
161 - try {
162 - stream = streams.borrowObject(ep);
163 - stream.write(message);
164 - future.complete(null);
165 - } catch (Exception e) {
166 - future.completeExceptionally(e);
167 - } finally {
168 - try {
169 - streams.returnObject(ep, stream);
170 - } catch (Exception e) {
171 - log.warn("Failed to return stream to pool");
172 - }
173 - }
174 - return future;
175 - }
176 -
177 - @Override
178 - public CompletableFuture<byte[]> sendAndReceive(
179 - Endpoint ep,
180 - String type,
181 - byte[] payload,
182 - Executor executor) {
183 - CompletableFuture<byte[]> response = new CompletableFuture<>();
184 - Callback callback = new Callback(response, executor);
185 - Long messageId = messageIdGenerator.incrementAndGet();
186 - responseFutures.put(messageId, callback);
187 - DefaultMessage message = new DefaultMessage(messageId, localEp, type, payload);
188 - return sendAsync(ep, message).whenComplete((r, e) -> {
189 - if (e != null) {
190 - responseFutures.invalidate(messageId);
191 - }
192 - }).thenCompose(v -> response);
193 - }
194 -
195 - @Override
196 - public CompletableFuture<byte[]> sendAndReceive(
197 - Endpoint ep,
198 - String type,
199 - byte[] payload) {
200 - return sendAndReceive(ep, type, payload, MoreExecutors.directExecutor());
201 - }
202 -
203 - @Override
204 - public void registerHandler(String type, BiConsumer<Endpoint, byte[]> handler, Executor executor) {
205 - handlers.put(type, message -> executor.execute(() -> handler.accept(message.sender(), message.payload())));
206 - }
207 -
208 - @Override
209 - public void registerHandler(String type, BiFunction<Endpoint, byte[], byte[]> handler, Executor executor) {
210 - handlers.put(type, message -> executor.execute(() -> {
211 - byte[] responsePayload = handler.apply(message.sender(), message.payload());
212 - if (responsePayload != null) {
213 - DefaultMessage response = new DefaultMessage(message.id(),
214 - localEp,
215 - REPLY_MESSAGE_TYPE,
216 - responsePayload);
217 - sendAsync(message.sender(), response).whenComplete((result, error) -> {
218 - log.debug("Failed to respond", error);
219 - });
220 - }
221 - }));
222 - }
223 -
224 - @Override
225 - public void registerHandler(String type, BiFunction<Endpoint, byte[], CompletableFuture<byte[]>> handler) {
226 - handlers.put(type, message -> {
227 - handler.apply(message.sender(), message.payload()).whenComplete((result, error) -> {
228 - if (error == null) {
229 - DefaultMessage response = new DefaultMessage(message.id(),
230 - localEp,
231 - REPLY_MESSAGE_TYPE,
232 - result);
233 - sendAsync(message.sender(), response).whenComplete((r, e) -> {
234 - if (e != null) {
235 - log.debug("Failed to respond", e);
236 - }
237 - });
238 - }
239 - });
240 - });
241 - }
242 -
243 - @Override
244 - public void unregisterHandler(String type) {
245 - handlers.remove(type);
246 - }
247 -
248 - protected void dispatchLocally(DefaultMessage message) {
249 - String type = message.type();
250 - if (REPLY_MESSAGE_TYPE.equals(type)) {
251 - try {
252 - Callback callback =
253 - responseFutures.getIfPresent(message.id());
254 - if (callback != null) {
255 - callback.complete(message.payload());
256 - } else {
257 - log.warn("Received a reply for message id:[{}]. "
258 - + " from {}. But was unable to locate the"
259 - + " request handle", message.id(), message.sender());
260 - }
261 - } finally {
262 - responseFutures.invalidate(message.id());
263 - }
264 - return;
265 - }
266 - Consumer<DefaultMessage> handler = handlers.get(type);
267 - if (handler != null) {
268 - handler.accept(message);
269 - } else {
270 - log.debug("No handler registered for {}", type);
271 - }
272 - }
273 -
274 - // Get the next worker to which a client should be assigned
275 - private synchronized DefaultIOLoop nextWorker() {
276 - lastWorker = (lastWorker + 1) % NUM_WORKERS;
277 - return ioLoops.get(lastWorker);
278 - }
279 -
280 - /**
281 - * Initiates open connection request and registers the pending socket
282 - * channel with the given IO loop.
283 - *
284 - * @param loop loop with which the channel should be registered
285 - * @throws java.io.IOException if the socket could not be open or connected
286 - */
287 - private DefaultMessageStream createConnection(Endpoint ep, DefaultIOLoop loop) throws IOException {
288 - SocketAddress sa = new InetSocketAddress(ep.host().toString(), ep.port());
289 - SocketChannel ch = SocketChannel.open();
290 - ch.configureBlocking(false);
291 - DefaultMessageStream stream = loop.connectStream(ch);
292 - ch.connect(sa);
293 - return stream;
294 - }
295 -
296 - // Loop for accepting client connections
297 - private class DefaultAcceptorLoop extends AcceptorLoop {
298 -
299 - public DefaultAcceptorLoop(SocketAddress address) throws IOException {
300 - super(DefaultIOLoop.SELECT_TIMEOUT_MILLIS, address);
301 - }
302 -
303 - @Override
304 - protected void acceptConnection(ServerSocketChannel channel) throws IOException {
305 - SocketChannel sc = channel.accept();
306 - sc.configureBlocking(false);
307 -
308 - Socket so = sc.socket();
309 - so.setTcpNoDelay(SO_NO_DELAY);
310 - so.setReceiveBufferSize(SO_RCV_BUFFER_SIZE);
311 - so.setSendBufferSize(SO_SEND_BUFFER_SIZE);
312 -
313 - nextWorker().acceptStream(sc);
314 - }
315 - }
316 -
317 - private class DefaultMessageStreamFactory implements KeyedPoolableObjectFactory<Endpoint, DefaultMessageStream> {
318 -
319 - @Override
320 - public void activateObject(Endpoint endpoint, DefaultMessageStream stream) throws Exception {
321 - }
322 -
323 - @Override
324 - public void destroyObject(Endpoint ep, DefaultMessageStream stream) throws Exception {
325 - stream.close();
326 - }
327 -
328 - @Override
329 - public DefaultMessageStream makeObject(Endpoint ep) throws Exception {
330 - DefaultMessageStream stream = createConnection(ep, nextWorker()).connectedFuture().get();
331 - log.info("Established a new connection to {}", ep);
332 - return stream;
333 - }
334 -
335 - @Override
336 - public void passivateObject(Endpoint ep, DefaultMessageStream stream) throws Exception {
337 - }
338 -
339 - @Override
340 - public boolean validateObject(Endpoint ep, DefaultMessageStream stream) {
341 - return stream.isClosed();
342 - }
343 - }
344 -
345 -
346 - private final class Callback {
347 - private final CompletableFuture<byte[]> future;
348 - private final Executor executor;
349 -
350 - public Callback(CompletableFuture<byte[]> future, Executor executor) {
351 - this.future = future;
352 - this.executor = executor;
353 - }
354 -
355 - public void complete(byte[] value) {
356 - executor.execute(() -> future.complete(value));
357 - }
358 -
359 - public void completeExceptionally(Throwable error) {
360 - executor.execute(() -> future.completeExceptionally(error));
361 - }
362 - }
363 -}
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.SocketAddress;
27 -import java.nio.channels.ByteChannel;
28 -import java.nio.channels.SelectionKey;
29 -import java.nio.channels.SocketChannel;
30 -import java.text.DecimalFormat;
31 -import java.util.ArrayList;
32 -import java.util.List;
33 -import java.util.concurrent.ExecutionException;
34 -import java.util.concurrent.ExecutorService;
35 -import java.util.concurrent.Executors;
36 -import java.util.concurrent.FutureTask;
37 -import java.util.concurrent.Semaphore;
38 -import java.util.concurrent.TimeUnit;
39 -import java.util.concurrent.TimeoutException;
40 -
41 -import static java.lang.String.format;
42 -import static java.lang.System.nanoTime;
43 -import static java.lang.System.out;
44 -import static org.onlab.nio.IOLoopTestServer.PORT;
45 -import static org.onlab.util.Tools.delay;
46 -import static org.onlab.util.Tools.namedThreads;
47 -
48 -/**
49 - * Auxiliary test fixture to measure speed of NIO-based channels.
50 - */
51 -public class IOLoopTestClient {
52 -
53 - private static Logger log = LoggerFactory.getLogger(IOLoopTestClient.class);
54 -
55 - private final InetAddress ip;
56 - private final int port;
57 - private final int msgCount;
58 - private final int msgLength;
59 -
60 - private final List<CustomIOLoop> iloops = new ArrayList<>();
61 - private final ExecutorService ipool;
62 - private final ExecutorService wpool;
63 -
64 - Counter messages;
65 - Counter bytes;
66 - long latencyTotal = 0;
67 - long latencyCount = 0;
68 -
69 -
70 - /**
71 - * Main entry point to launch the client.
72 - *
73 - * @param args command-line arguments
74 - * @throws java.io.IOException if unable to connect to server
75 - * @throws InterruptedException if latch wait gets interrupted
76 - * @throws java.util.concurrent.ExecutionException if wait gets interrupted
77 - * @throws java.util.concurrent.TimeoutException if timeout occurred while waiting for completion
78 - */
79 - public static void main(String[] args)
80 - throws IOException, InterruptedException, ExecutionException, TimeoutException {
81 - startStandalone(args);
82 -
83 - System.exit(0);
84 - }
85 -
86 - /**
87 - * Starts a standalone IO loop test client.
88 - *
89 - * @param args command-line arguments
90 - */
91 - public static void startStandalone(String[] args)
92 - throws IOException, InterruptedException, ExecutionException, TimeoutException {
93 - InetAddress ip = InetAddress.getByName(args.length > 0 ? args[0] : "127.0.0.1");
94 - int wc = args.length > 1 ? Integer.parseInt(args[1]) : 6;
95 - int mc = args.length > 2 ? Integer.parseInt(args[2]) : 50 * 1000000;
96 - int ml = args.length > 3 ? Integer.parseInt(args[3]) : 128;
97 - int to = args.length > 4 ? Integer.parseInt(args[4]) : 60;
98 -
99 - log.info("Setting up client with {} workers sending {} {}-byte messages to {} server... ",
100 - wc, mc, ml, ip);
101 - IOLoopTestClient client = new IOLoopTestClient(ip, wc, mc, ml, PORT);
102 -
103 - client.start();
104 - delay(500);
105 -
106 - client.await(to);
107 - client.report();
108 - }
109 -
110 - /**
111 - * Creates a speed client.
112 - *
113 - * @param ip ip address of server
114 - * @param wc worker count
115 - * @param mc message count to send per client
116 - * @param ml message length in bytes
117 - * @param port socket port
118 - * @throws java.io.IOException if unable to create IO loops
119 - */
120 - public IOLoopTestClient(InetAddress ip, int wc, int mc, int ml, int port) throws IOException {
121 - this.ip = ip;
122 - this.port = port;
123 - this.msgCount = mc;
124 - this.msgLength = ml;
125 - this.wpool = Executors.newFixedThreadPool(wc, namedThreads("worker"));
126 - this.ipool = Executors.newFixedThreadPool(wc, namedThreads("io-loop"));
127 -
128 - for (int i = 0; i < wc; i++) {
129 - iloops.add(new CustomIOLoop());
130 - }
131 - }
132 -
133 - /**
134 - * Starts the client workers.
135 - *
136 - * @throws java.io.IOException if unable to open connection
137 - */
138 - public void start() throws IOException {
139 - messages = new Counter();
140 - bytes = new Counter();
141 -
142 - // First start up all the IO loops
143 - for (CustomIOLoop l : iloops) {
144 - ipool.execute(l);
145 - }
146 -
147 - // Wait for all of them to get going
148 - for (CustomIOLoop l : iloops) {
149 - l.awaitStart(1000);
150 - }
151 -
152 - // ... and Next open all connections; one-per-loop
153 - for (CustomIOLoop l : iloops) {
154 - openConnection(l);
155 - }
156 - }
157 -
158 -
159 - /**
160 - * Initiates open connection request and registers the pending socket
161 - * channel with the given IO loop.
162 - *
163 - * @param loop loop with which the channel should be registered
164 - * @throws java.io.IOException if the socket could not be open or connected
165 - */
166 - private void openConnection(CustomIOLoop loop) throws IOException {
167 - SocketAddress sa = new InetSocketAddress(ip, port);
168 - SocketChannel ch = SocketChannel.open();
169 - ch.configureBlocking(false);
170 - loop.connectStream(ch);
171 - ch.connect(sa);
172 - }
173 -
174 -
175 - /**
176 - * Waits for the client workers to complete.
177 - *
178 - * @param secs timeout in seconds
179 - * @throws java.util.concurrent.ExecutionException if execution failed
180 - * @throws InterruptedException if interrupt occurred while waiting
181 - * @throws java.util.concurrent.TimeoutException if timeout occurred
182 - */
183 - public void await(int secs) throws InterruptedException,
184 - ExecutionException, TimeoutException {
185 - for (CustomIOLoop l : iloops) {
186 - if (l.worker.task != null) {
187 - l.worker.task.get(secs, TimeUnit.SECONDS);
188 - latencyTotal += l.latencyTotal;
189 - latencyCount += l.latencyCount;
190 - }
191 - }
192 - messages.freeze();
193 - bytes.freeze();
194 - }
195 -
196 - /**
197 - * Reports on the accumulated throughput and latency.
198 - */
199 - public void report() {
200 - DecimalFormat f = new DecimalFormat("#,##0");
201 - out.println(format("Client: %s messages; %s bytes; %s mps; %s MBs; %s ns latency",
202 - f.format(messages.total()), f.format(bytes.total()),
203 - f.format(messages.throughput()),
204 - f.format(bytes.throughput() / (1024 * msgLength)),
205 - f.format(latencyTotal / latencyCount)));
206 - }
207 -
208 -
209 - // Loop for transfer of fixed-length messages
210 - private class CustomIOLoop extends IOLoop<TestMessage, TestMessageStream> {
211 -
212 - Worker worker = new Worker();
213 - long latencyTotal = 0;
214 - long latencyCount = 0;
215 -
216 -
217 - public CustomIOLoop() throws IOException {
218 - super(500);
219 - }
220 -
221 -
222 - @Override
223 - protected TestMessageStream createStream(ByteChannel channel) {
224 - return new TestMessageStream(msgLength, channel, this);
225 - }
226 -
227 - @Override
228 - protected synchronized void removeStream(MessageStream<TestMessage> stream) {
229 - super.removeStream(stream);
230 - messages.add(stream.messagesIn().total());
231 - bytes.add(stream.bytesIn().total());
232 - stream.messagesOut().reset();
233 - stream.bytesOut().reset();
234 - }
235 -
236 - @Override
237 - protected void processMessages(List<TestMessage> messages,
238 - MessageStream<TestMessage> stream) {
239 - for (TestMessage message : messages) {
240 - // TODO: summarize latency data better
241 - latencyTotal += nanoTime() - message.requestorTime();
242 - latencyCount++;
243 - }
244 - worker.release(messages.size());
245 - }
246 -
247 - @Override
248 - protected void connect(SelectionKey key) throws IOException {
249 - super.connect(key);
250 - TestMessageStream b = (TestMessageStream) key.attachment();
251 - Worker w = ((CustomIOLoop) b.loop()).worker;
252 - w.pump(b);
253 - }
254 -
255 - }
256 -
257 - /**
258 - * Auxiliary worker to connect and pump batched messages using blocking I/O.
259 - */
260 - private class Worker implements Runnable {
261 -
262 - private static final int BATCH_SIZE = 50;
263 - private static final int PERMITS = 2 * BATCH_SIZE;
264 -
265 - private TestMessageStream stream;
266 - private FutureTask<Worker> task;
267 -
268 - // Stuff to throttle pump
269 - private final Semaphore semaphore = new Semaphore(PERMITS);
270 - private int msgWritten;
271 -
272 - void pump(TestMessageStream stream) {
273 - this.stream = stream;
274 - task = new FutureTask<>(this, this);
275 - wpool.execute(task);
276 - }
277 -
278 - @Override
279 - public void run() {
280 - try {
281 - log.info("Worker started...");
282 -
283 - while (msgWritten < msgCount) {
284 - int size = Math.min(BATCH_SIZE, msgCount - msgWritten);
285 - writeBatch(size);
286 - msgWritten += size;
287 - }
288 -
289 - // Now try to get all the permits back before sending poison pill
290 - semaphore.acquireUninterruptibly(PERMITS);
291 - stream.close();
292 -
293 - log.info("Worker done...");
294 -
295 - } catch (IOException e) {
296 - log.error("Worker unable to perform I/O", e);
297 - }
298 - }
299 -
300 -
301 - private void writeBatch(int size) throws IOException {
302 - // Build a batch of messages
303 - List<TestMessage> batch = Lists.newArrayListWithCapacity(size);
304 - for (int i = 0; i < size; i++) {
305 - batch.add(new TestMessage(msgLength, nanoTime(), 0, stream.padding()));
306 - }
307 - acquire(size);
308 - stream.write(batch);
309 - }
310 -
311 -
312 - // Release permits based on the specified number of message credits
313 - private void release(int permits) {
314 - semaphore.release(permits);
315 - }
316 -
317 - // Acquire permit for a single batch
318 - private void acquire(int permits) {
319 - semaphore.acquireUninterruptibly(permits);
320 - }
321 -
322 - }
323 -
324 -}
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>
......