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

io.aeron.cluster.client.EgressPoller Maven / Gradle / Ivy

There is a newer version: 1.46.2
Show newest version
/*
 * Copyright 2014-2024 Real Logic Limited.
 *
 * Licensed 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
 *
 * https://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 io.aeron.cluster.client;

import io.aeron.Aeron;
import io.aeron.ControlledFragmentAssembler;
import io.aeron.Image;
import io.aeron.Subscription;
import io.aeron.cluster.codecs.*;
import io.aeron.logbuffer.ControlledFragmentHandler;
import io.aeron.logbuffer.Header;
import org.agrona.DirectBuffer;

/**
 * Poller for the egress from a cluster to capture administration message details.
 */
public final class EgressPoller implements ControlledFragmentHandler
{
    private final int fragmentLimit;
    private final MessageHeaderDecoder messageHeaderDecoder = new MessageHeaderDecoder();
    private final SessionEventDecoder sessionEventDecoder = new SessionEventDecoder();
    private final ChallengeDecoder challengeDecoder = new ChallengeDecoder();
    private final NewLeaderEventDecoder newLeaderEventDecoder = new NewLeaderEventDecoder();
    private final SessionMessageHeaderDecoder sessionMessageHeaderDecoder = new SessionMessageHeaderDecoder();
    private final ControlledFragmentAssembler fragmentAssembler = new ControlledFragmentAssembler(this);
    private final Subscription subscription;

    private Image egressImage;
    private long clusterSessionId = Aeron.NULL_VALUE;
    private long correlationId = Aeron.NULL_VALUE;
    private long leadershipTermId = Aeron.NULL_VALUE;
    private int leaderMemberId = Aeron.NULL_VALUE;
    private int templateId = Aeron.NULL_VALUE;
    private int version = 0;
    private boolean isPollComplete = false;
    private EventCode eventCode;
    private String detail = "";
    private byte[] encodedChallenge;

    /**
     * Construct a poller on the egress subscription.
     *
     * @param subscription  for egress from the cluster.
     * @param fragmentLimit for each poll operation.
     */
    public EgressPoller(final Subscription subscription, final int fragmentLimit)
    {
        this.subscription = subscription;
        this.fragmentLimit = fragmentLimit;
    }

    /**
     * Get the {@link Subscription} used for polling events.
     *
     * @return the {@link Subscription} used for polling events.
     */
    public Subscription subscription()
    {
        return subscription;
    }

    /**
     * {@link Image} for the egress response from the cluster which can be used for connection tracking.
     *
     * @return {@link Image} for the egress response from the cluster which can be used for connection tracking.
     */
    public Image egressImage()
    {
        return egressImage;
    }

    /**
     * Get the template id of the last received event.
     *
     * @return the template id of the last received event.
     */
    public int templateId()
    {
        return templateId;
    }

    /**
     * Cluster session id of the last polled event or {@link Aeron#NULL_VALUE} if poll returned nothing.
     *
     * @return cluster session id of the last polled event or {@link Aeron#NULL_VALUE} if not returned.
     */
    public long clusterSessionId()
    {
        return clusterSessionId;
    }

    /**
     * Correlation id of the last polled event or {@link Aeron#NULL_VALUE} if poll returned nothing.
     *
     * @return correlation id of the last polled event or {@link Aeron#NULL_VALUE} if not returned.
     */
    public long correlationId()
    {
        return correlationId;
    }

    /**
     * Leadership term id of the last polled event or {@link Aeron#NULL_VALUE} if poll returned nothing.
     *
     * @return leadership term id of the last polled event or {@link Aeron#NULL_VALUE} if not returned.
     */
    public long leadershipTermId()
    {
        return leadershipTermId;
    }

    /**
     * Leader cluster member id of the last polled event or {@link Aeron#NULL_VALUE} if poll returned nothing.
     *
     * @return leader cluster member id of the last polled event or {@link Aeron#NULL_VALUE} if poll returned nothing.
     */
    public int leaderMemberId()
    {
        return leaderMemberId;
    }

    /**
     * Get the event code returned from the last session event.
     *
     * @return the event code returned from the last session event.
     */
    public EventCode eventCode()
    {
        return eventCode;
    }

    /**
     * Version response from the server in semantic version form.
     *
     * @return response from the server in semantic version form.
     */
    public int version()
    {
        return version;
    }

    /**
     * Get the detail returned from the last session event.
     *
     * @return the detail returned from the last session event.
     */
    public String detail()
    {
        return detail;
    }

