com.taobao.drc.clusterclient.partition.CheckpointManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of consumer-core Show documentation
Show all versions of consumer-core Show documentation
The java consumer core component for Data Transmission Service
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();
}
};
}
}