// hold all non existing queues and their messages IDs
final HashMap<String, HashSet<Long>> phantomMessageQueues = new HashMap<String, HashSet<Long>>();
// delivery DB visitor to check message delivery and identify non existing queues
final QueueEntryTB queueEntryTB = new QueueEntryTB();
DatabaseVisitor messageDeliveryCheckVisitor = new DatabaseVisitor()
{
public void visit(DatabaseEntry key, DatabaseEntry value) throws DatabaseException
{
QueueEntryKey entryKey = (QueueEntryKey) queueEntryTB.entryToObject(key);
Long messageId = entryKey.getMessageId();
AMQShortString queueName = entryKey.getQueueName();
if (!existingQueues.contains(queueName))
{
String name = queueName.asString();
HashSet<Long> messages = phantomMessageQueues.get(name);
if (messages == null)
{
messages = new HashSet<Long>();
phantomMessageQueues.put(name, messages);
}
messages.add(messageId);
_count++;
}
else
{
queueMessages.add(messageId);
}
}
};
_oldMessageStore.visitDelivery(messageDeliveryCheckVisitor);
if (phantomMessageQueues.isEmpty())
{
_logger.info("No such messages were found");
}
else
{
_logger.info("Found " + messageDeliveryCheckVisitor.getVisitedCount()+ " such messages in total");
for (Entry<String, HashSet<Long>> phantomQueue : phantomMessageQueues.entrySet())
{
String queueName = phantomQueue.getKey();
HashSet<Long> messages = phantomQueue.getValue();
_logger.info(MessageFormat.format("There are {0} messages which were previously delivered to non-durable queue ''{1}''",messages.size(), queueName));
boolean createQueue;
if(!_interactive)
{
createQueue = true;
_logger.info("Running in batch-mode, marking queue as durable to ensure retention of the messages.");
}
else
{
createQueue = userInteract("Do you want to make this queue durable?\n"
+ "NOTE: Answering No will result in these messages being discarded!");
}
if (createQueue)
{
for (Long messageId : messages)
{
queueMessages.add(messageId);
}
AMQShortString name = new AMQShortString(queueName);
existingQueues.add(name);
QueueRecord record = new QueueRecord(name, null, false, null);
_newMessageStore.createQueue(record);
}
}
}
//Migrate _messageMetaDataDb;
_logger.info("Message MetaData");
final Database newMetaDataDB = _newMessageStore.getMetaDataDb();
final TupleBinding<Object> oldMetaDataTupleBinding = _oldMessageStore.getMetaDataTupleBindingFactory().getInstance();
final TupleBinding<Object> newMetaDataTupleBinding = _newMessageStore.getMetaDataTupleBindingFactory().getInstance();
DatabaseVisitor metaDataVisitor = new DatabaseVisitor()
{
public void visit(DatabaseEntry key, DatabaseEntry value) throws DatabaseException
{
_count++;
MessageMetaData metaData = (MessageMetaData) oldMetaDataTupleBinding.entryToObject(value);
// get message id
Long messageId = TupleBinding.getPrimitiveBinding(Long.class).entryToObject(key);
// ONLY copy data if message is delivered to existing queue
if (!queueMessages.contains(messageId))
{
return;
}
DatabaseEntry newValue = new DatabaseEntry();
newMetaDataTupleBinding.objectToEntry(metaData, newValue);
newMetaDataDB.put(null, key, newValue);
}
};
_oldMessageStore.visitMetaDataDb(metaDataVisitor);
logCount(metaDataVisitor.getVisitedCount(), "Message MetaData");
//Migrate _messageContentDb;
_logger.info("Message Contents");
final Database newContentDB = _newMessageStore.getContentDb();
final TupleBinding<MessageContentKey> oldContentKeyTupleBinding = new MessageContentKeyTB_4();
final TupleBinding<MessageContentKey> newContentKeyTupleBinding = new MessageContentKeyTB_5();
final TupleBinding contentTB = new ContentTB();
DatabaseVisitor contentVisitor = new DatabaseVisitor()
{
long _prevMsgId = -1; //Initialise to invalid value
int _bytesSeenSoFar = 0;
public void visit(DatabaseEntry key, DatabaseEntry value) throws DatabaseException
{
_count++;
//determine the msgId of the current entry
MessageContentKey_4 contentKey = (MessageContentKey_4) oldContentKeyTupleBinding.entryToObject(key);
long msgId = contentKey.getMessageId();
// ONLY copy data if message is delivered to existing queue
if (!queueMessages.contains(msgId))
{
return;
}
//if this is a new message, restart the byte offset count.
if(_prevMsgId != msgId)
{
_bytesSeenSoFar = 0;
}
//determine the content size
ByteBuffer content = (ByteBuffer) contentTB.entryToObject(value);
int contentSize = content.limit();
//create the new key: id + previously seen data count
MessageContentKey_5 newKey = new MessageContentKey_5(msgId, _bytesSeenSoFar);
DatabaseEntry newKeyEntry = new DatabaseEntry();
newContentKeyTupleBinding.objectToEntry(newKey, newKeyEntry);
DatabaseEntry newValueEntry = new DatabaseEntry();
contentTB.objectToEntry(content, newValueEntry);
newContentDB.put(null, newKeyEntry, newValueEntry);
_prevMsgId = msgId;
_bytesSeenSoFar += contentSize;
}
};
_oldMessageStore.visitContentDb(contentVisitor);
logCount(contentVisitor.getVisitedCount(), "Message Content");
//Migrate _deliveryDb;
_logger.info("Delivery Records");
final Database deliveryDb =_newMessageStore.getDeliveryDb();
DatabaseVisitor deliveryDbVisitor = new DatabaseVisitor()
{
public void visit(DatabaseEntry key, DatabaseEntry value) throws DatabaseException
{
_count++;
// get message id from entry key
QueueEntryKey entryKey = (QueueEntryKey) queueEntryTB.entryToObject(key);
AMQShortString queueName = entryKey.getQueueName();
// ONLY copy data if message queue exists
if (existingQueues.contains(queueName))
{