package voldemort.store.readonly.io;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

import org.apache.log4j.Logger;

/**
 * Facade around a MappedByteBuffer but we also support mlock on the mapped
 * pages, and closing all dependent resources.
 * 
 */
public class MappedFileReader implements Closeable {

    private FileChannel channel;

    private long offset = 0;

    private long length = 0;

    private Closer closer = new Closer();

    private File file;

    private int fd;

    private boolean fadvise = true;

    public File getFile() {
        return file;
    }

    public int getFd() {
        return fd;
    }

    public boolean isClosed() {
        return closer.isClosed();
    }

    @Override
    public String toString() {
        return file.toString();
    }

    private static final Logger log = Logger.getLogger(MappedFileReader.class);

    private FileInputStream in;

    private MappedByteBuffer mappedByteBuffer = null;

    public MappedFileReader(String path) throws IOException {
        this(new File(path));
    }

    public MappedFileReader(File file) throws IOException {

        init(file);

    }

    private void init(File file) throws IOException {

        this.file = file;

        this.in = new FileInputStream(file);
        this.channel = in.getChannel();
        this.fd = Native.getFd(in.getFD());

        this.length = file.length();

    }

    /**
     * Read from this mapped file.
     */
    public MappedByteBuffer map(boolean setAutoLock) throws IOException {

        try {

            if(mappedByteBuffer == null) {

                if(setAutoLock) {
                    closer.add(new MemLock(file, in.getFD(), offset, length));
                }

                mappedByteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, offset, length);

                closer.add(new MappedByteBufferCloser(mappedByteBuffer));

            }

            return mappedByteBuffer;

        } catch(IOException e) {

            log.error(String.format("Failed to map %s of length %,d at %,d",
                                    file.getPath(),
                                    length,
                                    offset), e);

            throw new IOException(String.format("Failed to map %s of length %,d at %,d",
                                                file.getPath(),
                                                length,
                                                offset), e);

        }

    }

    @Override
    public void close() throws IOException {

        if(closer.isClosed())
            return;

        closer.add(channel);
        closer.add(in);

        closer.close();

    }

    /**
     * A closeable which is smart enough to work on mapped byte buffers.
     */
    class MappedByteBufferCloser extends ByteBufferCloser {

        public MappedByteBufferCloser(ByteBuffer buff) {
            super(buff);
        }

        @Override
        public void close() throws IOException {

            super.close();

        }

    }

}

@@ -499,38 +499,8 @@
 l;%0A%0A
-    private long offset = 0;%0A%0A
     
@@ -617,45 +617,8 @@
 d;%0A%0A
-    private boolean fadvise = true;%0A%0A
     
@@ -1771,22 +1771,17 @@
 etFD(), 
-offset
+0
 , length
@@ -1881,22 +1881,17 @@
 D_ONLY, 
-offset
+0
 , length
@@ -2112,39 +2112,32 @@
 ap %25s of length 
-%25,d at 
 %25,d%22,%0A          
@@ -2181,95 +2181,15 @@
 h(),
-%0A                                    length,%0A                                    offset
+ length
 ), e
@@ -2272,15 +2272,8 @@
 gth 
-%25,d at 
 %25,d%22
@@ -2396,64 +2396,8 @@
 ngth
-,%0A                                                offset
 ), e

Remove unused fields from MappedFileReader