queue.lockManager.releaseLock(lock);
}
}
List<MessageContext> readMessagesFromShardUsingDefaultLock(String shardName, int itemsToPop) throws MessageQueueException, BusyLockException {
MutationBatch m = null;
MessageQueueEntry lockColumn = null;
ColumnListMutation<MessageQueueEntry> rowMutation = null;
int lockColumnCount = 0;
// Try locking first
try {
// 1. Write the lock column
lockColumn = MessageQueueEntry.newLockEntry(MessageQueueEntryState.None);
long curTimeMicros = TimeUUIDUtils.getTimeFromUUID(lockColumn.getTimestamp());
m = queue.keyspace.prepareMutationBatch().setConsistencyLevel(queue.consistencyLevel);
m.withRow(queue.queueColumnFamily, shardName).putColumn(lockColumn, curTimeMicros + queue.lockTimeout, queue.lockTtl);
m.execute();
// 2. Read back lock columns and entries
ColumnList<MessageQueueEntry> result = queue.keyspace.prepareQuery(queue.queueColumnFamily).setConsistencyLevel(queue.consistencyLevel).getKey(shardName)
.withColumnRange(ShardedDistributedMessageQueue.entrySerializer
.buildRange()
.greaterThanEquals((byte) MessageQueueEntryType.Lock.ordinal())
.lessThanEquals((byte) MessageQueueEntryType.Lock.ordinal())
.build()
)
.execute()
.getResult();
m = queue.keyspace.prepareMutationBatch().setConsistencyLevel(queue.consistencyLevel);
rowMutation = m.withRow(queue.queueColumnFamily, shardName);
rowMutation.deleteColumn(lockColumn);
int lockCount = 0;
boolean lockAcquired = false;
lockColumnCount = result.size();
for (Column<MessageQueueEntry> column : result) {
MessageQueueEntry lock = column.getName();
if (lock.getType() == MessageQueueEntryType.Lock) {
lockColumnCount++;
// Stale lock so we can discard it
if (column.getLongValue() < curTimeMicros) {
queue.stats.incExpiredLockCount();
rowMutation.deleteColumn(lock);
} else if (lock.getState() == MessageQueueEntryState.Acquired) {
throw new BusyLockException("Not first lock");
} else {
lockCount++;
if (lockCount == 1 && lock.getTimestamp().equals(lockColumn.getTimestamp())) {
lockAcquired = true;
}
}
if (!lockAcquired) {
throw new BusyLockException("Not first lock");
}
// Write the acquired lock column
lockColumn = MessageQueueEntry.newLockEntry(lockColumn.getTimestamp(), MessageQueueEntryState.Acquired);
rowMutation.putColumn(lockColumn, curTimeMicros + queue.lockTimeout, queue.lockTtl);
}
}
} catch (BusyLockException e) {
queue.stats.incLockContentionCount();
throw e;
} catch (ConnectionException e) {
LOG.error("Error reading shard " + shardName, e);
throw new MessageQueueException("Error", e);
} finally {
try {
m.execute();
} catch (Exception e) {
throw new MessageQueueException("Error committing lock", e);
}
}
long curTimeMicros = TimeUUIDUtils.getMicrosTimeFromUUID(lockColumn.getTimestamp());
m = queue.keyspace.prepareMutationBatch().setConsistencyLevel(queue.consistencyLevel);
// First, release the lock column
rowMutation = m.withRow(queue.queueColumnFamily, shardName);
rowMutation.deleteColumn(lockColumn);
return readMessagesInternal(shardName, itemsToPop, lockColumnCount, lockColumn, rowMutation, m, curTimeMicros);
}