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

com.taobao.drc.clusterclient.partition.CheckpointManager Maven / Gradle / Ivy

There is a newer version: 5.0.0.1.beta
Show newest version
package com.taobao.drc.clusterclient.partition;

import com.taobao.drc.clusterclient.util.Gaugeable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yangyang
 * @since 2017/7/7
 */
public class CheckpointManager implements Gaugeable, Iterable {
    public static final String KEY_CHECKPOINT_FIRST = "checkpoint.first";
    public static final String KEY_CHECKPOINT_LAST = "checkpoint.last";
    public static final String KEY_CHECKPOINT_LATEST = "checkpoint.latest";
    public static final String KEY_CHECKPOINT_QUEUE_SIZE = "checkpoint.queue.size";
    public static final String KEY_CHECKPOINT_QUEUE_CAPACITY = "checkpoint-manager.queue.capacity";

    private static final Logger logger = LoggerFactory.getLogger(CheckpointManager.class);

    private final int capacity;
    private int count;

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final BaseCheckpoint head = new BaseCheckpoint(null);
    private final BaseCheckpoint tail = new BaseCheckpoint(null);

    private BaseCheckpoint latest = null;

    public CheckpointManager(int capacity) {
        if (capacity <= 0) {
            throw new IllegalArgumentException("Illegal capacity [" + capacity + "]");
        }
        this.capacity = capacity;
        this.count = 0;

        head.setPrev(tail);
        head.setNext(tail);
        tail.setPrev(head);
        tail.setNext(head);
    }

    public void book(BaseCheckpoint checkpoint) throws InterruptedException {
        if (checkpoint == null) {
            throw new NullPointerException();
        }
        lock.lock();
        try {
            if (checkpoint.getPrev() != null || checkpoint.getNext() != null) {
                throw new IllegalArgumentException("Invalid checkpoint to book: checkpoint [" + checkpoint.toString() + "] may have already been booked");
            }
            while (count >= capacity) {
                logger.warn("ack too slow, checkpoint queue is full:count="+count+",capacity="+capacity);
                notFull.await();
            }
            checkpoint.setPrev(tail.getPrev());
            checkpoint.setNext(tail);
            tail.getPrev().setNext(checkpoint);
            tail.setPrev(checkpoint);
            latest = checkpoint;
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void ack(BaseCheckpoint checkpoint) {
        if (checkpoint == null) {
            throw new NullPointerException();
        }
        lock.lock();
        try {
            if (checkpoint.getPrev() == null || checkpoint.getNext() == null) {
                throw new NoSuchElementException("Invalid checkpoint to ack: checkpoint [" + checkpoint.toString() + "] may have already been committed");
            }
            if (checkpoint.isAcked()) {
                //throw new NoSuchElementException("Checkpoint [" + checkpoint + "] has already been acked");
                logger.debug("Checkpoint[[{}]] has already been acked",checkpoint);
            }
            else
            {
                BaseCheckpoint prev = checkpoint.getPrev();
                BaseCheckpoint next = checkpoint.getNext();
                prev.setNext(next);
                next.setPrev(prev);
                checkpoint.ack();
                count--;
                notFull.signal();
            }
        } finally {
            lock.unlock();
        }
    }

    public BaseCheckpoint getFirstNotAckedOrLatestCheckpoint() {
        lock.lock();
        try {
            if (count == 0) {
                return latest;
            }
            return head.getNext();
        } finally {
            lock.unlock();
        }
    }

    public int size() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }

    public int getCapacity() {
        return this.capacity;
    }

    private BaseCheckpoint getFirstCheckpoint() {
        if (head.getNext() == tail) {
            return null;
        }
        return head.getNext();
    }

    private BaseCheckpoint getLastCheckpoint() {
        if (tail.getPrev() == head) {
            return null;
        }
        return tail.getPrev();
    }

    @Override
    public Map getMetrics() {
        Map map = new TreeMap();
        map.put(KEY_CHECKPOINT_QUEUE_CAPACITY, capacity);
        lock.lock();
        try {
            map.put(KEY_CHECKPOINT_QUEUE_SIZE, size());
            if (getFirstCheckpoint() != null) {
                map.put(KEY_CHECKPOINT_FIRST, getFirstCheckpoint().toString());
            }
            if (getLastCheckpoint() != null) {
                map.put(KEY_CHECKPOINT_LAST, getLastCheckpoint().toString());
            }
            if (latest != null) {
                map.put(KEY_CHECKPOINT_LATEST, latest.toString());
            }
            return map;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public Iterator iterator() {
        return new Iterator() {
            private BaseCheckpoint current = head.getNext();

            @Override
            public boolean hasNext() {
                return current != null && current != tail;
            }

            @Override
            public BaseCheckpoint next() {
                lock.lock();
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                try {
                    BaseCheckpoint ret = current;
                    current = current.getNext();
                    while (current != null && current != tail) {
                        if (!current.isAcked()) {
                            break;
                        }
                        current = current.getNext();
                    }
                    return ret;
                } finally {
                    lock.unlock();
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy