Package com.amazonaws.services.kinesis.clientlibrary.lib.worker

Source Code of com.amazonaws.services.kinesis.clientlibrary.lib.worker.RecordProcessorCheckpointer

/*
* Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Amazon Software License (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/asl/
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.services.kinesis.clientlibrary.lib.worker;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amazonaws.services.kinesis.clientlibrary.exceptions.InvalidStateException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.KinesisClientLibDependencyException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.KinesisClientLibException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ShutdownException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ThrottlingException;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.ICheckpoint;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer;
import com.amazonaws.services.kinesis.clientlibrary.lib.checkpoint.SentinelCheckpoint;

/**
* This class is used to enable RecordProcessors to checkpoint their progress.
* The Amazon Kinesis Client Library will instantiate an object and provide a reference to the application
* RecordProcessor instance. Amazon Kinesis Client Library will create one instance per shard assignment.
*/
class RecordProcessorCheckpointer implements IRecordProcessorCheckpointer {

    private static final Log LOG = LogFactory.getLog(RecordProcessorCheckpointer.class);

    private ICheckpoint checkpoint;

    private String largestPermittedCheckpointValue;
    // Set to the last value set via checkpoint().
    // Sample use: verify application shutdown() invoked checkpoint() at the end of a shard.
    private String lastCheckpointValue;

    private ShardInfo shardInfo;

    private SequenceNumberValidator sequenceNumberValidator;

    private CheckpointValueComparator checkpointValueComparator;

    private String sequenceNumberAtShardEnd;

    /**
     * Only has package level access, since only the Amazon Kinesis Client Library should be creating these.
     *
     * @param checkpoint Used to checkpoint progress of a RecordProcessor
     * @param validator Used for validating sequence numbers
     * @param comparator Used for checking the order of checkpoint values
     */
    RecordProcessorCheckpointer(ShardInfo shardInfo,
            ICheckpoint checkpoint,
            SequenceNumberValidator validator,
            CheckpointValueComparator comparator) {
        this.shardInfo = shardInfo;
        this.checkpoint = checkpoint;
        this.sequenceNumberValidator = validator;
        this.checkpointValueComparator = comparator;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized void checkpoint()
        throws KinesisClientLibDependencyException, InvalidStateException, ThrottlingException, ShutdownException {
        advancePosition(this.largestPermittedCheckpointValue);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public synchronized void checkpoint(String sequenceNumber)
        throws KinesisClientLibDependencyException, InvalidStateException, ThrottlingException, ShutdownException,
        IllegalArgumentException {

        // throws exception if sequence number shouldn't be checkpointed for this shard
        sequenceNumberValidator.validateSequenceNumber(sequenceNumber);
        /*
         * If there isn't a last checkpoint value, we only care about checking the upper bound.
         * If there is a last checkpoint value, we want to check both the lower and upper bound.
         */
        if ((lastCheckpointValue == null
                || checkpointValueComparator.compare(lastCheckpointValue, sequenceNumber) <= 0)
                && checkpointValueComparator.compare(sequenceNumber, largestPermittedCheckpointValue) <= 0) {

            this.advancePosition(sequenceNumber);
        } else {
            throw new IllegalArgumentException("Could not checkpoint at sequence number " + sequenceNumber
                    + " it did not fall into acceptable range between the last sequence number checkpointed "
                    + this.lastCheckpointValue + " and the greatest sequence number passed to this record processor "
                    + this.largestPermittedCheckpointValue);
        }

    }

    /**
     * @return the lastCheckpointValue
     */
    String getLastCheckpointValue() {
        return lastCheckpointValue;
    }

    /**
     * Used for testing.
     *
     * @return the sequenceNumber
     */
    synchronized String getLargestPermittedCheckpointValue() {
        return largestPermittedCheckpointValue;
    }

    /**
     * @param largestPermittedCheckpointValue the checkpoint value to set
     */
    synchronized void setLargestPermittedCheckpointValue(String checkpointValue) {
        this.largestPermittedCheckpointValue = checkpointValue;
    }

    /**
     * Used to remember the last sequence number before SHARD_END to allow us to prevent the checkpointer from
     * checkpointing at the end of the shard twice (i.e. at the last sequence number and then again at SHARD_END).
     *
     * @param sequenceNumber
     */
    synchronized void setSequenceNumberAtShardEnd(String sequenceNumber) {
        this.sequenceNumberAtShardEnd = sequenceNumber;
    }

    /**
     * Internal API - has package level access only for testing purposes.
     *
     * @param sequenceNumber
     *
     * @throws KinesisClientLibDependencyException
     * @throws ThrottlingException
     * @throws ShutdownException
     * @throws InvalidStateException
     */
    void advancePosition(String sequenceNumber)
        throws KinesisClientLibDependencyException, InvalidStateException, ThrottlingException, ShutdownException {
        String checkpointValue = sequenceNumber;
        if (sequenceNumberAtShardEnd != null && sequenceNumberAtShardEnd.equals(sequenceNumber)) {
            // If we are about to checkpoint the very last sequence number for this shard, we might as well
            // just checkpoint at SHARD_END
            checkpointValue = SentinelCheckpoint.SHARD_END.toString();
        }
        // Don't checkpoint a value we already successfully checkpointed
        if (sequenceNumber != null && !sequenceNumber.equals(lastCheckpointValue)) {
            try {
                checkpoint.setCheckpoint(shardInfo.getShardId(), checkpointValue, shardInfo.getConcurrencyToken());
                lastCheckpointValue = checkpointValue;
            } catch (ThrottlingException e) {
                throw e;
            } catch (ShutdownException e) {
                throw e;
            } catch (InvalidStateException e) {
                throw e;
            } catch (KinesisClientLibDependencyException e) {
                throw e;
            } catch (KinesisClientLibException e) {
                LOG.warn("Caught exception setting checkpoint.", e);
                throw new KinesisClientLibDependencyException("Caught exception while checkpointing", e);
            }
        }
    }
}
TOP

Related Classes of com.amazonaws.services.kinesis.clientlibrary.lib.worker.RecordProcessorCheckpointer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.