    /**
     * Get the encoded challenge in the last challenge.
     *
     * @return the encoded challenge in the last challenge or null if last message was not a challenge.
     */
    public byte[] encodedChallenge()
    {
        return encodedChallenge;
    }

    /**
     * Has the last polling action received a complete event?
     *
     * @return true if the last polling action received a complete event.
     */
    public boolean isPollComplete()
    {
        return isPollComplete;
    }

    /**
     * Was last message a challenge or not?
     *
     * @return true if last message was a challenge or false if not.
     */
    public boolean isChallenged()
    {
        return ChallengeDecoder.TEMPLATE_ID == templateId;
    }

    /**
     * Reset last captured value and poll the egress subscription for output.
     *
     * @return number of fragments consumed.
     */
    public int poll()
    {
        if (isPollComplete)
        {
            isPollComplete = false;
            clusterSessionId = Aeron.NULL_VALUE;
            correlationId = Aeron.NULL_VALUE;
            leadershipTermId = Aeron.NULL_VALUE;
            leaderMemberId = Aeron.NULL_VALUE;
            templateId = Aeron.NULL_VALUE;
            version = 0;
            eventCode = null;
            detail = "";
            encodedChallenge = null;
        }

        return subscription.controlledPoll(fragmentAssembler, fragmentLimit);
    }

    /**
     * {@inheritDoc}
     */
    public ControlledFragmentAssembler.Action onFragment(
        final DirectBuffer buffer, final int offset, final int length, final Header header)
    {
        if (isPollComplete)
        {
            return Action.ABORT;
        }

        messageHeaderDecoder.wrap(buffer, offset);

        final int schemaId = messageHeaderDecoder.schemaId();
        if (schemaId != MessageHeaderDecoder.SCHEMA_ID)
        {
            throw new ClusterException("expected schemaId=" + MessageHeaderDecoder.SCHEMA_ID + ", actual=" + schemaId);
        }

        templateId = messageHeaderDecoder.templateId();
        switch (templateId)
        {
            case SessionMessageHeaderDecoder.TEMPLATE_ID:
                sessionMessageHeaderDecoder.wrap(
                    buffer,
                    offset + MessageHeaderDecoder.ENCODED_LENGTH,
                    messageHeaderDecoder.blockLength(),
                    messageHeaderDecoder.version());

                leadershipTermId = sessionMessageHeaderDecoder.leadershipTermId();
                clusterSessionId = sessionMessageHeaderDecoder.clusterSessionId();
                isPollComplete = true;
                return Action.BREAK;

            case SessionEventDecoder.TEMPLATE_ID:
                sessionEventDecoder.wrap(
                    buffer,
                    offset + MessageHeaderDecoder.ENCODED_LENGTH,
                    messageHeaderDecoder.blockLength(),
                    messageHeaderDecoder.version());

                clusterSessionId = sessionEventDecoder.clusterSessionId();
                correlationId = sessionEventDecoder.correlationId();
                leadershipTermId = sessionEventDecoder.leadershipTermId();
                leaderMemberId = sessionEventDecoder.leaderMemberId();
                eventCode = sessionEventDecoder.code();
                version = sessionEventDecoder.version();
                detail = sessionEventDecoder.detail();
                isPollComplete = true;
                egressImage = (Image)header.context();
                return Action.BREAK;

            case NewLeaderEventDecoder.TEMPLATE_ID:
                newLeaderEventDecoder.wrap(
                    buffer,
                    offset + MessageHeaderDecoder.ENCODED_LENGTH,
                    messageHeaderDecoder.blockLength(),
                    messageHeaderDecoder.version());

                clusterSessionId = newLeaderEventDecoder.clusterSessionId();
                leadershipTermId = newLeaderEventDecoder.leadershipTermId();
                leaderMemberId = newLeaderEventDecoder.leaderMemberId();
                detail = newLeaderEventDecoder.ingressEndpoints();
                isPollComplete = true;
                egressImage = (Image)header.context();
                return Action.BREAK;

            case ChallengeDecoder.TEMPLATE_ID:
                challengeDecoder.wrap(
                    buffer,
                    offset + MessageHeaderDecoder.ENCODED_LENGTH,
                    messageHeaderDecoder.blockLength(),
                    messageHeaderDecoder.version());

                encodedChallenge = new byte[challengeDecoder.encodedChallengeLength()];
                challengeDecoder.getEncodedChallenge(encodedChallenge, 0, challengeDecoder.encodedChallengeLength());

                clusterSessionId = challengeDecoder.clusterSessionId();
                correlationId = challengeDecoder.correlationId();
                isPollComplete = true;
                return Action.BREAK;
        }

        return Action.CONTINUE;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy