Package com.comcast.cqs.persistence

Source Code of com.comcast.cqs.persistence.CQSMessagePartitionedCassandraPersistence

/**
* Copyright 2012 Comcast Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.comcast.cqs.persistence;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;

import com.comcast.cmb.common.persistence.AbstractDurablePersistence;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence.CMB_SERIALIZER;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence.CmbColumn;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence.CmbColumnSlice;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence.CmbComposite;
import com.comcast.cmb.common.persistence.DurablePersistenceFactory;
import com.comcast.cmb.common.util.CMBErrorCodes;
import com.comcast.cmb.common.util.CMBProperties;
import com.comcast.cmb.common.util.PersistenceException;
import com.comcast.cqs.controller.CQSCache;
import com.comcast.cqs.model.CQSMessage;
import com.comcast.cqs.model.CQSQueue;
import com.comcast.cqs.util.CQSConstants;
import com.comcast.cqs.util.CQSErrorCodes;
import com.comcast.cqs.util.RandomNumberCollection;
import com.comcast.cqs.util.Util;
import com.eaio.uuid.UUIDGen;

/**
* Cassandra persistence for CQS Message
* @author aseem, vvenkatraman, bwolf
*
*/
public class CQSMessagePartitionedCassandraPersistence implements ICQSMessagePersistence {
 
  private static final String COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES = "CQSPartitionedQueueMessages";
  private static final Random rand = new Random();

  private static Logger logger = Logger.getLogger(CQSMessagePartitionedCassandraPersistence.class);
 
  private static final AbstractDurablePersistence cassandraHandler = DurablePersistenceFactory.getInstance();

  public CQSMessagePartitionedCassandraPersistence() {
  }

  @Override
  public String sendMessage(CQSQueue queue, int shard, CQSMessage message) throws PersistenceException, IOException, InterruptedException, NoSuchAlgorithmException, JSONException {
   
    if (queue == null) {
      throw new PersistenceException(CQSErrorCodes.NonExistentQueue, "The supplied queue does not exist");
    }
   
    if (message == null) {
      throw new PersistenceException(CQSErrorCodes.InvalidMessageContents, "The supplied message is invalid");
    }
   
    int delaySeconds = 0;
   
    if (message.getAttributes().containsKey(CQSConstants.DELAY_SECONDS)) {
      delaySeconds = Integer.parseInt(message.getAttributes().get(CQSConstants.DELAY_SECONDS));
    }
   
    long ts = System.currentTimeMillis() + delaySeconds*1000;
    CmbComposite columnName = cassandraHandler.getCmbComposite(AbstractDurablePersistence.newTime(ts, false), UUIDGen.getClockSeqAndNode());
    int ttl = queue.getMsgRetentionPeriod();
    int partition = rand.nextInt(queue.getNumberOfPartitions());
    String key = Util.hashQueueUrl(queue.getRelativeUrl()) + "_" + shard + "_" + partition;
   
    if (queue.isCompressed()) {
      message.setBody(Util.compress(message.getBody()));
    }

    message.setMessageId(key + ":" + columnName.get(0) + ":" + columnName.get(1));

    logger.debug("event=send_message ttl=" + ttl + " delay_sec=" + delaySeconds + " msg_id=" + message.getMessageId() + " key=" + key + " col=" + columnName);
   
    cassandraHandler.update(AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, key, columnName, getMessageJSON(message),
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.COMPOSITE_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER, ttl);

    return message.getMessageId();
  }
 
  public List<CQSMessage> extractMessagesFromColumnSlice(String queueUrl, int length, CmbComposite previousHandle, CmbComposite nextHandle, CmbColumnSlice<CmbComposite, String> columnSlice, boolean ignoreFirstLastColumn) throws PersistenceException, NoSuchAlgorithmException, IOException, JSONException  {
   
    List<CQSMessage> messageList = new ArrayList<CQSMessage>();

    if (columnSlice != null && columnSlice.getColumns() != null) {
     
      boolean noMatch = true;
     
      for (CmbColumn<CmbComposite, String> column : columnSlice.getColumns()) {
       
        CmbComposite columnName = column.getName();
       
        if (ignoreFirstLastColumn && (previousHandle != null && columnName.compareTo(previousHandle) == 0) || (nextHandle != null && columnName.compareTo(nextHandle) == 0)) {
          noMatch = false;
          continue;
        } else if (column.getValue() == null || column.getValue().length() == 0) {
          continue;
        }
       
        CQSMessage message = extractMessageFromJSON(queueUrl, column);
        messageList.add(message);
      }
     
      if (noMatch && messageList.size() > length) {
        messageList.remove(messageList.size() - 1);
      }
    }
   
    return messageList;
  }
 
