All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.crankuptheamps.client.PublishStore Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2022 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties.  This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights.  This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////

package com.crankuptheamps.client;
import com.crankuptheamps.client.exception.*;
import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;


/**
 * PublishStore is a memory-mapped file-backed store for storing outgoing messages.
 * As messages are stored, space is allocated from a pre-created flat buffer on disk.
 * As messages are discarded, space in that buffer is marked "free" for future store operations.
 * If messages are stored faster than they are published, the buffer is re-sized to create more capacity.
 * 
 * @author dnoor
 *
 */
public class PublishStore extends BlockPublishStore
{
    final static int DEFAULT_INITIAL_BLOCKS = 10 * 1000;
    private int _initialCapacity;
    private boolean _truncateOnClose = false;
    static class MMapStoreBuffer extends MemoryStoreBuffer
    {
        String _path;
        RandomAccessFile _file;
        FileChannel _channel;

        public MMapStoreBuffer(String path) throws StoreException
        {
            _path = path;
            try {
                _file = new RandomAccessFile(path, "rw");
            } catch (IOException e) {
                throw new StoreException(e);
            }
            _channel = _file.getChannel();
        }
        
        @Override
        public long getSize() throws IOException
        {
            if(_buffer == null)
            {
                if(_file.length() == 0)
                {
                    return 0;
                }
                _buffer = _channel.map(MapMode.READ_WRITE, 0, _file.length());
            }
            return _buffer.capacity();
        }
        
        @Override
        public void setSize(long newSize) throws IOException
        {
            if(_channel == null)
            {
                throw new IOException("The store is closed.");
            }
            if(_buffer != null) ((MappedByteBuffer)_buffer).force();
            _buffer = _channel.map(MapMode.READ_WRITE, 0, newSize);
        }
        
        public void close() throws Exception
        {
            _buffer = null;
            _store = null;
            if (_channel != null) _channel.close();
            if (_file != null) _file.close();
            _channel = null;
            _file = null;
        }
        
        public void sync() throws IOException
        {
            MappedByteBuffer b = ((MappedByteBuffer)_buffer);
            b.force();
            
        }
               
        @Override
        protected void finalize() throws Throwable
        {
            close();
            super.finalize();
        }
    }

    /**
     * Creates a new PublishStore with the given path.  Immediately proceeds to recovery if the file exists. 
     * @param path The path (absolute or relative) of the publish store
     * @throws StoreException Thrown when an operation on the store fails.
     */
    public PublishStore(String path) throws StoreException
    {
        this(path, DEFAULT_INITIAL_BLOCKS);
    }

    /**
     * Creates a new PublishStore with the given path.  Immediately proceeds to recovery if the file exists.
     * @param path The path (absolute or relative) of the publish store
     * @param initialCapacity The initial capacity (in 2k blocks) of the store.  This size is also used when
     *     resizing the store: the store is resized by this value each time the
     *     store grows. A general guideline for initial capacity is to set the
     *     capacity to messages_published_per_second * int(average_message_size / block_size) + 1.  
     * @throws StoreException Thrown when an operation on the store fails.
     */
    public PublishStore(String path, int initialCapacity) throws StoreException
    {
        super(new MMapStoreBuffer(path), initialCapacity, true);
        _initialCapacity = initialCapacity;
        recover();
        if (_usedList == null)
        {
            growFreeListIfEmpty();
        }
    }
    /**
     * Tells the PublishStore to truncate the file to its original size if there are no saved Messages when it is closed. 
     * This feature is not supported on Windows.
     * @param truncate If true, file will be truncated when the PublishStore is closed.
     */
    public void truncateOnClose(boolean truncate)
    {
        _truncateOnClose = truncate;
    }

    /**
     * Closes the memory mapped file.
     * @throws IOException Thrown when an operation on the file produces an IOException.
     */
    public void close() throws Exception
    {
        if (_buffer == null) return;
        long unpersistedCount = unpersistedCount();
        _buffer.close();
        if (_truncateOnClose && unpersistedCount == 0 &&
            !System.getProperty("os.name").startsWith("Windows"))
        {
            FileChannel channel = new FileOutputStream(((MMapStoreBuffer)_buffer)._path, true).getChannel();
            channel.truncate((long)_initialCapacity*BlockPublishStore.Block.SIZE);
        }
        _buffer = null;
    }
    
    /**
     * Forces any in memory changes to be written to persistant storage. 
     * @throws IOException Thrown when an operation on the file produces an IOException.
     */
    public void sync() throws IOException
    {
        ((MMapStoreBuffer)_buffer).sync();
    
    }

    /**
     * Overridden to call close() upon garbage collection.
     */
    @Override
    protected void finalize() throws Throwable
    {
        close();
        super.finalize();
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy