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 java.util.*;

import org.netbeans.mdr.persistence.*;

/** This is the base class for all extent types in the data file.  On disk,
* all extents begin with the same three fields:
*
* 
    *
  1. * bytes 0-1 magic number *
  2. * bytes 2-3 number of chunks *
  3. * bytes 4-7 next extent in chain (0 if none) *
* * There are three kinds of extent: *

* A normal extent is the first extent in a record. if the record does * not fit in one extent, those after the first are continuation extents. * These two kinds comprise the active extents, that is, extents which contain * live data. There are also extents which describe space in the file from * which records have been deleted. There are called deleted extents. *

* Active extents are chained together into records, as described above. * Deleted extents of the same size are also chained together, with the * start of each chain in the BtreeDataFile header. * @see BtreeDataFile */ abstract class BtreeExtent { /** magic number for normal extents */ static final int NORMAL_MAGIC = 0x2A2A; /** magic number for continuation extents */ static final int CONTINUATION_MAGIC = 0x6B6B; /** magic number for deleted extents */ static final int DELETED_MAGIC = 0x5F5F; /** number of chunks in extent */ final short chunks; /** The biggest extent possible */ public static final int MAX_EXTENT_SIZE = BtreeDataFile.BTREE_CHUNK_SIZE * BtreeDataFile.MAX_CHUNKS_IN_EXTENT; /** pointer to next extent in chain */ int nextInChain; /** offset in file */ final int myChunkNum; /** header has changed from disk copy */ boolean headerIsDirty; /** The file we are an extent of */ final BtreeDataFile owner; /* returns from getType() */ static final byte IS_NORMAL = 1; static final byte IS_CONTINUATION = 2; static final byte IS_DELETED = 3; /* returns from getTypeName() */ static final String NORMAL_NAME = "normal"; static final String CONTINUATION_NAME = "continuation"; static final String DELETED_NAME = "deleted"; /** create a BtreeExtent from another. This is used when changing types * of extents, for instance when deleting a record, and thus converting * all of its extents to deleted extents. * @param src the extent we are being created from */ BtreeExtent(BtreeExtent src) { chunks = src.chunks; myChunkNum = src.myChunkNum; owner = src.owner; headerIsDirty = true; } /** called by subclasses to intialize a BtreeExtent * @param file the BtreeDataFile this extent will belong to * @param chunkNum where this extent begins * @param numChunks the size of the extent */ BtreeExtent(BtreeDataFile file, int chunkNum, short numChunks) { owner = file; chunks = numChunks; myChunkNum = chunkNum; headerIsDirty = true; } /** Read an extent from the datafile, and use the magic number to determine * which subclass of BtreeExtent to create. * @param dataFile the file to read from * @param chunkNum the chunk where the extent begins * @return the extent * @exception StorageException if btree detects an inconsistency * or if an I/O error occurs */ final static BtreeExtent readExtent(BtreeDataFile dataFile, int chunkNum) throws StorageException { BtreeExtent extent = null; IntHolder offset = new IntHolder(); CachedPage page = dataFile.getChunk(chunkNum, offset); try { short magic = Converter.readShort(page.contents, offset); short chunks = Converter.readShort(page.contents, offset); switch (magic) { case NORMAL_MAGIC: extent = new NormalBtreeExtent(dataFile, chunkNum, chunks); break; case CONTINUATION_MAGIC: extent = new ContinuationBtreeExtent( dataFile, chunkNum, chunks); break; case DELETED_MAGIC: extent = new DeletedBtreeExtent(dataFile, chunkNum, chunks); break; default: throw new StoragePersistentDataException( MessageFormat.format( "Bad Magic Number {0} in header at offset {1}", new Object[] { new Integer(magic), new Integer(chunkNum)})); } extent.nextInChain = Converter.readInt(page.contents, offset); extent.headerIsDirty = false; extent.readHeaderFromPage(page.contents, offset); } finally { page.unpin(); } return extent; } /** read the type-specific parts of the extent header from the * buffer. * @param buffer the buffer to read from * @param offset the offset to being reading at */ abstract void readHeaderFromPage(byte buffer[], IntHolder offset); /** Write the header to the file cache if it is dirty. * @exception StorageException if btree detects an inconsistency * or if an I/O error occurs */ final void writeHeader() throws StorageException { if (!headerIsDirty) return; IntHolder offst = new IntHolder(); CachedPage page = owner.getChunk(myChunkNum, offst); try { page.setWritable(); Converter.writeShort(page.contents, offst, getMagic()); Converter.writeShort(page.contents, offst, chunks); Converter.writeInt(page.contents, offst, nextInChain); writeHeaderToPage(page, offst.getValue()); } finally { page.unpin(); } headerIsDirty = false; } /** write the type-specific part of the header to the file cache * @param page the page to write to * @param offset the offset to begin an */ protected abstract void writeHeaderToPage(CachedPage page, int offset); /** Get the magic number for this type of extent * @return the magic number */ abstract short getMagic(); /** get the size of the extent in chunks * @return the size */ int getSize() { return chunks; } /** set this exent to point to another. * @param next the starting chunk of the next extent, or 0, if this * is to be the last in its chain */ void setNext(int next) { if (nextInChain != next) { nextInChain = next; headerIsDirty = true; } } /** set this exent to point to another. * @param next the next extent in the chain (not null) */ void setNext(BtreeExtent next) { setNext(next.myChunkNum); } /** get the starting chunk for the next extent in the chain. * @return the next extent in the chain, or 0 if this is the last * in its chain */ int getNext() { return nextInChain; } /** get the starting chunk number of the extent * @return starting chunk number */ int getOffset() { return myChunkNum; } /** return type of extent * @return IS_NORMAL, IS_CONTINUTATION, or IS_DELETED */ abstract byte getType(); /** return name of type of extent * @return NORMAL_NAME, CONTINUTATION_NAME, or DELETED_NAME */ abstract String getTypeName(); /** return name of type of extent given type * @param extentType IS_NORMAL, IS_CONTINUTATION, or IS_DELETED * @return NORMAL_NAME, CONTINUTATION_NAME, or DELETED_NAME */ static String getTypeName(int extentType) { switch(extentType) { case IS_NORMAL: return NORMAL_NAME; case IS_CONTINUATION: return CONTINUATION_NAME; case IS_DELETED: return DELETED_NAME; } return "unknown"; } /** dump baisc header info */ public static final int DUMP_BASIC = 1; /** dump key as hex */ public static final int DUMP_KEY = 2; /** dump data as text */ public static final int DUMP_DATA = 4; /** dump data checksum */ public static final int DUMP_DATA_CHECKSUM = 8; /** dump extent as text (for debugging) * "level" is a bitmask. *

    *
  1. * DUMP_BASIC -- basic header info *
  2. * DUMP_KEY -- dump key as hex *
  3. * DUMP_DATA -- dump data as text *
  4. * DUMP_DATA_CHECKSUM -- dump data checksum *
* @param level bitmask of what to dump. * @param strm where to dump it to */ void dump(int level, PrintWriter strm) throws StorageException{ if ((level & DUMP_BASIC) != 0) { strm.println("Extent: " + myChunkNum); strm.println("Type: " + this.getClass().getName()); strm.println("Size: " + chunks); if (nextInChain > 0) strm.println("Next: " + nextInChain); } } /** utility to dump bytes as hex, 16 to a line * @param in source of bytes * @param out output stream * @param indent indentation for each new line */ static void dumpBytesAsHex(InputStream in, PrintWriter out, String indent) { try { int position = 0; int data; while ((data = in.read()) >= 0) { if (position >= 16) { out.println(); position = 0; } if (position == 0) out.print(indent); else out.print(" "); String hex = Integer.toHexString(data); if (hex.length() == 1) hex = "0" + hex; out.print(hex); position++; } if (position > 0) out.println(); } catch (IOException exc) { out.print("\n\nIO EXCEPTION!\n\n"); } } }
... 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.