org.elasticsearch.common.network.NetworkModule 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
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.common.network;
import org.elasticsearch.action.support.replication.ReplicationTask;
import org.elasticsearch.cluster.routing.allocation.command.AllocateEmptyPrimaryAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.AllocateReplicaAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.AllocateStalePrimaryAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.AllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.CancelAllocationCommand;
import org.elasticsearch.cluster.routing.allocation.command.MoveAllocationCommand;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.PageCacheRecycler;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.core.CheckedFunction;
import org.elasticsearch.http.HttpPreRequest;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.index.shard.PrimaryReplicaSyncer.ResyncTask;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.plugins.NetworkPlugin;
import org.elasticsearch.tasks.RawTaskStatus;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.telemetry.tracing.Tracer;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportInterceptor;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportRequestHandler;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.ParseField;
import org.elasticsearch.xcontent.XContentParser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
/**
* A module to handle registering and binding all network related classes.
*/
public final class NetworkModule {
public static final String TRANSPORT_TYPE_KEY = "transport.type";
public static final String HTTP_TYPE_KEY = "http.type";
public static final String HTTP_TYPE_DEFAULT_KEY = "http.type.default";
public static final String TRANSPORT_TYPE_DEFAULT_KEY = "transport.type.default";
public static final Setting TRANSPORT_DEFAULT_TYPE_SETTING = Setting.simpleString(
TRANSPORT_TYPE_DEFAULT_KEY,
Property.NodeScope
);
public static final Setting HTTP_DEFAULT_TYPE_SETTING = Setting.simpleString(HTTP_TYPE_DEFAULT_KEY, Property.NodeScope);
public static final Setting HTTP_TYPE_SETTING = Setting.simpleString(HTTP_TYPE_KEY, Property.NodeScope);
public static final Setting TRANSPORT_TYPE_SETTING = Setting.simpleString(TRANSPORT_TYPE_KEY, Property.NodeScope);
private final Settings settings;
private static final List namedWriteables = new ArrayList<>();
private static final List namedXContents = new ArrayList<>();
static {
registerAllocationCommand(
CancelAllocationCommand::new,
CancelAllocationCommand::fromXContent,
CancelAllocationCommand.COMMAND_NAME_FIELD
);
registerAllocationCommand(
MoveAllocationCommand::new,
MoveAllocationCommand::fromXContent,
MoveAllocationCommand.COMMAND_NAME_FIELD
);
registerAllocationCommand(
AllocateReplicaAllocationCommand::new,
AllocateReplicaAllocationCommand::fromXContent,
AllocateReplicaAllocationCommand.COMMAND_NAME_FIELD
);
registerAllocationCommand(
AllocateEmptyPrimaryAllocationCommand::new,
AllocateEmptyPrimaryAllocationCommand::fromXContent,
AllocateEmptyPrimaryAllocationCommand.COMMAND_NAME_FIELD
);
registerAllocationCommand(
AllocateStalePrimaryAllocationCommand::new,
AllocateStalePrimaryAllocationCommand::fromXContent,
AllocateStalePrimaryAllocationCommand.COMMAND_NAME_FIELD
);
namedWriteables.add(new NamedWriteableRegistry.Entry(Task.Status.class, ReplicationTask.Status.NAME, ReplicationTask.Status::new));
namedWriteables.add(new NamedWriteableRegistry.Entry(Task.Status.class, RawTaskStatus.NAME, RawTaskStatus::new));
namedWriteables.add(new NamedWriteableRegistry.Entry(Task.Status.class, ResyncTask.Status.NAME, ResyncTask.Status::new));
}
private final Map> transportFactories = new HashMap<>();
private final Map> transportHttpFactories = new HashMap<>();
private final List transportInterceptors = new ArrayList<>();
/**
* Creates a network module that custom networking classes can be plugged into.
* @param settings The settings for the node
*/
public NetworkModule(
Settings settings,
List plugins,
ThreadPool threadPool,
BigArrays bigArrays,
PageCacheRecycler pageCacheRecycler,
CircuitBreakerService circuitBreakerService,
NamedWriteableRegistry namedWriteableRegistry,
NamedXContentRegistry xContentRegistry,
NetworkService networkService,
HttpServerTransport.Dispatcher dispatcher,
BiConsumer perRequestThreadContext,
ClusterSettings clusterSettings,
Tracer tracer
) {
this.settings = settings;
for (NetworkPlugin plugin : plugins) {
Map> httpTransportFactory = plugin.getHttpTransports(
settings,
threadPool,
bigArrays,
pageCacheRecycler,
circuitBreakerService,
xContentRegistry,
networkService,
dispatcher,
perRequestThreadContext,
clusterSettings,
tracer
);
for (Map.Entry> entry : httpTransportFactory.entrySet()) {
registerHttpTransport(entry.getKey(), entry.getValue());
}
Map> transportFactory = plugin.getTransports(
settings,
threadPool,
pageCacheRecycler,
circuitBreakerService,
namedWriteableRegistry,
networkService
);
for (Map.Entry> entry : transportFactory.entrySet()) {
registerTransport(entry.getKey(), entry.getValue());
}
List transportInterceptors = plugin.getTransportInterceptors(
namedWriteableRegistry,
threadPool.getThreadContext()
);
for (TransportInterceptor interceptor : transportInterceptors) {
registerTransportInterceptor(interceptor);
}
}
}
/** Adds a transport implementation that can be selected by setting {@link #TRANSPORT_TYPE_KEY}. */
private void registerTransport(String key, Supplier factory) {
if (transportFactories.putIfAbsent(key, factory) != null) {
throw new IllegalArgumentException("transport for name: " + key + " is already registered");
}
}
/** Adds an http transport implementation that can be selected by setting {@link #HTTP_TYPE_KEY}. */
private void registerHttpTransport(String key, Supplier factory) {
if (transportHttpFactories.putIfAbsent(key, factory) != null) {
throw new IllegalArgumentException("transport for name: " + key + " is already registered");
}
}
// TODO: consider moving this to the ClusterModule
// this lives here instead of the more aptly named ClusterModule because it used to be used by the Transport client
/**
* Register an allocation command.
*
* @param reader the reader to read it from a stream
* @param parser the parser to read it from XContent
* @param commandName the names under which the command should be parsed. The {@link ParseField#getPreferredName()} is special because
* it is the name under which the command's reader is registered.
*/
private static void registerAllocationCommand(
Writeable.Reader reader,
CheckedFunction parser,
ParseField commandName
) {
namedXContents.add(new NamedXContentRegistry.Entry(AllocationCommand.class, commandName, parser));
namedWriteables.add(new NamedWriteableRegistry.Entry(AllocationCommand.class, commandName.getPreferredName(), reader));
}
public static List getNamedWriteables() {
return Collections.unmodifiableList(namedWriteables);
}
public static List getNamedXContents() {
return Collections.unmodifiableList(namedXContents);
}
public Supplier getHttpServerTransportSupplier() {
final String name;
if (HTTP_TYPE_SETTING.exists(settings)) {
name = HTTP_TYPE_SETTING.get(settings);
} else {
name = HTTP_DEFAULT_TYPE_SETTING.get(settings);
}
final Supplier factory = transportHttpFactories.get(name);
if (factory == null) {
throw new IllegalStateException("Unsupported http.type [" + name + "]");
}
return factory;
}
public Supplier getTransportSupplier() {
final String name;
if (TRANSPORT_TYPE_SETTING.exists(settings)) {
name = TRANSPORT_TYPE_SETTING.get(settings);
} else {
name = TRANSPORT_DEFAULT_TYPE_SETTING.get(settings);
}
final Supplier factory = transportFactories.get(name);
if (factory == null) {
throw new IllegalStateException("Unsupported transport.type [" + name + "]");
}
return factory;
}
/**
* Registers a new {@link TransportInterceptor}
*/
private void registerTransportInterceptor(TransportInterceptor interceptor) {
this.transportInterceptors.add(Objects.requireNonNull(interceptor, "interceptor must not be null"));
}
/**
* Returns a composite {@link TransportInterceptor} containing all registered interceptors
* @see #registerTransportInterceptor(TransportInterceptor)
*/
public TransportInterceptor getTransportInterceptor() {
return new CompositeTransportInterceptor(this.transportInterceptors);
}
static final class CompositeTransportInterceptor implements TransportInterceptor {
final List transportInterceptors;
private CompositeTransportInterceptor(List transportInterceptors) {
this.transportInterceptors = new ArrayList<>(transportInterceptors);
}
@Override
public TransportRequestHandler interceptHandler(
String action,
Executor executor,
boolean forceExecution,
TransportRequestHandler actualHandler
) {
for (TransportInterceptor interceptor : this.transportInterceptors) {
actualHandler = interceptor.interceptHandler(action, executor, forceExecution, actualHandler);
}
return actualHandler;
}
@Override
public AsyncSender interceptSender(AsyncSender sender) {
for (TransportInterceptor interceptor : this.transportInterceptors) {
sender = interceptor.interceptSender(sender);
}
return sender;
}
}
}