1 /**
2 * JDBM LICENSE v1.00
3 *
4 * Redistribution and use of this software and associated documentation
5 * ("Software"), with or without modification, are permitted provided
6 * that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain copyright
9 * statements and notices. Redistributions must also contain a
10 * copy of this document.
11 *
12 * 2. Redistributions in binary form must reproduce the
13 * above copyright notice, this list of conditions and the
14 * following disclaimer in the documentation and/or other
15 * materials provided with the distribution.
16 *
17 * 3. The name "JDBM" must not be used to endorse or promote
18 * products derived from this Software without prior written
19 * permission of Cees de Groot. For written permission,
20 * please contact cg@cdegroot.com.
21 *
22 * 4. Products derived from this Software may not be called "JDBM"
23 * nor may "JDBM" appear in their names without prior written
24 * permission of Cees de Groot.
25 *
26 * 5. Due credit should be given to the JDBM Project
27 * (http://jdbm.sourceforge.net/).
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
31 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
32 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
33 * CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
34 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
36 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
38 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
40 * OF THE POSSIBILITY OF SUCH DAMAGE.
41 *
42 * Copyright 2000 (C) Cees de Groot. All Rights Reserved.
43 * Contributions are Copyright (C) 2000 by their associated contributors.
44 *
45 * $Id: BlockIo.java,v 1.2 2002/08/06 05:18:36 boisvert Exp $
46 */
47
48 package jdbm.recman;
49
50 import java.io.*;
51
52 /**
53 * This class wraps a page-sized byte array and provides methods
54 * to read and write data to and from it. The readers and writers
55 * are just the ones that the rest of the toolkit needs, nothing else.
56 * Values written are compatible with java.io routines.
57 *
58 * @see java.io.DataInput
59 * @see java.io.DataOutput
60 */
61 public final class BlockIo implements java.io.Externalizable {
62
63 public final static long serialVersionUID = 2L;
64
65 private long blockId;
66
67 private transient byte[] data; // work area
68 private transient BlockView view = null;
69 private transient boolean dirty = false;
70 private transient int transactionCount = 0;
71
72 /**
73 * Default constructor for serialization
74 */
75 public BlockIo() {
76 // empty
77 }
78
79 /**
80 * Constructs a new BlockIo instance working on the indicated
81 * buffer.
82 */
83 BlockIo(long blockId, byte[] data) {
84 // removeme for production version
85 if (blockId > 10000000000L)
86 throw new Error("bogus block id " + blockId);
87 this.blockId = blockId;
88 this.data = data;
89 }
90
91 /**
92 * Returns the underlying array
93 */
94 byte[] getData() {
95 return data;
96 }
97
98 /**
99 * 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 }