Search in sources :

Example 1 with QueueEntryRow

use of co.cask.cdap.data2.transaction.queue.QueueEntryRow in project cdap by caskdata.

the class InMemoryQueue method dequeue.

public ImmutablePair<List<Key>, List<byte[]>> dequeue(Transaction tx, ConsumerConfig config, ConsumerState consumerState, int maxBatchSize) {
    List<Key> keys = Lists.newArrayListWithCapacity(maxBatchSize);
    List<byte[]> datas = Lists.newArrayListWithCapacity(maxBatchSize);
    NavigableSet<Key> keysToScan = consumerState.startKey == null ? entries.navigableKeySet() : entries.tailMap(consumerState.startKey).navigableKeySet();
    boolean updateStartKey = true;
    // navigableKeySet is immune to concurrent modification
    for (Key key : keysToScan) {
        if (keys.size() >= maxBatchSize) {
            break;
        }
        if (updateStartKey && key.txId < tx.getFirstShortInProgress()) {
            // See QueueEntryRow#canCommit for reason.
            consumerState.startKey = key;
        }
        if (tx.getReadPointer() < key.txId) {
            // the entry is newer than the current transaction. so are all subsequent entries. bail out.
            break;
        } else if (tx.isInProgress(key.txId)) {
            // the entry is in the exclude list of current transaction. There is a chance that visible entries follow.
            // next time we have to revisit this entry
            updateStartKey = false;
            continue;
        }
        Item item = entries.get(key);
        if (item == null) {
            // entry was deleted (evicted or undone) after we started iterating
            continue;
        }
        // check whether this is processed already
        ConsumerEntryState state = item.getConsumerState(config.getGroupId());
        if (ConsumerEntryState.PROCESSED.equals(state)) {
            // already processed but not yet evicted. move on
            continue;
        }
        if (config.getDequeueStrategy().equals(DequeueStrategy.FIFO)) {
            // for FIFO, attempt to claim the entry and return it
            if (item.claim(config)) {
                keys.add(key);
                datas.add(item.entry.getData());
            }
            // else: someone else claimed it, or it was already processed, move on, but we may have to revisit this.
            updateStartKey = false;
            continue;
        }
        // for hash/round robin, if group size is 1, just take it
        if (config.getGroupSize() == 1) {
            keys.add(key);
            datas.add(item.entry.getData());
            updateStartKey = false;
            continue;
        }
        // hash by entry hash key or entry id
        int hash;
        if (config.getDequeueStrategy().equals(DequeueStrategy.ROUND_ROBIN)) {
            hash = key.hashCode();
        } else {
            Integer hashFoundInEntry = item.entry.getHashKey(config.getHashKey());
            hash = hashFoundInEntry == null ? 0 : hashFoundInEntry;
        }
        // modulo of a negative is negative, make sure we're positive or 0.
        if (Math.abs(hash) % config.getGroupSize() == config.getInstanceId()) {
            keys.add(key);
            datas.add(item.entry.getData());
            updateStartKey = false;
        }
    }
    return keys.isEmpty() ? null : ImmutablePair.of(keys, datas);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConsumerEntryState(co.cask.cdap.data2.transaction.queue.ConsumerEntryState)

Aggregations

ConsumerEntryState (co.cask.cdap.data2.transaction.queue.ConsumerEntryState)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1