alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.mdr.persistence.btreeimpl.btreestorage;

import java.io.*;
import java.text.*;

import org.netbeans.mdr.persistence.*;

/** A map page, used by the log file to keep track of before-image pages 
*/
class MapPage {

    /* page size */
    private int pageSize;

    /* offset in the file of this page */
    private int myOffset;

    /* number of files being logged */
    private short numFiles;

    /* maximum page entries that fit */
    private short maxPages;

    /* file header data for these files */
    private long fileId;
    private long timeStamp;
    private long newTimeStamp;

    /* number of before-image pages mapped by this page */
    private short pageCount;

    /* checksum for this page */
    private short checksum;

    private static final int FIXED_SIZE = 40; /* size of above */

    /** end-of-file marks for each loggged file */
    private int oldEOF[];

    /** offsets for each page described by this map */
    private int offsets[];

    /** Create a new map mage
    * @param pgSz the page size
    * @param noFiles the number of files being logged
    * @param offset the offset into the file of this map page
    */
    MapPage(int pgSz, int noFiles, int offset) {
        myOffset = offset;
        pageSize = pgSz;
        numFiles = (short)noFiles;
        oldEOF = new int[numFiles];
        maxPages = (short)((pageSize - FIXED_SIZE - (4 * numFiles)) / 4);
        offsets = new int[maxPages];
    }


    /** Set EOF array 
    * @param files array of files
    * @exception StorageException I/O error determining EOF
    */
    void setEOFs(RandomAccessFile files[] ) throws StorageException {
        try {
            for (int i = 0; i < numFiles; i++) {
                oldEOF[i] = (int)files[i].length();
            }
        }
        catch (IOException ex) {
            throw new StorageIOException(ex);
        }
    }

    /** Get EOF for a file
    */
    int getEOF(int index) {
        return oldEOF[index];
    }

    /** create the next map page in a log filfilee
    * @param previous the previous map page for this file
    */
    MapPage(MapPage previous) {
        this(previous.pageSize, previous.numFiles, 
            previous.myOffset + ((previous.pageCount + 1) * previous.pageSize));
        setTimeStamps(previous.timeStamp, previous.newTimeStamp);
        oldEOF = new int[previous.oldEOF.length];
        System.arraycopy(previous.oldEOF, 0, oldEOF, 0, oldEOF.length);
    }

    /** Set the file ID for this map page 
    * @param fileId new file id
    */
    void setFileID(long id) {
        fileId = id;
    }

    /** set the time stamps for this map page
    * @param stamp the timestamp for the last comitted transaction
    * @param newStamp the timestamp for the currently outstanding transaction
    */
    void setTimeStamps(long stamp, long newStamp) {
        timeStamp = stamp;
        newTimeStamp = newStamp;
    }

    /** write the map page to a file
    * @param file the file to write it to
    * @exception StorageException I/O error writing the page
    */
    void write(RandomAccessFile file) throws StorageException {

        byte buffer[] = new byte[pageSize];
        IntHolder offset = new IntHolder(0);
        checksum = computeChecksum();
        Converter.writeInt(buffer, offset, pageSize);
        Converter.writeInt(buffer, offset, myOffset);
        Converter.writeShort(buffer, offset, numFiles);
        Converter.writeShort(buffer, offset, maxPages);
        Converter.writeShort(buffer, offset, pageCount);
        Converter.writeShort(buffer, offset, checksum);
        Converter.writeLong(buffer, offset, fileId);
        Converter.writeLong(buffer, offset, timeStamp);
        Converter.writeLong(buffer, offset, newTimeStamp);

        for (int i = 0; i < numFiles; i++)
            Converter.writeInt(buffer, offset, oldEOF[i]);

        for (int i = 0; i < pageCount; i++)
            Converter.writeInt(buffer, offset, offsets[i]);

        try {
            file.seek(myOffset);
            file.write(buffer);
        }
        catch (IOException ex) {
            throw new StorageIOException(ex);
        }
    }


    /** create a map page by reading from a file
    * @param file the file to read from
    * @param offset the offset in the file where the map page lives
    * @exception StorageException I/O error reading the file
    * @exception BadParameterException inconsistent page size
    */
    MapPage(RandomAccessFile file, int offset, int pgSz) 
        throws StorageException {

        byte buffer[] = new byte[pgSz];

        try {
            file.seek(offset);
            file.readFully(buffer);
        }
        catch (IOException ex) {
            throw new StorageIOException(ex);
        }

        IntHolder index = new IntHolder(0);
        pageSize = Converter.readInt(buffer, index);
        if (pageSize == 0)  {
            return;
        }
        else if (pageSize != pgSz) {
            throw new StoragePersistentDataException(
                MessageFormat.format(
                    "Invalid page size {0}: {1} expected",
                    new Object[] {
                        new Integer(pgSz),
                        new Integer(pageSize)}));
        }
        myOffset = Converter.readInt(buffer, index);
        numFiles = Converter.readShort(buffer, index);
        maxPages = Converter.readShort(buffer, index);
        pageCount = Converter.readShort(buffer, index);
        checksum = Converter.readShort(buffer, index);
        fileId = Converter.readLong(buffer, index);
        timeStamp = Converter.readLong(buffer, index);
        newTimeStamp = Converter.readLong(buffer, index);

        oldEOF = new int[numFiles];
        offsets = new int[pageCount];

        for (int i = 0; i < numFiles; i++)
            oldEOF[i] = Converter.readInt(buffer, index); 
        for (int i = 0; i < pageCount; i++)
            offsets[i] = Converter.readInt(buffer, index);

        if (checksum != computeChecksum()) 
            throw new StoragePersistentDataException(
                "Invalid checksum in MapPage");
    }

