* @throws InvalidRecordLocationException
* @throws IllegalStateException
*/
private void recover() throws IllegalStateException, InvalidRecordLocationException, IOException, JMSException {
RecordLocation pos = null;
int transactionCounter = 0;
log.info("Journal Recovery Started.");
// While we have records in the journal.
while ((pos = journal.getNextRecordLocation(pos)) != null) {
org.activeio.Packet data = journal.read(pos);
DataInputStream is = new DataInputStream(new PacketInputStream(data));
// Read the destination and packate from the record.
String destination = null;
Packet packet = null;
try {
byte type = is.readByte();
switch (type) {
case PACKET_RECORD_TYPE:
// Is the current packet part of the destination?
destination = is.readUTF();
packet = wireFormat.readPacket(data);
// Try to replay the packet.
if (packet instanceof ActiveMQMessage) {
ActiveMQMessage msg = (ActiveMQMessage) packet;
JournalMessageStore store = (JournalMessageStore) createMessageStore(destination, msg.getJMSActiveMQDestination().isQueue());
if( msg.getTransactionId()!=null ) {
transactionStore.addMessage(store, msg, pos);
} else {
store.replayAddMessage(msg);
transactionCounter++;
}
}
else if (packet instanceof MessageAck) {
MessageAck ack = (MessageAck) packet;
JournalMessageStore store = (JournalMessageStore) createMessageStore(destination, ack.getDestination().isQueue());
if( ack.getTransactionId()!=null ) {
transactionStore.removeMessage(store, ack, pos);
} else {
store.replayRemoveMessage(ack);
transactionCounter++;
}
}
else {
log.error("Unknown type of packet in transaction log which will be discarded: " + packet);
}
break;
case TX_COMMAND_RECORD_TYPE:
TxCommand command = new TxCommand();
command.setType(is.readByte());
command.setWasPrepared(is.readBoolean());
switch(command.getType()) {
case TxCommand.LOCAL_COMMIT:
case TxCommand.LOCAL_ROLLBACK:
command.setTransactionId(is.readUTF());
break;
default:
command.setTransactionId(ActiveMQXid.read(is));
break;
}
// Try to replay the packet.
switch(command.getType()) {
case TxCommand.XA_PREPARE:
transactionStore.replayPrepare(command.getTransactionId());
break;
case TxCommand.XA_COMMIT:
case TxCommand.LOCAL_COMMIT:
Tx tx = transactionStore.replayCommit(command.getTransactionId(), command.getWasPrepared());
// Replay the committed operations.
if( tx!=null) {
tx.getOperations();
for (Iterator iter = tx.getOperations().iterator(); iter.hasNext();) {
TxOperation op = (TxOperation) iter.next();
if( op.operationType == TxOperation.ADD_OPERATION_TYPE ) {
op.store.replayAddMessage((ActiveMQMessage) op.data);
}
if( op.operationType == TxOperation.REMOVE_OPERATION_TYPE) {
op.store.replayRemoveMessage((MessageAck) op.data);
}
if( op.operationType == TxOperation.ACK_OPERATION_TYPE) {
JournalAck ack = (JournalAck) op.data;
((JournalTopicMessageStore)op.store).replayAcknowledge(ack.getSubscription(), new MessageIdentity(ack.getMessageId()));
}
}
transactionCounter++;
}
break;
case TxCommand.LOCAL_ROLLBACK:
case TxCommand.XA_ROLLBACK:
transactionStore.replayRollback(command.getTransactionId());
break;
}
break;
case ACK_RECORD_TYPE:
destination = is.readUTF();
String subscription = is.readUTF();
String messageId = is.readUTF();
Object transactionId=null;
JournalTopicMessageStore store = (JournalTopicMessageStore) createMessageStore(destination, false);
if( transactionId!=null ) {
JournalAck ack = new JournalAck(destination, subscription, messageId, transactionId);
transactionStore.acknowledge(store, ack, pos);
} else {
store.replayAcknowledge(subscription, new MessageIdentity(messageId));
transactionCounter++;
}
case COMMAND_RECORD_TYPE:
break;
default:
log.error("Unknown type of record in transaction log which will be discarded: " + type);
break;
}
}
finally {
is.close();
}
}
RecordLocation location = writeCommand("RECOVERED", true);
journal.setMark(location, true);
log.info("Journal Recovered: " + transactionCounter + " message(s) in transactions recovered.");
}