  private CQSMessage extractMessageFromJSON(String queueUrl, CmbColumn column) throws JSONException, PersistenceException, IOException {
   
    CQSQueue queue = null;
    CQSMessage m = new CQSMessage();
   
    try {
      queue = CQSCache.getCachedQueue(queueUrl);
    } catch (Exception ex) {
      throw new PersistenceException(ex);
    }
   
    if (queue == null) {
      throw new PersistenceException(CMBErrorCodes.InternalError, "Unknown queue " + queueUrl);
    }
   
    JSONObject json = new JSONObject((String)column.getValue());

    m.setMessageId(json.getString("MessageId"));
    m.setReceiptHandle(json.getString("MessageId"));
    m.setMD5OfBody(json.getString("MD5OfBody"));
    m.setBody(json.getString("Body"));
   
    if (m.getAttributes() == null) {
      m.setAttributes(new HashMap<String, String>());
    }
   
    if (json.has(CQSConstants.SENT_TIMESTAMP)) {
      m.getAttributes().put(CQSConstants.SENT_TIMESTAMP, json.getString(CQSConstants.SENT_TIMESTAMP));
    }
   
    if (json.has(CQSConstants.APPROXIMATE_RECEIVE_COUNT)) {
      m.getAttributes().put(CQSConstants.APPROXIMATE_RECEIVE_COUNT, json.getString(CQSConstants.APPROXIMATE_RECEIVE_COUNT));
    }

    if (json.has(CQSConstants.SENDER_ID)) {
      m.getAttributes().put(CQSConstants.SENDER_ID, json.getString(CQSConstants.SENDER_ID));
    }
   
    m.setTimebasedId(column.getName());
   
    if (queue.isCompressed()) {
      m.setBody(Util.decompress(m.getBody()));
    }
   
      return m;
  }
 
  private String getMessageJSON(CQSMessage message) throws JSONException {
   
    Writer writer = new StringWriter();
      JSONWriter jw = new JSONWriter(writer);
      jw = jw.object();
   
      jw.key("MessageId").value(message.getMessageId());
     
      jw.key("MD5OfBody").value(message.getMD5OfBody());
      jw.key("Body").value(message.getBody());
   
    if (message.getAttributes() == null) {
      message.setAttributes(new HashMap<String, String>());
    }
   
    if (!message.getAttributes().containsKey(CQSConstants.SENT_TIMESTAMP)) {
      message.getAttributes().put(CQSConstants.SENT_TIMESTAMP, "" + System.currentTimeMillis());
    }
   
    if (!message.getAttributes().containsKey(CQSConstants.APPROXIMATE_RECEIVE_COUNT)) {
      message.getAttributes().put(CQSConstants.APPROXIMATE_RECEIVE_COUNT, "0");
    }
   
    if (message.getAttributes() != null) {
     
      for (String key : message.getAttributes().keySet()) {
       
        String value = message.getAttributes().get(key);
       
        if (value == null || value.isEmpty()) {
          value = "";
        }
       
        jw.key(key).value(value);
      }
    }
   
    jw.endObject();
   
    return writer.toString();
  }

