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

org.elassandra.discovery.AppliedClusterStateAction Maven / Gradle / Ivy

There is a newer version: 6.2.3.31
Show newest version
/*
 * 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.elassandra.discovery;

import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.discovery.DiscoverySettings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.EmptyTransportResponseHandler;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportException;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportRequestHandler;
import org.elasticsearch.transport.TransportRequestOptions;
import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.transport.TransportService;

import java.io.IOException;

public class AppliedClusterStateAction extends AbstractComponent {

    public static final String APPLIED_ACTION_NAME = "internal:discovery/cassandra/publish/applied";

    public interface AppliedClusterStateListener {
        /**
         * called when a cluster state has been committed and is ready to be processed
         */
        void onClusterStateApplied(String nodeId, String x2, Exception e, ActionListener processedListener);
    }

    private final TransportService transportService;
    private final AppliedClusterStateListener appliedClusterStateListener;
    private final DiscoverySettings discoverySettings;

    public AppliedClusterStateAction(
            Settings settings,
            TransportService transportService,
            AppliedClusterStateListener incomingClusterStateListener,
            DiscoverySettings discoverySettings) {
        super(settings);
        this.transportService = transportService;
        this.appliedClusterStateListener = incomingClusterStateListener;
        this.discoverySettings = discoverySettings;
        transportService.registerRequestHandler(APPLIED_ACTION_NAME, AppliedClusterStateRequest::new, ThreadPool.Names.SAME, false, false, new AppliedClusterStateRequestHandler());
    }

    public void sendAppliedToNode(final DiscoveryNode node, final ClusterState clusterState, final Exception exception) {
        try {
            logger.trace("sending commit for cluster state [{}] to [{}]",
                clusterState.metaData().x2(), node);
            TransportRequestOptions options = TransportRequestOptions.builder().withType(TransportRequestOptions.Type.STATE).build();
            // no need to put a timeout on the options here, because we want the response to eventually be received
            // and not log an error if it arrives after the timeout
            transportService.sendRequest(node, APPLIED_ACTION_NAME,
                    new AppliedClusterStateRequest(transportService.getLocalNode().getId(), clusterState.metaData().x2(), exception),
                    options,
                    new EmptyTransportResponseHandler(ThreadPool.Names.SAME) {
                        @Override
                        public void handleResponse(TransportResponse.Empty response) {
                            logger.debug("node {} responded to cluster state commit [{}]", node, clusterState.metaData().x2());
                        }

                        @Override
                        public void handleException(TransportException exp) {
                            logger.debug((org.apache.logging.log4j.util.Supplier) () ->
                                new ParameterizedMessage("failed to commit cluster state [{}] to {}", clusterState.metaData().x2(), node), exp);
                        }
                    }
                    );
        } catch (Exception t) {
            logger.warn((org.apache.logging.log4j.util.Supplier) () ->
                new ParameterizedMessage("error sending cluster state commit state [{}] to {}", clusterState.metaData().x2(), node), t);
        }
    }

    protected void handleAppliedRequest(AppliedClusterStateRequest request, final TransportChannel channel) {
        appliedClusterStateListener.onClusterStateApplied(request.nodeId, request.x2, request.e, new ActionListener() {

            @Override
            public void onResponse(Void ignore) {
                try {
                    // send a response to the master to indicate that this cluster state has been processed post committing it.
                    channel.sendResponse(TransportResponse.Empty.INSTANCE);
                } catch (Exception e) {
                    logger.debug("failed to send response on cluster state processed", e);
                    onFailure(e);
                }
            }

            @Override
            public void onFailure(Exception e) {
                try {
                    channel.sendResponse(e);
                } catch (Exception inner) {
                    inner.addSuppressed(e);
                    logger.debug("failed to send response on cluster state processed", inner);
                }
            }
        });
    }

    private class AppliedClusterStateRequestHandler implements TransportRequestHandler {
        @Override
        public void messageReceived(AppliedClusterStateRequest request, final TransportChannel channel) throws Exception {
            handleAppliedRequest(request, channel);
        }
    }

    protected static class AppliedClusterStateRequest extends TransportRequest {
        String nodeId;
        String x2;
        Exception e;

        public AppliedClusterStateRequest() {
        }

        public AppliedClusterStateRequest(String nodeId, String x2, Exception e) {
            this.nodeId = nodeId;
            this.x2 = x2;
            this.e = e;
        }

        @Override
        public void readFrom(StreamInput in) throws IOException {
            super.readFrom(in);
            nodeId = in.readString();
            x2 = in.readString();
            e = in.readException();
        }

        @Override
        public void writeTo(StreamOutput out) throws IOException {
            super.writeTo(out);
            out.writeString(this.nodeId);
            out.writeString(this.x2);
            out.writeException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy