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    }