/** * edu.utexas.GeDBIT.mckoi.store.NIOBufferedFile 28 Jan 2003 * * Mckoi SQL Database ( http://www.mckoi.com/database ) * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * Version 2 as published by the Free Software Foundation. * * 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 General Public License Version 2 for more details. * * You should have received a copy of the GNU General Public License * Version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Change Log: * * */ package GeDBIT.mckoi.store; import java.io.RandomAccessFile; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.MappedByteBuffer; /** * An implementation of AbstractBufferedFile that uses the NIO API to map pages * of the underlying file into memory. * * @author Tobias Downer */ class NIOBufferedFile extends AbstractBufferedFile { /** * The FileChannel object. */ private FileChannel access_file_channel; /** * The mode of the mapped byte buffer. */ private FileChannel.MapMode map_mode; /** * The current size of the file. */ private long file_size; /** * The constructor. */ public NIOBufferedFile(int unique_id, RandomAccessFile file, String mode, BufferManager manager) throws IOException { super(unique_id, file, manager); if (mode.equals("r")) { map_mode = FileChannel.MapMode.READ_ONLY; } else if (mode.equals("rw")) { map_mode = FileChannel.MapMode.READ_WRITE; } else { throw new RuntimeException("Unrecognised access mode."); } file_size = file.length(); access_file_channel = file.getChannel(); } // ---------- Implemented from AbstractBufferedFile ---------- public PageBuffer createPageFor(long position, int len) { return new NIOPageBuffer(position, len); } public void sizeChange(long old_size, long new_size) throws IOException { file_size = new_size; // If the store has a page buffer created over the given area, we // flush and reinitialize the page. NIOPageBuffer page_buffer = (NIOPageBuffer) getPageFromCache((old_size - 1) / page_size); if (page_buffer != null) { page_buffer.flushImpl(-1, -1); page_buffer.initImpl(); } } // ---------- Inner classes ---------- /** * This implementation of a page buffer initializes the page by reading the * page into a byte[] array in memory. */ class NIOPageBuffer extends PageBuffer { private long position; private int length; private MappedByteBuffer buffer; public NIOPageBuffer(long position, int length) { this.position = position; this.length = length; } public void initImpl() throws IOException { int map_size = (int) Math.min(file_size - position, (long) length); if (map_size < 0) { System.out.println("length = " + length); System.out.println("file_size = " + file_size); System.out.println("position = " + position); } buffer = access_file_channel.map(map_mode, position, map_size); } public byte readImpl(int position) { return buffer.get(position); } public void readImpl(int position, byte[] b, int off, int len) { buffer.position(position); buffer.get(b, off, len); } public void writeImpl(int position, byte b) { buffer.put(position, b); } public void writeImpl(int position, byte[] b, int off, int len) { buffer.position(position); buffer.put(b, off, len); } public void flushImpl(int p1, int p2) throws IOException { buffer.force(); } public void disposeImpl() { buffer = null; } } }