org.elasticsearch.transport.Transport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* 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.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.breaker.CircuitBreaker;
import org.elasticsearch.common.breaker.NoopCircuitBreaker;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.ConcurrentMapLong;
import java.io.Closeable;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Predicate;
public interface Transport extends LifecycleComponent {
/**
* Registers a new request handler
*/
void registerRequestHandler(RequestHandlerRegistry reg);
/**
* Returns the registered request handler registry for the given action or null
if it's not registered
* @param action the action to look up
*/
RequestHandlerRegistry getRequestHandler(String action);
void addMessageListener(TransportMessageListener listener);
boolean removeMessageListener(TransportMessageListener listener);
/**
* The address the transport is bound on.
*/
BoundTransportAddress boundAddress();
/**
* Further profile bound addresses
* @return null
iff profiles are unsupported, otherwise a map with name of profile and its bound transport address
*/
Map profileBoundAddresses();
/**
* Returns an address from its string representation.
*/
TransportAddress[] addressesFromString(String address, int perAddressLimit) throws UnknownHostException;
/**
* Returns a list of all local adresses for this transport
*/
List getLocalAddresses();
default CircuitBreaker getInFlightRequestBreaker() {
return new NoopCircuitBreaker("in-flight-noop");
}
/**
* Opens a new connection to the given node. When the connection is fully connected, the listener is
* called. A {@link Releasable} is returned representing the pending connection. If the caller of this
* method decides to move on before the listener is called with the completed connection, they should
* release the pending connection to prevent hanging connections.
*/
Releasable openConnection(DiscoveryNode node, ConnectionProfile profile, ActionListener listener);
TransportStats getStats();
ResponseHandlers getResponseHandlers();
/**
* A unidirectional connection to a {@link DiscoveryNode}
*/
interface Connection extends Closeable {
/**
* The node this connection is associated with
*/
DiscoveryNode getNode();
/**
* Sends the request to the node this connection is associated with
* @param requestId see {@link ResponseHandlers#add(ResponseContext)} for details
* @param action the action to execute
* @param request the request to send
* @param options request options to apply
* @throws NodeNotConnectedException if the given node is not connected
*/
void sendRequest(long requestId, String action, TransportRequest request, TransportRequestOptions options) throws
IOException, TransportException;
/**
* The listener's {@link ActionListener#onResponse(Object)} method will be called when this
* connection is closed. No implementations currently throw an exception during close, so
* {@link ActionListener#onFailure(Exception)} will not be called.
*
* @param listener to be called
*/
void addCloseListener(ActionListener listener);
boolean isClosed();
/**
* Returns the version of the node this connection was established with.
*/
default Version getVersion() {
return getNode().getVersion();
}
/**
* Returns a key that this connection can be cached on. Delegating subclasses must delegate method call to
* the original connection.
*/
default Object getCacheKey() {
return this;
}
@Override
void close();
}
/**
* This class represents a response context that encapsulates the actual response handler, the action and the connection it was
* executed on.
*/
final class ResponseContext {
private final TransportResponseHandler handler;
private final Connection connection;
private final String action;
ResponseContext(TransportResponseHandler handler, Connection connection, String action) {
this.handler = handler;
this.connection = connection;
this.action = action;
}
public TransportResponseHandler handler() {
return handler;
}
public Connection connection() {
return this.connection;
}
public String action() {
return this.action;
}
}
/**
* This class is a registry that allows
*/
final class ResponseHandlers {
private final ConcurrentMapLong> handlers = ConcurrentCollections
.newConcurrentMapLongWithAggressiveConcurrency();
private final AtomicLong requestIdGenerator = new AtomicLong();
/**
* Returns true
if the give request ID has a context associated with it.
*/
public boolean contains(long requestId) {
return handlers.containsKey(requestId);
}
/**
* Removes and return the {@link ResponseContext} for the given request ID or returns
* null
if no context is associated with this request ID.
*/
public ResponseContext remove(long requestId) {
return handlers.remove(requestId);
}
/**
* Adds a new response context and associates it with a new request ID.
* @return the new request ID
* @see Connection#sendRequest(long, String, TransportRequest, TransportRequestOptions)
*/
public long add(ResponseContext holder) {
long requestId = newRequestId();
ResponseContext existing = handlers.put(requestId, holder);
assert existing == null : "request ID already in use: " + requestId;
return requestId;
}
/**
* Returns a new request ID to use when sending a message via {@link Connection#sendRequest(long, String,
* TransportRequest, TransportRequestOptions)}
*/
long newRequestId() {
return requestIdGenerator.incrementAndGet();
}
/**
* Removes and returns all {@link ResponseContext} instances that match the predicate
*/
public List> prune(Predicate predicate) {
final List> holders = new ArrayList<>();
for (Map.Entry> entry : handlers.entrySet()) {
ResponseContext holder = entry.getValue();
if (predicate.test(holder)) {
ResponseContext remove = handlers.remove(entry.getKey());
if (remove != null) {
holders.add(holder);
}
}
}
return holders;
}
/**
* called by the {@link Transport} implementation when a response or an exception has been received for a previously
* sent request (before any processing or deserialization was done). Returns the appropriate response handler or null if not
* found.
*/
public TransportResponseHandler onResponseReceived(final long requestId,
final TransportMessageListener listener) {
ResponseContext context = handlers.remove(requestId);
listener.onResponseReceived(requestId, context);
if (context == null) {
return null;
} else {
return context.handler();
}
}
}
}