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 }