  @Override
  public Map<String, String> sendMessageBatch(CQSQueue queue,  int shard, List<CQSMessage> messages) throws PersistenceException,  IOException, InterruptedException, NoSuchAlgorithmException, JSONException {

    if (queue == null) {
      throw new PersistenceException(CQSErrorCodes.NonExistentQueue, "The supplied queue doesn't exist");
    }

    if (messages == null || messages.size() == 0) {
      throw new PersistenceException(CQSErrorCodes.InvalidQueryParameter,  "No messages are supplied.");
    }
   
    Map<CmbComposite, String> messageDataMap = new HashMap<CmbComposite, String>();
    Map<String, String> ret = new HashMap<String, String>();
    int ttl = queue.getMsgRetentionPeriod();
    String key = Util.hashQueueUrl(queue.getRelativeUrl()) + "_" + shard + "_" + rand.nextInt(queue.getNumberOfPartitions());
   
    for (CQSMessage message : messages) {

      if (message == null) {
        throw new PersistenceException(CQSErrorCodes.InvalidMessageContents, "The supplied message is invalid");
      }
     
      if (queue.isCompressed()) {
        message.setBody(Util.compress(message.getBody()));
      }
     
      int delaySeconds = 0;
     
      if (message.getAttributes().containsKey(CQSConstants.DELAY_SECONDS)) {
        delaySeconds = Integer.parseInt(message.getAttributes().get(CQSConstants.DELAY_SECONDS));
      }
     
      long ts = System.currentTimeMillis() + delaySeconds*1000;
      CmbComposite columnName = cassandraHandler.getCmbComposite(AbstractDurablePersistence.newTime(ts, false), UUIDGen.getClockSeqAndNode());

      message.setMessageId(key + ":" + columnName.get(0) + ":" + columnName.get(1));
     
      logger.debug("event=send_message_batch msg_id=" + message.getMessageId() + " ttl=" + ttl + " delay_sec=" + delaySeconds + " key=" + key + " col=" + columnName);
     
      String messageJson = getMessageJSON(message);
      messageDataMap.put(columnName, messageJson);
      ret.put(message.getSuppliedMessageId(), message.getMessageId());
    }

    cassandraHandler.insertRow(AbstractDurablePersistence.CQS_KEYSPACE, key, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, messageDataMap,
        CMB_SERIALIZER.STRING_SERIALIZER,
        CMB_SERIALIZER.COMPOSITE_SERIALIZER,
        CMB_SERIALIZER.STRING_SERIALIZER, ttl);
   
    return ret;
  }

