/**
* edu.utexas.GeDBIT.mckoi.store.PageBuffer 24 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.IOException;
/**
* Abstract class that defines a page of data from the underlying file. We
* should be able to read and write data to/from a PageBuffer with as little
* overhead as possible.
* <p>
* This class is used by implementations of AbstractBufferedFile and the
* BufferManager.
*
* @author Tobias Downer
*/
abstract class PageBuffer {
/**
* When stored in a page hash map for a file, points to the next page with
* this hash key.
*/
PageBuffer next_page_in_hash;
/**
* The unique id of the file this page is part of.
*/
private int file_unique_id;
/**
* The page number that this represents in the buffer.
*/
private long page_number;
/**
* The time this page was last accessed. This value is reset each time the
* page is requested.
*/
private long t;
/**
* The number of times this page has been accessed since it was created.
*/
private int access_count;
/**
* The first position in the buffer that was last written.
*/
private int first_write_position;
/**
* The last position in the buffer that was last written.
*/
private int last_write_position;
/**
* The number of references on this page.
*/
private int reference_count;
/**
* Set to true when the page is initialized.
*/
private boolean initialized;
/**
* Constructs the page.
*/
public PageBuffer() {
reference_count = 0;
initialized = false;
}
/**
* Sets the t value (the time when this buffer was last accessed).
*/
final void setT(long t) {
this.t = t;
}
/**
* Returns t (the last time this page was accessed).
*/
final long getT() {
return t;
}
/**
* Increment the access counter.
*/
final void incrementAccessCounter() {
++access_count;
}
/**
* Return the current access counter (the number of accesses to this page).
*/
final int getAccessCounter() {
return access_count;
}
/**
* Sets the page number for this page.
*/
final void setPageNumber(long page_number) {
this.page_number = page_number;
}
/**
* Returns the page number for this page.
*/
final long getPageNumber() {
return page_number;
}
/**
* Sets the unique_id of the file this page is part of.
*/
final void setFileUniqueID(int unique_id) {
this.file_unique_id = unique_id;
}
/**
* Gets the unique_id of the file this page is part of.
*/
final int getFileUniqueID() {
return file_unique_id;
}
/**
* Adds 1 to the reference counter on this page.
*/
final void referenceAdd() {
++reference_count;
}
/**
* Removes 1 from the reference counter on this page.
*/
final void referenceRemove() {
--reference_count;
}
/**
* Returns true if this PageBuffer is not in use (has 0 reference count and
* is not inialized.
*/
final boolean notInUse() {
return (reference_count <= 0 && !initialized);
}
/**
* Initializes the page buffer. If the buffer is already initialized then we
* just return. If it's not initialized we set up any internal structures
* that are required to be set up for access to this page.
*/
final void initialize() throws IOException {
if (!initialized) {
initImpl();
initialized = true;
access_count = 0;
first_write_position = Integer.MAX_VALUE;
last_write_position = -1;
}
}
/**
* Disposes of the page buffer if it can be disposed (there are no
* references to the page and the page is initialized). When disposed any
* internal resources are reclaimed. The page may later be initialized again
* if required.
*/
final void dispose() throws IOException {
referenceRemove();
if (reference_count <= 0) {
if (initialized) {
flush();
disposeImpl();
initialized = false;
} else {
throw new RuntimeException(
"Assertion failed: tried to dispose an uninitialized page.");
}
}
}
/**
* Returns a byte from this page at the given position.
*/
final byte read(int position) throws IOException {
return readImpl(position);
}
/**
* Reads a byte array from this page and copies the information into the
* buffer at the given offset.
*/
final void read(int position, byte[] buf, int off, int len)
throws IOException {
readImpl(position, buf, off, len);
}
/**
* Writes a byte to the given position in this page.
*/
final void write(int position, byte val) throws IOException {
first_write_position = Math.min(position, first_write_position);
last_write_position = Math.max(position + 1, last_write_position);
writeImpl(position, val);
}
/**
* Writes a byte array to this page at the given position.
*/
final void write(int position, byte[] buf, int off, int len)
throws IOException {
first_write_position = Math.min(position, first_write_position);
last_write_position = Math.max(position + len, last_write_position);
writeImpl(position, buf, off, len);
}
/**
* Flushes the information buffered by this page to the disk. This may write
* nothing if it is determined that no data in the page was changed.
*/
final void flush() throws IOException {
if (initialized) {
if (last_write_position >= 0) {
flushImpl(first_write_position, last_write_position);
first_write_position = Integer.MAX_VALUE;
last_write_position = -1;
}
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append('[');
buf.append(page_number);
buf.append('-');
buf.append(access_count);
buf.append('-');
buf.append(t);
buf.append(']');
return new String(buf);
}
// ---------- Abstract methods ----------
// These aren't commented because they are simply the implementation calls
// from the above methods.
protected abstract void initImpl() throws IOException;
protected abstract byte readImpl(int position) throws IOException;
protected abstract void readImpl(int position, byte[] buf, int off, int len)
throws IOException;
protected abstract void writeImpl(int position, byte val)
throws IOException;
protected abstract void writeImpl(int position, byte[] buf, int off, int len)
throws IOException;
// Flush the buffer between p1 (inclusive) and p2 (exclusive)
protected abstract void flushImpl(int p1, int p2) throws IOException;
/**
* Releases and disposes of any resources claimed by this object. This is
* called when old cached items are removed from the cache.
*/
protected abstract void disposeImpl() throws IOException;
}