Package org.mule.util.queue

Source Code of org.mule.util.queue.JournalPersistenceStrategy$HolderImpl

/*
* $Id: JournalPersistenceStrategy.java 2676 2006-08-10 13:37:18Z holger $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
*
* The software in this package is published under the terms of the BSD style
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/

package org.mule.util.queue;

import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;

import org.activeio.Packet;
import org.activeio.journal.Journal;
import org.activeio.journal.JournalEventListener;
import org.activeio.journal.RecordLocation;
import org.activeio.journal.active.JournalImpl;
import org.activeio.journal.active.LogFileManager;
import org.activeio.packet.ByteArrayPacket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.doomdark.uuid.UUID;
import org.doomdark.uuid.UUIDGenerator;
import org.mule.MuleManager;
import org.mule.config.MuleConfiguration;

import java.io.ByteArrayInputStream;
import org.apache.commons.io.output.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

/**
*
* TODO: this implementation is in alpha stage defragmentation should be handled
* correctly
*
* @author <a href="mailto:gnt@codehaus.org">Guillaume Nodet</a>
* @version $Revision: 2676 $
*/
public class JournalPersistenceStrategy
        implements
            QueuePersistenceStrategy,
            Runnable,
            JournalEventListener
{

    private static final Log logger = LogFactory.getLog(JournalPersistenceStrategy.class);

    private UUIDGenerator gen = UUIDGenerator.getInstance();
    private Journal journal;
    private Map marks;
    private Thread marker;
    private SortedSet pendingMarks;
    private SortedSet unusedMarks;
    private Object markLock = new Object();
    private RecordLocation overflowLocation = null;
    private File store;

    private static final byte STORE_BYTE = 0;
    private static final byte DELETE_BYTE = 1;

    private static final int UUID_LENGTH = new UUID().asByteArray().length;

    public JournalPersistenceStrategy() throws IOException
    {
        super();
    }

    protected UUID getId(Object obj)
    {
        return gen.generateTimeBasedUUID();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.transaction.xa.queue.QueuePersistenceStrategy#store(java.lang.Object)
     */
    public Object store(String queue, Object obj) throws IOException
    {
        UUID id = getId(obj);
        ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeByte(STORE_BYTE);
        oos.writeUTF(queue);
        oos.write(id.asByteArray());
        oos.writeObject(obj);
        oos.close();
        Packet packet = new ByteArrayPacket(baos.toByteArray());
        RecordLocation loc = journal.write(packet, false);
        synchronized (markLock) {
            marks.put(id, loc);
            pendingMarks.add(loc);
        }
        return id;
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.transaction.xa.queue.QueuePersistenceStrategy#load(java.lang.Object)
     */
    public Object load(String queue, Object id) throws IOException
    {
        try {
            RecordLocation loc = (RecordLocation)marks.get(id);
            Packet packet = journal.read(loc);
            ObjectInputStream ois = new ObjectInputStream(
                    new ByteArrayInputStream(packet.sliceAsBytes()));
            ois.readByte();
            ois.readUTF();
            ois.skipBytes(UUID_LENGTH);
            Object obj = ois.readObject();
            return obj;
        }
        catch (IOException e) {
            throw e;
        }
        catch (Exception e) {
            throw (IOException)new IOException().initCause(e);
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.transaction.xa.queue.QueuePersistenceStrategy#remove(java.lang.Object)
     */
    public void remove(String queue, Object id) throws IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
        baos.write(DELETE_BYTE);
        baos.write(((UUID)id).asByteArray());
        Packet packet = new ByteArrayPacket(baos.toByteArray());
        RecordLocation loc = journal.write(packet, false);
        synchronized (markLock) {
            unusedMarks.add(loc);
            loc = (RecordLocation)marks.remove(id);
            if (loc != null) {
                pendingMarks.remove(loc);
                unusedMarks.add(loc);
            }
            markLock.notify();
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.transaction.xa.queue.QueuePersistenceStrategy#restore()
     */
    public List restore() throws IOException
    {
        Map results = new HashMap();
        RecordLocation pos = null;
        logger.info("Journal Recovery Started.");
        try {
            synchronized (markLock) {
                // While we have records in the journal.
                while ((pos = journal.getNextRecordLocation(pos)) != null) {
                    Packet packet = journal.read(pos);
                    byte[] buffer = packet.sliceAsBytes();
                    if (buffer[0] == DELETE_BYTE) {
                        UUID id = new UUID(buffer, 1);
                        results.remove(id);
                        unusedMarks.add(pos);
                        RecordLocation loc = (RecordLocation)marks.remove(id);
                        if (loc != null) {
                            pendingMarks.remove(loc);
                            unusedMarks.add(loc);
                        }
                        markLock.notify();
                    }
                    else {
                        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer));
                        ois.readByte();
                        String queue = ois.readUTF();
                        byte[] buf = new byte[UUID_LENGTH];
                        ois.read(buf);
                        UUID id = new UUID(buf);
                        results.put(id, new HolderImpl(queue, id));
                        marks.put(id, pos);
                        pendingMarks.add(pos);
                    }
                }
            }
        }
        catch (IOException e) {
            throw e;
        }
        catch (Exception e) {
            throw (IOException)new IOException().initCause(e);
        }

        logger.info("Journal Recovered: " + results.size() + " message(s) in transactions recovered.");
        return new ArrayList(results.values());
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.util.queue.QueuePersistenceStrategy#open()
     */
    public void open() throws IOException
    {
        File s = store;
        if (s == null) {
            s = new File(MuleManager.getConfiguration().getWorkingDirectory() + File.separator
                    + MuleConfiguration.DEFAULT_QUEUE_STORE);
        }
        s.mkdirs();
        journal = new JournalImpl(s, 8, LogFileManager.DEFAULT_LOGFILE_SIZE);
        journal.setJournalEventListener(this);
        marks = new ConcurrentHashMap();
        pendingMarks = new TreeSet();
        unusedMarks = new TreeSet();
        marker = new Thread(this, "JournalPersistenceStrategy");
        marker.setDaemon(true);
        marker.start();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.mule.transaction.xa.queue.QueuePersistenceStrategy#close()
     */
    public void close() throws IOException
    {
        marker.interrupt();
        journal.close();
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Runnable#run()
     */
    public void run()
    {
        try {
            while (!Thread.interrupted()) {
                Thread.sleep(100);

                synchronized (markLock) {
                    try {
                        SortedSet m;
                        if (overflowLocation != null) {
                            RecordLocation overflowLoc = overflowLocation;
                            overflowLocation = null;
                            m = pendingMarks.headSet(overflowLoc);
                            if (m != null && m.size() > 0) {
                                logger.trace("Relocating " + m.size() + " records");
                                int nbRecord = 0;
                                while (m.size() > 0) {
                                    RecordLocation loc = (RecordLocation)m.first();
                                    Packet packet = journal.read(loc);
                                    RecordLocation newLoc = journal.write(packet, false);
                                    ObjectInputStream ois = new ObjectInputStream(
                                            new ByteArrayInputStream(packet.sliceAsBytes()));
                                    ois.readByte();
                                    String queue = ois.readUTF();
                                    byte[] buf = new byte[UUID_LENGTH];
                                    ois.read(buf);
                                    UUID id = new UUID(buf);

                                    if (++nbRecord % 10 == 0) {
                                        RecordLocation n = journal.getNextRecordLocation(loc);
                                        journal.setMark(n != null ? n : loc, false);
                                        // unusedMarks.headSet(loc).clear();
                                    }
                                    unusedMarks.add(loc);
                                    pendingMarks.add(newLoc);
                                    marks.put(id, newLoc);
                                    m.remove(loc);
                                }
                            }
                        }
                        // No more pending marks
                        // so clear all unused marks and mark to last
                        if (pendingMarks.isEmpty()) {
                            m = unusedMarks;
                            // There are pending marks
                        }
                        else {
                            RecordLocation pendingMark = (RecordLocation)pendingMarks.first();
                            m = unusedMarks.headSet(pendingMark);
                        }
                        // Is there anything to do ?
                        if (!m.isEmpty()) {
                            RecordLocation last = (RecordLocation)m.last();
                            RecordLocation n = journal.getNextRecordLocation((RecordLocation)m.last());
                            if (n == null) {
                                n = last;
                            }
                            if (logger.isDebugEnabled()) {
                                logger.debug("Marking to " + n + " / "
                                        + (pendingMarks.isEmpty() ? "null" : pendingMarks.last()));
                            }
                            if (journal.getMark() == null || n.compareTo(journal.getMark()) > 0) {
                                journal.setMark(n, false);
                            }
                            m.clear();
                        }
                    }
                    catch (Exception e) {
                        logger.warn("Error when relocating records", e);
                    }
                }
            }
        }
        catch (InterruptedException e) {
            logger.debug("Marker thread interrupted");
        }
    }

    protected static class HolderImpl implements Holder
    {
        private String queue;
        private Object id;

        public HolderImpl(String queue, Object id)
        {
            this.queue = queue;
            this.id = id;
        }

        public Object getId()
        {
            return id;
        }

        public String getQueue()
        {
            return queue;
        }
    }

    public void overflowNotification(RecordLocation safeLoc)
    {
        overflowLocation = safeLoc;
        logger.debug("Overflow to " + safeLoc);
    }

    public File getStore()
    {
        return store;
    }

    public void setStore(File store)
    {
        this.store = store;
    }

    public boolean isTransient()
    {
        return false;
    }
}
TOP

Related Classes of org.mule.util.queue.JournalPersistenceStrategy$HolderImpl

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.