/* * CS 4420: Database System Implementation * Class Project - Code for Implementation of Indexing using B+ Trees * AUTHOR: Tushar Sugandhi * Last Updated:02/18/2007 * * * NOTE: You may use the public functions in this class for implementing * indexing in your database system. * Also note that each object of BTree class is capable of handleing ATMOST * 20 indices. (That is, it can handle indexing on 20 attributes.) * * READ the comments from main() function carefully to understand how to use the public functions in this class * * READ the code for ReadBlock() and MapBlock() to understand the usage of * java.nio classes. * */ import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.*; interface c { public static final int ORDER = 64; public static final int BLOCKSIZE = ORDER*2 * 8; public static final int BUCKETPTR = ORDER*2 -1; public static final int NLEN = 40; public static final int NIDX = 20; } class Node { short leafNode ; short keyCount; long []keys; long []pointers; public Node() { keys = new long[c.ORDER -1]; pointers=new long [c.ORDER]; } } class InsertKeyVal { public int returnVal; public long key; public long ptr; public InsertKeyVal() { returnVal = 0; key = 0; ptr = 0; } } class RecursiveInsertVal { public boolean returnVal; public long key; public long ptr; public RecursiveInsertVal() { returnVal = false; key = 0; ptr = 0; } } class Head { long rootBlock; long allocBlock; byte [] junk; public Head() { junk = new byte[c.BLOCKSIZE - 2*8]; } } class Bucket { long [] pointers; long nextBucket; public Bucket() { pointers = new long [c.BUCKETPTR]; } } class IndexInfo { boolean isUsed; FileChannel fileChannel; String indexFilename; boolean isdupKeyPresent; long rootBlock; long allocBlock; long currentBlock; short currentKey; short currentPtr; public IndexInfo() { isUsed = false; indexFilename = ""; isdupKeyPresent = false; rootBlock = 0; allocBlock = 0; currentBlock = 0; currentKey = 0; currentPtr = 0; } } public class BTree { private IndexInfo [] indexTable; public Bucket bucket; public BTree () { indexTable = new IndexInfo[c.NIDX]; for(int k =0;k key) break; return i; } private long CheckBucket(final int index, Node node,long key, long ptr) { try { ptr = -1; if(getCurrentBlock(index) >= 0) { long nextPtr=-1; key = node.keys[getCurrentKey(index)-1]; ptr = node.pointers[getCurrentKey(index)]; if(getDupKeys(index)) { //bucket = new Bucket(); MappedByteBuffer mbb = ReadBlock(indexTable[index].fileChannel,ptr, c.BLOCKSIZE); for(int i =0; i node.keyCount) { setCurrentBlock(index, node.pointers[0]); setCurrentKey(index,(short)1); } } } }catch (Exception ex) { System.out.println("Error Checking Bucket."); ex.printStackTrace(); } return ptr; } private InsertKeyVal InsertKey(final int index, Node node, final int keyIndex, long key, long ptr) { InsertKeyVal returnObject = new InsertKeyVal(); long [] keys; keys = new long [c.ORDER]; long [] pointers; pointers = new long[c.ORDER+1]; int count, count1, count2; int k; count = node.keyCount + 1; count1 = count < c.ORDER ? count : c.ORDER/2; count2 = count - count1; for(k = c.ORDER/2; k < keyIndex; k++) { keys[k] = node.keys[k]; pointers[k+1] = node.pointers[k+1]; } keys[keyIndex] = key; pointers[keyIndex+1] = ptr; for(k = keyIndex; k < node.keyCount; k++) { keys[k+1] = node.keys[k]; pointers[k+2] = node.pointers[k+1]; } for(k = keyIndex; k < count1; k++) { node.keys[k] = keys[k]; node.pointers[k+1] = pointers[k+1]; } node.keyCount = (short)count1; if(count2>0) { int s, d; Node nnode = new Node(); nnode.leafNode = node.leafNode; s=0; if(node.leafNode==0) { count2 -= 1; s=1; } for(s += c.ORDER/2, d = 0; d < count2; s++, d++) { nnode.keys[d] = keys[s]; nnode.pointers[d] = pointers[s]; } nnode.pointers[d] = pointers[s]; nnode.keyCount = (short)count2; key = keys[c.ORDER/2]; ptr = indexTable[index].allocBlock++; if(node.leafNode>0) { nnode.pointers[0] = node.pointers[0]; node.pointers[0] = ptr; } MappedByteBuffer mbb; try { mbb = MapBlock(indexTable[index].fileChannel, ptr, c.BLOCKSIZE); mbb.putShort(nnode.leafNode); mbb.putShort(nnode.keyCount); for (int ii =0;ii0) && node.keys[keyIndex-1] == key; RecursiveInsertVal tempReturn = new RecursiveInsertVal(); if(node.leafNode==0) { tempReturn = RecInsert(index, node.pointers[keyIndex], key, ptr); split = tempReturn.returnVal; key = tempReturn.key; ptr = tempReturn.ptr; } if(split || node.leafNode==1 && !equalKey) { if(node.leafNode==1 && getDupKeys(index)) ptr = NewBucket(index, ptr, -1); InsertKeyVal retObj = InsertKey(index, node, keyIndex, key, ptr); key = retObj.key; ptr = retObj.ptr; int split1 = retObj.returnVal; if(split1 > 0){split = true;}else {split=false;} MappedByteBuffer mbb3 = MapBlock(indexTable[index].fileChannel, block, c.BLOCKSIZE); mbb3.putShort(node.leafNode); mbb3.putShort(node.keyCount); for(int len=0;len= 0; i++); if(i < c.BUCKETPTR) { bucket.pointers[i] = ptr; if(i < c.BUCKETPTR-1) bucket.pointers[i+1] = -1; mbb2.position(i*8); mbb2.putLong(ptr); mbb2.putLong(-1); } else { System.out.println("ERROR: Bucket Overflow."); } } else if(node.leafNode==1) { insertionErr = -1; } returnVal.returnVal = split; returnVal.key = key; returnVal.ptr = ptr; return returnVal; } private int insertionErr; private boolean getUsed (int i ){return indexTable[i].isUsed;}; private boolean getDupKeys (int i ) {return indexTable[i].isdupKeyPresent;}; private long getRootBlock (int i ) {return indexTable[i].rootBlock;}; private long getAllocBlock (int i ) {return indexTable[i].allocBlock;}; private long getCurrentBlock (int i ) {return indexTable[i].currentBlock;}; private short getCurrentKey (int i ) {return indexTable[i].currentKey;}; private short getCurrentPtr (int i ) {return indexTable[i].currentPtr;}; private void setUsed (int i, boolean used ) { indexTable[i].isUsed = used;}; private void setDupKeys (int i, boolean DupKey ) { indexTable[i].isdupKeyPresent = DupKey;}; private void setRootBlock (int i, long RB ) { indexTable[i].rootBlock = RB;}; private void setAllocBlock (int i, long ALB) { indexTable[i].allocBlock = ALB;}; private void setCurrentBlock (int i, long CB) { indexTable[i].currentBlock = CB;}; private void setCurrentKey (int i, short CK ) { indexTable[i].currentKey = CK;}; private void setCurrentPtr (int i, short CP ) { indexTable[i].currentPtr = CP;}; //////////////////Public Functions Implementation starts here//////////////////////////////////////////// //open or create index file, find free entry in index information table, //fill in entry, dupKeys is true if duplicate keys are allowed, false if not, //return number of entry in table public int OpenIndex (final String name,final boolean dupKeys) { int i; int j; for(i = 0; i < c.NIDX; i++) if(!getUsed(i)) break; if(i==c.NIDX) { System.out.println("All indices are used. Use another BTree object or close unused indices."); return -1; } setUsed(i,true); indexTable[i].indexFilename = name; setDupKeys(i,dupKeys); try{ RandomAccessFile rand = new RandomAccessFile(indexTable[i].indexFilename, "rw"); indexTable[i].fileChannel = rand.getChannel(); if(rand.length()==0) { Node node = new Node(); setRootBlock(i, 1); setAllocBlock(i,2); WriteHead(i); node.leafNode = 1; node.keyCount = 0; for(j = 0; j < c.ORDER-1; j++) { node.pointers[j] = -1; node.keys[j] = 0; } node.pointers[c.ORDER - 1] = -1; MappedByteBuffer mbb = MapBlock(indexTable[i].fileChannel, 1, c.BLOCKSIZE); mbb.putShort(node.leafNode); mbb.putShort(node.keyCount); for (int c=0;c