Quadcap Embeddable Database

com/quadcap/sql/file/LogBuffer.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.InputStream; 00042 import java.io.IOException; 00043 import java.io.OutputStream; 00044 00045 import java.util.Properties; 00046 00047 import com.quadcap.util.Debug; 00048 import com.quadcap.util.Util; 00049 00050 /** 00051 * A bounded buffer based on an underlying RandomAccess 00052 * 00053 * @author Stan Bailes 00054 */ 00055 public class LogBuffer { 00056 RandomAccess ra; 00057 00058 /** 00059 * "Begin" pointer. 00060 */ 00061 int bX; 00062 00063 /** 00064 * "End" pointer 00065 */ 00066 int eX; 00067 00068 /** 00069 * "Checkpoint" pointer 00070 */ 00071 int cX; 00072 00073 /** 00074 * Size Limit, in octets. 00075 */ 00076 int maxSize = 128 * 1024 * 1024; 00077 00078 /** 00079 * Total header bytes 00080 */ 00081 static final int headerSize = 16; 00082 00083 /** 00084 * Default constructor (for factory) 00085 */ 00086 public LogBuffer() {} 00087 00088 /** 00089 * Initialize from existing randomaccess 00090 */ 00091 public void init(RandomAccess ra, Properties props) throws IOException { 00092 this.ra = ra; 00093 this.bX = ra.readInt(0); 00094 this.eX = ra.readInt(4); 00095 this.cX = ra.readInt(8); 00096 maxSize = Integer.parseInt(props.getProperty("maxLogSize", "" + maxSize)); 00097 } 00098 00099 /** 00100 * Create a new one 00101 * 00102 * @param ra the underlying random access interface to the store 00103 * @param m the maximum size of this buffer. 00104 */ 00105 public void init(RandomAccess ra, int m) throws IOException { 00106 this.ra = ra; 00107 this.bX = 0; 00108 this.eX = 0; 00109 this.cX = 0; 00110 this.maxSize = m; 00111 sync(); 00112 } 00113 00114 /** 00115 * Return an InputStream which will supply a subset of the buffer starting 00116 * at 'pos' and ending at the current buffer end 00117 */ 00118 public InputStream getInputStream(int pos) { 00119 return new LogInputStream(this, pos, this.eX); 00120 } 00121 00122 /** 00123 * Return an OutputStream which can be used to write to the end of 00124 * the buffer 00125 */ 00126 public OutputStream getOutputStream() { 00127 return new LogOutputStream(this); 00128 } 00129 00130 /** 00131 * Return the current end position (the position of the next byte to 00132 * be written) 00133 */ 00134 public int getEnd() { return eX; } 00135 00136 /** 00137 * Return the current begin position (the position of the first byte 00138 * written 00139 */ 00140 public int getBegin() { return bX; } 00141 00142 /** 00143 * Return the value marking the end of the last checkpoint 00144 */ 00145 public int getCheckpoint() { return cX; } 00146 00147 /** 00148 * Set the checkpoint value 00149 */ 00150 public void checkpoint() { this.cX = this.eX; } 00151 00152 /** 00153 * Move the begin pointer past some bytes. 00154 */ 00155 public void setBegin(int b) { 00156 //#ifdef DEBUG 00157 if (Trace.bit(13)) { 00158 Debug.println(toString() + ".setBegin(" + b + ")"); 00159 } 00160 //#endif 00161 bX = b; 00162 } 00163 00164 /** 00165 * Reset the buffer to its empty state 00166 */ 00167 public void reset() { 00168 //#ifdef DEBUG 00169 if (Trace.bit(13)) { 00170 Debug.println(toString() + ".reset() -----------------------"); 00171 } 00172 //#endif 00173 bX = 0; 00174 eX = 0; 00175 cX = 0; 00176 } 00177 00178 /** 00179 * Truncate the underlying region to the current actual size of the 00180 * buffer 00181 */ 00182 public void truncate() throws IOException { 00183 ra.resize(size() + headerSize); 00184 } 00185 00186 /** 00187 * Return the size of the active area 00188 */ 00189 public int size() { 00190 return eX - bX; 00191 } 00192 00193 /** 00194 * Read a range of bytes from the buffer 00195 */ 00196 public int read(int pos, byte[] buf, int off, int cnt) 00197 throws IOException 00198 { 00199 int ret = 0; 00200 if (cnt > 0) { 00201 ra.read(pos + headerSize, buf, off, cnt); 00202 ret = cnt; 00203 } 00204 //#ifdef DEBUG 00205 if (Trace.bit(13)) { 00206 Debug.println(toString() + ".read(" + pos + ", " + cnt + ") = " + 00207 ret + ", " + 00208 Util.hexBytes(buf, off, ret)); 00209 } 00210 //#endif 00211 return ret; 00212 } 00213 00214 /** 00215 * Read a single byte 00216 */ 00217 public int readByte(int pos) throws IOException { 00218 int ret = ra.readByte(pos + headerSize); 00219 //#ifdef DEBUG 00220 if (Trace.bit(13)) { 00221 Debug.println(toString() + ".read(" + pos + ") = " + ret); 00222 } 00223 //#endif 00224 return ret; 00225 } 00226 00227 /** 00228 * Write a range of bytes to the end of the buffer, updating 'eX' to 00229 * point to the new end of the buffer. 00230 */ 00231 public void write(byte[] buf, int off, int cnt) 00232 throws IOException 00233 { 00234 //#ifdef DEBUG 00235 if (Trace.bit(13)) { 00236 Debug.println(toString() + ".write(" + 00237 Util.hexBytes(buf, off, cnt) + ")"); 00238 } 00239 //#endif 00240 if (eX + cnt > maxSize) { 00241 //#ifdef DEBUG 00242 Debug.println("eX: " + eX + ", write(" + off + ": " + 00243 Util.strBytes(buf, off, cnt)); 00244 //#endif 00245 throw new IOException("LogBuffer full: " + eX + " + " + cnt + " bytes"); 00246 } 00247 if (cnt > 0) { 00248 ra.write(eX + headerSize, buf, off, cnt); 00249 eX += cnt; 00250 } 00251 } 00252 00253 /** 00254 * Write a single byte to the buffer. Do not modify eX. 00255 */ 00256 public void writeByte(int pos, int b) throws IOException { 00257 //#ifdef DEBUG 00258 if (Trace.bit(13)) { 00259 Debug.println(toString() + ".writeByte(" + 00260 pos + ", " + b + ")"); 00261 } 00262 //#endif 00263 ra.writeByte(pos + headerSize, b); 00264 } 00265 00266 /** 00267 * Flush any changes to disk. 00268 */ 00269 public void sync() throws IOException { 00270 //#ifdef DEBUG 00271 if (Trace.bit(13) || Trace.bit(24)) { 00272 Debug.println(toString() + ".sync()"); 00273 } 00274 //#endif 00275 ra.writeInt(0, bX); 00276 ra.writeInt(4, eX); 00277 ra.writeInt(8, cX); 00278 ra.writeInt(12, maxSize); 00279 ra.flush(); 00280 } 00281 00282 /** 00283 * Close the file 00284 */ 00285 public void close() throws IOException { 00286 //#ifdef DEBUG 00287 if (Trace.bit(13)) { 00288 Debug.println(toString() + ".close()"); 00289 } 00290 //#endif 00291 sync(); 00292 ra.close(); 00293 } 00294 00295 /** 00296 * Perform buffer-wrapping address incrementing math 00297 */ 00298 public int addPos(int pos, int amt) { 00299 int ret = pos + amt; 00300 return ret; 00301 } 00302 00303 /** 00304 * Inner input stream 00305 */ 00306 class LogInputStream extends InputStream { 00307 LogBuffer b; 00308 int pos; 00309 int lim; 00310 00311 LogInputStream(LogBuffer b, int pos, int lim) { 00312 //#ifdef DEBUG 00313 if (Trace.bit(13)) { 00314 Debug.println("CIS(" + pos + "-" + lim + ")"); 00315 } 00316 //#endif 00317 this.b = b; 00318 this.pos = pos; 00319 this.lim = lim; 00320 } 00321 00322 public int read(byte[] buf, int off, int cnt) 00323 throws IOException 00324 { 00325 //#ifdef DEBUG 00326 int xpos = pos; 00327 //#endif 00328 int xpos2 = pos + cnt; 00329 if (xpos2 > lim) { 00330 cnt -= (xpos2 - lim); 00331 } 00332 int ret = -1; 00333 if (cnt > 0) { 00334 ret = b.read(pos, buf, off, cnt); 00335 if (ret > 0) { 00336 pos = b.addPos(pos, ret); 00337 } else { 00338 ret = -1; 00339 } 00340 } 00341 //#ifdef DEBUG 00342 if (Trace.bit(14)) { 00343 Debug.println("CIS[" + xpos + "-" + lim + 00344 "].read() = " + ret + ": " + 00345 Util.hexBytes(buf, off, ret)); 00346 } 00347 //#endif 00348 return ret; 00349 } 00350 00351 public int read() throws IOException { 00352 //#ifdef DEBUG 00353 int xpos = pos; 00354 //#endif 00355 int ret = b.readByte(pos); 00356 if (ret >= 0) { 00357 pos = b.addPos(pos, 1); 00358 } 00359 //#ifdef DEBUG 00360 if (Trace.bit(14)) { 00361 Debug.println("CIS[" + xpos + "].read() = " + ret); 00362 } 00363 //#endif 00364 return ret; 00365 } 00366 } 00367 00368 /** 00369 * Inner output stream 00370 */ 00371 class LogOutputStream extends OutputStream { 00372 LogBuffer b; 00373 00374 LogOutputStream(LogBuffer b) { 00375 this.b = b; 00376 } 00377 00378 public void write(byte[] buf, int off, int cnt) throws IOException { 00379 //#ifdef DEBUG 00380 if (Trace.bit(14)) { 00381 Debug.println("COS[" + b.eX + "].write(" + 00382 Util.hexBytes(buf, off, cnt) + ")"); 00383 } 00384 //#endif 00385 b.write(buf, off, cnt); 00386 } 00387 00388 public void write(int x) throws IOException { 00389 //#ifdef DEBUG 00390 if (Trace.bit(14)) { 00391 Debug.println("COS[" + b.eX + "].write(" + x + ")"); 00392 } 00393 //#endif 00394 if (false) { 00395 b.writeByte(b.eX, x); 00396 b.eX = addPos(b.eX, 1); 00397 } else { 00398 byte[] fu = new byte[1]; 00399 fu[0] = (byte)x; 00400 write(fu, 0, 1); 00401 } 00402 } 00403 } 00404 00405 //#ifdef DEBUG 00406 00407 public String toString() { 00408 return "LogBuffer(" + maxSize + "," + bX + "," + eX + "," + cX + ")"; 00409 } 00410 00411 public static void main(String[] args) { 00412 try { 00413 test1(); 00414 } catch (Throwable t) { 00415 Debug.print(t); 00416 } 00417 } 00418 00419 static void test1() throws Exception { 00420 int size = 100000; 00421 ByteArrayRandomAccess bra = new ByteArrayRandomAccess(size + 12); 00422 BufferedRandomAccess bbra = new BufferedRandomAccess(bra); 00423 LogBuffer cb = new LogBuffer(); 00424 cb.init(bbra, size); 00425 00426 // for (int i = 0; i < size; i++) { 00427 // cb.writeByte(i, (byte)(i & 0xff)); 00428 // } 00429 // for (int i = 0; i < size; i++) { 00430 // int ret = cb.readByte(i); 00431 // if (ret != (i & 0xff)) { 00432 // throw new Exception("LogBuffer.test1 " + i + 00433 // " (" + (i&0xff) + ")" + 00434 // ", got " + ret); 00435 // } 00436 // } 00437 00438 int xs = 12; 00439 int[] poss = new int[xs]; 00440 int[] sizz = new int[xs]; 00441 int beg = cb.getBegin(); 00442 byte[] buf = new byte[4096]; 00443 byte[] rbuf = new byte[4096]; 00444 OutputStream os = cb.getOutputStream(); 00445 int wsize = 1; 00446 for (int i = 0; i < xs; i++) { 00447 poss[i] = cb.getEnd(); 00448 sizz[i] = wsize+1; 00449 wsize += wsize; 00450 makeBuf(buf, i, sizz[i]); 00451 os.write(buf, 0, sizz[i]); 00452 for (int j = 0; j < i; j++) { 00453 makeBuf(buf, j, sizz[j]); 00454 InputStream is = cb.getInputStream(poss[j]); 00455 is.read(rbuf, 0, sizz[i]); 00456 if (Util.compareBytes(buf, 0, sizz[j], rbuf, 0, sizz[j]) != 0){ 00457 throw new Exception("R " + i + ": " + 00458 Util.hexBytes(buf, 0, sizz[i]) + 00459 " vs " + j + ": " + 00460 Util.hexBytes(rbuf, 0, sizz[i])); 00461 } 00462 } 00463 } 00464 00465 } 00466 00467 static void makeBuf(byte[] buf, int x, int siz) { 00468 x *= 13; 00469 for (int i = 0; i < siz; i++) { 00470 buf[i] = (byte)(x++); 00471 } 00472 } 00473 00474 //#endif 00475 00476 }