View Javadoc

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 }