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 */
047
048 package jdbm.recman;
049
050 import java.io.*;
051
052 /**
053 * This class wraps a page-sized byte array and provides methods
054 * to read and write data to and from it. The readers and writers
055 * are just the ones that the rest of the toolkit needs, nothing else.
056 * Values written are compatible with java.io routines.
057 *
058 * @see java.io.DataInput
059 * @see java.io.DataOutput
060 */
061 public final class BlockIo implements java.io.Externalizable {
062
063 public final static long serialVersionUID = 2L;
064
065 private long blockId;
066
067 private transient byte[] data; // work area
068 private transient BlockView view = null;
069 private transient boolean dirty = false;
070 private transient int transactionCount = 0;
071
072 /**
073 * Default constructor for serialization
074 */
075 public BlockIo() {
076 // empty
077 }
078
079 /**
080 * Constructs a new BlockIo instance working on the indicated
081 * buffer.
082 */
083 BlockIo(long blockId, byte[] data) {
084 // removeme for production version
085 if (blockId > 10000000000L)
086 throw new Error("bogus block id " + blockId);
087 this.blockId = blockId;
088 this.data = data;
089 }
090
091 /**
092 * Returns the underlying array
093 */
094 byte[] getData() {
095 return data;
096 }
097
098 /**
099 * Sets the block number. Should only be called by RecordFile.
100 */
101 void setBlockId(long id) {
102 if (isInTransaction())
103 throw new Error("BlockId assigned for transaction block");
104 // removeme for production version
105 if (id > 10000000000L)
106 throw new Error("bogus block id " + id);
107 blockId = id;
108 }
109
110 /**
111 * Returns the block number.
112 */
113 long getBlockId() {
114 return blockId;
115 }
116
117 /**
118 * Returns the current view of the block.
119 */
120 public BlockView getView() {
121 return view;
122 }
123
124 /**
125 * Sets the current view of the block.
126 */
127 public void setView(BlockView view) {
128 this.view = view;
129 }
130
131 /**
132 * Sets the dirty flag
133 */
134 void setDirty() {
135 dirty = true;
136 }
137
138 /**
139 * Clears the dirty flag
140 */
141 void setClean() {
142 dirty = false;
143 }
144
145 /**
146 * Returns true if the dirty flag is set.
147 */
148 boolean isDirty() {
149 return dirty;
150 }
151
152 /**
153 * Returns true if the block is still dirty with respect to the
154 * transaction log.
155 */
156 boolean isInTransaction() {
157 return transactionCount != 0;
158 }
159
160 /**
161 * Increments transaction count for this block, to signal that this
162 * block is in the log but not yet in the data file. The method also
163 * takes a snapshot so that the data may be modified in new transactions.
164 */
165 synchronized void incrementTransactionCount() {
166 transactionCount++;
167 // @fixme(alex)
168 setClean();
169 }
170
171 /**
172 * Decrements transaction count for this block, to signal that this
173 * block has been written from the log to the data file.
174 */
175 synchronized void decrementTransactionCount() {
176 transactionCount--;
177 if (transactionCount < 0)
178 throw new Error("transaction count on block "
179 + getBlockId() + " below zero!");
180
181 }
182
183 /**
184 * Reads a byte from the indicated position
185 */
186 public byte readByte(int pos) {
187 return data[pos];
188 }
189
190 /**
191 * Writes a byte to the indicated position
192 */
193 public void writeByte(int pos, byte value) {
194 data[pos] = value;
195 setDirty();
196 }
197
198 /**
199 * Reads a short from the indicated position
200 */
201 public short readShort(int pos) {
202 return (short)
203 (((short) (data[pos+0] & 0xff) << 8) |
204 ((short) (data[pos+1] & 0xff) << 0));
205 }
206
207 /**
208 * Writes a short to the indicated position
209 */
210 public void writeShort(int pos, short value) {
211 data[pos+0] = (byte)(0xff & (value >> 8));
212 data[pos+1] = (byte)(0xff & (value >> 0));
213 setDirty();
214 }
215
216 /**
217 * Reads an int from the indicated position
218 */
219 public int readInt(int pos) {
220 return
221 (((int)(data[pos+0] & 0xff) << 24) |
222 ((int)(data[pos+1] & 0xff) << 16) |
223 ((int)(data[pos+2] & 0xff) << 8) |
224 ((int)(data[pos+3] & 0xff) << 0));
225 }
226
227 /**
228 * Writes an int to the indicated position
229 */
230 public void writeInt(int pos, int value) {
231 data[pos+0] = (byte)(0xff & (value >> 24));
232 data[pos+1] = (byte)(0xff & (value >> 16));
233 data[pos+2] = (byte)(0xff & (value >> 8));
234 data[pos+3] = (byte)(0xff & (value >> 0));
235 setDirty();
236 }
237
238 /**
239 * Reads a long from the indicated position
240 */
241 public long readLong( int pos )
242 {
243 // Contributed by Erwin Bolwidt <ejb@klomp.org>
244 // Gives about 15% performance improvement
245 return
246 ( (long)( ((data[pos+0] & 0xff) << 24) |
247 ((data[pos+1] & 0xff) << 16) |
248 ((data[pos+2] & 0xff) << 8) |
249 ((data[pos+3] & 0xff) ) ) << 32 ) |
250 ( (long)( ((data[pos+4] & 0xff) << 24) |
251 ((data[pos+5] & 0xff) << 16) |
252 ((data[pos+6] & 0xff) << 8) |
253 ((data[pos+7] & 0xff) ) ) & 0xffffffff );
254 /* Original version by Alex Boisvert. Might be faster on 64-bit JVMs.
255 return
256 (((long)(data[pos+0] & 0xff) << 56) |
257 ((long)(data[pos+1] & 0xff) << 48) |
258 ((long)(data[pos+2] & 0xff) << 40) |
259 ((long)(data[pos+3] & 0xff) << 32) |
260 ((long)(data[pos+4] & 0xff) << 24) |
261 ((long)(data[pos+5] & 0xff) << 16) |
262 ((long)(data[pos+6] & 0xff) << 8) |
263 ((long)(data[pos+7] & 0xff) << 0));
264 */
265 }
266
267 /**
268 * Writes a long to the indicated position
269 */
270 public void writeLong(int pos, long value) {
271 data[pos+0] = (byte)(0xff & (value >> 56));
272 data[pos+1] = (byte)(0xff & (value >> 48));
273 data[pos+2] = (byte)(0xff & (value >> 40));
274 data[pos+3] = (byte)(0xff & (value >> 32));
275 data[pos+4] = (byte)(0xff & (value >> 24));
276 data[pos+5] = (byte)(0xff & (value >> 16));
277 data[pos+6] = (byte)(0xff & (value >> 8));
278 data[pos+7] = (byte)(0xff & (value >> 0));
279 setDirty();
280 }
281
282 // overrides java.lang.Object
283
284 public String toString() {
285 return "BlockIO("
286 + blockId + ","
287 + dirty + ","
288 + view + ")";
289 }
290
291 // implement externalizable interface
292 public void readExternal(ObjectInput in)
293 throws IOException, ClassNotFoundException {
294 blockId = in.readLong();
295 int length = in.readInt();
296 data = new byte[length];
297 in.readFully(data);
298 }
299
300 // implement externalizable interface
301 public void writeExternal(ObjectOutput out) throws IOException {
302 out.writeLong(blockId);
303 out.writeInt(data.length);
304 out.write(data);
305 }
306
307 }