-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Remove client connections from TcpTransport #31886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
6b6981f
Work on connection manager
Tim-Brooks 744375e
WIP
Tim-Brooks 002b371
WIP
Tim-Brooks 06a0093
At least fix checkstyle
Tim-Brooks f9e7080
Fix test
Tim-Brooks 67bc0b2
Add comment
Tim-Brooks 31e3acf
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 17a334a
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks c3544ad
Remove additional listeners
Tim-Brooks fc886bf
Work on fixing tests
Tim-Brooks f699321
Remove unused
Tim-Brooks 03acc19
Fix checkstyle
Tim-Brooks 796a728
Work on test infra
Tim-Brooks 8005de4
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 43dd3ad
Work on tests
Tim-Brooks acb743a
Remove methods
Tim-Brooks 2eacbfa
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks ca9fe7c
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks aaf2d87
Use new behaviors
Tim-Brooks f5778c0
Fix some tests
Tim-Brooks 2302fa1
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 95a7b85
Working on fixing tests
Tim-Brooks 2c5badd
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 5106852
Work on fixing tests
Tim-Brooks af37b63
Fix tests
Tim-Brooks 3e4b898
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 0436eb0
Work on transport client nodes service tests
Tim-Brooks f429f9b
fix tests and temporarily mute test
Tim-Brooks 28eafbb
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks c45c5ef
Fix tests
Tim-Brooks 2e8a026
Fix checkstyle
Tim-Brooks 630cfaa
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 3ee4743
Work on cleaning up
Tim-Brooks 293a572
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 2789d0d
Make connection methods required
Tim-Brooks 617521f
Work on tests
Tim-Brooks 76d429c
Fix tests
Tim-Brooks 8c26686
java doc
Tim-Brooks 071490a
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 44f6e1d
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 4c26165
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks 453b853
Merge remote-tracking branch 'upstream/master' into new_cm
Tim-Brooks d18be8c
Changes from review
Tim-Brooks f259bae
Changes docs
Tim-Brooks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
232 changes: 232 additions & 0 deletions
232
server/src/main/java/org/elasticsearch/transport/ConnectionManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,232 @@ | ||
| /* | ||
| * 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; | ||
|
|
||
| import org.apache.logging.log4j.Logger; | ||
| import org.apache.logging.log4j.message.ParameterizedMessage; | ||
| import org.elasticsearch.cluster.node.DiscoveryNode; | ||
| import org.elasticsearch.common.CheckedBiConsumer; | ||
| import org.elasticsearch.common.component.Lifecycle; | ||
| import org.elasticsearch.common.lease.Releasable; | ||
| import org.elasticsearch.common.unit.TimeValue; | ||
| import org.elasticsearch.common.util.concurrent.AbstractLifecycleRunnable; | ||
| import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; | ||
| import org.elasticsearch.common.util.concurrent.KeyedLock; | ||
| import org.elasticsearch.core.internal.io.IOUtils; | ||
| import org.elasticsearch.threadpool.ThreadPool; | ||
|
|
||
| import java.io.Closeable; | ||
| import java.io.IOException; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentMap; | ||
| import java.util.concurrent.CopyOnWriteArrayList; | ||
|
|
||
| import static org.elasticsearch.common.util.concurrent.ConcurrentCollections.newConcurrentMap; | ||
|
|
||
| public class ConnectionManager implements Closeable { | ||
|
|
||
| private final ConcurrentMap<DiscoveryNode, Transport.Connection> connectedNodes = newConcurrentMap(); | ||
| private final KeyedLock<String> connectionLock = new KeyedLock<>(); | ||
| private final Logger logger; | ||
| private final Transport transport; | ||
| private final ThreadPool threadPool; | ||
| private final TimeValue pingSchedule; | ||
| private final Lifecycle lifecycle = new Lifecycle(); | ||
| private final DelegatingNodeConnectionListener connectionListener = new DelegatingNodeConnectionListener(); | ||
|
|
||
| public ConnectionManager(Logger logger, Transport transport, ThreadPool threadPool, TimeValue pingSchedule) { | ||
| this.logger = logger; | ||
| this.transport = transport; | ||
| this.threadPool = threadPool; | ||
| this.pingSchedule = pingSchedule; | ||
| this.lifecycle.moveToStarted(); | ||
|
|
||
| if (pingSchedule.millis() > 0) { | ||
| threadPool.schedule(pingSchedule, ThreadPool.Names.GENERIC, new ScheduledPing()); | ||
| } | ||
| } | ||
|
|
||
| public void addListener(TransportConnectionListener.NodeConnection listener) { | ||
| this.connectionListener.listeners.add(listener); | ||
| } | ||
|
|
||
| public void removeListener(TransportConnectionListener.NodeConnection listener) { | ||
| this.connectionListener.listeners.remove(listener); | ||
| } | ||
|
|
||
| public void connectToNode(DiscoveryNode node, ConnectionProfile connectionProfile, | ||
| CheckedBiConsumer<Transport.Connection, ConnectionProfile, IOException> connectionValidator) | ||
| throws ConnectTransportException { | ||
| if (node == null) { | ||
| throw new ConnectTransportException(null, "can't connect to a null node"); | ||
| } | ||
| ensureOpen(); | ||
| try (Releasable ignored = connectionLock.acquire(node.getId())) { | ||
| Transport.Connection connection = connectedNodes.get(node); | ||
| if (connection != null) { | ||
| return; | ||
| } | ||
| boolean success = false; | ||
| try { | ||
| connection = transport.openConnection(node, connectionProfile); | ||
| connectionValidator.accept(connection, connectionProfile); | ||
| // we acquire a connection lock, so no way there is an existing connection | ||
| connectedNodes.put(node, connection); | ||
| if (logger.isDebugEnabled()) { | ||
| logger.debug("connected to node [{}]", node); | ||
| } | ||
| try { | ||
| connectionListener.onNodeConnected(node); | ||
| } finally { | ||
| // TODO: Need to add node disconnect listener | ||
| if (connection.isClosed()) { | ||
| // we got closed concurrently due to a disconnect or some other event on the channel. | ||
| // the close callback will close the NodeChannel instance first and then try to remove | ||
| // the connection from the connected nodes. It will NOT acquire the connectionLock for | ||
| // the node to prevent any blocking calls on network threads. Yet, we still establish a happens | ||
| // before relationship to the connectedNodes.put since we check if we can remove the | ||
| // (DiscoveryNode, NodeChannels) tuple from the map after we closed. Here we check if it's closed an if so we | ||
| // try to remove it first either way one of the two wins even if the callback has run before we even added the | ||
| // tuple to the map since in that case we remove it here again | ||
| if (connectedNodes.remove(node, connection)) { | ||
| connectionListener.onNodeDisconnected(node); | ||
| } | ||
| throw new NodeNotConnectedException(node, "connection concurrently closed"); | ||
| } | ||
| } | ||
| success = true; | ||
| } catch (ConnectTransportException e) { | ||
| throw e; | ||
| } catch (Exception e) { | ||
| throw new ConnectTransportException(node, "general node connection failure", e); | ||
| } finally { | ||
| if (success == false) { // close the connection if there is a failure | ||
| logger.trace(() -> new ParameterizedMessage("failed to connect to [{}], cleaning dangling connections", node)); | ||
| IOUtils.closeWhileHandlingException(connection); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public Transport.Connection getConnection(DiscoveryNode node) { | ||
| Transport.Connection connection = connectedNodes.get(node); | ||
| if (connection == null) { | ||
| throw new NodeNotConnectedException(node, "Node not connected"); | ||
| } | ||
| return connection; | ||
| } | ||
|
|
||
| public boolean nodeConnected(DiscoveryNode node) { | ||
| return connectedNodes.containsKey(node); | ||
| } | ||
|
|
||
| public void disconnectFromNode(DiscoveryNode node) { | ||
| // TODO: Do we need to lock here? | ||
| Transport.Connection nodeChannels = connectedNodes.remove(node); | ||
| if (nodeChannels != null) { // if we found it and removed it we close and notify | ||
| IOUtils.closeWhileHandlingException(nodeChannels, () -> connectionListener.onNodeDisconnected(node)); | ||
| } | ||
| } | ||
|
|
||
| private void ensureOpen() { | ||
| if (lifecycle.started() == false) { | ||
| throw new IllegalStateException("connection manager is closed"); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void close() { | ||
| lifecycle.moveToStopped(); | ||
| // TODO: Either add locking externally or in here. | ||
| // we are holding a write lock so nobody modifies the connectedNodes / openConnections map - it's safe to first close | ||
| // all instances and then clear them maps | ||
| Iterator<Map.Entry<DiscoveryNode, Transport.Connection>> iterator = connectedNodes.entrySet().iterator(); | ||
| while (iterator.hasNext()) { | ||
| Map.Entry<DiscoveryNode, Transport.Connection> next = iterator.next(); | ||
| try { | ||
| IOUtils.closeWhileHandlingException(next.getValue()); | ||
| connectionListener.onNodeDisconnected(next.getKey()); | ||
| } finally { | ||
| iterator.remove(); | ||
| } | ||
| } | ||
|
|
||
| lifecycle.moveToClosed(); | ||
| } | ||
|
|
||
| private class ScheduledPing extends AbstractLifecycleRunnable { | ||
|
|
||
| private ScheduledPing() { | ||
| super(lifecycle, logger); | ||
| } | ||
|
|
||
| @Override | ||
| protected void doRunInLifecycle() { | ||
| for (Map.Entry<DiscoveryNode, Transport.Connection> entry : connectedNodes.entrySet()) { | ||
| Transport.Connection connection = entry.getValue(); | ||
| if (connection.supportsPing()) { | ||
| connection.sendPing(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| protected void onAfterInLifecycle() { | ||
| try { | ||
| threadPool.schedule(pingSchedule, ThreadPool.Names.GENERIC, this); | ||
| } catch (EsRejectedExecutionException ex) { | ||
| if (ex.isExecutorShutdown()) { | ||
| logger.debug("couldn't schedule new ping execution, executor is shutting down", ex); | ||
| } else { | ||
| throw ex; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void onFailure(Exception e) { | ||
| if (lifecycle.stoppedOrClosed()) { | ||
| logger.trace("failed to send ping transport message", e); | ||
| } else { | ||
| logger.warn("failed to send ping transport message", e); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private static final class DelegatingNodeConnectionListener implements TransportConnectionListener.NodeConnection { | ||
|
|
||
| private final List<TransportConnectionListener.NodeConnection> listeners = new CopyOnWriteArrayList<>(); | ||
|
|
||
| @Override | ||
| public void onNodeDisconnected(DiscoveryNode key) { | ||
| for (TransportConnectionListener.NodeConnection listener : listeners) { | ||
| listener.onNodeDisconnected(key); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void onNodeConnected(DiscoveryNode node) { | ||
| for (TransportConnectionListener.NodeConnection listener : listeners) { | ||
| listener.onNodeConnected(node); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add some javadocs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also love to see a unittest for this one. that would be awesome!