001: package com.quadcap.sql.file;
002:
003: /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.IOException;
042:
043: import com.quadcap.util.ConfigNumber;
044: import com.quadcap.util.Debug;
045: import com.quadcap.util.Util;
046:
047: /**
048: * This class represents a block/page of data in a random access file,
049: * which may be cached. The key is an Integer specifying the block
050: * number, while the data is a byte array containing the actual
051: * data.
052: *
053: * @author Stan Bailes
054: */
055: public class Block extends Cacheable implements Page {
056: private byte[] buf;
057:
058: public long getPageNum() {
059: return key;
060: }
061:
062: /**
063: * Initialize this block. Create the buffer if necessary, and initialize
064: * the buffer contents from the underlying store. We assume that the
065: * <code>BlockStore.read()</code> method will fill the buffer with zeros
066: * if we're attempting to "read" a block that doesn't exist yet.
067: *
068: * @param store the underlying <code>BlockStore</code> which manages
069: * the blocks.
070: * @param key an <code>Integer</code> specifying the block number.
071: */
072: public void init(Object store, long key) throws IOException {
073: //#ifdef DEBUG
074: if (Trace.bit(0)) {
075: Debug.println("Block.init(" + store + ", " + key + ")");
076: }
077: //#endif
078: super .init(store, key);
079: BlockStore bs = (BlockStore) store;
080: if (buf == null)
081: buf = new byte[bs.blockSize()];
082: bs.read(getPageNum(), buf);
083: setDirty(false);
084: }
085:
086: /**
087: * Write the contents of the buffer back to the underlying store.
088: */
089: public final void flush() throws IOException {
090: //#ifdef DEBUG
091: if (Trace.bit(1)) {
092: Debug.println(0, "Block[" + key + "].flush()");
093: }
094: //#endif
095: if (dirty) {
096: //#ifdef DEBUG
097: if (Trace.bit(0)) {
098: Debug.println("flush [" + getPageNum() + "]");
099: }
100: //#endif
101: BlockStore bs = (BlockStore) store;
102: bs.write(getPageNum(), buf);
103: setDirty(false);
104: }
105: }
106:
107: /**
108: * From the Cacheable class, return the underlying data object.
109: * When used as a <tt>Block</tt>, we typically use the <tt>read()</tt>
110: * and <tt>write</tt> methods to access the underlying data...
111: */
112: public final Object getData() {
113: return buf;
114: }
115:
116: /**
117: * Return a reference to the array containing the data for this
118: * block, and create a new buffer, so that the reference returned
119: * can be used in a subsequent <code>setData</code> call to another
120: * buffer. This allows the contents of one block to be moved to
121: * another block with a minimum of array copying.
122: */
123: public byte[] getDataAndReset() {
124: //#ifdef DEBUG
125: if (Trace.bit(0)) {
126: Debug.println("Block[" + key + "].getDataAndReset()");
127: }
128: //#endif
129: byte[] r = buf;
130: buf = new byte[r.length];
131: setDirty(true);
132: return r;
133: }
134:
135: /**
136: * From the Cacheable class, set the underlying data object.
137: * When used as a <tt>Block</tt>, we typically use the <tt>read()</tt>
138: * and <tt>write</tt> methods to access the underlying data...
139: */
140: public void setData(Object obj) {
141: //#ifdef DEBUG
142: if (Trace.bit(0)) {
143: Debug.println("Block[" + key + "].setData(" + obj + ")");
144: }
145: //#endif
146: byte[] r = (byte[]) obj;
147: if (r.length != buf.length) {
148: throw new RuntimeException("Bad buffer length!");
149: }
150: buf = r;
151: setDirty(true);
152: }
153:
154: /**
155: * Only a debugging version implemented so far...
156: */
157: public String toString() {
158: StringBuffer sb = new StringBuffer();
159: sb.append("[key(" + getKey() + "), dirty(" + dirty
160: + "), refcount(" + refCount + ")]");
161: return sb.toString();
162: }
163:
164: /**
165: * Read a range of bytes from the page.
166: *
167: * @param pos the offset in the page of the first byte to read
168: * @param pbuf the buffer into which the bytes are placed.
169: * @param offset the offset in <code>pbuf</code> where the first byte
170: * is placed.
171: * @param len the number of bytes to read
172: */
173: public final int read(int pos, byte[] pbuf, int offset, int len) {
174: //#ifdef DEBUG
175: if (Trace.bit(1)) {
176: Debug.println("Block[" + key + "].read(" + pos + ", " + len
177: + ")" + ", offset = " + offset + ", buf.len = "
178: + buf.length + ", pbuf.len = " + pbuf.length);
179: }
180: //#endif
181:
182: System.arraycopy(buf, pos, pbuf, offset, len);
183: //#ifdef DEBUG
184: if (Trace.bit(0)) {
185: Debug.println("Block[" + key + "].read(" + pos + ", " + len
186: + "): " + Util.strBytes(pbuf, offset, len));
187: }
188: //#endif
189: return len;
190: }
191:
192: /**
193: * Write a range of bytes to the page.
194: *
195: * @param pos the offset in the page of the first byte to write
196: * @param pbuf the buffer from which the bytes are obtained
197: * @param offset the offset in <code>pbuf</code> of the first byte
198: * to write
199: * @param len the number of bytes to write
200: */
201: public final int write(int pos, byte[] pbuf, int offset, int len) {
202: //#ifdef DEBUG
203: if (Trace.bit(0)) {
204: Debug.println("Block[" + key + "].write(" + pos + ", "
205: + Util.strBytes(pbuf, offset, len) + ")");
206: }
207: //#endif
208: System.arraycopy(pbuf, offset, buf, pos, len);
209: setDirty(true);
210: return len;
211: }
212:
213: public final byte readByte(int pos) {
214: //#ifdef DEBUG
215: if (Trace.bit(1)) {
216: Debug.println("Block[" + key + "].read(" + (pos) + "): "
217: + buf[pos]);
218: }
219: //#endif
220: return buf[pos];
221: }
222:
223: public final void writeByte(int pos, byte val) {
224: //#ifdef DEBUG
225: if (Trace.bit(0)) {
226: Debug.println("Block[" + key + "].write(" + pos + "): "
227: + val);
228: }
229: //#endif
230: buf[pos] = val;
231: setDirty(true);
232: }
233:
234: /**
235: * Read a short (2-byte) value from the page.
236: *
237: * @param pos the offset in the page of the short.
238: */
239: public final short readShort(int pos) {
240: short ret = ByteUtil.getShort(buf, pos);
241: //#ifdef DEBUG
242: if (Trace.bit(1)) {
243: Debug.println("Block[" + key + "].readShort(" + pos
244: + ") = " + ret);
245: }
246: //#endif
247: return ret;
248: }
249:
250: /**
251: * Write a short (2-byte) value to the page.
252: *
253: * @param pos the offset in the page of the short.
254: * @param val the short value to write.
255: */
256: public final void writeShort(int pos, short val) {
257: //#ifdef DEBUG
258: if (Trace.bit(0)) {
259: Debug.println("Block[" + key + "].writeShort(" + pos + ", "
260: + val + ")");
261: }
262: //#endif
263: ByteUtil.putShort(buf, pos, val);
264: setDirty(true);
265: }
266:
267: /**
268: * Read an integer (4-byte) value from the page.
269: *
270: * @param pos the offset in the page of the integer.
271: */
272: public final int readInt(int pos) {
273: int ret = ByteUtil.getInt(buf, pos);
274: //#ifdef DEBUG
275: if (Trace.bit(1)) {
276: Debug.println("Block[" + key + "].readInt(" + pos + ") = "
277: + ret);
278: }
279: //#endif
280: return ret;
281: }
282:
283: /**
284: * Write an integer (4-byte) value to the page.
285: *
286: * @param pos the offset in the page of the integer.
287: * @param val the integer value to write.
288: */
289: public final void writeInt(int pos, int val) {
290: //#ifdef DEBUG
291: if (Trace.bit(0)) {
292: Debug.println("Block[" + key + "].writeInt(" + pos + ", "
293: + val + ")");
294: }
295: //#endif
296: ByteUtil.putInt(buf, pos, val);
297: setDirty(true);
298: }
299:
300: /**
301: * Read a long (8-byte) value from the page.
302: *
303: * @param pos the offset in the page of the long.
304: */
305: public final long readLong(int pos) {
306: long ret = ByteUtil.getLong(buf, pos);
307: //#ifdef DEBUG
308: if (Trace.bit(1)) {
309: Debug.println("Block[" + key + "].readLong(" + pos + ") = "
310: + ret);
311: }
312: //#endif
313: return ret;
314: }
315:
316: /**
317: * Write a long (8-byte) value to the page.
318: *
319: * @param pos the offset in the page of the long.
320: * @param val the long value to write.
321: */
322: public final void writeLong(int pos, long val) {
323: //#ifdef DEBUG
324: if (Trace.bit(0)) {
325: Debug.println("Block[" + key + "].writeLong(" + pos + ", "
326: + val + ")");
327: }
328: //#endif
329: ByteUtil.putLong(buf, pos, val);
330: setDirty(true);
331: }
332:
333: public final void takeData(Page p) {
334: setData(((Block) p).getDataAndReset());
335: }
336:
337: public void clear() {
338: for (int i = 0; i < buf.length; i++)
339: buf[i] = 0;
340: setDirty(true);
341: }
342:
343: //#ifdef DEBUG
344: // used for test below
345: void init() {
346: buf = new byte[32];
347: }
348:
349: // A 12 bit (two base64 chars) signature. Live dangerously.
350: public String signature() {
351: return signature(buf);
352: }
353:
354: public static String signature(byte[] buf) {
355: return signature(buf, 0, buf.length);
356: }
357:
358: public static String signature(byte[] buf, int off, int cnt) {
359: byte[] b = com.quadcap.io.Base64OutputStream.base64;
360: int h = 31415;
361: long tot = 0;
362: for (int i = 0; i < cnt; i++) {
363: tot += buf[off + i];
364: h ^= (h << 7) ^ (h >> 3) ^ buf[off + i];
365: }
366: return "" + (char) b[(h >> 1) & 63] + (char) b[(h >> 8) & 63]
367: + (char) b[(h >> 16) & 63] + ((tot == 0) ? "*" : "");
368: }
369:
370: public static void main(String args[]) {
371: Block b = new Block();
372: b.init();
373: b.writeInt(20, 128);
374: byte[] bufx = new byte[32];
375: b.read(20, bufx, 0, 4);
376: int v = b.readInt(20);
377: }
378: //#endif
379: }
|