Package org.codehaus.activemq.store.journal

Source Code of org.codehaus.activemq.store.journal.JournalMessageStore$AckData

/**
*
* Copyright 2004 Hiram Chirino
* Copyright 2004 Protique Ltd
*
* 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 org.codehaus.activemq.store.journal;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import javax.jms.JMSException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.journal.RecordLocation;
import org.codehaus.activemq.message.ActiveMQMessage;
import org.codehaus.activemq.message.MessageAck;
import org.codehaus.activemq.service.MessageIdentity;
import org.codehaus.activemq.service.QueueMessageContainer;
import org.codehaus.activemq.store.MessageStore;
import org.codehaus.activemq.store.cache.CacheMessageStore;
import org.codehaus.activemq.store.cache.CacheMessageStoreAware;
import org.codehaus.activemq.util.Callback;
import org.codehaus.activemq.util.TransactionTemplate;

/**
* A MessageStore that uses a Journal to store it's messages.
*
* @version $Revision: 1.7 $
*/
public class JournalMessageStore implements MessageStore, CacheMessageStoreAware {

  private static final Log log = LogFactory.getLog(JournalMessageStore.class);
 
  private final static class AckData {
    private final RecordLocation location;
    private final MessageAck ack;
    AckData(MessageAck ack, RecordLocation location) {
      this.ack = ack;
      this.location = location;     
    }
  }
 
  private final JournalPersistenceAdapter peristenceAdapter;
  private final MessageStore longTermStore;
  private final String destinationName;
  private final TransactionTemplate transactionTemplate;
 
  private HashMap addedMessageLocations = new HashMap();
  private ArrayList removedMessageLocations = new ArrayList();
 
  /** A MessageStore that we can use to retreive messages quickly. */
  private MessageStore cacheMessageStore = this;
 
  private boolean sync = true;

  public JournalMessageStore(JournalPersistenceAdapter adapter, MessageStore checkpointStore, String destinationName, boolean sync) {
    this.peristenceAdapter = adapter;
    this.longTermStore = checkpointStore;
    this.destinationName = destinationName;
    this.sync=sync;
    this.transactionTemplate = new TransactionTemplate(adapter);
  }

  /**
   * Not synchronized since the Journal has better throughput if you increase
   * the number of conncurrent writes that it is doing.
   */
  public MessageIdentity addMessage(ActiveMQMessage message) throws JMSException {
    boolean sync = message.isReceiptRequired();
    RecordLocation location = peristenceAdapter.writePacket(destinationName, message, sync);
    synchronized(this) {
      addedMessageLocations.put(message.getJMSMessageIdentity(), location);
    }

    // Update the messageIdentity sequence number so that we can reteive the message
    // from the journal at a later time.
    MessageIdentity messageIdentity = message.getJMSMessageIdentity();
    messageIdentity.setSequenceNumber(location);
    return messageIdentity;
 
 
  /**
   */
  public void removeMessage(MessageIdentity identity, MessageAck ack)
      throws JMSException {

    RecordLocation ackLocation = peristenceAdapter.writePacket(destinationName, ack, sync);

    synchronized(this) {
      RecordLocation addLocation = (RecordLocation) addedMessageLocations.remove(identity);     
      if( addLocation==null ) {
        removedMessageLocations.add(new AckData(ack, ackLocation));
      }
    }   
  }

  /**
   * @return
   * @throws JMSException
   */
  public RecordLocation checkpoint() throws JMSException {
    final RecordLocation rc[] = new RecordLocation[]{null};
   
    // swap out the message hashmaps..
    final ArrayList addedMessageIdentitys;
    final ArrayList removedMessageLocations;
    synchronized(this) {
      addedMessageIdentitys = new ArrayList(this.addedMessageLocations.keySet());
      removedMessageLocations = this.removedMessageLocations;
      this.removedMessageLocations = new ArrayList();
    }
   
    transactionTemplate.run(new Callback() {
      public void execute() throws Throwable {
       
        // Checkpoint the added messages.
        Iterator iterator = addedMessageIdentitys.iterator();
        while (iterator.hasNext()) {         
          MessageIdentity identity = (MessageIdentity) iterator.next();
         
          ActiveMQMessage msg = getCacheMessage(identity);
          longTermStore.addMessage(msg);
          synchronized(this) {
            RecordLocation location = (RecordLocation)addedMessageLocations.remove(identity);
            if( rc[0]==null || rc[0].compareTo(location)<0 ) {
              rc[0] = location;
            }
          }
         
        }       
       
        // Checkpoint the removed messages.
        iterator = removedMessageLocations.iterator();
        while (iterator.hasNext()) {         
          AckData data = (AckData)iterator.next();
          longTermStore.removeMessage(data.ack.getMessageIdentity(),data.ack);

          if( rc[0]==null || rc[0].compareTo(data.location)<0 ) {
            rc[0] = data.location;
          }
        }       
       
      }

    });
   
    return rc[0];
  }
 
  private ActiveMQMessage getCacheMessage(MessageIdentity identity) throws JMSException {
    return cacheMessageStore.getMessage(identity);
  }

  /**
   *
   */
  public ActiveMQMessage getMessage(MessageIdentity identitythrows JMSException {
    ActiveMQMessage answer=null;
   
    Object location = identity.getSequenceNumber();
    if( location==null ) {
      // The sequence number may not have been set but it may still be in the journal.
      synchronized(this) {
        location = addedMessageLocations.get(identity);
      }
    }
    // Do we have a Journal sequence number?
    if(location!=null && location instanceof RecordLocation) {
      answer = (ActiveMQMessage) peristenceAdapter.readPacket((RecordLocation)location);
      if( answer !=null )
        return answer;
    }
   
    // If all else fails try the long term message store.
    return longTermStore.getMessage(identity);
  }

  /**
   * Replays the checkpointStore first as those messages are the oldest ones,
   * then messages are replayed from the transaction log and then the cache is
   * updated.
   *
   * @param container
   * @throws JMSException
   */
  public synchronized void recover(final QueueMessageContainer container)
      throws JMSException {
    longTermStore.recover(container);
  }

  public void start() throws JMSException {
    longTermStore.start();
  }

  public void stop() throws JMSException {
    longTermStore.stop();
  }

  /**
   * @return Returns the longTermStore.
   */
  public MessageStore getLongTermStore() {
    return longTermStore;
  }

  /**
   * @see org.codehaus.activemq.store.cache.CacheMessageStoreAware#setCacheMessageStore(org.codehaus.activemq.store.cache.CacheMessageStore)
   */
  public void setCacheMessageStore(CacheMessageStore store) {
    cacheMessageStore = store;
    // Propagate the setCacheMessageStore method call to the longTermStore if possible.
    if( longTermStore instanceof CacheMessageStoreAware ) {
      ((CacheMessageStoreAware)longTermStore).setCacheMessageStore(store);
    }
  }
}
TOP

Related Classes of org.codehaus.activemq.store.journal.JournalMessageStore$AckData

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.