001: /**
002: * JDBM LICENSE v1.00
003: *
004: * Redistribution and use of this software and associated documentation
005: * ("Software"), with or without modification, are permitted provided
006: * that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain copyright
009: * statements and notices. Redistributions must also contain a
010: * copy of this document.
011: *
012: * 2. Redistributions in binary form must reproduce the
013: * above copyright notice, this list of conditions and the
014: * following disclaimer in the documentation and/or other
015: * materials provided with the distribution.
016: *
017: * 3. The name "JDBM" must not be used to endorse or promote
018: * products derived from this Software without prior written
019: * permission of Cees de Groot. For written permission,
020: * please contact cg@cdegroot.com.
021: *
022: * 4. Products derived from this Software may not be called "JDBM"
023: * nor may "JDBM" appear in their names without prior written
024: * permission of Cees de Groot.
025: *
026: * 5. Due credit should be given to the JDBM Project
027: * (http://jdbm.sourceforge.net/).
028: *
029: * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
030: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
031: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
032: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
033: * CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
034: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
035: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
036: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
037: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
038: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
039: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
040: * OF THE POSSIBILITY OF SUCH DAMAGE.
041: *
042: * Copyright 2000 (C) Cees de Groot. All Rights Reserved.
043: * Contributions are Copyright (C) 2000 by their associated contributors.
044: *
045: * $Id: BlockIo.java,v 1.2 2002/08/06 05:18:36 boisvert Exp $
046: */package jdbm.recman;
047:
048: import java.io.*;
049:
050: /**
051: * This class wraps a page-sized byte array and provides methods
052: * to read and write data to and from it. The readers and writers
053: * are just the ones that the rest of the toolkit needs, nothing else.
054: * Values written are compatible with java.io routines.
055: *
056: * @see java.io.DataInput
057: * @see java.io.DataOutput
058: */
059: public final class BlockIo implements java.io.Externalizable {
060:
061: public final static long serialVersionUID = 2L;
062:
063: private long blockId;
064:
065: private transient byte[] data; // work area
066: private transient BlockView view = null;
067: private transient boolean dirty = false;
068: private transient int transactionCount = 0;
069:
070: /**
071: * Default constructor for serialization
072: */
073: public BlockIo() {
074: // empty
075: }
076:
077: /**
078: * Constructs a new BlockIo instance working on the indicated
079: * buffer.
080: */
081: BlockIo(long blockId, byte[] data) {
082: // removeme for production version
083: if (blockId > 10000000000L)
084: throw new Error("bogus block id " + blockId);
085: this .blockId = blockId;
086: this .data = data;
087: }
088:
089: /**
090: * Returns the underlying array
091: */
092: byte[] getData() {
093: return data;
094: }
095:
096: /**
097: * Sets the block number. Should only be called by RecordFile.
098: */
099: void setBlockId(long id) {
100: if (isInTransaction())
101: throw new Error("BlockId assigned for transaction block");
102: // removeme for production version
103: if (id > 10000000000L)
104: throw new Error("bogus block id " + id);
105: blockId = id;
106: }
107:
108: /**
109: * Returns the block number.
110: */
111: long getBlockId() {
112: return blockId;
113: }
114:
115: /**
116: * Returns the current view of the block.
117: */
118: public BlockView getView() {
119: return view;
120: }
121:
122: /**
123: * Sets the current view of the block.
124: */
125: public void setView(BlockView view) {
126: this .view = view;
127: }
128:
129: /**
130: * Sets the dirty flag
131: */
132: void setDirty() {
133: dirty = true;
134: }
135:
136: /**
137: * Clears the dirty flag
138: */
139: void setClean() {
140: dirty = false;
141: }
142:
143: /**
144: * Returns true if the dirty flag is set.
145: */
146: boolean isDirty() {
147: return dirty;
148: }
149:
150: /**
151: * Returns true if the block is still dirty with respect to the
152: * transaction log.
153: */
154: boolean isInTransaction() {
155: return transactionCount != 0;
156: }
157:
158: /**
159: * Increments transaction count for this block, to signal that this
160: * block is in the log but not yet in the data file. The method also
161: * takes a snapshot so that the data may be modified in new transactions.
162: */
163: synchronized void incrementTransactionCount() {
164: transactionCount++;
165: // @fixme(alex)
166: setClean();
167: }
168:
169: /**
170: * Decrements transaction count for this block, to signal that this
171: * block has been written from the log to the data file.
172: */
173: synchronized void decrementTransactionCount() {
174: transactionCount--;
175: if (transactionCount < 0)
176: throw new Error("transaction count on block "
177: + getBlockId() + " below zero!");
178:
179: }
180:
181: /**
182: * Reads a byte from the indicated position
183: */
184: public byte readByte(int pos) {
185: return data[pos];
186: }
187:
188: /**
189: * Writes a byte to the indicated position
190: */
191: public void writeByte(int pos, byte value) {
192: data[pos] = value;
193: setDirty();
194: }
195:
196: /**
197: * Reads a short from the indicated position
198: */
199: public short readShort(int pos) {
200: return (short) (((short) (data[pos + 0] & 0xff) << 8) | ((short) (data[pos + 1] & 0xff) << 0));
201: }
202:
203: /**
204: * Writes a short to the indicated position
205: */
206: public void writeShort(int pos, short value) {
207: data[pos + 0] = (byte) (0xff & (value >> 8));
208: data[pos + 1] = (byte) (0xff & (value >> 0));
209: setDirty();
210: }
211:
212: /**
213: * Reads an int from the indicated position
214: */
215: public int readInt(int pos) {
216: return (((int) (data[pos + 0] & 0xff) << 24)
217: | ((int) (data[pos + 1] & 0xff) << 16)
218: | ((int) (data[pos + 2] & 0xff) << 8) | ((int) (data[pos + 3] & 0xff) << 0));
219: }
220:
221: /**
222: * Writes an int to the indicated position
223: */
224: public void writeInt(int pos, int value) {
225: data[pos + 0] = (byte) (0xff & (value >> 24));
226: data[pos + 1] = (byte) (0xff & (value >> 16));
227: data[pos + 2] = (byte) (0xff & (value >> 8));
228: data[pos + 3] = (byte) (0xff & (value >> 0));
229: setDirty();
230: }
231:
232: /**
233: * Reads a long from the indicated position
234: */
235: public long readLong(int pos) {
236: // Contributed by Erwin Bolwidt <ejb@klomp.org>
237: // Gives about 15% performance improvement
238: return ((long) (((data[pos + 0] & 0xff) << 24)
239: | ((data[pos + 1] & 0xff) << 16)
240: | ((data[pos + 2] & 0xff) << 8) | ((data[pos + 3] & 0xff))) << 32)
241: | ((long) (((data[pos + 4] & 0xff) << 24)
242: | ((data[pos + 5] & 0xff) << 16)
243: | ((data[pos + 6] & 0xff) << 8) | ((data[pos + 7] & 0xff))) & 0xffffffff);
244: /* Original version by Alex Boisvert. Might be faster on 64-bit JVMs.
245: return
246: (((long)(data[pos+0] & 0xff) << 56) |
247: ((long)(data[pos+1] & 0xff) << 48) |
248: ((long)(data[pos+2] & 0xff) << 40) |
249: ((long)(data[pos+3] & 0xff) << 32) |
250: ((long)(data[pos+4] & 0xff) << 24) |
251: ((long)(data[pos+5] & 0xff) << 16) |
252: ((long)(data[pos+6] & 0xff) << 8) |
253: ((long)(data[pos+7] & 0xff) << 0));
254: */
255: }
256:
257: /**
258: * Writes a long to the indicated position
259: */
260: public void writeLong(int pos, long value) {
261: data[pos + 0] = (byte) (0xff & (value >> 56));
262: data[pos + 1] = (byte) (0xff & (value >> 48));
263: data[pos + 2] = (byte) (0xff & (value >> 40));
264: data[pos + 3] = (byte) (0xff & (value >> 32));
265: data[pos + 4] = (byte) (0xff & (value >> 24));
266: data[pos + 5] = (byte) (0xff & (value >> 16));
267: data[pos + 6] = (byte) (0xff & (value >> 8));
268: data[pos + 7] = (byte) (0xff & (value >> 0));
269: setDirty();
270: }
271:
272: // overrides java.lang.Object
273:
274: public String toString() {
275: return "BlockIO(" + blockId + "," + dirty + "," + view + ")";
276: }
277:
278: // implement externalizable interface
279: public void readExternal(ObjectInput in) throws IOException,
280: ClassNotFoundException {
281: blockId = in.readLong();
282: int length = in.readInt();
283: data = new byte[length];
284: in.readFully(data);
285: }
286:
287: // implement externalizable interface
288: public void writeExternal(ObjectOutput out) throws IOException {
289: out.writeLong(blockId);
290: out.writeInt(data.length);
291: out.write(data);
292: }
293:
294: }
|