Quadcap Embeddable Database

com/quadcap/sql/index/Btree.java

Go to the documentation of this file.
00001 package com.quadcap.sql.index; 00002 00003 /* Copyright 1997 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.IOException; 00042 import java.io.PrintWriter; 00043 00044 import java.util.HashSet; 00045 import java.util.Iterator; 00046 import java.util.Set; 00047 00048 import com.quadcap.sql.file.BlockFile; 00049 00050 import com.quadcap.util.Debug; 00051 import com.quadcap.util.Util; 00052 00053 /** 00054 * A Btree implementation. Most of the real work happens in the Bnode 00055 * class. 00056 * 00057 * @author Stan Bailes 00058 */ 00059 public class Btree implements BIndex { 00060 BlockFile file; 00061 Comparator compare; 00062 long rootBlock; 00063 Bnode root; 00064 Object lock; 00065 byte[] tbuf = new byte[16]; 00066 00067 /** 00068 * Open a btree index. Fetch the root block and create an empty tree if 00069 * the block is zero, open the existing tree otherwise. 00070 * 00071 * @param file the (already opened) blockfile 00072 * @param compare the compare function for key ordering 00073 * @param rootBlock the block number of the root block of this tree 00074 * @param create if true, initialize the rootblock to be empty. 00075 * 00076 * @exception IOException if an I/O error occurs opening or accessing 00077 * the file. 00078 */ 00079 public Btree(BlockFile file, Comparator compare, 00080 long rootBlock, boolean create) 00081 throws IOException 00082 { 00083 //#ifdef DEBUG 00084 if (Trace.bit(0)) { 00085 Debug.println("Btree(" + file + ", " + rootBlock + ", " + 00086 create + ")"); 00087 } 00088 //#endif 00089 this.file = file; 00090 this.lock = file.getLock(); 00091 this.compare = compare; 00092 this.rootBlock = rootBlock; 00093 this.root = getNode(rootBlock); 00094 if (create) { 00095 root.init(true); 00096 } else { 00097 root.checkMagic(); 00098 } 00099 } 00100 00101 /** 00102 * Open a btree index. Fetch the root block and create an empty tree if 00103 * the block is zero, open the existing tree otherwise. 00104 * 00105 * @param file the (already opened) blockfile 00106 * @param rootBlock the block number of the root block of this tree 00107 * @param create if true, initialize the rootblock to be empty. 00108 * 00109 * @exception IOException if an I/O error occurs opening or accessing 00110 * the file. 00111 */ 00112 public Btree(BlockFile file, long rootBlock, boolean create) 00113 throws IOException 00114 { 00115 this(file, Comparator.compare, rootBlock, create); 00116 } 00117 00118 public int size() throws IOException { 00119 return getRoot().size(); 00120 } 00121 00122 final private BCursor getMyCursor() throws IOException { 00123 return BtreeCursor.get(this, true); 00124 // *Don't* put in activeCursors 00125 } 00126 00127 /** 00128 * Get the data bytes for the specified key. If the key is found, 00129 * return the length of the data portion and place as many bytes 00130 * as will fit in the data array. If the key isn't found, return 00131 * -1. 00132 */ 00133 public int get(byte[] key, int klen, byte[] data) throws IOException { 00134 synchronized (lock) { 00135 BCursor cursor = getMyCursor(); 00136 try { 00137 if (!cursor.seek(key)) return -1; 00138 return cursor.getVal(data); 00139 } finally { 00140 cursor.release(); 00141 } 00142 } 00143 } 00144 00145 public byte[] get(byte[] key) throws IOException { 00146 synchronized (lock) { 00147 BCursor cursor = getMyCursor(); 00148 try { 00149 if (!cursor.seek(key, key.length)) return null; 00150 int len = cursor.getValLen(); 00151 byte[] ret = new byte[len]; 00152 if (cursor.getVal(ret) != len) { 00153 throw new IOException("What the hella?"); 00154 } 00155 return ret; 00156 } finally { 00157 cursor.release(); 00158 } 00159 } 00160 } 00161 00162 public boolean delete(byte[] key) throws IOException { 00163 synchronized (lock) { 00164 BCursor cursor = getMyCursor(); 00165 try { 00166 boolean ret = cursor.seek(key, key.length); 00167 if (ret) ret = cursor.delete(); 00168 return ret; 00169 } finally { 00170 cursor.release(); 00171 } 00172 } 00173 } 00174 00175 public boolean deleteObs(byte[] key) throws IOException { 00176 synchronized (lock) { 00177 //#ifdef DEBUG 00178 if (Trace.bit(0)) { 00179 Debug.println(0, "BTree[" + rootBlock + "].delete(" + 00180 Util.hexBytes(key) + ")"); 00181 } 00182 //#endif 00183 return getRoot().delete(key); 00184 } 00185 } 00186 00187 public void set(byte[] key, byte[] val) throws IOException { 00188 set(key, key.length, val, 0, val.length); 00189 } 00190 00191 public void insert(byte[] key, int klen, 00192 byte[] val, int off, int len) throws IOException { 00193 synchronized (lock) { 00194 //#ifdef DEBUG 00195 if (Trace.bit(0)) { 00196 Debug.println("Btree[" + rootBlock + "].insert(" + 00197 Util.hexBytes(key, 0, klen) + ", " + 00198 Util.hexBytes(val, off, len) + ")"); 00199 } 00200 //#endif 00201 getRoot().set(key, klen, val, off, len, true, false); 00202 notifyUpdate(null); 00203 } 00204 } 00205 00206 public void update(byte[] key, int klen, 00207 byte[] val, int off, int len) throws IOException { 00208 synchronized (lock) { 00209 //#ifdef DEBUG 00210 if (Trace.bit(0)) { 00211 Debug.println("Btree[" + rootBlock + "].update(" + 00212 Util.hexBytes(key, 0, klen) + ", " + 00213 Util.hexBytes(val, off, len) + ")"); 00214 } 00215 //#endif 00216 getRoot().set(key, klen, val, off, len, false, true); 00217 notifyUpdate(null); 00218 } 00219 } 00220 00221 public boolean set(byte[] key, int klen, 00222 byte[] val, int off, int len) throws IOException { 00223 synchronized (lock) { 00224 //#ifdef DEBUG 00225 if (Trace.bit(0)) { 00226 Debug.println("Btree[" + rootBlock + "].set(" + 00227 Util.hexBytes(key) + ", " + 00228 Util.hexBytes(val) + ")"); 00229 } 00230 //#endif 00231 boolean ret = getRoot().set(key, klen, val, off, len, true, true); 00232 notifyUpdate(null); 00233 return ret; 00234 } 00235 } 00236 00237 Bnode getNode(long ref) { 00238 return new Bnode(this, ref); 00239 } 00240 00241 Bnode getRoot() { return root; } 00242 00243 public long getRootBlock() { 00244 return rootBlock; 00245 } 00246 00247 void setRoot(long ref) { 00248 root = getNode(rootBlock = ref); 00249 } 00250 00251 /** 00252 * Return a reference to the underlying <code>BlockFile</code. 00253 */ 00254 public BlockFile getFile() { return file; } 00255 00256 /** 00257 * Return the comparator used to collate keys 00258 */ 00259 public Comparator getComparator() { 00260 return compare; 00261 } 00262 00263 /** 00264 * Get a cursor 00265 */ 00266 public BCursor getCursor() throws IOException { 00267 return getCursor(false); 00268 } 00269 00270 Set activeCursors = new HashSet(); 00271 00272 /** 00273 * Get a cursor 00274 */ 00275 public BCursor getCursor(boolean skipSetup) throws IOException { 00276 BCursor bc = null; 00277 synchronized (lock) { 00278 bc = BtreeCursor.get(this, skipSetup); 00279 activeCursors.add(bc); 00280 } 00281 return bc; 00282 } 00283 00284 public void releaseCursor(BCursor c) { 00285 synchronized (lock) { 00286 try { 00287 c.close(); 00288 } catch (Throwable t) {} 00289 activeCursors.remove(c); 00290 } 00291 } 00292 00293 public void notifyUpdate(BCursor notMe) { 00294 final Iterator iter = activeCursors.iterator(); 00295 while (iter.hasNext()) { 00296 BtreeCursor bc = (BtreeCursor)iter.next(); 00297 if (bc != notMe) bc.unsetup(); 00298 } 00299 } 00300 00301 /** 00302 * Destroy this tree and free all of its resources 00303 */ 00304 public void free() throws IOException { 00305 //#ifdef DEBUG 00306 if (activeCursors.size() > 0) { 00307 final Iterator iter = activeCursors.iterator(); 00308 while (iter.hasNext()) { 00309 BtreeCursor ac = (BtreeCursor)iter.next(); 00310 Debug.println("Active cursor: " + ac); 00311 Debug.println("Error detected at: " + Util.stackTrace()); 00312 try { 00313 ac.release(); 00314 } catch (Throwable t) { 00315 } 00316 } 00317 throw new IOException("Btree.free() called with active cursors"); 00318 } 00319 if (Trace.bit(0)) { 00320 Debug.println("Btree[" + rootBlock + "].free()"); 00321 //Debug.println(Util.stackTrace()); 00322 } 00323 //#endif 00324 getRoot().free(); 00325 } 00326 00327 //#ifdef DEBUG 00328 public String toString() { 00329 return "Btree[" + rootBlock + "]"; 00330 } 00331 00332 public void display(PrintWriter w) throws IOException { 00333 BCursor bc = getCursor(false); 00334 try { 00335 while (bc.next()) { 00336 w.println("[" + new String(bc.getKey()) + "] = " + 00337 new String(bc.getVal())); 00338 } 00339 } finally { 00340 bc.release(); 00341 } 00342 00343 } 00344 //#endif 00345 } 00346