if (cacheAvailable) {
// get the messageIds from in redis list
ShardedJedis jedis = null;
boolean brokenJedis = false;
try {
jedis = getResource();
// process revisible-set before getting from queue
tryCheckAndProcessRevisibleSet(queue.getRelativeUrl(), shard, CMBProperties.getInstance().getRedisRevisibleSetFrequencySec());
try {
if (checkAndSetVisibilityProcessing(queue.getRelativeUrl(), shard, CMBProperties.getInstance().getRedisRevisibleFrequencySec())) {
logger.debug("event=scheduled_revisibility_processor");
}
} catch (SetFailedException e) {
}
boolean done = false;
while (!done) {
boolean emptyQueue = false;
HashMap<String, String> messageIdToMemId = new HashMap<String, String>();
List<String> messageIds = new LinkedList<String>();
for (int i = 0; i < maxNumberOfMessages && !emptyQueue; i++) {
long ts1 = System.currentTimeMillis();
String memId;
if (visibilityTO > 0) {
memId = jedis.lpop(queue.getRelativeUrl() + "-" + shard + "-Q");
} else {
memId = jedis.lindex(queue.getRelativeUrl() + "-" + shard + "-Q", i);
}
long ts2 = System.currentTimeMillis();
CQSControllerServlet.valueAccumulator.addToCounter(AccumulatorName.RedisTime, (ts2 - ts1));
if (memId == null || memId.equals("nil")) { //done
emptyQueue = true;
} else {
String messageId = getMemQueueMessageMessageId(queue.getRelativeUrlHash(),memId);
messageIds.add(messageId);
messageIdToMemId.put(messageId, memId);
}
}
if (messageIds.size() == 0) {
CQSMonitor.getInstance().registerEmptyResp(queue.getRelativeUrl(), 1);
return Collections.emptyList();
}
// By here messageIds have Underlying layer's messageids.
// Get messages from underlying layer. The total returned may not be what was
// in mem cache since master-master replication to Cassandra could mean other
// colo deleted the message form underlying storage.
logger.debug("event=found_msg_ids_in_redis num_mem_ids=" + messageIds.size());
try {
Map<String, CQSMessage> persisMap = persistenceStorage.getMessages(queue.getRelativeUrl(), messageIds);
for (Entry<String, CQSMessage> messageIdToMessage : persisMap.entrySet()) {
String memId = messageIdToMemId.get(messageIdToMessage.getKey());
if (memId == null) {
throw new IllegalStateException("Underlying storage layer returned a message that was not requested");
}
CQSMessage message = messageIdToMessage.getValue();
if (message == null) {
logger.warn("event=message_is_null msg_id=" + messageIdToMessage.getKey());
continue;
}
//check if message returned is expired. This will only happen if payload coming from payload-cache. Cassandra
//expires old messages just fine. If expired, skip over and continue.
if (isMessageExpired(queue, memId)) {
try {
logger.debug("event=message_expired message_id=" + memId);
persistenceStorage.deleteMessage(queue.getRelativeUrl(), message.getMessageId());
} catch (Exception e) {
//its fine to ignore this exception since message must have been auto-deleted from Cassandra
//but we need to do this to clean up payloadcache
logger.debug("event=message_already_deleted_in_cassandra msg_id=" + message.getMessageId());
}
continue;
}
//hide message if visibilityTO is greater than 0
if (visibilityTO > 0) {
long ts1 = System.currentTimeMillis();
jedis.hset(queue.getRelativeUrl() + "-" + shard + "-H", memId, Long.toString(System.currentTimeMillis() + (visibilityTO * 1000)));
long ts2 = System.currentTimeMillis();
CQSControllerServlet.valueAccumulator.addToCounter(AccumulatorName.RedisTime, (ts2 - ts1));
}
message.setMessageId(memId);
message.setReceiptHandle(memId);
//get message-attributes and populate in message
Map<String, String> msgAttrs = (message.getAttributes() != null) ? message.getAttributes() : new HashMap<String, String>();
List<String> attrs = jedis.hmget(queue.getRelativeUrl() + "-" + shard + "-A-" + memId, CQSConstants.REDIS_APPROXIMATE_FIRST_RECEIVE_TIMESTAMP, CQSConstants.REDIS_APPROXIMATE_RECEIVE_COUNT);
if (attrs.get(0) == null) {
String firstRecvTS = Long.toString(System.currentTimeMillis());
jedis.hset(queue.getRelativeUrl() + "-" + shard + "-A-" + memId, CQSConstants.REDIS_APPROXIMATE_FIRST_RECEIVE_TIMESTAMP, firstRecvTS);
msgAttrs.put(CQSConstants.APPROXIMATE_FIRST_RECEIVE_TIMESTAMP, firstRecvTS);
} else {
msgAttrs.put(CQSConstants.APPROXIMATE_FIRST_RECEIVE_TIMESTAMP, attrs.get(0));
}
int recvCount = 1;
if (attrs.get(1) != null) {
recvCount = Integer.parseInt(attrs.get(1)) + 1;
}
jedis.hset(queue.getRelativeUrl() + "-" + shard + "-A-" + memId, CQSConstants.REDIS_APPROXIMATE_RECEIVE_COUNT, Integer.toString(recvCount));
jedis.expire(queue.getRelativeUrl() + "-" + shard + "-A-" + memId, 3600 * 24 * 14); //14 days expiration if not deleted
msgAttrs.put(CQSConstants.APPROXIMATE_RECEIVE_COUNT, Integer.toString(recvCount));
message.setAttributes(msgAttrs);
ret.add(message);
}
if (ret.size() > 0) { //There may be cases where the underlying persistent message has two memIds while
//cache filling. In such cases trying to retrieve message for the second memId may result in no message
//returned. We should skip over those memIds and continue till we find at least one valid memId
done = true;
} else {
for (String messageId : messageIds) {
logger.debug("event=bad_mem_id_found msg_id=" + messageId + " action=skip_message");
}
}
} catch (HTimedOutException e1) { //If Hector timedout, push messages back
logger.error("event=hector_timeout num_messages=" + messageIds.size() + " action=pushing_messages_back_to_redis");
if (visibilityTO > 0) {
for (String messageId : messageIds) {
String memId = messageIdToMemId.get(messageId);
jedis.lpush(queue.getRelativeUrl() + "-" + shard + "-Q", memId);
}
}
throw e1;
}
}