if (cacheAvailable) {
// get the messageIds from in redis list
ShardedJedis jedis = null;
boolean brokenJedis = false;
try {
jedis = getResource();
String key = queue.getRelativeUrl() + "-" + shard + "-Q";
Jedis j = jedis.getShard(key);
boolean done = false;
Set <String> memIds;
while (!done) {
boolean emptyQueue = false;
HashMap<String, String> messageIdToMemId = new HashMap<String, String>();
List<String> messageIds = new LinkedList<String>();
//use lua script if visibilityTO > 0
if (visibilityTO > 0) {
List <String> keys = new LinkedList <String>();
keys.add(key);
List <String> args = new LinkedList <String>();
args.add(String.valueOf(System.currentTimeMillis() - queue.getMsgRetentionPeriod() * 1000));//min
args.add(String.valueOf(System.currentTimeMillis()));//max
args.add(String.valueOf(maxNumberOfMessages));//number of message
args.add(String.valueOf(System.currentTimeMillis()+visibilityTO*1000)); //new score
long ts1 = System.currentTimeMillis();
try {
memIds = new HashSet<String>((List <String>)j.evalsha(luaChangeScoreToHigherSHA, keys, args));
} catch (JedisDataException e) {
if (e.getMessage().startsWith("NOSCRIPT")) {
luaChangeScoreToHigherSHA = new String(j.scriptLoad(luaChangeScoreToHigher.getBytes()));
memIds = new HashSet<String>((List <String>)j.evalsha(luaChangeScoreToHigherSHA, keys, args));
} else {
throw e;
}
}
long ts2 = System.currentTimeMillis();
CQSControllerServlet.valueAccumulator.addToCounter(AccumulatorName.RedisTime, (ts2 - ts1));
}
else {
long ts1 = System.currentTimeMillis();
memIds = jedis.zrangeByScore(key, System.currentTimeMillis() - queue.getMsgRetentionPeriod() * 1000, System.currentTimeMillis(), 0, maxNumberOfMessages);
long ts2 = System.currentTimeMillis();
CQSControllerServlet.valueAccumulator.addToCounter(AccumulatorName.RedisTime, (ts2 - ts1));
if (memIds == null || memIds.equals("nil")) { //done
emptyQueue = true;
}
}
for (String memId: memIds) {
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());
//underlying layer does not have this message, remove it from Redis layer
jedis.zrem(key,memId);
continue;
}
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 (PersistenceException e1) { //If cassandra exception, push messages back
logger.error("event=persistence_exception num_messages=" + messageIds.size() + " action=pushing_messages_back_to_redis");
if (visibilityTO > 0) {
for (String messageId : messageIds) {
String memId = messageIdToMemId.get(messageId);
jedis.zadd(queue.getRelativeUrl() + "-" + shard + "-Q", System.currentTimeMillis() , memId);
}
}
throw e1;
}
}