org.elasticsearch.index.seqno.RetentionLeaseSyncAction 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 - Open Source, Distributed, RESTful Search Engine
/*
* 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.index.seqno;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.store.AlreadyClosedException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.WriteResponse;
import org.elasticsearch.action.support.replication.ReplicatedWriteRequest;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.action.support.replication.ReplicationTask;
import org.elasticsearch.action.support.replication.TransportWriteAction;
import org.elasticsearch.cluster.action.shard.ShardStateAction;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.IndexingPressure;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.index.shard.IndexShardClosedException;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.indices.SystemIndices;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportException;
import org.elasticsearch.transport.TransportResponseHandler;
import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.core.Strings.format;
/**
* Write action responsible for syncing retention leases to replicas. This action is deliberately a write action so that if a replica misses
* a retention lease sync then that shard will be marked as stale.
*/
public class RetentionLeaseSyncAction extends TransportWriteAction<
RetentionLeaseSyncAction.Request,
RetentionLeaseSyncAction.Request,
RetentionLeaseSyncAction.Response> {
public static final String ACTION_NAME = "indices:admin/seq_no/retention_lease_sync";
private static final Logger LOGGER = LogManager.getLogger(RetentionLeaseSyncAction.class);
protected static Logger getLogger() {
return LOGGER;
}
@Inject
public RetentionLeaseSyncAction(
final Settings settings,
final TransportService transportService,
final ClusterService clusterService,
final IndicesService indicesService,
final ThreadPool threadPool,
final ShardStateAction shardStateAction,
final ActionFilters actionFilters,
final IndexingPressure indexingPressure,
final SystemIndices systemIndices
) {
super(
settings,
ACTION_NAME,
transportService,
clusterService,
indicesService,
threadPool,
shardStateAction,
actionFilters,
RetentionLeaseSyncAction.Request::new,
RetentionLeaseSyncAction.Request::new,
(service, ignore) -> ThreadPool.Names.MANAGEMENT,
false,
indexingPressure,
systemIndices
);
}
@Override
protected void doExecute(Task parentTask, Request request, ActionListener listener) {
assert false : "use RetentionLeaseSyncAction#sync";
}
final void sync(
ShardId shardId,
String primaryAllocationId,
long primaryTerm,
RetentionLeases retentionLeases,
ActionListener listener
) {
final ThreadContext threadContext = threadPool.getThreadContext();
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
// we have to execute under the system context so that if security is enabled the sync is authorized
threadContext.markAsSystemContext();
final Request request = new Request(shardId, retentionLeases);
try (var ignored = threadContext.newTraceContext()) {
final ReplicationTask task = (ReplicationTask) taskManager.register("transport", "retention_lease_sync", request);
transportService.sendChildRequest(
clusterService.localNode(),
transportPrimaryAction,
new ConcreteShardRequest<>(request, primaryAllocationId, primaryTerm),
task,
transportOptions,
new TransportResponseHandler() {
@Override
public ReplicationResponse read(StreamInput in) throws IOException {
return newResponseInstance(in);
}
@Override
public void handleResponse(ReplicationResponse response) {
task.setPhase("finished");
taskManager.unregister(task);
listener.onResponse(response);
}
@Override
public void handleException(TransportException e) {
if (ExceptionsHelper.unwrap(
e,
IndexNotFoundException.class,
AlreadyClosedException.class,
IndexShardClosedException.class
) == null) {
getLogger().warn(() -> format("%s retention lease sync failed", shardId), e);
}
task.setPhase("finished");
taskManager.unregister(task);
listener.onFailure(e);
}
}
);
}
}
}
@Override
protected void dispatchedShardOperationOnPrimary(
Request request,
IndexShard primary,
ActionListener> listener
) {
ActionListener.completeWith(listener, () -> {
assert request.waitForActiveShards().equals(ActiveShardCount.NONE) : request.waitForActiveShards();
Objects.requireNonNull(request);
Objects.requireNonNull(primary);
primary.persistRetentionLeases();
return new WritePrimaryResult<>(request, new Response(), null, primary, getLogger(), postWriteRefresh);
});
}
@Override
protected void dispatchedShardOperationOnReplica(Request request, IndexShard replica, ActionListener listener) {
ActionListener.completeWith(listener, () -> {
Objects.requireNonNull(request);
Objects.requireNonNull(replica);
replica.updateRetentionLeasesOnReplica(request.getRetentionLeases());
replica.persistRetentionLeases();
return new WriteReplicaResult<>(request, null, null, replica, getLogger());
});
}
@Override
public ClusterBlockLevel indexBlockLevel() {
return null;
}
public static final class Request extends ReplicatedWriteRequest {
private RetentionLeases retentionLeases;
public RetentionLeases getRetentionLeases() {
return retentionLeases;
}
public Request(StreamInput in) throws IOException {
super(in);
retentionLeases = new RetentionLeases(in);
}
public Request(final ShardId shardId, final RetentionLeases retentionLeases) {
super(Objects.requireNonNull(shardId));
this.retentionLeases = Objects.requireNonNull(retentionLeases);
waitForActiveShards(ActiveShardCount.NONE);
}
@Override
public void writeTo(final StreamOutput out) throws IOException {
super.writeTo(Objects.requireNonNull(out));
retentionLeases.writeTo(out);
}
@Override
public Task createTask(long id, String type, String action, TaskId parentTaskId, Map headers) {
return new ReplicationTask(id, type, action, "retention_lease_sync shardId=" + shardId, parentTaskId, headers);
}
@Override
public String toString() {
return "RetentionLeaseSyncAction.Request{"
+ "retentionLeases="
+ retentionLeases
+ ", shardId="
+ shardId
+ ", timeout="
+ timeout
+ ", index='"
+ index
+ '\''
+ ", waitForActiveShards="
+ waitForActiveShards
+ '}';
}
}
public static final class Response extends ReplicationResponse implements WriteResponse {
public Response() {}
Response(StreamInput in) throws IOException {
super(in);
}
@Override
public void setForcedRefresh(final boolean forcedRefresh) {
// ignore
}
}
@Override
protected Response newResponseInstance(StreamInput in) throws IOException {
return new Response(in);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy