All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.index.seqno.RetentionLeaseActions Maven / Gradle / Ivy

/*
 * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
 * License v3.0 only", or the "Server Side Public License, v 1".
 */

package org.elasticsearch.index.seqno;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.RemoteClusterActionType;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.single.shard.SingleShardRequest;
import org.elasticsearch.action.support.single.shard.TransportSingleShardAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.routing.ShardsIterator;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.core.Releasable;
import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.injection.guice.Inject;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;

import java.io.IOException;
import java.util.Objects;

/**
 * This class holds all actions related to retention leases. Note carefully that these actions are executed under a primary permit. Care is
 * taken to thread the listener through the invocations so that for the sync APIs we do not notify the listener until these APIs have
 * responded with success. Additionally, note the use of
 * {@link TransportSingleShardAction#asyncShardOperation(SingleShardRequest, ShardId, ActionListener)} to handle the case when acquiring
 * permits goes asynchronous because acquiring permits is blocked
 */
public class RetentionLeaseActions {

    public static final long RETAIN_ALL = -1;
    public static final ActionType ADD = new ActionType<>("indices:admin/seq_no/add_retention_lease");
    public static final ActionType RENEW = new ActionType<>("indices:admin/seq_no/renew_retention_lease");
    public static final ActionType REMOVE = new ActionType<>("indices:admin/seq_no/remove_retention_lease");

    public static final RemoteClusterActionType REMOTE_ADD = RemoteClusterActionType.emptyResponse(ADD.name());
    public static final RemoteClusterActionType REMOTE_RENEW = RemoteClusterActionType.emptyResponse(RENEW.name());
    public static final RemoteClusterActionType REMOTE_REMOVE = RemoteClusterActionType.emptyResponse(REMOVE.name());

    abstract static class TransportRetentionLeaseAction> extends TransportSingleShardAction {

        private final IndicesService indicesService;

        @Inject
        TransportRetentionLeaseAction(
            final String name,
            final ThreadPool threadPool,
            final ClusterService clusterService,
            final TransportService transportService,
            final ActionFilters actionFilters,
            final IndexNameExpressionResolver indexNameExpressionResolver,
            final IndicesService indicesService,
            final Writeable.Reader requestSupplier
        ) {
            super(
                name,
                threadPool,
                clusterService,
                transportService,
                actionFilters,
                indexNameExpressionResolver,
                requestSupplier,
                threadPool.executor(ThreadPool.Names.MANAGEMENT)
            );
            this.indicesService = Objects.requireNonNull(indicesService);
        }

        @Override
        protected ShardsIterator shards(final ClusterState state, final InternalRequest request) {
            return state.routingTable().shardRoutingTable(request.concreteIndex(), request.request().getShardId().id()).primaryShardIt();
        }

        @Override
        protected void asyncShardOperation(T request, ShardId shardId, final ActionListener listener) {
            final IndexService indexService = indicesService.indexServiceSafe(shardId.getIndex());
            final IndexShard indexShard = indexService.getShard(shardId.id());
            indexShard.acquirePrimaryOperationPermit(listener.delegateFailureAndWrap((delegatedListener, releasable) -> {
                try (Releasable ignore = releasable) {
                    doRetentionLeaseAction(indexShard, request, delegatedListener);
                }
            }), EsExecutors.DIRECT_EXECUTOR_SERVICE);
        }

        @Override
        protected ActionResponse.Empty shardOperation(final T request, final ShardId shardId) {
            throw new UnsupportedOperationException();
        }

        abstract void doRetentionLeaseAction(IndexShard indexShard, T request, ActionListener listener);

        @Override
        protected final Writeable.Reader getResponseReader() {
            return in -> ActionResponse.Empty.INSTANCE;
        }

        @Override
        protected boolean resolveIndex(final T request) {
            return false;
        }

    }

    public static class TransportAddAction extends TransportRetentionLeaseAction {

        @Inject
        public TransportAddAction(
            final ThreadPool threadPool,
            final ClusterService clusterService,
            final TransportService transportService,
            final ActionFilters actionFilters,
            final IndexNameExpressionResolver indexNameExpressionResolver,
            final IndicesService indicesService
        ) {
            super(
                ADD.name(),
                threadPool,
                clusterService,
                transportService,
                actionFilters,
                indexNameExpressionResolver,
                indicesService,
                AddRequest::new
            );
        }

        @Override
        void doRetentionLeaseAction(
            final IndexShard indexShard,
            final AddRequest request,
            final ActionListener listener
        ) {
            indexShard.addRetentionLease(
                request.getId(),
                request.getRetainingSequenceNumber(),
                request.getSource(),
                listener.map(r -> ActionResponse.Empty.INSTANCE)
            );
        }
    }

    public static class TransportRenewAction extends TransportRetentionLeaseAction {

        @Inject
        public TransportRenewAction(
            final ThreadPool threadPool,
            final ClusterService clusterService,
            final TransportService transportService,
            final ActionFilters actionFilters,
            final IndexNameExpressionResolver indexNameExpressionResolver,
            final IndicesService indicesService
        ) {
            super(
                RENEW.name(),
                threadPool,
                clusterService,
                transportService,
                actionFilters,
                indexNameExpressionResolver,
                indicesService,
                RenewRequest::new
            );
        }

        @Override
        void doRetentionLeaseAction(
            final IndexShard indexShard,
            final RenewRequest request,
            final ActionListener listener
        ) {
            indexShard.renewRetentionLease(request.getId(), request.getRetainingSequenceNumber(), request.getSource());
            listener.onResponse(ActionResponse.Empty.INSTANCE);
        }

    }

    public static class TransportRemoveAction extends TransportRetentionLeaseAction {

        @Inject
        public TransportRemoveAction(
            final ThreadPool threadPool,
            final ClusterService clusterService,
            final TransportService transportService,
            final ActionFilters actionFilters,
            final IndexNameExpressionResolver indexNameExpressionResolver,
            final IndicesService indicesService
        ) {
            super(
                REMOVE.name(),
                threadPool,
                clusterService,
                transportService,
                actionFilters,
                indexNameExpressionResolver,
                indicesService,
                RemoveRequest::new
            );
        }

        @Override
        void doRetentionLeaseAction(
            final IndexShard indexShard,
            final RemoveRequest request,
            final ActionListener listener
        ) {
            indexShard.removeRetentionLease(request.getId(), listener.map(r -> ActionResponse.Empty.INSTANCE));
        }
    }

    private abstract static class Request> extends SingleShardRequest {

        private final ShardId shardId;

        public ShardId getShardId() {
            return shardId;
        }

        private final String id;

        public String getId() {
            return id;
        }

        Request(StreamInput in) throws IOException {
            super(in);
            shardId = new ShardId(in);
            id = in.readString();
        }

        Request(final ShardId shardId, final String id) {
            super(Objects.requireNonNull(shardId).getIndexName());
            this.shardId = shardId;
            this.id = Objects.requireNonNull(id);
        }

        @Override
        public ActionRequestValidationException validate() {
            return null;
        }

        @Override
        public void writeTo(final StreamOutput out) throws IOException {
            super.writeTo(out);
            shardId.writeTo(out);
            out.writeString(id);
        }

    }

    private abstract static class AddOrRenewRequest> extends Request {

        private final long retainingSequenceNumber;

        public long getRetainingSequenceNumber() {
            return retainingSequenceNumber;
        }

        private final String source;

        public String getSource() {
            return source;
        }

        AddOrRenewRequest(StreamInput in) throws IOException {
            super(in);
            retainingSequenceNumber = in.readZLong();
            source = in.readString();
        }

        AddOrRenewRequest(final ShardId shardId, final String id, final long retainingSequenceNumber, final String source) {
            super(shardId, id);
            if (retainingSequenceNumber < 0 && retainingSequenceNumber != RETAIN_ALL) {
                throw new IllegalArgumentException("retaining sequence number [" + retainingSequenceNumber + "] out of range");
            }
            this.retainingSequenceNumber = retainingSequenceNumber;
            this.source = Objects.requireNonNull(source);
        }

        @Override
        public void writeTo(final StreamOutput out) throws IOException {
            super.writeTo(out);
            out.writeZLong(retainingSequenceNumber);
            out.writeString(source);
        }

    }

    public static class AddRequest extends AddOrRenewRequest {

        AddRequest(StreamInput in) throws IOException {
            super(in);
        }

        public AddRequest(final ShardId shardId, final String id, final long retainingSequenceNumber, final String source) {
            super(shardId, id, retainingSequenceNumber, source);
        }

    }

    public static class RenewRequest extends AddOrRenewRequest {

        RenewRequest(StreamInput in) throws IOException {
            super(in);
        }

        public RenewRequest(final ShardId shardId, final String id, final long retainingSequenceNumber, final String source) {
            super(shardId, id, retainingSequenceNumber, source);
        }

    }

    public static class RemoveRequest extends Request {

        RemoveRequest(StreamInput in) throws IOException {
            super(in);
        }

        public RemoveRequest(final ShardId shardId, final String id) {
            super(shardId, id);
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy