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