org.jsl.collider.ShMem Maven / Gradle / Ivy
/*
* Copyright (C) 2013 Sergey Zubarev, [email protected]
*
* This file is a part of JS-Collider framework.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package org.jsl.collider;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class ShMem
{
protected static final Logger s_logger = Logger.getLogger( "org.jsl.collider.ShMem" );
public static class Channel
{
protected final File m_file;
protected final int m_blockSize;
protected final int m_nextBlockPos;
protected final FileChannel m_fileChannel;
protected MappedByteBuffer [] m_mbb;
public Channel( File file, int blockSize, boolean init ) throws IOException
{
m_file = file;
m_blockSize = blockSize;
m_nextBlockPos = (blockSize - 4);
m_fileChannel = new RandomAccessFile(file, "rw").getChannel();
m_mbb = new MappedByteBuffer[8];
for (int idx=0; idx<2; idx++)
{
m_mbb[idx] = m_fileChannel.map( FileChannel.MapMode.READ_WRITE, idx*m_blockSize, m_blockSize );
if (init)
{
m_mbb[idx].putInt( m_nextBlockPos, -1 );
/* It is better to set all possible permission to the file
* for a case if server runs under different user.
*/
if (!file.setReadable(true, false))
{
if (s_logger.isLoggable(Level.WARNING))
s_logger.warning( "File.setReadable('" + file.getAbsolutePath() + "') failed." );
}
if (!file.setWritable(true, false))
{
if (s_logger.isLoggable(Level.WARNING))
s_logger.warning( "File.setWritable('" + file.getAbsolutePath() + "') failed." );
}
}
}
}
public final int getBlockSize()
{
return m_blockSize;
}
public final File getFile()
{
return m_file;
}
public void close()
{
try
{
m_fileChannel.close();
}
catch (IOException ex)
{
if (s_logger.isLoggable(Level.WARNING))
s_logger.warning( ex.toString() );
}
if (!m_file.delete())
{
if (s_logger.isLoggable(Level.WARNING))
s_logger.warning( "File.delete('" + m_file.getAbsolutePath() + "') failed." );
}
}
}
public static class ChannelIn extends Channel
{
private int m_idx;
public ChannelIn( File file, int blockSize, boolean init ) throws IOException
{
super( file, blockSize, init );
m_idx = 0;
}
public final int handleData( int size, Session.Listener listener )
{
for (;;)
{
final MappedByteBuffer buf = m_mbb[m_idx];
assert( buf.capacity() == m_blockSize );
int pos = buf.position();
final int blockBytes = (m_nextBlockPos - pos);
if (size <= blockBytes)
{
pos += size;
buf.limit( pos );
//FIXME listener.onDataReceived( buf );
buf.position( pos );
return 0;
}
buf.limit( m_nextBlockPos );
//FIXME listener.onDataReceived( buf );
buf.clear();
final int nextIdx = buf.getInt( m_nextBlockPos );
buf.putInt( m_nextBlockPos, -1 );
size -= blockBytes;
if ((nextIdx >= m_mbb.length) || (m_mbb[nextIdx] == null))
{
/* The block is not mapped yet. */
if (nextIdx >= m_mbb.length)
{
MappedByteBuffer [] mbb = new MappedByteBuffer[m_mbb.length*2];
System.arraycopy( m_mbb, 0, mbb, 0, m_mbb.length );
m_mbb = mbb;
}
MappedByteBuffer nextBuf;
try
{
nextBuf = m_fileChannel.map(
FileChannel.MapMode.READ_WRITE, nextIdx*m_blockSize, m_blockSize );
}
catch (IOException ex)
{
if (s_logger.isLoggable(Level.WARNING))
{
s_logger.warning(
"FileChannel.map(" + m_file.getAbsolutePath() + ", " +
nextIdx*m_blockSize + ", " + m_blockSize + "') failed." );
}
/* Most probably error is not recoverable.
* Let's return -1 notifying caller to close connection.
*/
return -1;
}
m_mbb[nextIdx] = nextBuf;
}
m_idx = nextIdx;
}
}
}
public static class ChannelOut extends Channel
{
private int m_idx;
public ChannelOut( File file, int blockSize, boolean init ) throws IOException
{
super( file, blockSize, init );
m_idx = 0;
}
public final int addData( ByteBuffer data )
{
final int dataPosition = data.position();
final int dataLimit = data.limit();
int bytesRemaining = (dataLimit - dataPosition);
int pos = dataPosition;
MappedByteBuffer buf = m_mbb[m_idx];
copyLoop: for (;;)
{
final int space = (buf.remaining() - 4);
if (bytesRemaining <= space)
{
buf.put( data );
return (dataLimit - dataPosition);
}
if (space > 0)
{
pos += space;
bytesRemaining -= space;
data.limit( pos );
buf.put( data );
data.limit( dataLimit );
}
int idx = 0;
for (; idx
© 2015 - 2024 Weber Informatics LLC | Privacy Policy