diff --git a/qa/smoke-test-client/src/test/java/org/elasticsearch/smoketest/ESSmokeClientTestCase.java b/qa/smoke-test-client/src/test/java/org/elasticsearch/smoketest/ESSmokeClientTestCase.java index 908e8e1c71114..8ad8605554f39 100644 --- a/qa/smoke-test-client/src/test/java/org/elasticsearch/smoketest/ESSmokeClientTestCase.java +++ b/qa/smoke-test-client/src/test/java/org/elasticsearch/smoketest/ESSmokeClientTestCase.java @@ -32,7 +32,6 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.transport.MockTcpTransportPlugin; import org.elasticsearch.transport.client.PreBuiltTransportClient; -import org.elasticsearch.transport.nio.NioTransportPlugin; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -82,16 +81,9 @@ private static Client startClient(Path tempDir, TransportAddress... transportAdd .put("client.transport.ignore_cluster_name", true) .put(Environment.PATH_HOME_SETTING.getKey(), tempDir); final Collection> plugins; - boolean usNio = random().nextBoolean(); - String transportKey; - Class transportPlugin; - if (usNio) { - transportKey = NioTransportPlugin.NIO_TRANSPORT_NAME; - transportPlugin = NioTransportPlugin.class; - } else { - transportKey = MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME; - transportPlugin = MockTcpTransportPlugin.class; - } + String transportKey = MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME; + Class transportPlugin = MockTcpTransportPlugin.class; + if (random().nextBoolean()) { builder.put(NetworkModule.TRANSPORT_TYPE_KEY, transportKey); plugins = Collections.singleton(transportPlugin); diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/HttpSmokeTestCase.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/HttpSmokeTestCase.java index bb13d486a9adc..f01c523e86273 100644 --- a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/HttpSmokeTestCase.java +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/HttpSmokeTestCase.java @@ -24,7 +24,6 @@ import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.transport.MockTcpTransportPlugin; import org.elasticsearch.transport.Netty4Plugin; -import org.elasticsearch.transport.nio.NioTransportPlugin; import org.junit.BeforeClass; import java.util.Arrays; @@ -47,8 +46,6 @@ public static void setUpTransport() { private static String getTypeKey(Class clazz) { if (clazz.equals(MockTcpTransportPlugin.class)) { return MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME; - } else if (clazz.equals(NioTransportPlugin.class)) { - return NioTransportPlugin.NIO_TRANSPORT_NAME; } else { assert clazz.equals(Netty4Plugin.class); return Netty4Plugin.NETTY_TRANSPORT_NAME; diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java index ec6d8731b94a9..88e7fb1144c92 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java @@ -112,7 +112,6 @@ import org.elasticsearch.test.junit.listeners.ReproduceInfoPrinter; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.MockTcpTransportPlugin; -import org.elasticsearch.transport.nio.NioTransportPlugin; import org.joda.time.DateTimeZone; import org.junit.After; import org.junit.AfterClass; @@ -128,8 +127,8 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.time.ZoneId; import java.security.Security; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -991,19 +990,12 @@ public static String randomGeohash(int minPrecision, int maxPrecision) { return geohashGenerator.ofStringLength(random(), minPrecision, maxPrecision); } - private static boolean useNio; - - @BeforeClass - public static void setUseNio() throws Exception { - useNio = randomBoolean(); - } - public static String getTestTransportType() { - return useNio ? NioTransportPlugin.NIO_TRANSPORT_NAME : MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME; + return MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME; } public static Class getTestTransportPlugin() { - return useNio ? NioTransportPlugin.class : MockTcpTransportPlugin.class; + return MockTcpTransportPlugin.class; } private static final GeohashGenerator geohashGenerator = new GeohashGenerator(); diff --git a/test/framework/src/main/java/org/elasticsearch/test/ExternalTestCluster.java b/test/framework/src/main/java/org/elasticsearch/test/ExternalTestCluster.java index 12375e66b297f..a9cc49f11386b 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ExternalTestCluster.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ExternalTestCluster.java @@ -36,7 +36,6 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.transport.MockTcpTransportPlugin; import org.elasticsearch.transport.MockTransportClient; -import org.elasticsearch.transport.nio.NioTransportPlugin; import java.io.IOException; import java.net.InetSocketAddress; @@ -84,12 +83,9 @@ public ExternalTestCluster(Path tempDir, Settings additionalSettings, Collection if (addMockTcpTransport) { String transport = getTestTransportType(); clientSettingsBuilder.put(NetworkModule.TRANSPORT_TYPE_KEY, transport); - if (pluginClasses.contains(MockTcpTransportPlugin.class) == false && - pluginClasses.contains(NioTransportPlugin.class) == false) { + if (pluginClasses.contains(MockTcpTransportPlugin.class) == false) { pluginClasses = new ArrayList<>(pluginClasses); - if (transport.equals(NioTransportPlugin.NIO_TRANSPORT_NAME)) { - pluginClasses.add(NioTransportPlugin.class); - } else { + if (transport.equals(MockTcpTransportPlugin.MOCK_TCP_TRANSPORT_NAME)) { pluginClasses.add(MockTcpTransportPlugin.class); } } diff --git a/test/framework/src/main/java/org/elasticsearch/transport/MockTransportClient.java b/test/framework/src/main/java/org/elasticsearch/transport/MockTransportClient.java index 027b26e32d736..05723573c1b0b 100644 --- a/test/framework/src/main/java/org/elasticsearch/transport/MockTransportClient.java +++ b/test/framework/src/main/java/org/elasticsearch/transport/MockTransportClient.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.transport.nio.NioTransportPlugin; import java.util.ArrayList; import java.util.Arrays; @@ -59,14 +58,6 @@ private static Collection> addMockTransportIfMissing(Set plugins.add(MockTcpTransportPlugin.class); return plugins; } - } else if (NioTransportPlugin.NIO_TRANSPORT_NAME.equals(transportType)) { - if (plugins.contains(NioTransportPlugin.class)) { - return plugins; - } else { - plugins = new ArrayList<>(plugins); - plugins.add(NioTransportPlugin.class); - return plugins; - } } return plugins; } diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptingSelector.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptingSelector.java deleted file mode 100644 index 23775b4bc1665..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptingSelector.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Selector implementation that handles {@link NioServerSocketChannel}. It's main piece of functionality is - * accepting new channels. - */ -public class AcceptingSelector extends ESSelector { - - private final AcceptorEventHandler eventHandler; - private final ConcurrentLinkedQueue newChannels = new ConcurrentLinkedQueue<>(); - - public AcceptingSelector(AcceptorEventHandler eventHandler) throws IOException { - super(eventHandler); - this.eventHandler = eventHandler; - } - - public AcceptingSelector(AcceptorEventHandler eventHandler, Selector selector) throws IOException { - super(eventHandler, selector); - this.eventHandler = eventHandler; - } - - @Override - void processKey(SelectionKey selectionKey) { - NioServerSocketChannel serverChannel = (NioServerSocketChannel) selectionKey.attachment(); - if (selectionKey.isAcceptable()) { - try { - eventHandler.acceptChannel(serverChannel); - } catch (IOException e) { - eventHandler.acceptException(serverChannel, e); - } - } - } - - @Override - void preSelect() { - setUpNewServerChannels(); - } - - @Override - void cleanup() { - channelsToClose.addAll(newChannels); - } - - /** - * Schedules a NioServerSocketChannel to be registered with this selector. The channel will by queued and - * eventually registered next time through the event loop. - * - * @param serverSocketChannel the channel to register - */ - public void scheduleForRegistration(NioServerSocketChannel serverSocketChannel) { - newChannels.add(serverSocketChannel); - ensureSelectorOpenForEnqueuing(newChannels, serverSocketChannel); - wakeup(); - } - - private void setUpNewServerChannels() { - NioServerSocketChannel newChannel; - while ((newChannel = this.newChannels.poll()) != null) { - assert newChannel.getSelector() == this : "The channel must be registered with the selector with which it was created"; - try { - if (newChannel.isOpen()) { - newChannel.register(); - SelectionKey selectionKey = newChannel.getSelectionKey(); - selectionKey.attach(newChannel); - eventHandler.serverChannelRegistered(newChannel); - } else { - eventHandler.registrationException(newChannel, new ClosedChannelException()); - } - } catch (IOException e) { - eventHandler.registrationException(newChannel, e); - } - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptorEventHandler.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptorEventHandler.java deleted file mode 100644 index ba0fa9356b9eb..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/AcceptorEventHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.message.ParameterizedMessage; -import org.elasticsearch.transport.nio.channel.ChannelFactory; -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.SelectionKeyUtils; - -import java.io.IOException; -import java.util.function.Supplier; - -/** - * Event handler designed to handle events from server sockets - */ -public class AcceptorEventHandler extends EventHandler { - - private final Supplier selectorSupplier; - - public AcceptorEventHandler(Logger logger, Supplier selectorSupplier) { - super(logger); - this.selectorSupplier = selectorSupplier; - } - - /** - * This method is called when a NioServerSocketChannel is successfully registered. It should only be - * called once per channel. - * - * @param nioServerSocketChannel that was registered - */ - void serverChannelRegistered(NioServerSocketChannel nioServerSocketChannel) { - SelectionKeyUtils.setAcceptInterested(nioServerSocketChannel); - } - - /** - * This method is called when an attempt to register a server channel throws an exception. - * - * @param channel that was registered - * @param exception that occurred - */ - void registrationException(NioServerSocketChannel channel, Exception exception) { - logger.error(new ParameterizedMessage("failed to register server channel: {}", channel), exception); - } - - /** - * This method is called when a server channel signals it is ready to accept a connection. All of the - * accept logic should occur in this call. - * - * @param nioServerChannel that can accept a connection - */ - void acceptChannel(NioServerSocketChannel nioServerChannel) throws IOException { - ChannelFactory channelFactory = nioServerChannel.getChannelFactory(); - SocketSelector selector = selectorSupplier.get(); - NioSocketChannel nioSocketChannel = channelFactory.acceptNioChannel(nioServerChannel, selector); - nioServerChannel.getAcceptContext().accept(nioSocketChannel); - } - - /** - * This method is called when an attempt to accept a connection throws an exception. - * - * @param nioServerChannel that accepting a connection - * @param exception that occurred - */ - void acceptException(NioServerSocketChannel nioServerChannel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("exception while accepting new channel from server channel: {}", - nioServerChannel), exception); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/ESSelector.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/ESSelector.java deleted file mode 100644 index 91e308a33b5ff..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/ESSelector.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.action.support.PlainActionFuture; -import org.elasticsearch.transport.nio.channel.NioChannel; - -import java.io.Closeable; -import java.io.IOException; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.Iterator; -import java.util.Set; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -/** - * This is a basic selector abstraction used by {@link org.elasticsearch.transport.nio.NioTransport}. This - * selector wraps a raw nio {@link Selector}. When you call {@link #runLoop()}, the selector will run until - * {@link #close()} is called. This instance handles closing of channels. Users should call - * {@link #queueChannelClose(NioChannel)} to schedule a channel for close by this selector. - *

- * Children of this class should implement the specific {@link #processKey(SelectionKey)}, - * {@link #preSelect()}, and {@link #cleanup()} functionality. - */ -public abstract class ESSelector implements Closeable { - - final Selector selector; - final ConcurrentLinkedQueue channelsToClose = new ConcurrentLinkedQueue<>(); - - private final EventHandler eventHandler; - private final ReentrantLock runLock = new ReentrantLock(); - private final CountDownLatch exitedLoop = new CountDownLatch(1); - private final AtomicBoolean isClosed = new AtomicBoolean(false); - private final PlainActionFuture isRunningFuture = PlainActionFuture.newFuture(); - private volatile Thread thread; - - ESSelector(EventHandler eventHandler) throws IOException { - this(eventHandler, Selector.open()); - } - - ESSelector(EventHandler eventHandler, Selector selector) throws IOException { - this.eventHandler = eventHandler; - this.selector = selector; - } - - /** - * Starts this selector. The selector will run until {@link #close()} is called. - */ - public void runLoop() { - if (runLock.tryLock()) { - isRunningFuture.onResponse(true); - try { - setThread(); - while (isOpen()) { - singleLoop(); - } - } finally { - try { - cleanupAndCloseChannels(); - } finally { - try { - selector.close(); - } catch (IOException e) { - eventHandler.closeSelectorException(e); - } finally { - runLock.unlock(); - exitedLoop.countDown(); - } - } - } - } else { - throw new IllegalStateException("selector is already running"); - } - } - - void singleLoop() { - try { - closePendingChannels(); - preSelect(); - - int ready = selector.select(300); - if (ready > 0) { - Set selectionKeys = selector.selectedKeys(); - Iterator keyIterator = selectionKeys.iterator(); - while (keyIterator.hasNext()) { - SelectionKey sk = keyIterator.next(); - keyIterator.remove(); - if (sk.isValid()) { - try { - processKey(sk); - } catch (CancelledKeyException cke) { - eventHandler.genericChannelException((NioChannel) sk.attachment(), cke); - } - } else { - eventHandler.genericChannelException((NioChannel) sk.attachment(), new CancelledKeyException()); - } - } - } - } catch (ClosedSelectorException e) { - if (isOpen()) { - throw e; - } - } catch (IOException e) { - eventHandler.selectException(e); - } catch (Exception e) { - eventHandler.uncaughtException(e); - } - } - - void cleanupAndCloseChannels() { - cleanup(); - channelsToClose.addAll(selector.keys().stream().map(sk -> (NioChannel) sk.attachment()).collect(Collectors.toList())); - closePendingChannels(); - } - - /** - * Called by the base {@link ESSelector} class when there is a {@link SelectionKey} to be handled. - * - * @param selectionKey the key to be handled - * @throws CancelledKeyException thrown when the key has already been cancelled - */ - abstract void processKey(SelectionKey selectionKey) throws CancelledKeyException; - - /** - * Called immediately prior to a raw {@link Selector#select()} call. Should be used to implement - * channel registration, handling queued writes, and other work that is not specifically processing - * a selection key. - */ - abstract void preSelect(); - - /** - * Called once as the selector is being closed. - */ - abstract void cleanup(); - - void setThread() { - thread = Thread.currentThread(); - } - - public boolean isOnCurrentThread() { - return Thread.currentThread() == thread; - } - - void wakeup() { - // TODO: Do we need the wakeup optimizations that some other libraries use? - selector.wakeup(); - } - - @Override - public void close() throws IOException { - if (isClosed.compareAndSet(false, true)) { - wakeup(); - if (isRunning()) { - try { - exitedLoop.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Thread was interrupted while waiting for selector to close", e); - } - } else if (selector.isOpen()) { - selector.close(); - } - } - } - - public void queueChannelClose(NioChannel channel) { - assert channel.getSelector() == this : "Must schedule a channel for closure with its selector"; - channelsToClose.offer(channel); - ensureSelectorOpenForEnqueuing(channelsToClose, channel); - wakeup(); - } - - public Selector rawSelector() { - return selector; - } - - public boolean isOpen() { - return isClosed.get() == false; - } - - public boolean isRunning() { - return runLock.isLocked(); - } - - public PlainActionFuture isRunningFuture() { - return isRunningFuture; - } - - /** - * This is a convenience method to be called after some object (normally channels) are enqueued with this - * selector. This method will check if the selector is still open. If it is open, normal operation can - * proceed. - * - * If the selector is closed, then we attempt to remove the object from the queue. If the removal - * succeeds then we throw an {@link IllegalStateException} indicating that normal operation failed. If - * the object cannot be removed from the queue, then the object has already been handled by the selector - * and operation can proceed normally. - * - * If this method is called from the selector thread, we will not throw an exception as the selector - * thread can manipulate its queues internally even if it is no longer open. - * - * @param queue the queue to which the object was added - * @param objectAdded the objected added - * @param the object type - */ - void ensureSelectorOpenForEnqueuing(ConcurrentLinkedQueue queue, O objectAdded) { - if (isOpen() == false && isOnCurrentThread() == false) { - if (queue.remove(objectAdded)) { - throw new IllegalStateException("selector is already closed"); - } - } - } - - private void closePendingChannels() { - NioChannel channel; - while ((channel = channelsToClose.poll()) != null) { - eventHandler.handleClose(channel); - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/EventHandler.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/EventHandler.java deleted file mode 100644 index 8521f71616266..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/EventHandler.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.message.ParameterizedMessage; -import org.elasticsearch.transport.nio.channel.NioChannel; - -import java.io.IOException; -import java.nio.channels.Selector; - -public abstract class EventHandler { - - protected final Logger logger; - - public EventHandler(Logger logger) { - this.logger = logger; - } - - /** - * This method handles an IOException that was thrown during a call to {@link Selector#select(long)}. - * - * @param exception the exception - */ - void selectException(IOException exception) { - logger.warn(new ParameterizedMessage("io exception during select [thread={}]", Thread.currentThread().getName()), exception); - } - - /** - * This method handles an IOException that was thrown during a call to {@link Selector#close()}. - * - * @param exception the exception - */ - void closeSelectorException(IOException exception) { - logger.warn(new ParameterizedMessage("io exception while closing selector [thread={}]", Thread.currentThread().getName()), - exception); - } - - /** - * This method handles an exception that was uncaught during a select loop. - * - * @param exception that was uncaught - */ - void uncaughtException(Exception exception) { - Thread thread = Thread.currentThread(); - thread.getUncaughtExceptionHandler().uncaughtException(thread, exception); - } - - /** - * This method handles the closing of an NioChannel - * - * @param channel that should be closed - */ - void handleClose(NioChannel channel) { - try { - channel.closeFromSelector(); - } catch (IOException e) { - closeException(channel, e); - } - assert channel.isOpen() == false : "Should always be done as we are on the selector thread"; - } - - /** - * This method is called when an attempt to close a channel throws an exception. - * - * @param channel that was being closed - * @param exception that occurred - */ - void closeException(NioChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("exception while closing channel: {}", channel), exception); - } - - /** - * This method is called when handling an event from a channel fails due to an unexpected exception. - * An example would be if checking ready ops on a {@link java.nio.channels.SelectionKey} threw - * {@link java.nio.channels.CancelledKeyException}. - * - * @param channel that caused the exception - * @param exception that was thrown - */ - void genericChannelException(NioChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("exception while handling event for channel: {}", channel), exception); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/InboundChannelBuffer.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/InboundChannelBuffer.java deleted file mode 100644 index 11d340a30a0c8..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/InboundChannelBuffer.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.ExceptionsHelper; -import org.elasticsearch.common.lease.Releasable; -import org.elasticsearch.common.util.BigArrays; - -import java.nio.ByteBuffer; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; - -/** - * This is a channel byte buffer composed internally of 16kb pages. When an entire message has been read - * and consumed, the {@link #release(long)} method releases the bytes from the head of the buffer and closes - * the pages internally. If more space is needed at the end of the buffer {@link #ensureCapacity(long)} can - * be called and the buffer will expand using the supplier provided. - */ -public final class InboundChannelBuffer implements Releasable { - - private static final int PAGE_SIZE = BigArrays.BYTE_PAGE_SIZE; - private static final int PAGE_MASK = PAGE_SIZE - 1; - private static final int PAGE_SHIFT = Integer.numberOfTrailingZeros(PAGE_SIZE); - private static final ByteBuffer[] EMPTY_BYTE_BUFFER_ARRAY = new ByteBuffer[0]; - - - private final ArrayDeque pages; - private final Supplier pageSupplier; - private final AtomicBoolean isClosed = new AtomicBoolean(false); - - private long capacity = 0; - private long internalIndex = 0; - // The offset is an int as it is the offset of where the bytes begin in the first buffer - private int offset = 0; - - public InboundChannelBuffer(Supplier pageSupplier) { - this.pageSupplier = pageSupplier; - this.pages = new ArrayDeque<>(); - this.capacity = PAGE_SIZE * pages.size(); - ensureCapacity(PAGE_SIZE); - } - - @Override - public void close() { - if (isClosed.compareAndSet(false, true)) { - Page page; - List closingExceptions = new ArrayList<>(); - while ((page = pages.pollFirst()) != null) { - try { - page.close(); - } catch (RuntimeException e) { - closingExceptions.add(e); - } - } - ExceptionsHelper.rethrowAndSuppress(closingExceptions); - } - } - - public void ensureCapacity(long requiredCapacity) { - if (isClosed.get()) { - throw new IllegalStateException("Cannot allocate new pages if the buffer is closed."); - } - if (capacity < requiredCapacity) { - int numPages = numPages(requiredCapacity + offset); - int pagesToAdd = numPages - pages.size(); - for (int i = 0; i < pagesToAdd; i++) { - Page page = pageSupplier.get(); - pages.addLast(page); - } - capacity += pagesToAdd * PAGE_SIZE; - } - } - - /** - * This method will release bytes from the head of this buffer. If you release bytes past the current - * index the index is truncated to zero. - * - * @param bytesToRelease number of bytes to drop - */ - public void release(long bytesToRelease) { - if (bytesToRelease > capacity) { - throw new IllegalArgumentException("Releasing more bytes [" + bytesToRelease + "] than buffer capacity [" + capacity + "]."); - } - - int pagesToRelease = pageIndex(offset + bytesToRelease); - for (int i = 0; i < pagesToRelease; i++) { - pages.removeFirst().close(); - } - capacity -= bytesToRelease; - internalIndex = Math.max(internalIndex - bytesToRelease, 0); - offset = indexInPage(bytesToRelease + offset); - } - - /** - * This method will return an array of {@link ByteBuffer} representing the bytes from the beginning of - * this buffer up through the index argument that was passed. The buffers will be duplicates of the - * internal buffers, so any modifications to the markers {@link ByteBuffer#position()}, - * {@link ByteBuffer#limit()}, etc will not modify the this class. - * - * @param to the index to slice up to - * @return the byte buffers - */ - public ByteBuffer[] sliceBuffersTo(long to) { - if (to > capacity) { - throw new IndexOutOfBoundsException("can't slice a channel buffer with capacity [" + capacity + - "], with slice parameters to [" + to + "]"); - } else if (to == 0) { - return EMPTY_BYTE_BUFFER_ARRAY; - } - long indexWithOffset = to + offset; - int pageCount = pageIndex(indexWithOffset); - int finalLimit = indexInPage(indexWithOffset); - if (finalLimit != 0) { - pageCount += 1; - } - - ByteBuffer[] buffers = new ByteBuffer[pageCount]; - Iterator pageIterator = pages.iterator(); - ByteBuffer firstBuffer = pageIterator.next().byteBuffer.duplicate(); - firstBuffer.position(firstBuffer.position() + offset); - buffers[0] = firstBuffer; - for (int i = 1; i < buffers.length; i++) { - buffers[i] = pageIterator.next().byteBuffer.duplicate(); - } - if (finalLimit != 0) { - buffers[buffers.length - 1].limit(finalLimit); - } - - return buffers; - } - - /** - * This method will return an array of {@link ByteBuffer} representing the bytes from the index passed - * through the end of this buffer. The buffers will be duplicates of the internal buffers, so any - * modifications to the markers {@link ByteBuffer#position()}, {@link ByteBuffer#limit()}, etc will not - * modify the this class. - * - * @param from the index to slice from - * @return the byte buffers - */ - public ByteBuffer[] sliceBuffersFrom(long from) { - if (from > capacity) { - throw new IndexOutOfBoundsException("can't slice a channel buffer with capacity [" + capacity + - "], with slice parameters from [" + from + "]"); - } else if (from == capacity) { - return EMPTY_BYTE_BUFFER_ARRAY; - } - long indexWithOffset = from + offset; - - int pageIndex = pageIndex(indexWithOffset); - int indexInPage = indexInPage(indexWithOffset); - - ByteBuffer[] buffers = new ByteBuffer[pages.size() - pageIndex]; - Iterator pageIterator = pages.descendingIterator(); - for (int i = buffers.length - 1; i > 0; --i) { - buffers[i] = pageIterator.next().byteBuffer.duplicate(); - } - ByteBuffer firstPostIndexBuffer = pageIterator.next().byteBuffer.duplicate(); - firstPostIndexBuffer.position(firstPostIndexBuffer.position() + indexInPage); - buffers[0] = firstPostIndexBuffer; - - return buffers; - } - - public void incrementIndex(long delta) { - if (delta < 0) { - throw new IllegalArgumentException("Cannot increment an index with a negative delta [" + delta + "]"); - } - - long newIndex = delta + internalIndex; - if (newIndex > capacity) { - throw new IllegalArgumentException("Cannot increment an index [" + internalIndex + "] with a delta [" + delta + - "] that will result in a new index [" + newIndex + "] that is greater than the capacity [" + capacity + "]."); - } - internalIndex = newIndex; - } - - public long getIndex() { - return internalIndex; - } - - public long getCapacity() { - return capacity; - } - - public long getRemaining() { - long remaining = capacity - internalIndex; - assert remaining >= 0 : "The remaining [" + remaining + "] number of bytes should not be less than zero."; - return remaining; - } - - private int numPages(long capacity) { - final long numPages = (capacity + PAGE_MASK) >>> PAGE_SHIFT; - if (numPages > Integer.MAX_VALUE) { - throw new IllegalArgumentException("pageSize=" + (PAGE_MASK + 1) + " is too small for such as capacity: " + capacity); - } - return (int) numPages; - } - - private int pageIndex(long index) { - return (int) (index >>> PAGE_SHIFT); - } - - private int indexInPage(long index) { - return (int) (index & PAGE_MASK); - } - - public static class Page implements Releasable { - - private final ByteBuffer byteBuffer; - private final Releasable releasable; - - public Page(ByteBuffer byteBuffer, Releasable releasable) { - this.byteBuffer = byteBuffer; - this.releasable = releasable; - } - - @Override - public void close() { - releasable.close(); - } - - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioGroup.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/NioGroup.java deleted file mode 100644 index b0e1862c706ca..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioGroup.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.apache.lucene.util.IOUtils; -import org.elasticsearch.transport.nio.channel.ChannelFactory; -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * The NioGroup is a group of selectors for interfacing with java nio. When it is started it will create the - * configured number of socket and acceptor selectors. Each selector will be running in a dedicated thread. - * Server connections can be bound using the {@link #bindServerChannel(InetSocketAddress, ChannelFactory)} - * method. Client connections can be opened using the {@link #openChannel(InetSocketAddress, ChannelFactory)} - * method. - *

- * The logic specific to a particular channel is provided by the {@link ChannelFactory} passed to the method - * when the channel is created. This is what allows an NioGroup to support different channel types. - */ -public class NioGroup implements AutoCloseable { - - - private final ArrayList acceptors; - private final RoundRobinSupplier acceptorSupplier; - - private final ArrayList socketSelectors; - private final RoundRobinSupplier socketSelectorSupplier; - - private final AtomicBoolean isOpen = new AtomicBoolean(true); - - public NioGroup(Logger logger, ThreadFactory acceptorThreadFactory, int acceptorCount, - BiFunction, AcceptorEventHandler> acceptorEventHandlerFunction, - ThreadFactory socketSelectorThreadFactory, int socketSelectorCount, - Function socketEventHandlerFunction) throws IOException { - acceptors = new ArrayList<>(acceptorCount); - socketSelectors = new ArrayList<>(socketSelectorCount); - - try { - for (int i = 0; i < socketSelectorCount; ++i) { - SocketSelector selector = new SocketSelector(socketEventHandlerFunction.apply(logger)); - socketSelectors.add(selector); - } - startSelectors(socketSelectors, socketSelectorThreadFactory); - - for (int i = 0; i < acceptorCount; ++i) { - SocketSelector[] childSelectors = this.socketSelectors.toArray(new SocketSelector[this.socketSelectors.size()]); - Supplier selectorSupplier = new RoundRobinSupplier<>(childSelectors); - AcceptingSelector acceptor = new AcceptingSelector(acceptorEventHandlerFunction.apply(logger, selectorSupplier)); - acceptors.add(acceptor); - } - startSelectors(acceptors, acceptorThreadFactory); - } catch (Exception e) { - try { - close(); - } catch (Exception e1) { - e.addSuppressed(e1); - } - throw e; - } - - socketSelectorSupplier = new RoundRobinSupplier<>(socketSelectors.toArray(new SocketSelector[socketSelectors.size()])); - acceptorSupplier = new RoundRobinSupplier<>(acceptors.toArray(new AcceptingSelector[acceptors.size()])); - } - - public S bindServerChannel(InetSocketAddress address, ChannelFactory factory) - throws IOException { - ensureOpen(); - if (acceptors.isEmpty()) { - throw new IllegalArgumentException("There are no acceptors configured. Without acceptors, server channels are not supported."); - } - return factory.openNioServerSocketChannel(address, acceptorSupplier.get()); - } - - public S openChannel(InetSocketAddress address, ChannelFactory factory) throws IOException { - ensureOpen(); - return factory.openNioChannel(address, socketSelectorSupplier.get()); - } - - @Override - public void close() throws IOException { - if (isOpen.compareAndSet(true, false)) { - IOUtils.close(Stream.concat(acceptors.stream(), socketSelectors.stream()).collect(Collectors.toList())); - } - } - - private static void startSelectors(Iterable selectors, ThreadFactory threadFactory) { - for (ESSelector acceptor : selectors) { - if (acceptor.isRunning() == false) { - threadFactory.newThread(acceptor::runLoop).start(); - acceptor.isRunningFuture().actionGet(); - } - } - } - - private void ensureOpen() { - if (isOpen.get() == false) { - throw new IllegalStateException("NioGroup is closed."); - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransport.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransport.java deleted file mode 100644 index bb28d93f85a84..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransport.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.recycler.Recycler; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.PageCacheRecycler; -import org.elasticsearch.common.util.concurrent.EsExecutors; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TcpTransport; -import org.elasticsearch.transport.Transports; -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.TcpChannelFactory; -import org.elasticsearch.transport.nio.channel.TcpNioServerSocketChannel; -import org.elasticsearch.transport.nio.channel.TcpNioSocketChannel; -import org.elasticsearch.transport.nio.channel.TcpReadContext; -import org.elasticsearch.transport.nio.channel.TcpWriteContext; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import static org.elasticsearch.common.settings.Setting.intSetting; -import static org.elasticsearch.common.util.concurrent.ConcurrentCollections.newConcurrentMap; -import static org.elasticsearch.common.util.concurrent.EsExecutors.daemonThreadFactory; - -public class NioTransport extends TcpTransport { - - public static final String TRANSPORT_WORKER_THREAD_NAME_PREFIX = Transports.NIO_TRANSPORT_WORKER_THREAD_NAME_PREFIX; - public static final String TRANSPORT_ACCEPTOR_THREAD_NAME_PREFIX = Transports.NIO_TRANSPORT_ACCEPTOR_THREAD_NAME_PREFIX; - - public static final Setting NIO_WORKER_COUNT = - new Setting<>("transport.nio.worker_count", - (s) -> Integer.toString(EsExecutors.numberOfProcessors(s) * 2), - (s) -> Setting.parseInt(s, 1, "transport.nio.worker_count"), Setting.Property.NodeScope); - - public static final Setting NIO_ACCEPTOR_COUNT = - intSetting("transport.nio.acceptor_count", 1, 1, Setting.Property.NodeScope); - - private final PageCacheRecycler pageCacheRecycler; - private final ConcurrentMap profileToChannelFactory = newConcurrentMap(); - private volatile NioGroup nioGroup; - private volatile TcpChannelFactory clientChannelFactory; - - public NioTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, - PageCacheRecycler pageCacheRecycler, NamedWriteableRegistry namedWriteableRegistry, - CircuitBreakerService circuitBreakerService) { - super("nio", settings, threadPool, bigArrays, circuitBreakerService, namedWriteableRegistry, networkService); - this.pageCacheRecycler = pageCacheRecycler; - } - - @Override - protected TcpNioServerSocketChannel bind(String name, InetSocketAddress address) throws IOException { - TcpChannelFactory channelFactory = this.profileToChannelFactory.get(name); - return nioGroup.bindServerChannel(address, channelFactory); - } - - @Override - protected TcpNioSocketChannel initiateChannel(DiscoveryNode node, TimeValue connectTimeout, ActionListener connectListener) - throws IOException { - TcpNioSocketChannel channel = nioGroup.openChannel(node.getAddress().address(), clientChannelFactory); - channel.addConnectListener(connectListener); - return channel; - } - - @Override - protected void doStart() { - boolean success = false; - try { - int acceptorCount = 0; - boolean useNetworkServer = NetworkService.NETWORK_SERVER.get(settings); - if (useNetworkServer) { - acceptorCount = NioTransport.NIO_ACCEPTOR_COUNT.get(settings); - } - nioGroup = new NioGroup(logger, daemonThreadFactory(this.settings, TRANSPORT_ACCEPTOR_THREAD_NAME_PREFIX), acceptorCount, - AcceptorEventHandler::new, daemonThreadFactory(this.settings, TRANSPORT_WORKER_THREAD_NAME_PREFIX), - NioTransport.NIO_WORKER_COUNT.get(settings), this::getSocketEventHandler); - - ProfileSettings clientProfileSettings = new ProfileSettings(settings, "default"); - clientChannelFactory = new TcpChannelFactory(clientProfileSettings, getContextSetter("client"), getServerContextSetter()); - - if (useNetworkServer) { - // loop through all profiles and start them up, special handling for default one - for (ProfileSettings profileSettings : profileSettings) { - String profileName = profileSettings.profileName; - Consumer contextSetter = getContextSetter(profileName); - TcpChannelFactory factory = new TcpChannelFactory(profileSettings, contextSetter, getServerContextSetter()); - profileToChannelFactory.putIfAbsent(profileName, factory); - bindServer(profileSettings); - } - } - - super.doStart(); - success = true; - } catch (IOException e) { - throw new ElasticsearchException(e); - } finally { - if (success == false) { - doStop(); - } - } - } - - @Override - protected void stopInternal() { - try { - nioGroup.close(); - } catch (Exception e) { - logger.warn("unexpected exception while stopping nio group", e); - } - profileToChannelFactory.clear(); - } - - protected SocketEventHandler getSocketEventHandler(Logger logger) { - return new SocketEventHandler(logger); - } - - final void exceptionCaught(NioSocketChannel channel, Exception exception) { - onException((TcpNioSocketChannel) channel, exception); - } - - private Consumer getContextSetter(String profileName) { - return (c) -> { - Supplier pageSupplier = () -> { - Recycler.V bytes = pageCacheRecycler.bytePage(false); - return new InboundChannelBuffer.Page(ByteBuffer.wrap(bytes.v()), bytes); - }; - c.setContexts(new TcpReadContext(c, new TcpReadHandler(profileName, this), new InboundChannelBuffer(pageSupplier)), - new TcpWriteContext(c), this::exceptionCaught); - }; - } - - private void acceptChannel(NioSocketChannel channel) { - serverAcceptedChannel((TcpNioSocketChannel) channel); - - } - - private Consumer getServerContextSetter() { - return (c) -> c.setAcceptContext(this::acceptChannel); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransportPlugin.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransportPlugin.java deleted file mode 100644 index e158fe6fe97c3..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/NioTransportPlugin.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.elasticsearch.transport.nio; - -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.PageCacheRecycler; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.plugins.NetworkPlugin; -import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.Transport; - -import java.util.Collections; -import java.util.Map; -import java.util.function.Supplier; - -public class NioTransportPlugin extends Plugin implements NetworkPlugin { - - public static final String NIO_TRANSPORT_NAME = "nio-transport"; - - @Override - public Map> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, - PageCacheRecycler pageCacheRecycler, - CircuitBreakerService circuitBreakerService, - NamedWriteableRegistry namedWriteableRegistry, - NetworkService networkService) { - Settings settings1; - if (NioTransport.NIO_WORKER_COUNT.exists(settings) == false) { - // As this is only used for tests right now, limit the number of worker threads. - settings1 = Settings.builder().put(settings).put(NioTransport.NIO_WORKER_COUNT.getKey(), 2).build(); - } else { - settings1 = settings; - } - return Collections.singletonMap(NIO_TRANSPORT_NAME, - () -> new NioTransport(settings1, threadPool, networkService, bigArrays, pageCacheRecycler, namedWriteableRegistry, - circuitBreakerService)); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/RoundRobinSupplier.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/RoundRobinSupplier.java deleted file mode 100644 index 395b955f7ab36..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/RoundRobinSupplier.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; - -public class RoundRobinSupplier implements Supplier { - - private final S[] selectors; - private final int count; - private AtomicInteger counter = new AtomicInteger(0); - - public RoundRobinSupplier(S[] selectors) { - this.count = selectors.length; - this.selectors = selectors; - } - - public S get() { - return selectors[counter.getAndIncrement() % count]; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketEventHandler.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketEventHandler.java deleted file mode 100644 index 799e81dd4a413..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketEventHandler.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.message.ParameterizedMessage; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.transport.nio.channel.NioChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.SelectionKeyUtils; -import org.elasticsearch.transport.nio.channel.WriteContext; - -import java.io.IOException; - -/** - * Event handler designed to handle events from non-server sockets - */ -public class SocketEventHandler extends EventHandler { - - private final Logger logger; - - public SocketEventHandler(Logger logger) { - super(logger); - this.logger = logger; - } - - /** - * This method is called when a NioSocketChannel is successfully registered. It should only be called - * once per channel. - * - * @param channel that was registered - */ - void handleRegistration(NioSocketChannel channel) { - SelectionKeyUtils.setConnectAndReadInterested(channel); - } - - /** - * This method is called when an attempt to register a channel throws an exception. - * - * @param channel that was registered - * @param exception that occurred - */ - void registrationException(NioSocketChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("failed to register socket channel: {}", channel), exception); - exceptionCaught(channel, exception); - } - - /** - * This method is called when a NioSocketChannel is successfully connected. It should only be called - * once per channel. - * - * @param channel that was registered - */ - void handleConnect(NioSocketChannel channel) { - SelectionKeyUtils.removeConnectInterested(channel); - } - - /** - * This method is called when an attempt to connect a channel throws an exception. - * - * @param channel that was connecting - * @param exception that occurred - */ - void connectException(NioSocketChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("failed to connect to socket channel: {}", channel), exception); - exceptionCaught(channel, exception); - } - - /** - * This method is called when a channel signals it is ready for be read. All of the read logic should - * occur in this call. - * - * @param channel that can be read - */ - void handleRead(NioSocketChannel channel) throws IOException { - int bytesRead = channel.getReadContext().read(); - if (bytesRead == -1) { - handleClose(channel); - } - } - - /** - * This method is called when an attempt to read from a channel throws an exception. - * - * @param channel that was being read - * @param exception that occurred - */ - void readException(NioSocketChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("exception while reading from socket channel: {}", channel), exception); - exceptionCaught(channel, exception); - } - - /** - * This method is called when a channel signals it is ready to receive writes. All of the write logic - * should occur in this call. - * - * @param channel that can be read - */ - void handleWrite(NioSocketChannel channel) throws IOException { - WriteContext channelContext = channel.getWriteContext(); - channelContext.flushChannel(); - if (channelContext.hasQueuedWriteOps()) { - SelectionKeyUtils.setWriteInterested(channel); - } else { - SelectionKeyUtils.removeWriteInterested(channel); - } - } - - /** - * This method is called when an attempt to write to a channel throws an exception. - * - * @param channel that was being written to - * @param exception that occurred - */ - void writeException(NioSocketChannel channel, Exception exception) { - logger.debug(() -> new ParameterizedMessage("exception while writing to socket channel: {}", channel), exception); - exceptionCaught(channel, exception); - } - - /** - * This method is called when handling an event from a channel fails due to an unexpected exception. - * An example would be if checking ready ops on a {@link java.nio.channels.SelectionKey} threw - * {@link java.nio.channels.CancelledKeyException}. - * - * @param channel that caused the exception - * @param exception that was thrown - */ - void genericChannelException(NioChannel channel, Exception exception) { - super.genericChannelException(channel, exception); - exceptionCaught((NioSocketChannel) channel, exception); - } - - /** - * This method is called when a listener attached to a channel operation throws an exception. - * - * @param listener that was called - * @param exception that occurred - */ - void listenerException(ActionListener listener, Exception exception) { - logger.warn(new ParameterizedMessage("exception while executing listener: {}", listener), exception); - } - - private void exceptionCaught(NioSocketChannel channel, Exception e) { - channel.getExceptionContext().accept(channel, e); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketSelector.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketSelector.java deleted file mode 100644 index ee4252e40a80a..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/SocketSelector.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.SelectionKeyUtils; -import org.elasticsearch.transport.nio.channel.WriteContext; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Selector implementation that handles {@link NioSocketChannel}. It's main piece of functionality is - * handling connect, read, and write events. - */ -public class SocketSelector extends ESSelector { - - private final ConcurrentLinkedQueue newChannels = new ConcurrentLinkedQueue<>(); - private final ConcurrentLinkedQueue queuedWrites = new ConcurrentLinkedQueue<>(); - private final SocketEventHandler eventHandler; - - public SocketSelector(SocketEventHandler eventHandler) throws IOException { - super(eventHandler); - this.eventHandler = eventHandler; - } - - public SocketSelector(SocketEventHandler eventHandler, Selector selector) throws IOException { - super(eventHandler, selector); - this.eventHandler = eventHandler; - } - - @Override - void processKey(SelectionKey selectionKey) { - NioSocketChannel nioSocketChannel = (NioSocketChannel) selectionKey.attachment(); - int ops = selectionKey.readyOps(); - if ((ops & SelectionKey.OP_CONNECT) != 0) { - attemptConnect(nioSocketChannel, true); - } - - if (nioSocketChannel.isConnectComplete()) { - if ((ops & SelectionKey.OP_WRITE) != 0) { - handleWrite(nioSocketChannel); - } - - if ((ops & SelectionKey.OP_READ) != 0) { - handleRead(nioSocketChannel); - } - } - } - - @Override - void preSelect() { - setUpNewChannels(); - handleQueuedWrites(); - } - - @Override - void cleanup() { - WriteOperation op; - while ((op = queuedWrites.poll()) != null) { - executeFailedListener(op.getListener(), new ClosedSelectorException()); - } - channelsToClose.addAll(newChannels); - } - - /** - * Schedules a NioSocketChannel to be registered by this selector. The channel will by queued and eventually - * registered next time through the event loop. - * @param nioSocketChannel the channel to register - */ - public void scheduleForRegistration(NioSocketChannel nioSocketChannel) { - newChannels.offer(nioSocketChannel); - ensureSelectorOpenForEnqueuing(newChannels, nioSocketChannel); - wakeup(); - } - - - /** - * Queues a write operation to be handled by the event loop. This can be called by any thread and is the - * api available for non-selector threads to schedule writes. - * - * @param writeOperation to be queued - */ - public void queueWrite(WriteOperation writeOperation) { - queuedWrites.offer(writeOperation); - if (isOpen() == false) { - boolean wasRemoved = queuedWrites.remove(writeOperation); - if (wasRemoved) { - writeOperation.getListener().onFailure(new ClosedSelectorException()); - } - } else { - wakeup(); - } - } - - /** - * Queues a write operation directly in a channel's buffer. Channel buffers are only safe to be accessed - * by the selector thread. As a result, this method should only be called by the selector thread. - * - * @param writeOperation to be queued in a channel's buffer - */ - public void queueWriteInChannelBuffer(WriteOperation writeOperation) { - assert isOnCurrentThread() : "Must be on selector thread"; - NioSocketChannel channel = writeOperation.getChannel(); - WriteContext context = channel.getWriteContext(); - try { - SelectionKeyUtils.setWriteInterested(channel); - context.queueWriteOperations(writeOperation); - } catch (Exception e) { - executeFailedListener(writeOperation.getListener(), e); - } - } - - /** - * Executes a success listener with consistent exception handling. This can only be called from current - * selector thread. - * - * @param listener to be executed - * @param value to provide to listener - */ - public void executeListener(ActionListener listener, V value) { - assert isOnCurrentThread() : "Must be on selector thread"; - try { - listener.onResponse(value); - } catch (Exception e) { - eventHandler.listenerException(listener, e); - } - } - - /** - * Executes a failed listener with consistent exception handling. This can only be called from current - * selector thread. - * - * @param listener to be executed - * @param exception to provide to listener - */ - public void executeFailedListener(ActionListener listener, Exception exception) { - assert isOnCurrentThread() : "Must be on selector thread"; - try { - listener.onFailure(exception); - } catch (Exception e) { - eventHandler.listenerException(listener, e); - } - } - - private void handleWrite(NioSocketChannel nioSocketChannel) { - try { - eventHandler.handleWrite(nioSocketChannel); - } catch (Exception e) { - eventHandler.writeException(nioSocketChannel, e); - } - } - - private void handleRead(NioSocketChannel nioSocketChannel) { - try { - eventHandler.handleRead(nioSocketChannel); - } catch (Exception e) { - eventHandler.readException(nioSocketChannel, e); - } - } - - private void handleQueuedWrites() { - WriteOperation writeOperation; - while ((writeOperation = queuedWrites.poll()) != null) { - if (writeOperation.getChannel().isWritable()) { - queueWriteInChannelBuffer(writeOperation); - } else { - executeFailedListener(writeOperation.getListener(), new ClosedChannelException()); - } - } - } - - private void setUpNewChannels() { - NioSocketChannel newChannel; - while ((newChannel = this.newChannels.poll()) != null) { - setupChannel(newChannel); - } - } - - private void setupChannel(NioSocketChannel newChannel) { - assert newChannel.getSelector() == this : "The channel must be registered with the selector with which it was created"; - try { - if (newChannel.isOpen()) { - newChannel.register(); - SelectionKey key = newChannel.getSelectionKey(); - key.attach(newChannel); - eventHandler.handleRegistration(newChannel); - attemptConnect(newChannel, false); - } else { - eventHandler.registrationException(newChannel, new ClosedChannelException()); - } - } catch (Exception e) { - eventHandler.registrationException(newChannel, e); - } - } - - private void attemptConnect(NioSocketChannel newChannel, boolean connectEvent) { - try { - if (newChannel.finishConnect()) { - eventHandler.handleConnect(newChannel); - } else if (connectEvent) { - eventHandler.connectException(newChannel, new IOException("Received OP_CONNECT but connect failed")); - } - } catch (Exception e) { - eventHandler.connectException(newChannel, e); - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/TcpReadHandler.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/TcpReadHandler.java deleted file mode 100644 index 5c2ecea54c3f0..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/TcpReadHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.TcpNioSocketChannel; - -import java.io.IOException; - -public class TcpReadHandler { - - private final String profile; - private final NioTransport transport; - - public TcpReadHandler(String profile, NioTransport transport) { - this.profile = profile; - this.transport = transport; - } - - public void handleMessage(BytesReference reference, TcpNioSocketChannel channel, int messageBytesLength) { - try { - transport.messageReceived(reference, channel, profile, channel.getRemoteAddress(), messageBytesLength); - } catch (IOException e) { - handleException(channel, e); - } - } - - public void handleException(NioSocketChannel channel, Exception e) { - transport.exceptionCaught(channel, e); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/WriteOperation.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/WriteOperation.java deleted file mode 100644 index 0a2ef15b0815a..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/WriteOperation.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.BytesRefIterator; -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; - -public class WriteOperation { - - private final NioSocketChannel channel; - private final ActionListener listener; - private final ByteBuffer[] buffers; - private final int[] offsets; - private final int length; - private int internalIndex; - - public WriteOperation(NioSocketChannel channel, BytesReference bytesReference, ActionListener listener) { - this.channel = channel; - this.listener = listener; - this.buffers = toByteBuffers(bytesReference); - this.offsets = new int[buffers.length]; - int offset = 0; - for (int i = 0; i < buffers.length; i++) { - ByteBuffer buffer = buffers[i]; - offsets[i] = offset; - offset += buffer.remaining(); - } - length = offset; - } - - public ByteBuffer[] getByteBuffers() { - return buffers; - } - - public ActionListener getListener() { - return listener; - } - - public NioSocketChannel getChannel() { - return channel; - } - - public boolean isFullyFlushed() { - return internalIndex == length; - } - - public int flush() throws IOException { - int written = channel.write(getBuffersToWrite()); - internalIndex += written; - return written; - } - - private ByteBuffer[] getBuffersToWrite() { - int offsetIndex = getOffsetIndex(internalIndex); - - ByteBuffer[] postIndexBuffers = new ByteBuffer[buffers.length - offsetIndex]; - - ByteBuffer firstBuffer = buffers[offsetIndex].duplicate(); - firstBuffer.position(internalIndex - offsets[offsetIndex]); - postIndexBuffers[0] = firstBuffer; - int j = 1; - for (int i = (offsetIndex + 1); i < buffers.length; ++i) { - postIndexBuffers[j++] = buffers[i].duplicate(); - } - - return postIndexBuffers; - } - - private int getOffsetIndex(int offset) { - final int i = Arrays.binarySearch(offsets, offset); - return i < 0 ? (-(i + 1)) - 1 : i; - } - - private static ByteBuffer[] toByteBuffers(BytesReference bytesReference) { - BytesRefIterator byteRefIterator = bytesReference.iterator(); - BytesRef r; - try { - // Most network messages are composed of three buffers. - ArrayList buffers = new ArrayList<>(3); - while ((r = byteRefIterator.next()) != null) { - buffers.add(ByteBuffer.wrap(r.bytes, r.offset, r.length)); - } - return buffers.toArray(new ByteBuffer[buffers.size()]); - - } catch (IOException e) { - // this is really an error since we don't do IO in our bytesreferences - throw new AssertionError("won't happen", e); - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/AbstractNioChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/AbstractNioChannel.java deleted file mode 100644 index 046b4d4c53671..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/AbstractNioChannel.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.transport.nio.ESSelector; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.NetworkChannel; -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * This is a basic channel abstraction used by the {@link org.elasticsearch.transport.nio.NioTransport}. - *

- * A channel is open once it is constructed. The channel remains open and {@link #isOpen()} will return - * true until the channel is explicitly closed. - *

- * A channel lifecycle has two stages: - *

    - *
  1. OPEN - When a channel has been created. This is the state of a channel that can perform normal operations. - *
  2. CLOSED - The channel has been set to closed. All this means is that the channel has been scheduled to be - * closed. The underlying raw channel may not yet be closed. The underlying channel has been closed if the close - * future has been completed. - *
- * - * @param the type of raw channel this AbstractNioChannel uses - */ -public abstract class AbstractNioChannel implements NioChannel { - - final S socketChannel; - // This indicates if the channel has been scheduled to be closed. Read the closeFuture to determine if - // the channel close process has completed. - final AtomicBoolean isClosing = new AtomicBoolean(false); - - private final InetSocketAddress localAddress; - private final CompletableFuture closeContext = new CompletableFuture<>(); - private final ESSelector selector; - private SelectionKey selectionKey; - - AbstractNioChannel(S socketChannel, ESSelector selector) throws IOException { - this.socketChannel = socketChannel; - this.localAddress = (InetSocketAddress) socketChannel.getLocalAddress(); - this.selector = selector; - } - - @Override - public boolean isOpen() { - return closeContext.isDone() == false; - } - - @Override - public InetSocketAddress getLocalAddress() { - return localAddress; - } - - /** - * Schedules a channel to be closed by the selector event loop with which it is registered. - *

- * If the channel is open and the state can be transitioned to closed, the close operation will - * be scheduled with the event loop. - *

- * If the channel is already set to closed, it is assumed that it is already scheduled to be closed. - */ - @Override - public void close() { - if (isClosing.compareAndSet(false, true)) { - selector.queueChannelClose(this); - } - } - - /** - * Closes the channel synchronously. This method should only be called from the selector thread. - *

- * Once this method returns, the channel will be closed. - */ - @Override - public void closeFromSelector() throws IOException { - assert selector.isOnCurrentThread() : "Should only call from selector thread"; - isClosing.set(true); - if (closeContext.isDone() == false) { - try { - closeRawChannel(); - closeContext.complete(null); - } catch (IOException e) { - closeContext.completeExceptionally(e); - throw e; - } - } - } - - /** - * This method attempts to registered a channel with the raw nio selector. It also sets the selection - * key. - * - * @throws ClosedChannelException if the raw channel was closed - */ - @Override - public void register() throws ClosedChannelException { - setSelectionKey(socketChannel.register(selector.rawSelector(), 0)); - } - - @Override - public ESSelector getSelector() { - return selector; - } - - @Override - public SelectionKey getSelectionKey() { - return selectionKey; - } - - @Override - public S getRawChannel() { - return socketChannel; - } - - @Override - public void addCloseListener(ActionListener listener) { - closeContext.whenComplete(ActionListener.toBiConsumer(listener)); - } - - // Package visibility for testing - void setSelectionKey(SelectionKey selectionKey) { - this.selectionKey = selectionKey; - } - // Package visibility for testing - - void closeRawChannel() throws IOException { - socketChannel.close(); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ChannelFactory.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ChannelFactory.java deleted file mode 100644 index 97433cf4d0aad..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ChannelFactory.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.mocksocket.PrivilegedSocketAccess; -import org.elasticsearch.transport.nio.AcceptingSelector; -import org.elasticsearch.transport.nio.SocketSelector; - -import java.io.Closeable; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; - -public abstract class ChannelFactory { - - private final ChannelFactory.RawChannelFactory rawChannelFactory; - - /** - * This will create a {@link ChannelFactory} using the raw channel factory passed to the constructor. - * - * @param rawChannelFactory a factory that will construct the raw socket channels - */ - ChannelFactory(RawChannelFactory rawChannelFactory) { - this.rawChannelFactory = rawChannelFactory; - } - - public Socket openNioChannel(InetSocketAddress remoteAddress, SocketSelector selector) throws IOException { - SocketChannel rawChannel = rawChannelFactory.openNioChannel(remoteAddress); - Socket channel = internalCreateChannel(selector, rawChannel); - scheduleChannel(channel, selector); - return channel; - } - - public Socket acceptNioChannel(NioServerSocketChannel serverChannel, SocketSelector selector) throws IOException { - SocketChannel rawChannel = rawChannelFactory.acceptNioChannel(serverChannel); - Socket channel = internalCreateChannel(selector, rawChannel); - scheduleChannel(channel, selector); - return channel; - } - - public ServerSocket openNioServerSocketChannel(InetSocketAddress address, AcceptingSelector selector) throws IOException { - ServerSocketChannel rawChannel = rawChannelFactory.openNioServerSocketChannel(address); - ServerSocket serverChannel = internalCreateServerChannel(selector, rawChannel); - scheduleServerChannel(serverChannel, selector); - return serverChannel; - } - - /** - * This method should return a new {@link NioSocketChannel} implementation. When this method has - * returned, the channel should be fully created and setup. Read and write contexts and the channel - * exception handler should have been set. - * - * @param selector the channel will be registered with - * @param channel the raw channel - * @return the channel - * @throws IOException related to the creation of the channel - */ - public abstract Socket createChannel(SocketSelector selector, SocketChannel channel) throws IOException; - - /** - * This method should return a new {@link NioServerSocketChannel} implementation. When this method has - * returned, the channel should be fully created and setup. - * - * @param selector the channel will be registered with - * @param channel the raw channel - * @return the server channel - * @throws IOException related to the creation of the channel - */ - public abstract ServerSocket createServerChannel(AcceptingSelector selector, ServerSocketChannel channel) throws IOException; - - private Socket internalCreateChannel(SocketSelector selector, SocketChannel rawChannel) throws IOException { - try { - Socket channel = createChannel(selector, rawChannel); - assert channel.getReadContext() != null : "read context should have been set on channel"; - assert channel.getWriteContext() != null : "write context should have been set on channel"; - assert channel.getExceptionContext() != null : "exception handler should have been set on channel"; - return channel; - } catch (Exception e) { - closeRawChannel(rawChannel, e); - throw e; - } - } - - private ServerSocket internalCreateServerChannel(AcceptingSelector selector, ServerSocketChannel rawChannel) throws IOException { - try { - return createServerChannel(selector, rawChannel); - } catch (Exception e) { - closeRawChannel(rawChannel, e); - throw e; - } - } - - private void scheduleChannel(Socket channel, SocketSelector selector) { - try { - selector.scheduleForRegistration(channel); - } catch (IllegalStateException e) { - closeRawChannel(channel.getRawChannel(), e); - throw e; - } - } - - private void scheduleServerChannel(ServerSocket channel, AcceptingSelector selector) { - try { - selector.scheduleForRegistration(channel); - } catch (IllegalStateException e) { - closeRawChannel(channel.getRawChannel(), e); - throw e; - } - } - - private static void closeRawChannel(Closeable c, Exception e) { - try { - c.close(); - } catch (IOException closeException) { - e.addSuppressed(closeException); - } - } - - static class RawChannelFactory { - - private final boolean tcpNoDelay; - private final boolean tcpKeepAlive; - private final boolean tcpReusedAddress; - private final int tcpSendBufferSize; - private final int tcpReceiveBufferSize; - - RawChannelFactory(boolean tcpNoDelay, boolean tcpKeepAlive, boolean tcpReusedAddress, int tcpSendBufferSize, - int tcpReceiveBufferSize) { - this.tcpNoDelay = tcpNoDelay; - this.tcpKeepAlive = tcpKeepAlive; - this.tcpReusedAddress = tcpReusedAddress; - this.tcpSendBufferSize = tcpSendBufferSize; - this.tcpReceiveBufferSize = tcpReceiveBufferSize; - } - - SocketChannel openNioChannel(InetSocketAddress remoteAddress) throws IOException { - SocketChannel socketChannel = SocketChannel.open(); - try { - configureSocketChannel(socketChannel); - PrivilegedSocketAccess.connect(socketChannel, remoteAddress); - } catch (IOException e) { - closeRawChannel(socketChannel, e); - throw e; - } - return socketChannel; - } - - SocketChannel acceptNioChannel(NioServerSocketChannel serverChannel) throws IOException { - ServerSocketChannel serverSocketChannel = serverChannel.getRawChannel(); - SocketChannel socketChannel = PrivilegedSocketAccess.accept(serverSocketChannel); - try { - configureSocketChannel(socketChannel); - } catch (IOException e) { - closeRawChannel(socketChannel, e); - throw e; - } - return socketChannel; - } - - ServerSocketChannel openNioServerSocketChannel(InetSocketAddress address) throws IOException { - ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); - serverSocketChannel.configureBlocking(false); - java.net.ServerSocket socket = serverSocketChannel.socket(); - try { - socket.setReuseAddress(tcpReusedAddress); - serverSocketChannel.bind(address); - } catch (IOException e) { - closeRawChannel(serverSocketChannel, e); - throw e; - } - return serverSocketChannel; - } - - private void configureSocketChannel(SocketChannel channel) throws IOException { - channel.configureBlocking(false); - java.net.Socket socket = channel.socket(); - socket.setTcpNoDelay(tcpNoDelay); - socket.setKeepAlive(tcpKeepAlive); - socket.setReuseAddress(tcpReusedAddress); - if (tcpSendBufferSize > 0) { - socket.setSendBufferSize(tcpSendBufferSize); - } - if (tcpReceiveBufferSize > 0) { - socket.setSendBufferSize(tcpReceiveBufferSize); - } - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioChannel.java deleted file mode 100644 index 93bc4faa4c5d5..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioChannel.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.transport.nio.ESSelector; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.NetworkChannel; -import java.nio.channels.SelectionKey; - -public interface NioChannel { - - boolean isOpen(); - - InetSocketAddress getLocalAddress(); - - void close(); - - void closeFromSelector() throws IOException; - - void register() throws ClosedChannelException; - - ESSelector getSelector(); - - SelectionKey getSelectionKey(); - - NetworkChannel getRawChannel(); - - /** - * Adds a close listener to the channel. Multiple close listeners can be added. There is no guarantee - * about the order in which close listeners will be executed. If the channel is already closed, the - * listener is executed immediately. - * - * @param listener to be called at close - */ - void addCloseListener(ActionListener listener); -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannel.java deleted file mode 100644 index ffbd8f7a9874e..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannel.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.transport.nio.AcceptingSelector; - -import java.io.IOException; -import java.nio.channels.ServerSocketChannel; -import java.util.function.Consumer; - -public class NioServerSocketChannel extends AbstractNioChannel { - - private final ChannelFactory channelFactory; - private Consumer acceptContext; - - public NioServerSocketChannel(ServerSocketChannel socketChannel, ChannelFactory channelFactory, AcceptingSelector selector) - throws IOException { - super(socketChannel, selector); - this.channelFactory = channelFactory; - } - - public ChannelFactory getChannelFactory() { - return channelFactory; - } - - /** - * This method sets the accept context for a server socket channel. The accept context is called when a - * new channel is accepted. The parameter passed to the context is the new channel. - * - * @param acceptContext to call - */ - public void setAcceptContext(Consumer acceptContext) { - this.acceptContext = acceptContext; - } - - public Consumer getAcceptContext() { - return acceptContext; - } - - @Override - public String toString() { - return "NioServerSocketChannel{" + - "localAddress=" + getLocalAddress() + - '}'; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioSocketChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioSocketChannel.java deleted file mode 100644 index 06f8aec627936..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/NioSocketChannel.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.transport.nio.InboundChannelBuffer; -import org.elasticsearch.transport.nio.SocketSelector; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SocketChannel; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; - -public class NioSocketChannel extends AbstractNioChannel { - - private final InetSocketAddress remoteAddress; - private final CompletableFuture connectContext = new CompletableFuture<>(); - private final SocketSelector socketSelector; - private final AtomicBoolean contextsSet = new AtomicBoolean(false); - private WriteContext writeContext; - private ReadContext readContext; - private BiConsumer exceptionContext; - private Exception connectException; - - public NioSocketChannel(SocketChannel socketChannel, SocketSelector selector) throws IOException { - super(socketChannel, selector); - this.remoteAddress = (InetSocketAddress) socketChannel.getRemoteAddress(); - this.socketSelector = selector; - } - - @Override - public void closeFromSelector() throws IOException { - assert socketSelector.isOnCurrentThread() : "Should only call from selector thread"; - // Even if the channel has already been closed we will clear any pending write operations just in case - if (writeContext.hasQueuedWriteOps()) { - writeContext.clearQueuedWriteOps(new ClosedChannelException()); - } - readContext.close(); - - super.closeFromSelector(); - } - - @Override - public SocketSelector getSelector() { - return socketSelector; - } - - public int write(ByteBuffer[] buffers) throws IOException { - if (buffers.length == 1) { - return socketChannel.write(buffers[0]); - } else { - return (int) socketChannel.write(buffers); - } - } - - public int read(InboundChannelBuffer buffer) throws IOException { - int bytesRead = (int) socketChannel.read(buffer.sliceBuffersFrom(buffer.getIndex())); - - if (bytesRead == -1) { - return bytesRead; - } - - buffer.incrementIndex(bytesRead); - return bytesRead; - } - - public void setContexts(ReadContext readContext, WriteContext writeContext, BiConsumer exceptionContext) { - if (contextsSet.compareAndSet(false, true)) { - this.readContext = readContext; - this.writeContext = writeContext; - this.exceptionContext = exceptionContext; - } else { - throw new IllegalStateException("Contexts on this channel were already set. They should only be once."); - } - } - - public WriteContext getWriteContext() { - return writeContext; - } - - public ReadContext getReadContext() { - return readContext; - } - - public BiConsumer getExceptionContext() { - return exceptionContext; - } - - public InetSocketAddress getRemoteAddress() { - return remoteAddress; - } - - public boolean isConnectComplete() { - return isConnectComplete0(); - } - - public boolean isWritable() { - return isClosing.get() == false; - } - - public boolean isReadable() { - return isClosing.get() == false; - } - - /** - * This method will attempt to complete the connection process for this channel. It should be called for - * new channels or for a channel that has produced a OP_CONNECT event. If this method returns true then - * the connection is complete and the channel is ready for reads and writes. If it returns false, the - * channel is not yet connected and this method should be called again when a OP_CONNECT event is - * received. - * - * @return true if the connection process is complete - * @throws IOException if an I/O error occurs - */ - public boolean finishConnect() throws IOException { - if (isConnectComplete0()) { - return true; - } else if (connectContext.isCompletedExceptionally()) { - Exception exception = connectException; - if (exception == null) { - throw new AssertionError("Should have received connection exception"); - } else if (exception instanceof IOException) { - throw (IOException) exception; - } else { - throw (RuntimeException) exception; - } - } - - boolean isConnected = socketChannel.isConnected(); - if (isConnected == false) { - isConnected = internalFinish(); - } - if (isConnected) { - connectContext.complete(null); - } - return isConnected; - } - - public void addConnectListener(ActionListener listener) { - connectContext.whenComplete(ActionListener.toBiConsumer(listener)); - } - - @Override - public String toString() { - return "NioSocketChannel{" + - "localAddress=" + getLocalAddress() + - ", remoteAddress=" + remoteAddress + - '}'; - } - - private boolean internalFinish() throws IOException { - try { - return socketChannel.finishConnect(); - } catch (IOException | RuntimeException e) { - connectException = e; - connectContext.completeExceptionally(e); - throw e; - } - } - - private boolean isConnectComplete0() { - return connectContext.isDone() && connectContext.isCompletedExceptionally() == false; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ReadContext.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ReadContext.java deleted file mode 100644 index 243a6d8b239c2..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/ReadContext.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import java.io.IOException; - -public interface ReadContext extends AutoCloseable { - - int read() throws IOException; - - @Override - void close(); - -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/SelectionKeyUtils.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/SelectionKeyUtils.java deleted file mode 100644 index b0cf5552064fd..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/SelectionKeyUtils.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import java.nio.channels.CancelledKeyException; -import java.nio.channels.SelectionKey; - -public final class SelectionKeyUtils { - - private SelectionKeyUtils() {} - - public static void setWriteInterested(NioChannel channel) throws CancelledKeyException { - SelectionKey selectionKey = channel.getSelectionKey(); - selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_WRITE); - } - - public static void removeWriteInterested(NioChannel channel) throws CancelledKeyException { - SelectionKey selectionKey = channel.getSelectionKey(); - selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_WRITE); - } - - public static void setConnectAndReadInterested(NioChannel channel) throws CancelledKeyException { - SelectionKey selectionKey = channel.getSelectionKey(); - selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_CONNECT | SelectionKey.OP_READ); - } - - public static void removeConnectInterested(NioChannel channel) throws CancelledKeyException { - SelectionKey selectionKey = channel.getSelectionKey(); - selectionKey.interestOps(selectionKey.interestOps() & ~SelectionKey.OP_CONNECT); - } - - public static void setAcceptInterested(NioServerSocketChannel channel) { - SelectionKey selectionKey = channel.getSelectionKey(); - selectionKey.interestOps(selectionKey.interestOps() | SelectionKey.OP_ACCEPT); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpChannelFactory.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpChannelFactory.java deleted file mode 100644 index 03d6db18e5a41..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpChannelFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.transport.TcpTransport; -import org.elasticsearch.transport.nio.AcceptingSelector; -import org.elasticsearch.transport.nio.SocketSelector; - -import java.io.IOException; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.function.Consumer; - -/** - * This is an implementation of {@link ChannelFactory} which returns channels that adhere to the - * {@link org.elasticsearch.transport.TcpChannel} interface. The channels will use the provided - * {@link TcpTransport.ProfileSettings}. The provided context setters will be called with the channel after - * construction. - */ -public class TcpChannelFactory extends ChannelFactory { - - private final Consumer contextSetter; - private final Consumer serverContextSetter; - - public TcpChannelFactory(TcpTransport.ProfileSettings profileSettings, Consumer contextSetter, - Consumer serverContextSetter) { - super(new RawChannelFactory(profileSettings.tcpNoDelay, - profileSettings.tcpKeepAlive, - profileSettings.reuseAddress, - Math.toIntExact(profileSettings.sendBufferSize.getBytes()), - Math.toIntExact(profileSettings.receiveBufferSize.getBytes()))); - this.contextSetter = contextSetter; - this.serverContextSetter = serverContextSetter; - } - - @Override - public TcpNioSocketChannel createChannel(SocketSelector selector, SocketChannel channel) throws IOException { - TcpNioSocketChannel nioChannel = new TcpNioSocketChannel(channel, selector); - contextSetter.accept(nioChannel); - return nioChannel; - } - - @Override - public TcpNioServerSocketChannel createServerChannel(AcceptingSelector selector, ServerSocketChannel channel) throws IOException { - TcpNioServerSocketChannel nioServerChannel = new TcpNioServerSocketChannel(channel, this, selector); - serverContextSetter.accept(nioServerChannel); - return nioServerChannel; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoder.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoder.java deleted file mode 100644 index b2ba70fb2365d..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoder.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.unit.ByteSizeValue; -import org.elasticsearch.monitor.jvm.JvmInfo; -import org.elasticsearch.transport.TcpHeader; -import org.elasticsearch.transport.TcpTransport; - -import java.io.IOException; -import java.io.StreamCorruptedException; - -public class TcpFrameDecoder { - - private static final long NINETY_PER_HEAP_SIZE = (long) (JvmInfo.jvmInfo().getMem().getHeapMax().getBytes() * 0.9); - private static final int HEADER_SIZE = TcpHeader.MARKER_BYTES_SIZE + TcpHeader.MESSAGE_LENGTH_SIZE; - - private int expectedMessageLength = -1; - - public BytesReference decode(BytesReference bytesReference) throws IOException { - if (bytesReference.length() >= 6) { - int messageLength = readHeaderBuffer(bytesReference); - int totalLength = messageLength + HEADER_SIZE; - if (totalLength > bytesReference.length()) { - expectedMessageLength = totalLength; - return null; - } else if (totalLength == bytesReference.length()) { - expectedMessageLength = -1; - return bytesReference; - } else { - expectedMessageLength = -1; - return bytesReference.slice(0, totalLength); - } - } else { - return null; - } - } - - public int expectedMessageLength() { - return expectedMessageLength; - } - - private int readHeaderBuffer(BytesReference headerBuffer) throws IOException { - if (headerBuffer.get(0) != 'E' || headerBuffer.get(1) != 'S') { - if (appearsToBeHTTP(headerBuffer)) { - throw new TcpTransport.HttpOnTransportException("This is not a HTTP port"); - } - - throw new StreamCorruptedException("invalid internal transport message format, got (" - + Integer.toHexString(headerBuffer.get(0) & 0xFF) + "," - + Integer.toHexString(headerBuffer.get(1) & 0xFF) + "," - + Integer.toHexString(headerBuffer.get(2) & 0xFF) + "," - + Integer.toHexString(headerBuffer.get(3) & 0xFF) + ")"); - } - final int messageLength; - try (StreamInput input = headerBuffer.streamInput()) { - input.skip(TcpHeader.MARKER_BYTES_SIZE); - messageLength = input.readInt(); - } - - if (messageLength == -1) { - // This is a ping - return 0; - } - - if (messageLength <= 0) { - throw new StreamCorruptedException("invalid data length: " + messageLength); - } - - if (messageLength > NINETY_PER_HEAP_SIZE) { - throw new IllegalArgumentException("transport content length received [" + new ByteSizeValue(messageLength) + "] exceeded [" - + new ByteSizeValue(NINETY_PER_HEAP_SIZE) + "]"); - } - - return messageLength; - } - - private static boolean appearsToBeHTTP(BytesReference headerBuffer) { - return bufferStartsWith(headerBuffer, "GET") || - bufferStartsWith(headerBuffer, "POST") || - bufferStartsWith(headerBuffer, "PUT") || - bufferStartsWith(headerBuffer, "HEAD") || - bufferStartsWith(headerBuffer, "DELETE") || - // TODO: Actually 'OPTIONS'. But that does not currently fit in 6 bytes - bufferStartsWith(headerBuffer, "OPTION") || - bufferStartsWith(headerBuffer, "PATCH") || - bufferStartsWith(headerBuffer, "TRACE"); - } - - private static boolean bufferStartsWith(BytesReference buffer, String method) { - char[] chars = method.toCharArray(); - for (int i = 0; i < chars.length; i++) { - if (buffer.get(i) != chars[i]) { - return false; - } - } - return true; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioServerSocketChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioServerSocketChannel.java deleted file mode 100644 index 496295bd3203b..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioServerSocketChannel.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.TcpChannel; -import org.elasticsearch.transport.nio.AcceptingSelector; - -import java.io.IOException; -import java.nio.channels.ServerSocketChannel; - -/** - * This is an implementation of {@link NioServerSocketChannel} that adheres to the {@link TcpChannel} - * interface. As it is a server socket, setting SO_LINGER and sending messages is not supported. - */ -public class TcpNioServerSocketChannel extends NioServerSocketChannel implements TcpChannel { - - TcpNioServerSocketChannel(ServerSocketChannel socketChannel, TcpChannelFactory channelFactory, AcceptingSelector selector) - throws IOException { - super(socketChannel, channelFactory, selector); - } - - @Override - public void sendMessage(BytesReference reference, ActionListener listener) { - throw new UnsupportedOperationException("Cannot send a message to a server channel."); - } - - @Override - public void setSoLinger(int value) throws IOException { - throw new UnsupportedOperationException("Cannot set SO_LINGER on a server channel."); - } - - @Override - public String toString() { - return "TcpNioServerSocketChannel{" + - "localAddress=" + getLocalAddress() + - '}'; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioSocketChannel.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioSocketChannel.java deleted file mode 100644 index f1ee1bd4e67ad..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpNioSocketChannel.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.TcpChannel; -import org.elasticsearch.transport.nio.SocketSelector; - -import java.io.IOException; -import java.net.StandardSocketOptions; -import java.nio.channels.SocketChannel; - -public class TcpNioSocketChannel extends NioSocketChannel implements TcpChannel { - - public TcpNioSocketChannel(SocketChannel socketChannel, SocketSelector selector) throws IOException { - super(socketChannel, selector); - } - - public void sendMessage(BytesReference reference, ActionListener listener) { - getWriteContext().sendMessage(reference, listener); - } - - @Override - public void setSoLinger(int value) throws IOException { - if (isOpen()) { - getRawChannel().setOption(StandardSocketOptions.SO_LINGER, value); - } - } - - @Override - public String toString() { - return "TcpNioSocketChannel{" + - "localAddress=" + getLocalAddress() + - ", remoteAddress=" + getRemoteAddress() + - '}'; - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpReadContext.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpReadContext.java deleted file mode 100644 index 24a671412d220..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpReadContext.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.common.bytes.ByteBufferReference; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.bytes.CompositeBytesReference; -import org.elasticsearch.transport.nio.InboundChannelBuffer; -import org.elasticsearch.transport.nio.TcpReadHandler; - -import java.io.IOException; -import java.nio.ByteBuffer; - -public class TcpReadContext implements ReadContext { - - private final TcpReadHandler handler; - private final TcpNioSocketChannel channel; - private final InboundChannelBuffer channelBuffer; - private final TcpFrameDecoder frameDecoder = new TcpFrameDecoder(); - - public TcpReadContext(NioSocketChannel channel, TcpReadHandler handler, InboundChannelBuffer channelBuffer) { - this.handler = handler; - this.channel = (TcpNioSocketChannel) channel; - this.channelBuffer = channelBuffer; - } - - @Override - public int read() throws IOException { - if (channelBuffer.getRemaining() == 0) { - // Requiring one additional byte will ensure that a new page is allocated. - channelBuffer.ensureCapacity(channelBuffer.getCapacity() + 1); - } - - int bytesRead = channel.read(channelBuffer); - - if (bytesRead == -1) { - return bytesRead; - } - - BytesReference message; - - // Frame decoder will throw an exception if the message is improperly formatted, the header is incorrect, - // or the message is corrupted - while ((message = frameDecoder.decode(toBytesReference(channelBuffer))) != null) { - int messageLengthWithHeader = message.length(); - - try { - BytesReference messageWithoutHeader = message.slice(6, message.length() - 6); - - // A message length of 6 bytes it is just a ping. Ignore for now. - if (messageLengthWithHeader != 6) { - handler.handleMessage(messageWithoutHeader, channel, messageWithoutHeader.length()); - } - } catch (Exception e) { - handler.handleException(channel, e); - } finally { - channelBuffer.release(messageLengthWithHeader); - } - } - - return bytesRead; - } - - @Override - public void close() { - channelBuffer.close(); - } - - private static BytesReference toBytesReference(InboundChannelBuffer channelBuffer) { - ByteBuffer[] writtenToBuffers = channelBuffer.sliceBuffersTo(channelBuffer.getIndex()); - ByteBufferReference[] references = new ByteBufferReference[writtenToBuffers.length]; - for (int i = 0; i < references.length; ++i) { - references[i] = new ByteBufferReference(writtenToBuffers[i]); - } - - return new CompositeBytesReference(references); - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpWriteContext.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpWriteContext.java deleted file mode 100644 index 63b876c098764..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/TcpWriteContext.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.nio.SocketSelector; -import org.elasticsearch.transport.nio.WriteOperation; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.util.LinkedList; - -public class TcpWriteContext implements WriteContext { - - private final NioSocketChannel channel; - private final LinkedList queued = new LinkedList<>(); - - public TcpWriteContext(NioSocketChannel channel) { - this.channel = channel; - } - - @Override - public void sendMessage(BytesReference reference, ActionListener listener) { - if (channel.isWritable() == false) { - listener.onFailure(new ClosedChannelException()); - return; - } - - WriteOperation writeOperation = new WriteOperation(channel, reference, listener); - SocketSelector selector = channel.getSelector(); - if (selector.isOnCurrentThread() == false) { - selector.queueWrite(writeOperation); - return; - } - - // TODO: Eval if we will allow writes from sendMessage - selector.queueWriteInChannelBuffer(writeOperation); - } - - @Override - public void queueWriteOperations(WriteOperation writeOperation) { - assert channel.getSelector().isOnCurrentThread() : "Must be on selector thread to queue writes"; - queued.add(writeOperation); - } - - @Override - public void flushChannel() throws IOException { - assert channel.getSelector().isOnCurrentThread() : "Must be on selector thread to flush writes"; - int ops = queued.size(); - if (ops == 1) { - singleFlush(queued.pop()); - } else if (ops > 1) { - multiFlush(); - } - } - - @Override - public boolean hasQueuedWriteOps() { - assert channel.getSelector().isOnCurrentThread() : "Must be on selector thread to access queued writes"; - return queued.isEmpty() == false; - } - - @Override - public void clearQueuedWriteOps(Exception e) { - assert channel.getSelector().isOnCurrentThread() : "Must be on selector thread to clear queued writes"; - for (WriteOperation op : queued) { - channel.getSelector().executeFailedListener(op.getListener(), e); - } - queued.clear(); - } - - private void singleFlush(WriteOperation headOp) throws IOException { - try { - headOp.flush(); - } catch (IOException e) { - channel.getSelector().executeFailedListener(headOp.getListener(), e); - throw e; - } - - if (headOp.isFullyFlushed()) { - channel.getSelector().executeListener(headOp.getListener(), null); - } else { - queued.push(headOp); - } - } - - private void multiFlush() throws IOException { - boolean lastOpCompleted = true; - while (lastOpCompleted && queued.isEmpty() == false) { - WriteOperation op = queued.pop(); - singleFlush(op); - lastOpCompleted = op.isFullyFlushed(); - } - } -} diff --git a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/WriteContext.java b/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/WriteContext.java deleted file mode 100644 index 718b7daf8c628..0000000000000 --- a/test/framework/src/main/java/org/elasticsearch/transport/nio/channel/WriteContext.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.transport.nio.WriteOperation; - -import java.io.IOException; - -public interface WriteContext { - - void sendMessage(BytesReference reference, ActionListener listener); - - void queueWriteOperations(WriteOperation writeOperation); - - void flushChannel() throws IOException; - - boolean hasQueuedWriteOps(); - - void clearQueuedWriteOps(Exception e); - -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptingSelectorTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptingSelectorTests.java deleted file mode 100644 index 4e35f6177f5dc..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptingSelectorTests.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; -import org.elasticsearch.transport.nio.utils.TestSelectionKey; -import org.junit.Before; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.security.PrivilegedActionException; -import java.util.Collections; -import java.util.HashSet; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class AcceptingSelectorTests extends ESTestCase { - - private AcceptingSelector selector; - private NioServerSocketChannel serverChannel; - private AcceptorEventHandler eventHandler; - private TestSelectionKey selectionKey; - private Selector rawSelector; - - @Before - public void setUp() throws Exception { - super.setUp(); - - eventHandler = mock(AcceptorEventHandler.class); - serverChannel = mock(NioServerSocketChannel.class); - - rawSelector = mock(Selector.class); - selector = new AcceptingSelector(eventHandler, rawSelector); - this.selector.setThread(); - - selectionKey = new TestSelectionKey(0); - selectionKey.attach(serverChannel); - when(serverChannel.getSelectionKey()).thenReturn(selectionKey); - when(serverChannel.getSelector()).thenReturn(selector); - when(serverChannel.isOpen()).thenReturn(true); - } - - public void testRegisteredChannel() throws IOException, PrivilegedActionException { - selector.scheduleForRegistration(serverChannel); - - selector.preSelect(); - - verify(eventHandler).serverChannelRegistered(serverChannel); - } - - public void testClosedChannelWillNotBeRegistered() throws Exception { - when(serverChannel.isOpen()).thenReturn(false); - selector.scheduleForRegistration(serverChannel); - - selector.preSelect(); - - verify(eventHandler).registrationException(same(serverChannel), any(ClosedChannelException.class)); - } - - public void testRegisterChannelFailsDueToException() throws Exception { - selector.scheduleForRegistration(serverChannel); - - ClosedChannelException closedChannelException = new ClosedChannelException(); - doThrow(closedChannelException).when(serverChannel).register(); - - selector.preSelect(); - - verify(eventHandler).registrationException(serverChannel, closedChannelException); - } - - public void testAcceptEvent() throws IOException { - selectionKey.setReadyOps(SelectionKey.OP_ACCEPT); - - selector.processKey(selectionKey); - - verify(eventHandler).acceptChannel(serverChannel); - } - - public void testAcceptException() throws IOException { - selectionKey.setReadyOps(SelectionKey.OP_ACCEPT); - IOException ioException = new IOException(); - - doThrow(ioException).when(eventHandler).acceptChannel(serverChannel); - - selector.processKey(selectionKey); - - verify(eventHandler).acceptException(serverChannel, ioException); - } - - public void testCleanup() throws IOException { - selector.scheduleForRegistration(serverChannel); - - selector.preSelect(); - - TestSelectionKey key = new TestSelectionKey(0); - key.attach(serverChannel); - when(rawSelector.keys()).thenReturn(new HashSet<>(Collections.singletonList(key))); - - selector.cleanupAndCloseChannels(); - - verify(eventHandler).handleClose(serverChannel); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptorEventHandlerTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptorEventHandlerTests.java deleted file mode 100644 index 48a9e65f00dff..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/AcceptorEventHandlerTests.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.ChannelFactory; -import org.elasticsearch.transport.nio.channel.DoNotRegisterServerChannel; -import org.elasticsearch.transport.nio.channel.NioServerSocketChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.ReadContext; -import org.elasticsearch.transport.nio.channel.WriteContext; -import org.junit.Before; - -import java.io.IOException; -import java.nio.channels.SelectionKey; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class AcceptorEventHandlerTests extends ESTestCase { - - private AcceptorEventHandler handler; - private SocketSelector socketSelector; - private ChannelFactory channelFactory; - private NioServerSocketChannel channel; - private Consumer acceptedChannelCallback; - - @Before - @SuppressWarnings("unchecked") - public void setUpHandler() throws IOException { - channelFactory = mock(ChannelFactory.class); - socketSelector = mock(SocketSelector.class); - acceptedChannelCallback = mock(Consumer.class); - ArrayList selectors = new ArrayList<>(); - selectors.add(socketSelector); - handler = new AcceptorEventHandler(logger, new RoundRobinSupplier<>(selectors.toArray(new SocketSelector[selectors.size()]))); - - AcceptingSelector selector = mock(AcceptingSelector.class); - channel = new DoNotRegisterServerChannel(mock(ServerSocketChannel.class), channelFactory, selector); - channel.setAcceptContext(acceptedChannelCallback); - channel.register(); - } - - public void testHandleRegisterSetsOP_ACCEPTInterest() { - assertEquals(0, channel.getSelectionKey().interestOps()); - - handler.serverChannelRegistered(channel); - - assertEquals(SelectionKey.OP_ACCEPT, channel.getSelectionKey().interestOps()); - } - - public void testHandleAcceptCallsChannelFactory() throws IOException { - NioSocketChannel childChannel = new NioSocketChannel(mock(SocketChannel.class), socketSelector); - when(channelFactory.acceptNioChannel(same(channel), same(socketSelector))).thenReturn(childChannel); - - handler.acceptChannel(channel); - - verify(channelFactory).acceptNioChannel(same(channel), same(socketSelector)); - - } - - @SuppressWarnings("unchecked") - public void testHandleAcceptCallsServerAcceptCallback() throws IOException { - NioSocketChannel childChannel = new NioSocketChannel(mock(SocketChannel.class), socketSelector); - childChannel.setContexts(mock(ReadContext.class), mock(WriteContext.class), mock(BiConsumer.class)); - when(channelFactory.acceptNioChannel(same(channel), same(socketSelector))).thenReturn(childChannel); - - handler.acceptChannel(channel); - - verify(acceptedChannelCallback).accept(childChannel); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/ESSelectorTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/ESSelectorTests.java deleted file mode 100644 index 6459447c1a865..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/ESSelectorTests.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.NioChannel; -import org.junit.Before; - -import java.io.IOException; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; - -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ESSelectorTests extends ESTestCase { - - private ESSelector selector; - private EventHandler handler; - private Selector rawSelector; - - @Before - public void setUp() throws Exception { - super.setUp(); - handler = mock(EventHandler.class); - rawSelector = mock(Selector.class); - selector = new TestSelector(handler, rawSelector); - } - - public void testQueueChannelForClosed() throws IOException { - NioChannel channel = mock(NioChannel.class); - when(channel.getSelector()).thenReturn(selector); - - selector.queueChannelClose(channel); - - selector.singleLoop(); - - verify(handler).handleClose(channel); - } - - public void testSelectorClosedExceptionIsNotCaughtWhileRunning() throws IOException { - boolean closedSelectorExceptionCaught = false; - when(rawSelector.select(anyInt())).thenThrow(new ClosedSelectorException()); - try { - this.selector.singleLoop(); - } catch (ClosedSelectorException e) { - closedSelectorExceptionCaught = true; - } - - assertTrue(closedSelectorExceptionCaught); - } - - public void testIOExceptionWhileSelect() throws IOException { - IOException ioException = new IOException(); - - when(rawSelector.select(anyInt())).thenThrow(ioException); - - this.selector.singleLoop(); - - verify(handler).selectException(ioException); - } - - public void testSelectorClosedIfOpenAndEventLoopNotRunning() throws IOException { - when(rawSelector.isOpen()).thenReturn(true); - selector.close(); - verify(rawSelector).close(); - } - - private static class TestSelector extends ESSelector { - - TestSelector(EventHandler eventHandler, Selector selector) throws IOException { - super(eventHandler, selector); - } - - @Override - void processKey(SelectionKey selectionKey) throws CancelledKeyException { - - } - - @Override - void preSelect() { - - } - - @Override - void cleanup() { - - } - } - -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/InboundChannelBufferTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/InboundChannelBufferTests.java deleted file mode 100644 index 9620f4c9c7660..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/InboundChannelBufferTests.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.test.ESTestCase; - -import java.nio.ByteBuffer; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; - -public class InboundChannelBufferTests extends ESTestCase { - - private static final int PAGE_SIZE = BigArrays.PAGE_SIZE_IN_BYTES; - private final Supplier defaultPageSupplier = () -> - new InboundChannelBuffer.Page(ByteBuffer.allocate(BigArrays.BYTE_PAGE_SIZE), () -> {}); - - public void testNewBufferHasSinglePage() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(PAGE_SIZE, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE, channelBuffer.getRemaining()); - assertEquals(0, channelBuffer.getIndex()); - } - - public void testExpandCapacity() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(PAGE_SIZE, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE, channelBuffer.getRemaining()); - - channelBuffer.ensureCapacity(PAGE_SIZE + 1); - - assertEquals(PAGE_SIZE * 2, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE * 2, channelBuffer.getRemaining()); - } - - public void testExpandCapacityMultiplePages() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(PAGE_SIZE, channelBuffer.getCapacity()); - - int multiple = randomInt(80); - channelBuffer.ensureCapacity(PAGE_SIZE + ((multiple * PAGE_SIZE) - randomInt(500))); - - assertEquals(PAGE_SIZE * (multiple + 1), channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE * (multiple + 1), channelBuffer.getRemaining()); - } - - public void testExpandCapacityRespectsOffset() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(PAGE_SIZE, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE, channelBuffer.getRemaining()); - - int offset = randomInt(300); - - channelBuffer.release(offset); - - assertEquals(PAGE_SIZE - offset, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE - offset, channelBuffer.getRemaining()); - - channelBuffer.ensureCapacity(PAGE_SIZE + 1); - - assertEquals(PAGE_SIZE * 2 - offset, channelBuffer.getCapacity()); - assertEquals(PAGE_SIZE * 2 - offset, channelBuffer.getRemaining()); - } - - public void testIncrementIndex() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(0, channelBuffer.getIndex()); - assertEquals(PAGE_SIZE, channelBuffer.getRemaining()); - - channelBuffer.incrementIndex(10); - - assertEquals(10, channelBuffer.getIndex()); - assertEquals(PAGE_SIZE - 10, channelBuffer.getRemaining()); - } - - public void testIncrementIndexWithOffset() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - assertEquals(0, channelBuffer.getIndex()); - assertEquals(PAGE_SIZE, channelBuffer.getRemaining()); - - channelBuffer.release(10); - assertEquals(PAGE_SIZE - 10, channelBuffer.getRemaining()); - - channelBuffer.incrementIndex(10); - - assertEquals(10, channelBuffer.getIndex()); - assertEquals(PAGE_SIZE - 20, channelBuffer.getRemaining()); - - channelBuffer.release(2); - assertEquals(8, channelBuffer.getIndex()); - assertEquals(PAGE_SIZE - 20, channelBuffer.getRemaining()); - } - - public void testReleaseClosesPages() { - ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); - Supplier supplier = () -> { - AtomicBoolean atomicBoolean = new AtomicBoolean(); - queue.add(atomicBoolean); - return new InboundChannelBuffer.Page(ByteBuffer.allocate(PAGE_SIZE), () -> atomicBoolean.set(true)); - }; - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(supplier); - channelBuffer.ensureCapacity(PAGE_SIZE * 4); - - assertEquals(PAGE_SIZE * 4, channelBuffer.getCapacity()); - assertEquals(4, queue.size()); - - for (AtomicBoolean closedRef : queue) { - assertFalse(closedRef.get()); - } - - channelBuffer.release(2 * PAGE_SIZE); - - assertEquals(PAGE_SIZE * 2, channelBuffer.getCapacity()); - - assertTrue(queue.poll().get()); - assertTrue(queue.poll().get()); - assertFalse(queue.poll().get()); - assertFalse(queue.poll().get()); - } - - public void testClose() { - ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); - Supplier supplier = () -> { - AtomicBoolean atomicBoolean = new AtomicBoolean(); - queue.add(atomicBoolean); - return new InboundChannelBuffer.Page(ByteBuffer.allocate(PAGE_SIZE), () -> atomicBoolean.set(true)); - }; - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(supplier); - channelBuffer.ensureCapacity(PAGE_SIZE * 4); - - assertEquals(4, queue.size()); - - for (AtomicBoolean closedRef : queue) { - assertFalse(closedRef.get()); - } - - channelBuffer.close(); - - for (AtomicBoolean closedRef : queue) { - assertTrue(closedRef.get()); - } - - expectThrows(IllegalStateException.class, () -> channelBuffer.ensureCapacity(1)); - } - - public void testAccessByteBuffers() { - InboundChannelBuffer channelBuffer = new InboundChannelBuffer(defaultPageSupplier); - - int pages = randomInt(50) + 5; - channelBuffer.ensureCapacity(pages * PAGE_SIZE); - - long capacity = channelBuffer.getCapacity(); - - ByteBuffer[] postIndexBuffers = channelBuffer.sliceBuffersFrom(channelBuffer.getIndex()); - int i = 0; - for (ByteBuffer buffer : postIndexBuffers) { - while (buffer.hasRemaining()) { - buffer.put((byte) (i++ % 127)); - } - } - - int indexIncremented = 0; - int bytesReleased = 0; - while (indexIncremented < capacity) { - assertEquals(indexIncremented - bytesReleased, channelBuffer.getIndex()); - - long amountToInc = Math.min(randomInt(2000), channelBuffer.getRemaining()); - ByteBuffer[] postIndexBuffers2 = channelBuffer.sliceBuffersFrom(channelBuffer.getIndex()); - assertEquals((byte) ((channelBuffer.getIndex() + bytesReleased) % 127), postIndexBuffers2[0].get()); - ByteBuffer[] preIndexBuffers = channelBuffer.sliceBuffersTo(channelBuffer.getIndex()); - if (preIndexBuffers.length > 0) { - ByteBuffer preIndexBuffer = preIndexBuffers[preIndexBuffers.length - 1]; - assertEquals((byte) ((channelBuffer.getIndex() + bytesReleased - 1) % 127), preIndexBuffer.get(preIndexBuffer.limit() - 1)); - } - if (randomBoolean()) { - long bytesToRelease = Math.min(randomInt(50), channelBuffer.getIndex()); - channelBuffer.release(bytesToRelease); - bytesReleased += bytesToRelease; - } - channelBuffer.incrementIndex(amountToInc); - indexIncremented += amountToInc; - } - - assertEquals(0, channelBuffer.sliceBuffersFrom(channelBuffer.getIndex()).length); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/NioGroupTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/NioGroupTests.java deleted file mode 100644 index f9b3cbb4e5026..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/NioGroupTests.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.common.CheckedRunnable; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.ChannelFactory; - -import java.io.IOException; -import java.net.InetSocketAddress; - -import static org.elasticsearch.common.util.concurrent.EsExecutors.daemonThreadFactory; -import static org.mockito.Mockito.mock; - -public class NioGroupTests extends ESTestCase { - - private NioGroup nioGroup; - - @Override - public void setUp() throws Exception { - super.setUp(); - nioGroup = new NioGroup(logger, daemonThreadFactory(Settings.EMPTY, "acceptor"), 1, AcceptorEventHandler::new, - daemonThreadFactory(Settings.EMPTY, "selector"), 1, SocketEventHandler::new); - } - - @Override - public void tearDown() throws Exception { - nioGroup.close(); - super.tearDown(); - } - - public void testStartAndClose() throws IOException { - // ctor starts threads. So we are testing that close() stops the threads. Our thread linger checks - // will throw an exception is stop fails - nioGroup.close(); - } - - @SuppressWarnings("unchecked") - public void testCannotOperateAfterClose() throws IOException { - nioGroup.close(); - - IllegalStateException ise = expectThrows(IllegalStateException.class, - () -> nioGroup.bindServerChannel(mock(InetSocketAddress.class), mock(ChannelFactory.class))); - assertEquals("NioGroup is closed.", ise.getMessage()); - ise = expectThrows(IllegalStateException.class, - () -> nioGroup.openChannel(mock(InetSocketAddress.class), mock(ChannelFactory.class))); - assertEquals("NioGroup is closed.", ise.getMessage()); - } - - public void testCanCloseTwice() throws IOException { - nioGroup.close(); - nioGroup.close(); - } - - public void testExceptionAtStartIsHandled() throws IOException { - RuntimeException ex = new RuntimeException(); - CheckedRunnable ctor = () -> new NioGroup(logger, r -> {throw ex;}, 1, - AcceptorEventHandler::new, daemonThreadFactory(Settings.EMPTY, "selector"), 1, SocketEventHandler::new); - RuntimeException runtimeException = expectThrows(RuntimeException.class, ctor::run); - assertSame(ex, runtimeException); - // ctor starts threads. So we are testing that a failure to construct will stop threads. Our thread - // linger checks will throw an exception is stop fails - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java deleted file mode 100644 index a4786b4f3d8e6..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/SimpleNioTransportTests.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.elasticsearch.Version; -import org.elasticsearch.cluster.node.DiscoveryNode; -import org.elasticsearch.common.io.stream.NamedWriteableRegistry; -import org.elasticsearch.common.network.NetworkService; -import org.elasticsearch.common.settings.ClusterSettings; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.transport.TransportAddress; -import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.MockPageCacheRecycler; -import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; -import org.elasticsearch.node.Node; -import org.elasticsearch.test.transport.MockTransportService; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.AbstractSimpleTransportTestCase; -import org.elasticsearch.transport.BindTransportException; -import org.elasticsearch.transport.ConnectTransportException; -import org.elasticsearch.transport.TcpChannel; -import org.elasticsearch.transport.TcpTransport; -import org.elasticsearch.transport.Transport; -import org.elasticsearch.transport.TransportService; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Collections; - -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; - -public class SimpleNioTransportTests extends AbstractSimpleTransportTestCase { - - public static MockTransportService nioFromThreadPool(Settings settings, ThreadPool threadPool, final Version version, - ClusterSettings clusterSettings, boolean doHandshake) { - NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(Collections.emptyList()); - NetworkService networkService = new NetworkService(Collections.emptyList()); - Transport transport = new NioTransport(settings, threadPool, - networkService, BigArrays.NON_RECYCLING_INSTANCE, new MockPageCacheRecycler(settings), namedWriteableRegistry, - new NoneCircuitBreakerService()) { - - @Override - protected Version executeHandshake(DiscoveryNode node, TcpChannel channel, TimeValue timeout) throws IOException, - InterruptedException { - if (doHandshake) { - return super.executeHandshake(node, channel, timeout); - } else { - return version.minimumCompatibilityVersion(); - } - } - - @Override - protected Version getCurrentVersion() { - return version; - } - - @Override - protected SocketEventHandler getSocketEventHandler(Logger logger) { - return new TestingSocketEventHandler(logger); - } - }; - MockTransportService mockTransportService = - MockTransportService.createNewService(Settings.EMPTY, transport, version, threadPool, clusterSettings, Collections.emptySet()); - mockTransportService.start(); - return mockTransportService; - } - - @Override - protected MockTransportService build(Settings settings, Version version, ClusterSettings clusterSettings, boolean doHandshake) { - settings = Settings.builder().put(settings) - .put(TcpTransport.PORT.getKey(), "0") - .build(); - MockTransportService transportService = nioFromThreadPool(settings, threadPool, version, clusterSettings, doHandshake); - transportService.start(); - return transportService; - } - - @Override - protected void closeConnectionChannel(Transport transport, Transport.Connection connection) throws IOException { - @SuppressWarnings("unchecked") - TcpTransport.NodeChannels channels = (TcpTransport.NodeChannels) connection; - TcpChannel.closeChannels(channels.getChannels().subList(0, randomIntBetween(1, channels.getChannels().size())), true); - } - - public void testConnectException() throws UnknownHostException { - try { - serviceA.connectToNode(new DiscoveryNode("C", new TransportAddress(InetAddress.getByName("localhost"), 9876), - emptyMap(), emptySet(),Version.CURRENT)); - fail("Expected ConnectTransportException"); - } catch (ConnectTransportException e) { - assertThat(e.getMessage(), containsString("connect_exception")); - assertThat(e.getMessage(), containsString("[127.0.0.1:9876]")); - Throwable cause = e.getCause(); - assertThat(cause, instanceOf(IOException.class)); - } - } - - public void testBindUnavailableAddress() { - // this is on a lower level since it needs access to the TransportService before it's started - int port = serviceA.boundAddress().publishAddress().getPort(); - Settings settings = Settings.builder() - .put(Node.NODE_NAME_SETTING.getKey(), "foobar") - .put(TransportService.TRACE_LOG_INCLUDE_SETTING.getKey(), "") - .put(TransportService.TRACE_LOG_EXCLUDE_SETTING.getKey(), "NOTHING") - .put("transport.tcp.port", port) - .build(); - ClusterSettings clusterSettings = new ClusterSettings(settings, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - BindTransportException bindTransportException = expectThrows(BindTransportException.class, () -> { - MockTransportService transportService = nioFromThreadPool(settings, threadPool, Version.CURRENT, clusterSettings, true); - try { - transportService.start(); - } finally { - transportService.stop(); - transportService.close(); - } - }); - assertEquals("Failed to bind to ["+ port + "]", bindTransportException.getMessage()); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketEventHandlerTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketEventHandlerTests.java deleted file mode 100644 index b547273d30925..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketEventHandlerTests.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.DoNotRegisterChannel; -import org.elasticsearch.transport.nio.channel.NioChannel; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.ReadContext; -import org.elasticsearch.transport.nio.channel.SelectionKeyUtils; -import org.elasticsearch.transport.nio.channel.TcpWriteContext; -import org.junit.Before; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.SelectionKey; -import java.nio.channels.SocketChannel; -import java.util.function.BiConsumer; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class SocketEventHandlerTests extends ESTestCase { - - private BiConsumer exceptionHandler; - - private SocketEventHandler handler; - private NioSocketChannel channel; - private ReadContext readContext; - private SocketChannel rawChannel; - - @Before - @SuppressWarnings("unchecked") - public void setUpHandler() throws IOException { - exceptionHandler = mock(BiConsumer.class); - SocketSelector socketSelector = mock(SocketSelector.class); - handler = new SocketEventHandler(logger); - rawChannel = mock(SocketChannel.class); - channel = new DoNotRegisterChannel(rawChannel, socketSelector); - readContext = mock(ReadContext.class); - when(rawChannel.finishConnect()).thenReturn(true); - - channel.setContexts(readContext, new TcpWriteContext(channel), exceptionHandler); - channel.register(); - channel.finishConnect(); - - when(socketSelector.isOnCurrentThread()).thenReturn(true); - } - - public void testRegisterAddsOP_CONNECTAndOP_READInterest() throws IOException { - handler.handleRegistration(channel); - assertEquals(SelectionKey.OP_READ | SelectionKey.OP_CONNECT, channel.getSelectionKey().interestOps()); - } - - public void testRegistrationExceptionCallsExceptionHandler() throws IOException { - CancelledKeyException exception = new CancelledKeyException(); - handler.registrationException(channel, exception); - verify(exceptionHandler).accept(channel, exception); - } - - public void testConnectRemovesOP_CONNECTInterest() throws IOException { - SelectionKeyUtils.setConnectAndReadInterested(channel); - handler.handleConnect(channel); - assertEquals(SelectionKey.OP_READ, channel.getSelectionKey().interestOps()); - } - - public void testConnectExceptionCallsExceptionHandler() throws IOException { - IOException exception = new IOException(); - handler.connectException(channel, exception); - verify(exceptionHandler).accept(channel, exception); - } - - public void testHandleReadDelegatesToReadContext() throws IOException { - when(readContext.read()).thenReturn(1); - - handler.handleRead(channel); - - verify(readContext).read(); - } - - public void testHandleReadMarksChannelForCloseIfPeerClosed() throws IOException { - NioSocketChannel nioSocketChannel = mock(NioSocketChannel.class); - when(nioSocketChannel.getReadContext()).thenReturn(readContext); - when(readContext.read()).thenReturn(-1); - - handler.handleRead(nioSocketChannel); - - verify(nioSocketChannel).closeFromSelector(); - } - - public void testReadExceptionCallsExceptionHandler() throws IOException { - IOException exception = new IOException(); - handler.readException(channel, exception); - verify(exceptionHandler).accept(channel, exception); - } - - @SuppressWarnings("unchecked") - public void testHandleWriteWithCompleteFlushRemovesOP_WRITEInterest() throws IOException { - SelectionKey selectionKey = channel.getSelectionKey(); - setWriteAndRead(channel); - assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, selectionKey.interestOps()); - - BytesArray bytesArray = new BytesArray(new byte[1]); - channel.getWriteContext().queueWriteOperations(new WriteOperation(channel, bytesArray, mock(ActionListener.class))); - - when(rawChannel.write(ByteBuffer.wrap(bytesArray.array()))).thenReturn(1); - handler.handleWrite(channel); - - assertEquals(SelectionKey.OP_READ, selectionKey.interestOps()); - } - - @SuppressWarnings("unchecked") - public void testHandleWriteWithInCompleteFlushLeavesOP_WRITEInterest() throws IOException { - SelectionKey selectionKey = channel.getSelectionKey(); - setWriteAndRead(channel); - assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, selectionKey.interestOps()); - - BytesArray bytesArray = new BytesArray(new byte[1]); - channel.getWriteContext().queueWriteOperations(new WriteOperation(channel, bytesArray, mock(ActionListener.class))); - - when(rawChannel.write(ByteBuffer.wrap(bytesArray.array()))).thenReturn(0); - handler.handleWrite(channel); - - assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, selectionKey.interestOps()); - } - - public void testHandleWriteWithNoOpsRemovesOP_WRITEInterest() throws IOException { - SelectionKey selectionKey = channel.getSelectionKey(); - setWriteAndRead(channel); - assertEquals(SelectionKey.OP_READ | SelectionKey.OP_WRITE, channel.getSelectionKey().interestOps()); - - handler.handleWrite(channel); - - assertEquals(SelectionKey.OP_READ, selectionKey.interestOps()); - } - - private void setWriteAndRead(NioChannel channel) { - SelectionKeyUtils.setConnectAndReadInterested(channel); - SelectionKeyUtils.removeConnectInterested(channel); - SelectionKeyUtils.setWriteInterested(channel); - } - - public void testWriteExceptionCallsExceptionHandler() throws IOException { - IOException exception = new IOException(); - handler.writeException(channel, exception); - verify(exceptionHandler).accept(channel, exception); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketSelectorTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketSelectorTests.java deleted file mode 100644 index 1b67d9d099b27..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/SocketSelectorTests.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.elasticsearch.transport.nio.channel.WriteContext; -import org.elasticsearch.transport.nio.utils.TestSelectionKey; -import org.junit.Before; - -import java.io.IOException; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.ClosedSelectorException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.util.Collections; -import java.util.HashSet; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class SocketSelectorTests extends ESTestCase { - - private SocketSelector socketSelector; - private SocketEventHandler eventHandler; - private NioSocketChannel channel; - private TestSelectionKey selectionKey; - private WriteContext writeContext; - private ActionListener listener; - private BytesReference bufferReference = new BytesArray(new byte[1]); - private Selector rawSelector; - - @Before - @SuppressWarnings("unchecked") - public void setUp() throws Exception { - super.setUp(); - eventHandler = mock(SocketEventHandler.class); - channel = mock(NioSocketChannel.class); - writeContext = mock(WriteContext.class); - listener = mock(ActionListener.class); - selectionKey = new TestSelectionKey(0); - selectionKey.attach(channel); - rawSelector = mock(Selector.class); - - this.socketSelector = new SocketSelector(eventHandler, rawSelector); - this.socketSelector.setThread(); - - when(channel.isOpen()).thenReturn(true); - when(channel.getSelectionKey()).thenReturn(selectionKey); - when(channel.getWriteContext()).thenReturn(writeContext); - when(channel.isConnectComplete()).thenReturn(true); - when(channel.getSelector()).thenReturn(socketSelector); - } - - public void testRegisterChannel() throws Exception { - socketSelector.scheduleForRegistration(channel); - - socketSelector.preSelect(); - - verify(eventHandler).handleRegistration(channel); - } - - public void testClosedChannelWillNotBeRegistered() throws Exception { - when(channel.isOpen()).thenReturn(false); - socketSelector.scheduleForRegistration(channel); - - socketSelector.preSelect(); - - verify(eventHandler).registrationException(same(channel), any(ClosedChannelException.class)); - verify(channel, times(0)).finishConnect(); - } - - public void testRegisterChannelFailsDueToException() throws Exception { - socketSelector.scheduleForRegistration(channel); - - ClosedChannelException closedChannelException = new ClosedChannelException(); - doThrow(closedChannelException).when(channel).register(); - - socketSelector.preSelect(); - - verify(eventHandler).registrationException(channel, closedChannelException); - verify(channel, times(0)).finishConnect(); - } - - public void testSuccessfullyRegisterChannelWillConnect() throws Exception { - socketSelector.scheduleForRegistration(channel); - - when(channel.finishConnect()).thenReturn(true); - - socketSelector.preSelect(); - - verify(eventHandler).handleConnect(channel); - } - - public void testConnectIncompleteWillNotNotify() throws Exception { - socketSelector.scheduleForRegistration(channel); - - when(channel.finishConnect()).thenReturn(false); - - socketSelector.preSelect(); - - verify(eventHandler, times(0)).handleConnect(channel); - } - - public void testQueueWriteWhenNotRunning() throws Exception { - socketSelector.close(); - - socketSelector.queueWrite(new WriteOperation(channel, bufferReference, listener)); - - verify(listener).onFailure(any(ClosedSelectorException.class)); - } - - public void testQueueWriteChannelIsNoLongerWritable() throws Exception { - WriteOperation writeOperation = new WriteOperation(channel, bufferReference, listener); - socketSelector.queueWrite(writeOperation); - - when(channel.isWritable()).thenReturn(false); - socketSelector.preSelect(); - - verify(writeContext, times(0)).queueWriteOperations(writeOperation); - verify(listener).onFailure(any(ClosedChannelException.class)); - } - - public void testQueueWriteSelectionKeyThrowsException() throws Exception { - SelectionKey selectionKey = mock(SelectionKey.class); - - WriteOperation writeOperation = new WriteOperation(channel, bufferReference, listener); - CancelledKeyException cancelledKeyException = new CancelledKeyException(); - socketSelector.queueWrite(writeOperation); - - when(channel.isWritable()).thenReturn(true); - when(channel.getSelectionKey()).thenReturn(selectionKey); - when(selectionKey.interestOps(anyInt())).thenThrow(cancelledKeyException); - socketSelector.preSelect(); - - verify(writeContext, times(0)).queueWriteOperations(writeOperation); - verify(listener).onFailure(cancelledKeyException); - } - - public void testQueueWriteSuccessful() throws Exception { - WriteOperation writeOperation = new WriteOperation(channel, bufferReference, listener); - socketSelector.queueWrite(writeOperation); - - assertTrue((selectionKey.interestOps() & SelectionKey.OP_WRITE) == 0); - - when(channel.isWritable()).thenReturn(true); - socketSelector.preSelect(); - - verify(writeContext).queueWriteOperations(writeOperation); - assertTrue((selectionKey.interestOps() & SelectionKey.OP_WRITE) != 0); - } - - public void testQueueDirectlyInChannelBufferSuccessful() throws Exception { - WriteOperation writeOperation = new WriteOperation(channel, bufferReference, listener); - - assertTrue((selectionKey.interestOps() & SelectionKey.OP_WRITE) == 0); - - when(channel.isWritable()).thenReturn(true); - socketSelector.queueWriteInChannelBuffer(writeOperation); - - verify(writeContext).queueWriteOperations(writeOperation); - assertTrue((selectionKey.interestOps() & SelectionKey.OP_WRITE) != 0); - } - - public void testQueueDirectlyInChannelBufferSelectionKeyThrowsException() throws Exception { - SelectionKey selectionKey = mock(SelectionKey.class); - - WriteOperation writeOperation = new WriteOperation(channel, bufferReference, listener); - CancelledKeyException cancelledKeyException = new CancelledKeyException(); - - when(channel.isWritable()).thenReturn(true); - when(channel.getSelectionKey()).thenReturn(selectionKey); - when(selectionKey.interestOps(anyInt())).thenThrow(cancelledKeyException); - socketSelector.queueWriteInChannelBuffer(writeOperation); - - verify(writeContext, times(0)).queueWriteOperations(writeOperation); - verify(listener).onFailure(cancelledKeyException); - } - - public void testConnectEvent() throws Exception { - selectionKey.setReadyOps(SelectionKey.OP_CONNECT); - - when(channel.finishConnect()).thenReturn(true); - socketSelector.processKey(selectionKey); - - verify(eventHandler).handleConnect(channel); - } - - public void testConnectEventFinishUnsuccessful() throws Exception { - selectionKey.setReadyOps(SelectionKey.OP_CONNECT); - - when(channel.finishConnect()).thenReturn(false); - socketSelector.processKey(selectionKey); - - verify(eventHandler, times(0)).handleConnect(channel); - } - - public void testConnectEventFinishThrowException() throws Exception { - IOException ioException = new IOException(); - - selectionKey.setReadyOps(SelectionKey.OP_CONNECT); - - when(channel.finishConnect()).thenThrow(ioException); - socketSelector.processKey(selectionKey); - - verify(eventHandler, times(0)).handleConnect(channel); - verify(eventHandler).connectException(channel, ioException); - } - - public void testWillNotConsiderWriteOrReadUntilConnectionComplete() throws Exception { - IOException ioException = new IOException(); - - selectionKey.setReadyOps(SelectionKey.OP_WRITE | SelectionKey.OP_READ); - - doThrow(ioException).when(eventHandler).handleWrite(channel); - - when(channel.isConnectComplete()).thenReturn(false); - socketSelector.processKey(selectionKey); - - verify(eventHandler, times(0)).handleWrite(channel); - verify(eventHandler, times(0)).handleRead(channel); - } - - public void testSuccessfulWriteEvent() throws Exception { - selectionKey.setReadyOps(SelectionKey.OP_WRITE); - - socketSelector.processKey(selectionKey); - - verify(eventHandler).handleWrite(channel); - } - - public void testWriteEventWithException() throws Exception { - IOException ioException = new IOException(); - - selectionKey.setReadyOps(SelectionKey.OP_WRITE); - - doThrow(ioException).when(eventHandler).handleWrite(channel); - - socketSelector.processKey(selectionKey); - - verify(eventHandler).writeException(channel, ioException); - } - - public void testSuccessfulReadEvent() throws Exception { - selectionKey.setReadyOps(SelectionKey.OP_READ); - - socketSelector.processKey(selectionKey); - - verify(eventHandler).handleRead(channel); - } - - public void testReadEventWithException() throws Exception { - IOException ioException = new IOException(); - - selectionKey.setReadyOps(SelectionKey.OP_READ); - - doThrow(ioException).when(eventHandler).handleRead(channel); - - socketSelector.processKey(selectionKey); - - verify(eventHandler).readException(channel, ioException); - } - - public void testCleanup() throws Exception { - NioSocketChannel unRegisteredChannel = mock(NioSocketChannel.class); - - socketSelector.scheduleForRegistration(channel); - - socketSelector.preSelect(); - - socketSelector.queueWrite(new WriteOperation(mock(NioSocketChannel.class), new BytesArray(new byte[1]), listener)); - socketSelector.scheduleForRegistration(unRegisteredChannel); - - TestSelectionKey testSelectionKey = new TestSelectionKey(0); - testSelectionKey.attach(channel); - when(rawSelector.keys()).thenReturn(new HashSet<>(Collections.singletonList(testSelectionKey))); - - socketSelector.cleanupAndCloseChannels(); - - verify(listener).onFailure(any(ClosedSelectorException.class)); - verify(eventHandler).handleClose(channel); - verify(eventHandler).handleClose(unRegisteredChannel); - } - - public void testExecuteListenerWillHandleException() throws Exception { - RuntimeException exception = new RuntimeException(); - doThrow(exception).when(listener).onResponse(null); - - socketSelector.executeListener(listener, null); - - verify(eventHandler).listenerException(listener, exception); - } - - public void testExecuteFailedListenerWillHandleException() throws Exception { - IOException ioException = new IOException(); - RuntimeException exception = new RuntimeException(); - doThrow(exception).when(listener).onFailure(ioException); - - socketSelector.executeFailedListener(listener, ioException); - - verify(eventHandler).listenerException(listener, exception); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/TestingSocketEventHandler.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/TestingSocketEventHandler.java deleted file mode 100644 index a3cb92ad37663..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/TestingSocketEventHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.apache.logging.log4j.Logger; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; - -import java.io.IOException; -import java.util.Collections; -import java.util.Set; -import java.util.WeakHashMap; - -public class TestingSocketEventHandler extends SocketEventHandler { - - public TestingSocketEventHandler(Logger logger) { - super(logger); - } - - private Set hasConnectedMap = Collections.newSetFromMap(new WeakHashMap<>()); - - public void handleConnect(NioSocketChannel channel) { - assert hasConnectedMap.contains(channel) == false : "handleConnect should only be called once per channel"; - hasConnectedMap.add(channel); - super.handleConnect(channel); - } - - private Set hasConnectExceptionMap = Collections.newSetFromMap(new WeakHashMap<>()); - - public void connectException(NioSocketChannel channel, Exception e) { - assert hasConnectExceptionMap.contains(channel) == false : "connectException should only called at maximum once per channel"; - hasConnectExceptionMap.add(channel); - super.connectException(channel, e); - } - - public void handleRead(NioSocketChannel channel) throws IOException { - super.handleRead(channel); - } - - public void readException(NioSocketChannel channel, Exception e) { - super.readException(channel, e); - } - - public void handleWrite(NioSocketChannel channel) throws IOException { - super.handleWrite(channel); - } - - public void writeException(NioSocketChannel channel, Exception e) { - super.writeException(channel, e); - } - -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/WriteOperationTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/WriteOperationTests.java deleted file mode 100644 index 0085a9b204a31..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/WriteOperationTests.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.CompositeBytesReference; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.channel.NioSocketChannel; -import org.junit.Before; -import org.mockito.ArgumentCaptor; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.List; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class WriteOperationTests extends ESTestCase { - - private NioSocketChannel channel; - private ActionListener listener; - - @Before - @SuppressWarnings("unchecked") - public void setFields() { - channel = mock(NioSocketChannel.class); - listener = mock(ActionListener.class); - - } - - public void testFlush() throws IOException { - WriteOperation writeOp = new WriteOperation(channel, new BytesArray(new byte[10]), listener); - - - when(channel.write(any(ByteBuffer[].class))).thenReturn(10); - - writeOp.flush(); - - assertTrue(writeOp.isFullyFlushed()); - } - - public void testPartialFlush() throws IOException { - WriteOperation writeOp = new WriteOperation(channel, new BytesArray(new byte[10]), listener); - - when(channel.write(any(ByteBuffer[].class))).thenReturn(5); - - writeOp.flush(); - - assertFalse(writeOp.isFullyFlushed()); - } - - public void testMultipleFlushesWithCompositeBuffer() throws IOException { - BytesArray bytesReference1 = new BytesArray(new byte[10]); - BytesArray bytesReference2 = new BytesArray(new byte[15]); - BytesArray bytesReference3 = new BytesArray(new byte[3]); - CompositeBytesReference bytesReference = new CompositeBytesReference(bytesReference1, bytesReference2, bytesReference3); - WriteOperation writeOp = new WriteOperation(channel, bytesReference, listener); - - ArgumentCaptor buffersCaptor = ArgumentCaptor.forClass(ByteBuffer[].class); - - when(channel.write(buffersCaptor.capture())).thenReturn(5) - .thenReturn(5) - .thenReturn(2) - .thenReturn(15) - .thenReturn(1); - - writeOp.flush(); - assertFalse(writeOp.isFullyFlushed()); - writeOp.flush(); - assertFalse(writeOp.isFullyFlushed()); - writeOp.flush(); - assertFalse(writeOp.isFullyFlushed()); - writeOp.flush(); - assertFalse(writeOp.isFullyFlushed()); - writeOp.flush(); - assertTrue(writeOp.isFullyFlushed()); - - List values = buffersCaptor.getAllValues(); - ByteBuffer[] byteBuffers = values.get(0); - assertEquals(3, byteBuffers.length); - assertEquals(10, byteBuffers[0].remaining()); - - byteBuffers = values.get(1); - assertEquals(3, byteBuffers.length); - assertEquals(5, byteBuffers[0].remaining()); - - byteBuffers = values.get(2); - assertEquals(2, byteBuffers.length); - assertEquals(15, byteBuffers[0].remaining()); - - byteBuffers = values.get(3); - assertEquals(2, byteBuffers.length); - assertEquals(13, byteBuffers[0].remaining()); - - byteBuffers = values.get(4); - assertEquals(1, byteBuffers.length); - assertEquals(1, byteBuffers[0].remaining()); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/ChannelFactoryTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/ChannelFactoryTests.java deleted file mode 100644 index 2f4c619dcb237..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/ChannelFactoryTests.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.core.internal.io.IOUtils; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.AcceptingSelector; -import org.elasticsearch.transport.nio.SocketSelector; -import org.junit.After; -import org.junit.Before; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.function.BiConsumer; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ChannelFactoryTests extends ESTestCase { - - private ChannelFactory channelFactory; - private ChannelFactory.RawChannelFactory rawChannelFactory; - private SocketChannel rawChannel; - private ServerSocketChannel rawServerChannel; - private SocketSelector socketSelector; - private AcceptingSelector acceptingSelector; - - @Before - @SuppressWarnings("unchecked") - public void setupFactory() throws IOException { - rawChannelFactory = mock(TcpChannelFactory.RawChannelFactory.class); - channelFactory = new TestChannelFactory(rawChannelFactory); - socketSelector = mock(SocketSelector.class); - acceptingSelector = mock(AcceptingSelector.class); - rawChannel = SocketChannel.open(); - rawServerChannel = ServerSocketChannel.open(); - } - - @After - public void ensureClosed() throws IOException { - IOUtils.closeWhileHandlingException(rawChannel); - IOUtils.closeWhileHandlingException(rawServerChannel); - } - - public void testAcceptChannel() throws IOException { - NioServerSocketChannel serverChannel = mock(NioServerSocketChannel.class); - when(rawChannelFactory.acceptNioChannel(serverChannel)).thenReturn(rawChannel); - - NioSocketChannel channel = channelFactory.acceptNioChannel(serverChannel, socketSelector); - - verify(socketSelector).scheduleForRegistration(channel); - - assertEquals(socketSelector, channel.getSelector()); - assertEquals(rawChannel, channel.getRawChannel()); - } - - public void testAcceptedChannelRejected() throws IOException { - NioServerSocketChannel serverChannel = mock(NioServerSocketChannel.class); - when(rawChannelFactory.acceptNioChannel(serverChannel)).thenReturn(rawChannel); - doThrow(new IllegalStateException()).when(socketSelector).scheduleForRegistration(any()); - - expectThrows(IllegalStateException.class, () -> channelFactory.acceptNioChannel(serverChannel, socketSelector)); - - assertFalse(rawChannel.isOpen()); - } - - public void testOpenChannel() throws IOException { - InetSocketAddress address = mock(InetSocketAddress.class); - when(rawChannelFactory.openNioChannel(same(address))).thenReturn(rawChannel); - - NioSocketChannel channel = channelFactory.openNioChannel(address, socketSelector); - - verify(socketSelector).scheduleForRegistration(channel); - - assertEquals(socketSelector, channel.getSelector()); - assertEquals(rawChannel, channel.getRawChannel()); - } - - public void testOpenedChannelRejected() throws IOException { - InetSocketAddress address = mock(InetSocketAddress.class); - when(rawChannelFactory.openNioChannel(same(address))).thenReturn(rawChannel); - doThrow(new IllegalStateException()).when(socketSelector).scheduleForRegistration(any()); - - expectThrows(IllegalStateException.class, () -> channelFactory.openNioChannel(address, socketSelector)); - - assertFalse(rawChannel.isOpen()); - } - - public void testOpenServerChannel() throws IOException { - InetSocketAddress address = mock(InetSocketAddress.class); - when(rawChannelFactory.openNioServerSocketChannel(same(address))).thenReturn(rawServerChannel); - - NioServerSocketChannel channel = channelFactory.openNioServerSocketChannel(address, acceptingSelector); - - verify(acceptingSelector).scheduleForRegistration(channel); - - assertEquals(acceptingSelector, channel.getSelector()); - assertEquals(rawServerChannel, channel.getRawChannel()); - } - - public void testOpenedServerChannelRejected() throws IOException { - InetSocketAddress address = mock(InetSocketAddress.class); - when(rawChannelFactory.openNioServerSocketChannel(same(address))).thenReturn(rawServerChannel); - doThrow(new IllegalStateException()).when(acceptingSelector).scheduleForRegistration(any()); - - expectThrows(IllegalStateException.class, () -> channelFactory.openNioServerSocketChannel(address, acceptingSelector)); - - assertFalse(rawServerChannel.isOpen()); - } - - private static class TestChannelFactory extends ChannelFactory { - - TestChannelFactory(RawChannelFactory rawChannelFactory) { - super(rawChannelFactory); - } - - @SuppressWarnings("unchecked") - @Override - public NioSocketChannel createChannel(SocketSelector selector, SocketChannel channel) throws IOException { - NioSocketChannel nioSocketChannel = new NioSocketChannel(channel, selector); - nioSocketChannel.setContexts(mock(ReadContext.class), mock(WriteContext.class), mock(BiConsumer.class)); - return nioSocketChannel; - } - - @Override - public NioServerSocketChannel createServerChannel(AcceptingSelector selector, ServerSocketChannel channel) throws IOException { - return new NioServerSocketChannel(channel, this, selector); - } - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterChannel.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterChannel.java deleted file mode 100644 index f1f6ffb9f1138..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterChannel.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.transport.nio.SocketSelector; -import org.elasticsearch.transport.nio.utils.TestSelectionKey; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.SocketChannel; - -public class DoNotRegisterChannel extends NioSocketChannel { - - public DoNotRegisterChannel(SocketChannel socketChannel, SocketSelector selector) throws IOException { - super(socketChannel, selector); - } - - @Override - public void register() throws ClosedChannelException { - setSelectionKey(new TestSelectionKey(0)); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterServerChannel.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterServerChannel.java deleted file mode 100644 index 073f2acf384da..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/DoNotRegisterServerChannel.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.transport.nio.AcceptingSelector; -import org.elasticsearch.transport.nio.utils.TestSelectionKey; - -import java.io.IOException; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.ServerSocketChannel; - -public class DoNotRegisterServerChannel extends NioServerSocketChannel { - - public DoNotRegisterServerChannel(ServerSocketChannel channel, ChannelFactory channelFactory, AcceptingSelector selector) - throws IOException { - super(channel, channelFactory, selector); - } - - @Override - public void register() throws ClosedChannelException { - setSelectionKey(new TestSelectionKey(0)); - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannelTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannelTests.java deleted file mode 100644 index ba5d47fe8f8dd..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioServerSocketChannelTests.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.PlainActionFuture; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.AcceptingSelector; -import org.elasticsearch.transport.nio.AcceptorEventHandler; -import org.junit.After; -import org.junit.Before; - -import java.io.IOException; -import java.nio.channels.ServerSocketChannel; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; - -import static org.mockito.Mockito.mock; - -public class NioServerSocketChannelTests extends ESTestCase { - - private AcceptingSelector selector; - private AtomicBoolean closedRawChannel; - private Thread thread; - - @Before - @SuppressWarnings("unchecked") - public void setSelector() throws IOException { - selector = new AcceptingSelector(new AcceptorEventHandler(logger, mock(Supplier.class))); - thread = new Thread(selector::runLoop); - closedRawChannel = new AtomicBoolean(false); - thread.start(); - selector.isRunningFuture().actionGet(); - } - - @After - public void stopSelector() throws IOException, InterruptedException { - selector.close(); - thread.join(); - } - - public void testClose() throws Exception { - AtomicBoolean isClosed = new AtomicBoolean(false); - CountDownLatch latch = new CountDownLatch(1); - - NioChannel channel = new DoNotCloseServerChannel("nio", mock(ServerSocketChannel.class), mock(ChannelFactory.class), selector); - - channel.addCloseListener(new ActionListener() { - @Override - public void onResponse(Void o) { - isClosed.set(true); - latch.countDown(); - } - - @Override - public void onFailure(Exception e) { - isClosed.set(true); - latch.countDown(); - } - }); - - assertTrue(channel.isOpen()); - assertFalse(closedRawChannel.get()); - assertFalse(isClosed.get()); - - PlainActionFuture closeFuture = PlainActionFuture.newFuture(); - channel.addCloseListener(closeFuture); - channel.close(); - closeFuture.actionGet(); - - - assertTrue(closedRawChannel.get()); - assertFalse(channel.isOpen()); - latch.await(); - assertTrue(isClosed.get()); - } - - private class DoNotCloseServerChannel extends DoNotRegisterServerChannel { - - private DoNotCloseServerChannel(String profile, ServerSocketChannel channel, ChannelFactory channelFactory, - AcceptingSelector selector) throws IOException { - super(channel, channelFactory, selector); - } - - @Override - void closeRawChannel() throws IOException { - closedRawChannel.set(true); - } - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioSocketChannelTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioSocketChannelTests.java deleted file mode 100644 index fecaf8fe9701e..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/NioSocketChannelTests.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.action.support.PlainActionFuture; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.SocketEventHandler; -import org.elasticsearch.transport.nio.SocketSelector; -import org.junit.After; -import org.junit.Before; - -import java.io.IOException; -import java.net.ConnectException; -import java.nio.channels.SocketChannel; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class NioSocketChannelTests extends ESTestCase { - - private SocketSelector selector; - private AtomicBoolean closedRawChannel; - private Thread thread; - - @Before - @SuppressWarnings("unchecked") - public void startSelector() throws IOException { - selector = new SocketSelector(new SocketEventHandler(logger)); - thread = new Thread(selector::runLoop); - closedRawChannel = new AtomicBoolean(false); - thread.start(); - selector.isRunningFuture().actionGet(); - } - - @After - public void stopSelector() throws IOException, InterruptedException { - selector.close(); - thread.join(); - } - - @SuppressWarnings("unchecked") - public void testClose() throws Exception { - AtomicBoolean isClosed = new AtomicBoolean(false); - CountDownLatch latch = new CountDownLatch(1); - - NioSocketChannel socketChannel = new DoNotCloseChannel(mock(SocketChannel.class), selector); - socketChannel.setContexts(mock(ReadContext.class), mock(WriteContext.class), mock(BiConsumer.class)); - socketChannel.addCloseListener(new ActionListener() { - @Override - public void onResponse(Void o) { - isClosed.set(true); - latch.countDown(); - } - @Override - public void onFailure(Exception e) { - isClosed.set(true); - latch.countDown(); - } - }); - - assertTrue(socketChannel.isOpen()); - assertFalse(closedRawChannel.get()); - assertFalse(isClosed.get()); - - PlainActionFuture closeFuture = PlainActionFuture.newFuture(); - socketChannel.addCloseListener(closeFuture); - socketChannel.close(); - closeFuture.actionGet(); - - assertTrue(closedRawChannel.get()); - assertFalse(socketChannel.isOpen()); - latch.await(); - assertTrue(isClosed.get()); - } - - @SuppressWarnings("unchecked") - public void testConnectSucceeds() throws Exception { - SocketChannel rawChannel = mock(SocketChannel.class); - when(rawChannel.finishConnect()).thenReturn(true); - NioSocketChannel socketChannel = new DoNotCloseChannel(rawChannel, selector); - socketChannel.setContexts(mock(ReadContext.class), mock(WriteContext.class), mock(BiConsumer.class)); - selector.scheduleForRegistration(socketChannel); - - PlainActionFuture connectFuture = PlainActionFuture.newFuture(); - socketChannel.addConnectListener(connectFuture); - connectFuture.get(100, TimeUnit.SECONDS); - - assertTrue(socketChannel.isConnectComplete()); - assertTrue(socketChannel.isOpen()); - assertFalse(closedRawChannel.get()); - } - - @SuppressWarnings("unchecked") - public void testConnectFails() throws Exception { - SocketChannel rawChannel = mock(SocketChannel.class); - when(rawChannel.finishConnect()).thenThrow(new ConnectException()); - NioSocketChannel socketChannel = new DoNotCloseChannel(rawChannel, selector); - socketChannel.setContexts(mock(ReadContext.class), mock(WriteContext.class), mock(BiConsumer.class)); - selector.scheduleForRegistration(socketChannel); - - PlainActionFuture connectFuture = PlainActionFuture.newFuture(); - socketChannel.addConnectListener(connectFuture); - ExecutionException e = expectThrows(ExecutionException.class, () -> connectFuture.get(100, TimeUnit.SECONDS)); - assertTrue(e.getCause() instanceof IOException); - - assertFalse(socketChannel.isConnectComplete()); - // Even if connection fails the channel is 'open' until close() is called - assertTrue(socketChannel.isOpen()); - } - - private class DoNotCloseChannel extends DoNotRegisterChannel { - - private DoNotCloseChannel(SocketChannel channel, SocketSelector selector) throws IOException { - super(channel, selector); - } - - @Override - void closeRawChannel() throws IOException { - closedRawChannel.set(true); - } - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoderTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoderTests.java deleted file mode 100644 index 450016b1dc3b8..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpFrameDecoderTests.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.io.stream.BytesStreamOutput; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.TcpTransport; - -import java.io.IOException; -import java.io.StreamCorruptedException; - -import static org.hamcrest.Matchers.instanceOf; - -public class TcpFrameDecoderTests extends ESTestCase { - - private TcpFrameDecoder frameDecoder = new TcpFrameDecoder(); - - public void testDefaultExceptedMessageLengthIsNegative1() { - assertEquals(-1, frameDecoder.expectedMessageLength()); - } - - public void testDecodeWithIncompleteHeader() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.write(1); - streamOutput.write(1); - - assertNull(frameDecoder.decode(streamOutput.bytes())); - assertEquals(-1, frameDecoder.expectedMessageLength()); - } - - public void testDecodePing() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.writeInt(-1); - - BytesReference message = frameDecoder.decode(streamOutput.bytes()); - - assertEquals(-1, frameDecoder.expectedMessageLength()); - assertEquals(streamOutput.bytes(), message); - } - - public void testDecodePingWithStartOfSecondMessage() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.writeInt(-1); - streamOutput.write('E'); - streamOutput.write('S'); - - BytesReference message = frameDecoder.decode(streamOutput.bytes()); - - assertEquals(6, message.length()); - assertEquals(streamOutput.bytes().slice(0, 6), message); - } - - public void testDecodeMessage() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.writeInt(2); - streamOutput.write('M'); - streamOutput.write('A'); - - BytesReference message = frameDecoder.decode(streamOutput.bytes()); - - assertEquals(-1, frameDecoder.expectedMessageLength()); - assertEquals(streamOutput.bytes(), message); - } - - public void testDecodeIncompleteMessage() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.writeInt(3); - streamOutput.write('M'); - streamOutput.write('A'); - - BytesReference message = frameDecoder.decode(streamOutput.bytes()); - - assertEquals(9, frameDecoder.expectedMessageLength()); - assertNull(message); - } - - public void testInvalidLength() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('S'); - streamOutput.writeInt(-2); - streamOutput.write('M'); - streamOutput.write('A'); - - try { - frameDecoder.decode(streamOutput.bytes()); - fail("Expected exception"); - } catch (Exception ex) { - assertThat(ex, instanceOf(StreamCorruptedException.class)); - assertEquals("invalid data length: -2", ex.getMessage()); - } - } - - public void testInvalidHeader() throws IOException { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - streamOutput.write('E'); - streamOutput.write('C'); - byte byte1 = randomByte(); - byte byte2 = randomByte(); - streamOutput.write(byte1); - streamOutput.write(byte2); - streamOutput.write(randomByte()); - streamOutput.write(randomByte()); - streamOutput.write(randomByte()); - - try { - frameDecoder.decode(streamOutput.bytes()); - fail("Expected exception"); - } catch (Exception ex) { - assertThat(ex, instanceOf(StreamCorruptedException.class)); - String expected = "invalid internal transport message format, got (45,43," - + Integer.toHexString(byte1 & 0xFF) + "," - + Integer.toHexString(byte2 & 0xFF) + ")"; - assertEquals(expected, ex.getMessage()); - } - } - - public void testHTTPHeader() throws IOException { - String[] httpHeaders = {"GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS", "PATCH", "TRACE"}; - - for (String httpHeader : httpHeaders) { - BytesStreamOutput streamOutput = new BytesStreamOutput(1 << 14); - - for (char c : httpHeader.toCharArray()) { - streamOutput.write((byte) c); - } - streamOutput.write(new byte[6]); - - try { - BytesReference bytes = streamOutput.bytes(); - frameDecoder.decode(bytes); - fail("Expected exception"); - } catch (Exception ex) { - assertThat(ex, instanceOf(TcpTransport.HttpOnTransportException.class)); - assertEquals("This is not a HTTP port", ex.getMessage()); - } - } - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpReadContextTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpReadContextTests.java deleted file mode 100644 index f24c087e60a30..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpReadContextTests.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.CompositeBytesReference; -import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.InboundChannelBuffer; -import org.elasticsearch.transport.nio.TcpReadHandler; -import org.junit.Before; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Supplier; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class TcpReadContextTests extends ESTestCase { - - private TcpReadHandler handler; - private int messageLength; - private TcpNioSocketChannel channel; - private TcpReadContext readContext; - - @Before - public void init() { - handler = mock(TcpReadHandler.class); - - messageLength = randomInt(96) + 4; - channel = mock(TcpNioSocketChannel.class); - Supplier pageSupplier = () -> - new InboundChannelBuffer.Page(ByteBuffer.allocate(BigArrays.BYTE_PAGE_SIZE), () -> {}); - readContext = new TcpReadContext(channel, handler, new InboundChannelBuffer(pageSupplier)); - } - - public void testSuccessfulRead() throws IOException { - byte[] bytes = createMessage(messageLength); - byte[] fullMessage = combineMessageAndHeader(bytes); - - final AtomicLong bufferCapacity = new AtomicLong(); - when(channel.read(any(InboundChannelBuffer.class))).thenAnswer(invocationOnMock -> { - InboundChannelBuffer buffer = (InboundChannelBuffer) invocationOnMock.getArguments()[0]; - ByteBuffer byteBuffer = buffer.sliceBuffersFrom(buffer.getIndex())[0]; - bufferCapacity.set(buffer.getCapacity() - buffer.getIndex()); - byteBuffer.put(fullMessage); - buffer.incrementIndex(fullMessage.length); - return fullMessage.length; - }); - - readContext.read(); - - verify(handler).handleMessage(new BytesArray(bytes), channel, messageLength); - assertEquals(1024 * 16, bufferCapacity.get()); - - BytesArray bytesArray = new BytesArray(new byte[10]); - bytesArray.slice(5, 5); - bytesArray.slice(5, 0); - } - - public void testPartialRead() throws IOException { - byte[] part1 = createMessage(messageLength); - byte[] fullPart1 = combineMessageAndHeader(part1, messageLength + messageLength); - byte[] part2 = createMessage(messageLength); - - final AtomicLong bufferCapacity = new AtomicLong(); - final AtomicReference bytes = new AtomicReference<>(); - - when(channel.read(any(InboundChannelBuffer.class))).thenAnswer(invocationOnMock -> { - InboundChannelBuffer buffer = (InboundChannelBuffer) invocationOnMock.getArguments()[0]; - ByteBuffer byteBuffer = buffer.sliceBuffersFrom(buffer.getIndex())[0]; - bufferCapacity.set(buffer.getCapacity() - buffer.getIndex()); - byteBuffer.put(bytes.get()); - buffer.incrementIndex(bytes.get().length); - return bytes.get().length; - }); - - - bytes.set(fullPart1); - readContext.read(); - - assertEquals(1024 * 16, bufferCapacity.get()); - verifyZeroInteractions(handler); - - bytes.set(part2); - readContext.read(); - - assertEquals(1024 * 16 - fullPart1.length, bufferCapacity.get()); - - CompositeBytesReference reference = new CompositeBytesReference(new BytesArray(part1), new BytesArray(part2)); - verify(handler).handleMessage(reference, channel, messageLength + messageLength); - } - - public void testReadThrowsIOException() throws IOException { - IOException ioException = new IOException(); - when(channel.read(any())).thenThrow(ioException); - - try { - readContext.read(); - fail("Expected exception"); - } catch (Exception ex) { - assertSame(ioException, ex); - } - } - - public void closeClosesChannelBuffer() { - InboundChannelBuffer buffer = mock(InboundChannelBuffer.class); - TcpReadContext readContext = new TcpReadContext(channel, handler, buffer); - - readContext.close(); - - verify(buffer).close(); - } - - private static byte[] combineMessageAndHeader(byte[] bytes) { - return combineMessageAndHeader(bytes, bytes.length); - } - - private static byte[] combineMessageAndHeader(byte[] bytes, int messageLength) { - byte[] fullMessage = new byte[bytes.length + 6]; - ByteBuffer wrapped = ByteBuffer.wrap(fullMessage); - wrapped.put((byte) 'E'); - wrapped.put((byte) 'S'); - wrapped.putInt(messageLength); - wrapped.put(bytes); - return fullMessage; - } - - private static byte[] createMessage(int length) { - byte[] bytes = new byte[length]; - for (int i = 0; i < length; ++i) { - bytes[i] = randomByte(); - } - return bytes; - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpWriteContextTests.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpWriteContextTests.java deleted file mode 100644 index 33b84590aaa51..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/channel/TcpWriteContextTests.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.channel; - -import org.elasticsearch.action.ActionListener; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.transport.nio.SocketSelector; -import org.elasticsearch.transport.nio.WriteOperation; -import org.junit.Before; -import org.mockito.ArgumentCaptor; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.ClosedChannelException; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class TcpWriteContextTests extends ESTestCase { - - private SocketSelector selector; - private ActionListener listener; - private TcpWriteContext writeContext; - private NioSocketChannel channel; - - @Before - @SuppressWarnings("unchecked") - public void setUp() throws Exception { - super.setUp(); - selector = mock(SocketSelector.class); - listener = mock(ActionListener.class); - channel = mock(NioSocketChannel.class); - writeContext = new TcpWriteContext(channel); - - when(channel.getSelector()).thenReturn(selector); - when(selector.isOnCurrentThread()).thenReturn(true); - } - - public void testWriteFailsIfChannelNotWritable() throws Exception { - when(channel.isWritable()).thenReturn(false); - - writeContext.sendMessage(new BytesArray(generateBytes(10)), listener); - - verify(listener).onFailure(any(ClosedChannelException.class)); - } - - public void testSendMessageFromDifferentThreadIsQueuedWithSelector() throws Exception { - byte[] bytes = generateBytes(10); - BytesArray bytesArray = new BytesArray(bytes); - ArgumentCaptor writeOpCaptor = ArgumentCaptor.forClass(WriteOperation.class); - - when(selector.isOnCurrentThread()).thenReturn(false); - when(channel.isWritable()).thenReturn(true); - - writeContext.sendMessage(bytesArray, listener); - - verify(selector).queueWrite(writeOpCaptor.capture()); - WriteOperation writeOp = writeOpCaptor.getValue(); - - assertSame(listener, writeOp.getListener()); - assertSame(channel, writeOp.getChannel()); - assertEquals(ByteBuffer.wrap(bytes), writeOp.getByteBuffers()[0]); - } - - public void testSendMessageFromSameThreadIsQueuedInChannel() throws Exception { - byte[] bytes = generateBytes(10); - BytesArray bytesArray = new BytesArray(bytes); - ArgumentCaptor writeOpCaptor = ArgumentCaptor.forClass(WriteOperation.class); - - when(channel.isWritable()).thenReturn(true); - - writeContext.sendMessage(bytesArray, listener); - - verify(selector).queueWriteInChannelBuffer(writeOpCaptor.capture()); - WriteOperation writeOp = writeOpCaptor.getValue(); - - assertSame(listener, writeOp.getListener()); - assertSame(channel, writeOp.getChannel()); - assertEquals(ByteBuffer.wrap(bytes), writeOp.getByteBuffers()[0]); - } - - public void testWriteIsQueuedInChannel() throws Exception { - assertFalse(writeContext.hasQueuedWriteOps()); - - writeContext.queueWriteOperations(new WriteOperation(channel, new BytesArray(generateBytes(10)), listener)); - - assertTrue(writeContext.hasQueuedWriteOps()); - } - - public void testWriteOpsCanBeCleared() throws Exception { - assertFalse(writeContext.hasQueuedWriteOps()); - - writeContext.queueWriteOperations(new WriteOperation(channel, new BytesArray(generateBytes(10)), listener)); - - assertTrue(writeContext.hasQueuedWriteOps()); - - ClosedChannelException e = new ClosedChannelException(); - writeContext.clearQueuedWriteOps(e); - - verify(selector).executeFailedListener(listener, e); - - assertFalse(writeContext.hasQueuedWriteOps()); - } - - public void testQueuedWriteIsFlushedInFlushCall() throws Exception { - assertFalse(writeContext.hasQueuedWriteOps()); - - WriteOperation writeOperation = mock(WriteOperation.class); - writeContext.queueWriteOperations(writeOperation); - - assertTrue(writeContext.hasQueuedWriteOps()); - - when(writeOperation.isFullyFlushed()).thenReturn(true); - when(writeOperation.getListener()).thenReturn(listener); - writeContext.flushChannel(); - - verify(writeOperation).flush(); - verify(selector).executeListener(listener, null); - assertFalse(writeContext.hasQueuedWriteOps()); - } - - public void testPartialFlush() throws IOException { - assertFalse(writeContext.hasQueuedWriteOps()); - - WriteOperation writeOperation = mock(WriteOperation.class); - writeContext.queueWriteOperations(writeOperation); - - assertTrue(writeContext.hasQueuedWriteOps()); - - when(writeOperation.isFullyFlushed()).thenReturn(false); - writeContext.flushChannel(); - - verify(listener, times(0)).onResponse(null); - assertTrue(writeContext.hasQueuedWriteOps()); - } - - @SuppressWarnings("unchecked") - public void testMultipleWritesPartialFlushes() throws IOException { - assertFalse(writeContext.hasQueuedWriteOps()); - - ActionListener listener2 = mock(ActionListener.class); - WriteOperation writeOperation1 = mock(WriteOperation.class); - WriteOperation writeOperation2 = mock(WriteOperation.class); - when(writeOperation1.getListener()).thenReturn(listener); - when(writeOperation2.getListener()).thenReturn(listener2); - writeContext.queueWriteOperations(writeOperation1); - writeContext.queueWriteOperations(writeOperation2); - - assertTrue(writeContext.hasQueuedWriteOps()); - - when(writeOperation1.isFullyFlushed()).thenReturn(true); - when(writeOperation2.isFullyFlushed()).thenReturn(false); - writeContext.flushChannel(); - - verify(selector).executeListener(listener, null); - verify(listener2, times(0)).onResponse(channel); - assertTrue(writeContext.hasQueuedWriteOps()); - - when(writeOperation2.isFullyFlushed()).thenReturn(true); - - writeContext.flushChannel(); - - verify(selector).executeListener(listener2, null); - assertFalse(writeContext.hasQueuedWriteOps()); - } - - public void testWhenIOExceptionThrownListenerIsCalled() throws IOException { - assertFalse(writeContext.hasQueuedWriteOps()); - - WriteOperation writeOperation = mock(WriteOperation.class); - writeContext.queueWriteOperations(writeOperation); - - assertTrue(writeContext.hasQueuedWriteOps()); - - IOException exception = new IOException(); - when(writeOperation.flush()).thenThrow(exception); - when(writeOperation.getListener()).thenReturn(listener); - expectThrows(IOException.class, () -> writeContext.flushChannel()); - - verify(selector).executeFailedListener(listener, exception); - assertFalse(writeContext.hasQueuedWriteOps()); - } - - private byte[] generateBytes(int n) { - n += 10; - byte[] bytes = new byte[n]; - for (int i = 0; i < n; ++i) { - bytes[i] = randomByte(); - } - return bytes; - } -} diff --git a/test/framework/src/test/java/org/elasticsearch/transport/nio/utils/TestSelectionKey.java b/test/framework/src/test/java/org/elasticsearch/transport/nio/utils/TestSelectionKey.java deleted file mode 100644 index 0f0011f15533b..0000000000000 --- a/test/framework/src/test/java/org/elasticsearch/transport/nio/utils/TestSelectionKey.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.transport.nio.utils; - -import java.nio.channels.SelectableChannel; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.spi.AbstractSelectionKey; - -public class TestSelectionKey extends AbstractSelectionKey { - - private int ops = 0; - private int readyOps; - - public TestSelectionKey(int ops) { - this.ops = ops; - } - - @Override - public SelectableChannel channel() { - return null; - } - - @Override - public Selector selector() { - return null; - } - - @Override - public int interestOps() { - return ops; - } - - @Override - public SelectionKey interestOps(int ops) { - this.ops = ops; - return this; - } - - @Override - public int readyOps() { - return readyOps; - } - - public void setReadyOps(int readyOps) { - this.readyOps = readyOps; - } -}