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

com.github.arunsoman.ipc.mappedbus.MappedBusReader Maven / Gradle / Ivy

Go to download

Mappedbus is a Java based high throughput, low latency message bus, using either a memory mapped file or shared memory as transport

The newest version!
/* 
 * Copyright 2015 Caplogic AB. 
 * 
 * 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 com.github.arunsoman.ipc.mappedbus;

import java.io.EOFException;
import java.io.IOException;

import com.github.arunsoman.ipc.mappedbus.MappedBusConstants.Commit;
import com.github.arunsoman.ipc.mappedbus.MappedBusConstants.Length;
import com.github.arunsoman.ipc.mappedbus.MappedBusConstants.Rollback;
import com.github.arunsoman.ipc.mappedbus.MappedBusConstants.Structure;

/**
 * Class for reading messages from the bus.
 * 

* Messages can either be message based or byte array based. *

* The typical usage is as follows: *

 * {@code
 * // Construct a reader
 * MappedBusReader reader = new MappedBusReader("/tmp/test", 100000L, 32);
 * reader.open();
 * 
 * // A: read messages as objects
 * while (true) {
 *    if (reader.next()) {
 *       int type = reader.readType();
 *       if (type == 0) {
 *          reader.readMessage(priceUpdate)
 *       }
 *    }
 * }
 *
 * // B: read messages as byte arrays
 * while (true) {
 *    if (reader.next()) {
 *       int length = reader.read(buffer, 0);
 *    }
 * }
 *
 * // Close the reader
 * reader.close();
 * }
 * 
*/ public class MappedBusReader { protected static final long MAX_TIMEOUT_COUNT = 100; private final String fileName; private final long fileSize; private final int recordSize; private MemoryMappedFile mem; private long limit = Structure.Data; private long initialLimit; private int maxTimeout = 2000; protected long timerStart; protected long timeoutCounter; private boolean typeRead; /** * Constructs a new reader. * * @param fileName the name of the memory mapped file * @param fileSize the maximum size of the file * @param recordSize the maximum size of a record (excluding status flags and meta data) */ public MappedBusReader(String fileName, long fileSize, int recordSize) { this.fileName = fileName; this.fileSize = fileSize; this.recordSize = recordSize; } /** * Opens the reader. * * @throws IOException if there was a problem opening the file */ public void open() throws IOException { try { mem = new MemoryMappedFile(fileName, fileSize); } catch(Exception e) { throw new IOException("Unable to open the file: " + fileName, e); } initialLimit = mem.getLongVolatile(Structure.Limit); } /** * Sets the time for a reader to wait for a record to be committed. * * When the timeout occurs the reader will mark the record as "rolled back" and * the record is ignored. * * @param timeout the timeout in milliseconds */ public void setTimeout(int timeout) { this.maxTimeout = timeout; } /** * Steps forward to the next record if there's one available. * * The method has a timeout for how long it will wait for the commit field to be set. When the timeout is * reached it will set the roll back field and skip over the record. * * @return true, if there's a new record available, otherwise false * @throws EOFException in case the end of the file was reached */ public boolean next() throws EOFException { if (limit >= fileSize) { throw new EOFException("End of file was reached"); } if (mem.getLongVolatile(Structure.Limit) <= limit) { return false; } byte commit = mem.getByteVolatile(limit); byte rollback = mem.getByteVolatile(limit + Length.Commit); if (rollback == Rollback.Set) { limit += Length.RecordHeader + recordSize; timeoutCounter = 0; timerStart = 0; return false; } if (commit == Commit.Set) { timeoutCounter = 0; timerStart = 0; return true; } timeoutCounter++; if (timeoutCounter >= MAX_TIMEOUT_COUNT) { if (timerStart == 0) { timerStart = System.currentTimeMillis(); } else { if (System.currentTimeMillis() - timerStart >= maxTimeout) { mem.putByteVolatile(limit + Length.Commit, Rollback.Set); limit += Length.RecordHeader + recordSize; timeoutCounter = 0; timerStart = 0; return false; } } } return false; } /** * Reads the message type. * * @return the message type */ public int readType() { typeRead = true; limit += Length.StatusFlags; int type = mem.getInt(limit); limit += Length.Metadata; return type; } /** * Reads the next message. * * @param message the message object to populate * @return the message object */ public MappedBusMessage readMessage(MappedBusMessage message) { if (!typeRead) { readType(); } typeRead = false; message.read(mem, limit); limit += recordSize; return message; } /** * Reads the next buffer of data. * * @param dst the input buffer * @param offset the offset in the buffer of the first byte to read data into * @return the length of the record that was read */ public int readBuffer(byte[] dst, int offset) { limit += Length.StatusFlags; int length = mem.getInt(limit); limit += Length.Metadata; mem.getBytes(limit, dst, offset, length); limit += recordSize; return length; } /** * Indicates whether all records available when the reader was created have been read. * * @return true, if all records available from the start was read, otherwise false */ public boolean hasRecovered() { return limit >= initialLimit; } /** * Closes the reader. * * @throws IOException if there was an error closing the file */ public void close() throws IOException { try { mem.unmap(); } catch(Exception e) { throw new IOException("Unable to close the file", e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy