Quadcap Embeddable Database

com/quadcap/sql/file/Block.java

Go to the documentation of this file.
00001 package com.quadcap.sql.file; 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 00043 import com.quadcap.util.ConfigNumber; 00044 import com.quadcap.util.Debug; 00045 import com.quadcap.util.Util; 00046 00047 /** 00048 * This class represents a block/page of data in a random access file, 00049 * which may be cached. The key is an Integer specifying the block 00050 * number, while the data is a byte array containing the actual 00051 * data. 00052 * 00053 * @author Stan Bailes 00054 */ 00055 public class Block extends Cacheable implements Page { 00056 private byte[] buf; 00057 00058 public long getPageNum() { return key; } 00059 00060 /** 00061 * Initialize this block. Create the buffer if necessary, and initialize 00062 * the buffer contents from the underlying store. We assume that the 00063 * <code>BlockStore.read()</code> method will fill the buffer with zeros 00064 * if we're attempting to "read" a block that doesn't exist yet. 00065 * 00066 * @param store the underlying <code>BlockStore</code> which manages 00067 * the blocks. 00068 * @param key an <code>Integer</code> specifying the block number. 00069 */ 00070 public void init(Object store, long key) throws IOException { 00071 //#ifdef DEBUG 00072 if (Trace.bit(0)) { 00073 Debug.println("Block.init(" + store + ", " + key + ")"); 00074 } 00075 //#endif 00076 super.init(store, key); 00077 BlockStore bs = (BlockStore)store; 00078 if (buf == null) buf = new byte[bs.blockSize()]; 00079 bs.read(getPageNum(), buf); 00080 setDirty(false); 00081 } 00082 00083 /** 00084 * Write the contents of the buffer back to the underlying store. 00085 */ 00086 public final void flush() throws IOException { 00087 //#ifdef DEBUG 00088 if (Trace.bit(1)) { 00089 Debug.println(0, "Block[" + key + "].flush()"); 00090 } 00091 //#endif 00092 if (dirty) { 00093 //#ifdef DEBUG 00094 if (Trace.bit(0)) { 00095 Debug.println("flush [" + getPageNum() + "]"); 00096 } 00097 //#endif 00098 BlockStore bs = (BlockStore)store; 00099 bs.write(getPageNum(), buf); 00100 setDirty(false); 00101 } 00102 } 00103 00104 /** 00105 * From the Cacheable class, return the underlying data object. 00106 * When used as a <tt>Block</tt>, we typically use the <tt>read()</tt> 00107 * and <tt>write</tt> methods to access the underlying data... 00108 */ 00109 public final Object getData() { return buf; } 00110 00111 /** 00112 * Return a reference to the array containing the data for this 00113 * block, and create a new buffer, so that the reference returned 00114 * can be used in a subsequent <code>setData</code> call to another 00115 * buffer. This allows the contents of one block to be moved to 00116 * another block with a minimum of array copying. 00117 */ 00118 public byte[] getDataAndReset() { 00119 //#ifdef DEBUG 00120 if (Trace.bit(0)) { 00121 Debug.println("Block[" + key + "].getDataAndReset()"); 00122 } 00123 //#endif 00124 byte[] r = buf; 00125 buf = new byte[r.length]; 00126 setDirty(true); 00127 return r; 00128 } 00129 00130 /** 00131 * From the Cacheable class, set the underlying data object. 00132 * When used as a <tt>Block</tt>, we typically use the <tt>read()</tt> 00133 * and <tt>write</tt> methods to access the underlying data... 00134 */ 00135 public void setData(Object obj) { 00136 //#ifdef DEBUG 00137 if (Trace.bit(0)) { 00138 Debug.println("Block[" + key + "].setData(" + obj + ")"); 00139 } 00140 //#endif 00141 byte[] r = (byte[])obj; 00142 if (r.length != buf.length) { 00143 throw new RuntimeException("Bad buffer length!"); 00144 } 00145 buf = r; 00146 setDirty(true); 00147 } 00148 00149 /** 00150 * Only a debugging version implemented so far... 00151 */ 00152 public String toString() { 00153 StringBuffer sb = new StringBuffer(); 00154 sb.append("[key(" + getKey() + "), dirty(" + dirty + "), refcount(" + 00155 refCount + ")]"); 00156 return sb.toString(); 00157 } 00158 00159 /** 00160 * Read a range of bytes from the page. 00161 * 00162 * @param pos the offset in the page of the first byte to read 00163 * @param pbuf the buffer into which the bytes are placed. 00164 * @param offset the offset in <code>pbuf</code> where the first byte 00165 * is placed. 00166 * @param len the number of bytes to read 00167 */ 00168 public final int read(int pos, byte[] pbuf, int offset, int len) { 00169 //#ifdef DEBUG 00170 if (Trace.bit(1)) { 00171 Debug.println("Block[" + key + "].read(" + pos + ", " + len + ")" + 00172 ", offset = " + offset + ", buf.len = " + buf.length + 00173 ", pbuf.len = " + pbuf.length); 00174 } 00175 //#endif 00176 00177 System.arraycopy(buf, pos, pbuf, offset, len); 00178 //#ifdef DEBUG 00179 if (Trace.bit(0)) { 00180 Debug.println("Block[" + key + "].read(" + pos + ", " + len + 00181 "): " + Util.strBytes(pbuf, offset, len)); 00182 } 00183 //#endif 00184 return len; 00185 } 00186 00187 /** 00188 * Write a range of bytes to the page. 00189 * 00190 * @param pos the offset in the page of the first byte to write 00191 * @param pbuf the buffer from which the bytes are obtained 00192 * @param offset the offset in <code>pbuf</code> of the first byte 00193 * to write 00194 * @param len the number of bytes to write 00195 */ 00196 public final int write(int pos, byte[] pbuf, int offset, int len) { 00197 //#ifdef DEBUG 00198 if (Trace.bit(0)) { 00199 Debug.println("Block[" + key + "].write(" + pos + ", " + 00200 Util.strBytes(pbuf, offset, len) + ")"); 00201 } 00202 //#endif 00203 System.arraycopy(pbuf, offset, buf, pos, len); 00204 setDirty(true); 00205 return len; 00206 } 00207 00208 public final byte readByte(int pos) { 00209 //#ifdef DEBUG 00210 if (Trace.bit(1)) { 00211 Debug.println("Block[" + key + "].read(" + (pos) + "): " + buf[pos]); 00212 } 00213 //#endif 00214 return buf[pos]; 00215 } 00216 00217 public final void writeByte(int pos, byte val) { 00218 //#ifdef DEBUG 00219 if (Trace.bit(0)) { 00220 Debug.println("Block[" + key + "].write(" + pos + "): " + val); 00221 } 00222 //#endif 00223 buf[pos] = val; 00224 setDirty(true); 00225 } 00226 00227 /** 00228 * Read a short (2-byte) value from the page. 00229 * 00230 * @param pos the offset in the page of the short. 00231 */ 00232 public final short readShort(int pos) { 00233 short ret = ByteUtil.getShort(buf, pos); 00234 //#ifdef DEBUG 00235 if (Trace.bit(1)) { 00236 Debug.println("Block[" + key + "].readShort(" + pos + ") = " + ret); 00237 } 00238 //#endif 00239 return ret; 00240 } 00241 00242 /** 00243 * Write a short (2-byte) value to the page. 00244 * 00245 * @param pos the offset in the page of the short. 00246 * @param val the short value to write. 00247 */ 00248 public final void writeShort(int pos, short val) { 00249 //#ifdef DEBUG 00250 if (Trace.bit(0)) { 00251 Debug.println("Block[" + key + "].writeShort(" + pos + ", " + 00252 val + ")"); 00253 } 00254 //#endif 00255 ByteUtil.putShort(buf, pos, val); 00256 setDirty(true); 00257 } 00258 00259 /** 00260 * Read an integer (4-byte) value from the page. 00261 * 00262 * @param pos the offset in the page of the integer. 00263 */ 00264 public final int readInt(int pos) { 00265 int ret = ByteUtil.getInt(buf, pos); 00266 //#ifdef DEBUG 00267 if (Trace.bit(1)) { 00268 Debug.println("Block[" + key + "].readInt(" + pos + ") = " + ret); 00269 } 00270 //#endif 00271 return ret; 00272 } 00273 00274 /** 00275 * Write an integer (4-byte) value to the page. 00276 * 00277 * @param pos the offset in the page of the integer. 00278 * @param val the integer value to write. 00279 */ 00280 public final void writeInt(int pos, int val) { 00281 //#ifdef DEBUG 00282 if (Trace.bit(0)) { 00283 Debug.println("Block[" + key + "].writeInt(" + pos + ", " + 00284 val + ")"); 00285 } 00286 //#endif 00287 ByteUtil.putInt(buf, pos, val); 00288 setDirty(true); 00289 } 00290 00291 /** 00292 * Read a long (8-byte) value from the page. 00293 * 00294 * @param pos the offset in the page of the long. 00295 */ 00296 public final long readLong(int pos) { 00297 long ret = ByteUtil.getLong(buf, pos); 00298 //#ifdef DEBUG 00299 if (Trace.bit(1)) { 00300 Debug.println("Block[" + key + "].readLong(" + pos + ") = " + ret); 00301 } 00302 //#endif 00303 return ret; 00304 } 00305 00306 /** 00307 * Write a long (8-byte) value to the page. 00308 * 00309 * @param pos the offset in the page of the long. 00310 * @param val the long value to write. 00311 */ 00312 public final void writeLong(int pos, long val) { 00313 //#ifdef DEBUG 00314 if (Trace.bit(0)) { 00315 Debug.println("Block[" + key + "].writeLong(" + pos + ", " + 00316 val + ")"); 00317 } 00318 //#endif 00319 ByteUtil.putLong(buf, pos, val); 00320 setDirty(true); 00321 } 00322 00323 public final void takeData(Page p) { 00324 setData(((Block)p).getDataAndReset()); 00325 } 00326 00327 public void clear() { 00328 for (int i = 0; i < buf.length; i++) buf[i] = 0; 00329 setDirty(true); 00330 } 00331 00332 //#ifdef DEBUG 00333 // used for test below 00334 void init() { 00335 buf = new byte[32]; 00336 } 00337 00338 // A 12 bit (two base64 chars) signature. Live dangerously. 00339 public String signature() { 00340 return signature(buf); 00341 } 00342 00343 public static String signature(byte[] buf) { 00344 return signature(buf, 0, buf.length); 00345 } 00346 public static String signature(byte[] buf, int off, int cnt) { 00347 byte[] b = com.quadcap.io.Base64OutputStream.base64; 00348 int h = 31415; 00349 long tot = 0; 00350 for (int i = 0; i < cnt; i++) { 00351 tot += buf[off+i]; 00352 h ^= (h << 7) ^ (h >> 3) ^ buf[off + i]; 00353 } 00354 return "" + (char)b[(h >> 1) & 63] + (char)b[(h >> 8) & 63] + (char)b[(h >> 16) & 63] + 00355 ((tot == 0) ? "*" : ""); 00356 } 00357 00358 00359 public static void main(String args[]) { 00360 Block b = new Block(); 00361 b.init(); 00362 b.writeInt(20, 128); 00363 byte[] bufx = new byte[32]; 00364 b.read(20, bufx, 0, 4); 00365 int v = b.readInt(20); 00366 } 00367 //#endif 00368 }