  @Override
  public void deleteMessage(String queueUrl, String receiptHandle) throws PersistenceException {
   
    if (receiptHandle == null) {
      logger.error("event=delete_message event=no_receipt_handle queue_url=" + queueUrl);
      return;
    }
   
    String[] receiptHandleParts = receiptHandle.split(":");
   
    if (receiptHandleParts.length != 3) {
      logger.error("event=delete_message event=invalid_receipt_handle queue_url=" + queueUrl + " receipt_handle=" + receiptHandle);
      return;
    }
   
    CmbComposite columnName = cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(receiptHandleParts[1]), Long.parseLong(receiptHandleParts[2])));
   
    if (columnName != null) {
      logger.debug("event=delete_message receipt_handle=" + receiptHandle + " col=" + columnName + " key=" + receiptHandleParts[0]);
      cassandraHandler.delete(AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, receiptHandleParts[0], columnName, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.COMPOSITE_SERIALIZER);
    }
  }

  @Override
  public List<CQSMessage> receiveMessage(CQSQueue queue, Map<String, String> receiveAttributes) throws PersistenceException, IOException, NoSuchAlgorithmException, InterruptedException {
    throw new UnsupportedOperationException("ReceiveMessage is not supported, please call getMessages instead");
  }

  @Override
  public boolean changeMessageVisibility(CQSQueue queue, String receiptHandle, int visibilityTO) throws PersistenceException, IOException, NoSuchAlgorithmException, InterruptedException {
    throw new UnsupportedOperationException("ChangeMessageVisibility is not supported");
  }

  @Override
  public List<CQSMessage> peekQueue(String queueUrl, int shard, String previousReceiptHandle, String nextReceiptHandle, int length) throws PersistenceException, IOException, NoSuchAlgorithmException, JSONException {
   
    String queueHash = Util.hashQueueUrl(queueUrl);
    String key =  queueHash + "_" + shard + "_0";
    String handle = null;
    List<CQSMessage> messageList = new ArrayList<CQSMessage>();
    CmbComposite previousHandle = null;
    CmbComposite nextHandle = null;
   
    int numberPartitions = getNumberOfPartitions(queueUrl);
    int numberShards = getNumberOfShards(queueUrl);
   
    logger.debug("event=peek_queue queue_url=" + queueUrl + " prev_receipt_handle=" + previousReceiptHandle + " next_receipt_handle=" + nextReceiptHandle + " length=" + length + " num_partitions=" + numberPartitions);
   
    if (previousReceiptHandle != null) {
     
      handle = previousReceiptHandle;
      String[] handleParts = handle.split(":");
     
      if (handleParts.length != 3) {
        logger.error("event=peek_queue error_code=corrupt_receipt_handle receipt_handle=" + handle);
        throw new IllegalArgumentException("Corrupt receipt handle " + handle);
      }
     
      key = handleParts[0];
      previousHandle = cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(handleParts[1]), Long.parseLong(handleParts[2])));
   
    } else if (nextReceiptHandle != null) {
     
      handle = nextReceiptHandle;
      String[] handleParts = handle.split(":");
     
      if (handleParts.length != 3) {
        logger.error("action=peek_queue error_code=corrupt_receipt_handle receipt_handle=" + handle);
        throw new IllegalArgumentException("Corrupt receipt handle " + handle);
      }
     
      key = handleParts[0];
      nextHandle = cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(handleParts[1]), Long.parseLong(handleParts[2])));
    }
   
    String[] queueParts = key.split("_");
   
    if (queueParts.length != 3) {
      logger.error("event=peek_queue error_code=invalid_queue_key key=" + key);
      throw new IllegalArgumentException("Invalid queue key " + key);
    }
   
    int shardNumber = Integer.parseInt(queueParts[1]);
    int partitionNumber = Integer.parseInt(queueParts[2]);
   
    if (partitionNumber < 0 || partitionNumber > numberPartitions-1) {
      logger.error("event=peek_queue error_code=invalid_partition_number partition_number=" + partitionNumber);
      throw new IllegalArgumentException("Invalid queue partition number " + partitionNumber);     
    }
   
    if (shardNumber < 0 || shardNumber > numberShards-1) {
      logger.error("event=peek_queue error_code=invalid_shard_number shard_number=" + shardNumber);
      throw new IllegalArgumentException("Invalid queue shard number " + shardNumber);     
    }

    while (messageList.size() < length && -1 < partitionNumber && partitionNumber < numberPartitions) {
     
      key = queueHash + "_" + shardNumber + "_" + partitionNumber;
     
      CmbColumnSlice<CmbComposite, String> columnSlice = cassandraHandler.readColumnSlice(
          AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, key, previousHandle,
          nextHandle, length-messageList.size()+1, CMB_SERIALIZER.STRING_SERIALIZER,
          CMB_SERIALIZER.COMPOSITE_SERIALIZER,
          CMB_SERIALIZER.STRING_SERIALIZER);
     
      messageList.addAll(extractMessagesFromColumnSlice(queueUrl, length-messageList.size(), previousHandle, nextHandle, columnSlice, true));
     
      if (messageList.size() < length && -1 < partitionNumber && partitionNumber < numberPartitions) {
       
        if (previousHandle != null) {
         
          partitionNumber++;
         
          if (partitionNumber > -1) {
            previousHandle = cassandraHandler.getCmbComposite(Arrays.asList(AbstractDurablePersistence.newTime(System.currentTimeMillis()-1209600000, false), UUIDGen.getClockSeqAndNode()));
          }
       
        } else if (nextHandle != null) {
         
          partitionNumber--;
         
          if (partitionNumber < numberPartitions) {
            nextHandle = cassandraHandler.getCmbComposite(Arrays.asList(AbstractDurablePersistence.newTime(System.currentTimeMillis()+1209600000, false), UUIDGen.getClockSeqAndNode()));
          }
         
        } else {
          partitionNumber++;
        }
      }
    }
   
    return messageList;
  }

  @Override
  public void clearQueue(String queueUrl, int shard) throws PersistenceException, NoSuchAlgorithmException, UnsupportedEncodingException {
   
    int numberPartitions = getNumberOfPartitions(queueUrl);
   
    logger.debug("event=clear_queue queue_url=" + queueUrl + " num_partitions=" + numberPartitions);
   
    for (int i=0; i<numberPartitions; i++) {
      String key = Util.hashQueueUrl(queueUrl) + "_" + shard + "_" + i;
      //cassandraHandler.deleteSuperColumn(COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, key, null, CMB_SERIALIZER.STRING_SERIALIZER, CompositeSerializer.get());
      cassandraHandler.delete(AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, key, null, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER);
    }
  }

  @Override
  public Map<String, CQSMessage> getMessages(String queueUrl, List<String> ids) throws PersistenceException, NoSuchAlgorithmException, IOException, JSONException {
   
    Map<String, CQSMessage> messageMap = new HashMap<String, CQSMessage>();
   
    logger.debug("event=get_messages ids=" + ids);
   
    if (ids == null || ids.size() == 0) {
      return messageMap;
    } else if (ids.size() > 100) {
      return getMessagesBulk(queueUrl, ids);
    }
   
    for (String id: ids) {
     
      String[] idParts = id.split(":");
     
      if (idParts.length != 3) {
        logger.error("event=get_messages error_code=invalid_message_id id=" + id);
        throw new IllegalArgumentException("Invalid message id " + id);
      }
     
      CmbComposite columnName = cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(idParts[1]), Long.parseLong(idParts[2])));
     
      CmbColumn<CmbComposite, String> column = cassandraHandler.readColumn(AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES,
          idParts[0], columnName, CMB_SERIALIZER.STRING_SERIALIZER,
          CMB_SERIALIZER.COMPOSITE_SERIALIZER,
          CMB_SERIALIZER.STRING_SERIALIZER);
     
      CQSMessage message = null;
     
      if (column != null) {
        message = extractMessageFromJSON(queueUrl, column);
      }
     
      messageMap.put(id, message);
    }
   
    return messageMap;
  }
 
  private Map<String, CQSMessage> getMessagesBulk(String queueUrl, List<String> ids) throws NoSuchAlgorithmException, PersistenceException, IOException, JSONException {
   
    logger.debug("event=get_message_bulk ids=" + ids);
   
    Map<String, CQSMessage> messageMap = new HashMap<String, CQSMessage>();
    Set<String> messageIdSet = new HashSet<String>();
    Map<String, Map<String, String>> firstLastIdsForEachPartition = getFirstAndLastIdsForEachPartition(ids, messageIdSet);
   
    if (firstLastIdsForEachPartition.size() == 0) {
      return messageMap;
    }
   
    for (String queuePartition: firstLastIdsForEachPartition.keySet()) {
     
      int messageCount = 200;
      Map<String, String> firstLastForPartition = firstLastIdsForEachPartition.get(queuePartition);
      String firstParts[] = firstLastForPartition.get("First").split(":");
      String lastParts[] = firstLastForPartition.get("Last").split(":");
     
      CmbColumnSlice<CmbComposite, String> columnSlice = cassandraHandler.readColumnSlice(
          AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, queuePartition, cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(firstParts[0]), Long.parseLong(firstParts[1]))),
          cassandraHandler.getCmbComposite(Arrays.asList(Long.parseLong(lastParts[0]), Long.parseLong(lastParts[1]))), messageCount, CMB_SERIALIZER.STRING_SERIALIZER,
          CMB_SERIALIZER.COMPOSITE_SERIALIZER,
          CMB_SERIALIZER.STRING_SERIALIZER);
     
      List<CQSMessage> messageList = extractMessagesFromColumnSlice(queueUrl, messageCount, null, null, columnSlice, false);
     
      for (CQSMessage message: messageList) {
       
        if (messageIdSet.contains(message.getMessageId())) {
          messageMap.put(message.getMessageId(), message);
          messageIdSet.remove(message.getMessageId());
        }
      }
    }

    for (String messageId : messageIdSet) {
          messageMap.put(messageId, null);
      }
   
    return messageMap;
  }
 
  private Map<String, Map<String, String>> getFirstAndLastIdsForEachPartition(List<String> ids, Set<String> messageIdSet) {
   
    Map<String, Map<String, String>> firstLastForEachPartitionMap = new HashMap<String, Map<String, String>>();
   
    if (ids == null || ids.size() == 0) {
      return firstLastForEachPartitionMap;
    }
   
    for (String id: ids) {     
     
      messageIdSet.add(id);
      String[] idParts = id.split(":");
     
      if (idParts.length != 3) {
        logger.error("action=get_messages_bulk error_code=corrupt_receipt_handle receipt_handle=" + id);
        throw new IllegalArgumentException("Corrupt receipt handle " + id);
      }
     
      String queuePartition = idParts[0];
      final String messageId = idParts[1] + ":" + idParts[2];
     
      if (!firstLastForEachPartitionMap.containsKey(queuePartition)) {
        firstLastForEachPartitionMap.put(queuePartition, new HashMap<String, String>() {{put("First", messageId); put("Last", messageId);}});
      } else {
        Map<String, String> firstLastForPartition = firstLastForEachPartitionMap.get(queuePartition);
        if (firstLastForPartition.get("First").compareTo(messageId) > 0) {
          firstLastForPartition.put("First", messageId);
        }
        else if (firstLastForPartition.get("Last").compareTo(messageId) < 0) {
          firstLastForPartition.put("Last", messageId);
        }
      }
    }
   
    return firstLastForEachPartitionMap;
  }
 
  private int getNumberOfPartitions(String queueUrl) {

    int numberPartitions = CMBProperties.getInstance().getCQSNumberOfQueuePartitions();
   
    try {
     
      CQSQueue queue = CQSCache.getCachedQueue(queueUrl);
     
      if (queue != null) {
        numberPartitions = queue.getNumberOfPartitions();
      }
     
    } catch (Exception ex) {
      logger.warn("event=queue_cache_failure queue_url=" + queueUrl, ex);
    }

    return numberPartitions;
  }

  private int getNumberOfShards(String queueUrl) {

    int numberShards = 1;
   
    try {
     
      CQSQueue queue = CQSCache.getCachedQueue(queueUrl);
     
      if (queue != null) {
        numberShards = queue.getNumberOfShards();
      }
     
    } catch (Exception ex) {
      logger.warn("event=queue_cache_failure queue_url=" + queueUrl, ex);
    }

    return numberShards;
  }

  @Override
    public List<CQSMessage> peekQueueRandom(String queueUrl, int shard, int length) throws PersistenceException, IOException, NoSuchAlgorithmException, JSONException {
       
      String queueHash = Util.hashQueueUrl(queueUrl);

      int numberPartitions = getNumberOfPartitions(queueUrl);

      logger.debug("event=peek_queue_random queue_url=" + queueUrl + " shard=" + shard + " queue_hash=" + queueHash + " num_partitions=" + numberPartitions);
     
      List<CQSMessage> messageList = new ArrayList<CQSMessage>();
       
        if (length > numberPartitions) {
           
          // no randomness, get from all rows, subsequent calls will return the same result
           
          return peekQueue(queueUrl, shard, null, null, length);
       
        } else {
           
          // get from random set of rows
            // note: as a simplification we may return less messages than length if not all rows contain messages
           
          RandomNumberCollection rc = new RandomNumberCollection(numberPartitions);
            int numFound = 0;
           
            for (int i = 0; i < numberPartitions && numFound < length; i++) {
               
              int partition = rc.getNext();
                String key = queueHash + "_" + shard + "_" + partition;
               
                CmbColumnSlice<CmbComposite, String> columnSlice = cassandraHandler.readColumnSlice(
                    AbstractDurablePersistence.CQS_KEYSPACE, COLUMN_FAMILY_PARTITIONED_QUEUE_MESSAGES, key, null, null, 1,
                        CMB_SERIALIZER.STRING_SERIALIZER,
                        CMB_SERIALIZER.COMPOSITE_SERIALIZER,
                        CMB_SERIALIZER.STRING_SERIALIZER);
              
                List<CQSMessage> messages = extractMessagesFromColumnSlice(queueUrl, 1, null, null, columnSlice, false);
                numFound += messages.size();
                messageList.addAll(messages);
            }
           
            return messageList;
        }       
    }

  @Override
  public List<String> getIdsFromHead(String queueUrl, int shard, int num)
      throws PersistenceException {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public long getQueueMessageCount(String queueUrl) {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public boolean checkCacheConsistency(String queueUrl, int shard,
      boolean trueOnFiller) {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public long getQueueMessageCount(String queueUrl, boolean processHiddenIds)
      throws Exception {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public int getNumConnections() {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public long getCacheQueueMessageCount(String queueUrl) throws Exception {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public long getQueueNotVisibleMessageCount(String queueUrl,
      boolean visibilityProcessFlag) throws Exception {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public long getQueueDelayedMessageCount(String queueUrl,
      boolean visibilityProcessFlag) throws Exception {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public void flushAll() {
    // TODO Auto-generated method stub
   
  }

  @Override
  public boolean isAlive() {
    // TODO Auto-generated method stub
    return false;
  }

  @Override
  public int getNumberOfRedisShards() {
    // TODO Auto-generated method stub
    return 0;
  }

  @Override
  public void shutdown() {
    // TODO Auto-generated method stub
   
  }

  @Override
  public List<Map<String, String>> getInfo() {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public long getMemQueueMessageCreatedTS(String memId) {
    // TODO Auto-generated method stub
    return 0;
  }
}
TOP

Related Classes of com.comcast.cqs.persistence.CQSMessagePartitionedCassandraPersistence

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.