    /** see if this was a page of zeros */
    boolean isEmpty() {
        return pageSize == 0;
    }

    /** get next map page from log file
    * @exception StorageException I/O error reading the file
    * @exception BadParameterException inconsistent page size
    */
    MapPage getNext(RandomAccessFile file, int numPages) 
                            throws StorageException {
        if (!isFull())
            return null;

        int offset = myOffset + (pageSize * (pageCount + 1));
        if (offset >= (numPages * pageSize))
            return null;

        return new MapPage(file, offset, pageSize);
    }

    /** check that recovery parameters are consistent 
    * @exception BadParameterException parameters inconsistent with
    * map page
    */
    void checkParameters(int thePageSize, int theNumberOfFiles) 
            throws StorageException {
        if (thePageSize != pageSize) {
            throw new StoragePersistentDataException(
                "Map page contains wrong page size.");
        }

        if (theNumberOfFiles != numFiles) {
            throw new StoragePersistentDataException(
                    "Map page contains wrong number of files.");
        }
    }

    /** 
    * check timestamps in logged file
    * @param file file which contains header
    * @exception StorageException I/O error opening or reading the file or
    * file header is corrupt
    */
    void checkFileHeader(RandomAccessFile file) 
            throws StorageException {
        FileHeader header =  new FileHeader(file);

        if (header.timeStamp != timeStamp &&
            header.timeStamp != newTimeStamp) {

                throw new StoragePersistentDataException(
                            "Map page contains invalid timestamp" +
			    + header.timeStamp + " valid would be " +
			    timeStamp + " or " + newTimeStamp);
        }

        if (header.fileId != fileId) {
             throw new StoragePersistentDataException(
                    "Map page contains invalid file id");
        }
    }

    /**
    * where the next before-image  page should be written to
    */
    int nextPageOffset() {
        return myOffset + (pageCount + 1) * pageSize;
    }

    /** add a page to the map
    * @param page page to add
    */
    void add(CachedPage page) {
        offsets[pageCount++] = encode(page.key);
    }

    /** is this page full
    */
    boolean isFull() {
        return pageCount == maxPages;
    }

    /* encode file index and offset into an int */
    private int encode(PageID page) {
        return (page.fileIndex << 20) | (page.offset / pageSize);
    }

    /* decode file index and offset from an int */
    private PageID decode(int pageID) {
        return new PageID(pageID >>> 20, (pageID & 0XFFFFF) * pageSize);
    }

    /** cacluate the checksum for this map page */
    short computeChecksum() {
        int sum = 0;

        sum += fileId;
        sum += timeStamp;
        sum += newTimeStamp;
        sum += pageCount;
        for (int i = 0; i < numFiles; i++)
            sum += (oldEOF[i]);
        for (int i = 0; i < pageCount; i++)
            sum += offsets[i];

        return (short) ((sum & 0xFFFF) + (sum >>> 16));
    }

    /** set files to their pre-transaction size 
    * @exception StorageException I/O error truncating the files
    */
    void truncateFiles(RandomAccessFile files[]) throws StorageException{
        try {
            for (int i = 0; i < files.length; i++) {
                files[i].setLength(oldEOF[i]);
            }
        }
        catch (IOException ex) {
            throw new StorageIOException(ex);
        }
    }

    /** restore all of the before pages listed in this map page 
    * @exception StorageException I/O error restoring the pages
    */
    void recover(RandomAccessFile files[], RandomAccessFile logFile, 
                 int numPages, byte buffer[]) throws StorageException {
        try {
            for (int i = 0; i < pageCount; i++) {
                int logOffset = myOffset + (pageSize * (i + 1));
                if (logOffset >= (numPages * pageSize))
                    break;

                PageID entry = decode(offsets[i]);
                files[entry.fileIndex].seek(entry.offset);
                logFile.seek(logOffset);
                logFile.readFully(buffer);
                files[entry.fileIndex].write(buffer);
            }
        }
        catch (IOException ex) {
            throw new StorageIOException(ex);
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.