KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > data > StoredRecordHeader


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.data.StoredRecordHeader
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21 package org.apache.derby.impl.store.raw.data;
22
23 import org.apache.derby.iapi.services.sanity.SanityManager;
24
25 import org.apache.derby.iapi.store.raw.PageKey;
26 import org.apache.derby.iapi.store.raw.RecordHandle;
27
28 import java.io.IOException JavaDoc;
29 import java.io.EOFException JavaDoc;
30
31 import java.io.InputStream JavaDoc;
32 import java.io.OutputStream JavaDoc;
33
34 import org.apache.derby.iapi.services.io.CompressedNumber;
35
36 /**
37     A class StoredPage uses to cache record headers by passing instances
38     to BasePage, and to write stored versions of record headers.
39
40     Format
41
42     <PRE>
43
44     1 byte - status
45     compressed int - record identifier
46
47     compressed long - overflow page } only if hasOverflow() is true
48     compressed int - overflow id } " " "
49
50     compressed int - first field } only if hasFirstField set - otherwise 0
51
52     compressed int - number of fields in this portion - only if hasOverflow()
53                                 is false OR hasFirstField is true - otherwise 0
54     </PRE>
55
56 */

57
58 public final class StoredRecordHeader
59 {
60
61     /**************************************************************************
62      * Constants of the class
63      **************************************************************************
64      */

65
66     /**
67      * Status bits for the record header:
68      *
69      * RECORD_INITIAL - used when record header is first initialized
70      * RECORD_DELETED - used to indicate the record has been deleted
71      * RECORD_OVERFLOW - used to indicate the record has been
72      * overflowed, it will point to the overflow
73      * page and ID
74      * RECORD_HAS_FIRST_FIELD - used to indicate that firstField is stored.
75      * When RECORD_OVERFLOW and
76      * RECORD_HAS_FIRST_FIELD both are set, part of
77      * record is on the page, the record header
78      * also stores the overflow point to the next
79      * part of the record.
80      * RECORD_VALID_MASK - A mask of valid bits that can be set
81      * currently, such that the following assert can
82      * be made:
83      * ASSERT((status & ~RECORD_VALID_MASK) == 0))
84      **/

85     public static final int RECORD_INITIAL = 0x00;
86     public static final int RECORD_DELETED = 0x01;
87     public static final int RECORD_OVERFLOW = 0x02;
88     public static final int RECORD_HAS_FIRST_FIELD = 0x04;
89     public static final int RECORD_VALID_MASK = 0x0f;
90
91
92     /**************************************************************************
93      * Fields of the class
94      **************************************************************************
95      */

96
97     /**
98      * Actual identifier of the record
99      *
100      * <BR> MT - Mutable
101      **/

102     protected int id;
103
104     /**
105      * Status of the record.
106      *
107      * See above for description of fields:
108      * RECORD_INITIAL
109      * RECORD_DELETED
110      * RECORD_OVERFLOW
111      * RECORD_HAS_FIRST_FIELD
112      * RECORD_VALID_MASK
113      *
114      * <BR> MT - Mutable - single thread required.
115      **/

116     protected int status;
117
118     /**
119      * number of fields in the row.
120      **/

121     protected int numberFields;
122
123     /**
124      * A record handle that can represent the record, may be null.
125      **/

126     protected RecordHandle handle;
127
128
129     /**
130      * If (hasOverflow()) then this is the id of the row on page overflowPage
131      * where the next portion of the row can be found. In this case there
132      * are no "real" fields on this page. This situation comes about if a
133      * row has been updated such that the real first field no longer fits on
134      * the head page.
135      **/

136     protected int overflowId;
137
138
139     /**
140      * If (hasOverflow()) then this is the page where where the next portion of
141      * the row can be found. In this case there are no "real" fields on this
142      * page.
143      **/

144     protected long overflowPage;
145
146     /**
147      * if (hasFirstField()) then this field is the number of the column in
148      * the orginal row which is now stored as the first field in this row. This
149      * row is 2nd through N'th portion of a long row.
150      *
151      * For example if a row has its first 3 fields on page 0 and its next 3
152      * fields on page 1, then the record header of the row portion on page 1
153      * will have hasFirstField() set to true, and the value would be 4,
154      * indicating that the 4th field of the row is stored as the 1st field of
155      * the partial row portion stored on page 1.
156      **/

157     protected int firstField;
158
159
160     /**************************************************************************
161      * Constructors for This class:
162      **************************************************************************
163      */

164     public StoredRecordHeader()
165     {
166     }
167
168     public StoredRecordHeader(int id, int numberFields)
169     {
170         setId(id);
171         setNumberFields(numberFields);
172     }
173
174     public StoredRecordHeader(
175     byte data[],
176     int offset)
177     {
178         read(data, offset);
179     }
180
181     public StoredRecordHeader(StoredRecordHeader loadTargetFrom)
182     {
183         this.status = loadTargetFrom.status;
184         this.id = loadTargetFrom.id;
185         this.numberFields = loadTargetFrom.numberFields;
186         handle = null;
187
188         overflowId = loadTargetFrom.overflowId;
189         overflowPage = loadTargetFrom.overflowPage;
190         firstField = loadTargetFrom.firstField;
191     }
192
193     /**************************************************************************
194      * Public Accessor "Get" Methods of This class:
195      **************************************************************************
196      */

197
198     /**
199      * Get a record handle for the record.
200      * <p>
201      *
202      * <BR> MT - single thread required
203      **/

204     protected RecordHandle getHandle(
205     PageKey pageId,
206     int current_slot)
207     {
208         if (handle == null)
209             handle = new RecordId(pageId, id, current_slot);
210
211         return handle;
212     }
213
214     /**
215      * Get the record identifier
216      *
217      * <BR> MT - thread safe
218      **/

219     public final int getId()
220     {
221         return id;
222     }
223
224     public int getNumberFields()
225     {
226         return numberFields;
227     }
228
229     public long getOverflowPage()
230     {
231         return overflowPage;
232     }
233
234     public int getOverflowId()
235     {
236         return overflowId;
237     }
238
239     public int getFirstField()
240     {
241         return firstField;
242     }
243
244     public final boolean hasOverflow()
245     {
246         return ((status & RECORD_OVERFLOW) == RECORD_OVERFLOW);
247     }
248
249     protected final boolean hasFirstField()
250     {
251         return ((status & RECORD_HAS_FIRST_FIELD) == RECORD_HAS_FIRST_FIELD);
252     }
253
254     /**
255      * Get the deleted state of the record.
256      * <p>
257      *
258      * <BR> MT - single thread required
259      **/

260     public final boolean isDeleted()
261     {
262         return ((status & RECORD_DELETED) == RECORD_DELETED);
263     }
264
265
266     /**
267      * return the size of the record header.
268      * <p>
269      * Calculates the size of the record header, mostly used to allow a
270      * reader to skip over the record header and position on the 1st field
271      * of the record.
272      * <p>
273      * This low level routine is performance critical to processing lots of
274      * rows, so calls to CompressNumber have been hand inlined.
275      *
276      * @return The length of the record header.
277      *
278      * @exception StandardException Standard exception policy.
279      **/

280     public int size()
281     {
282         // account for length of fieldDataLength field stored as a compressed
283
// int plus one byte for status.
284
//
285
// int len = CompressedNumber.sizeInt(id) + 1;
286
int len =
287           (id <= CompressedNumber.MAX_COMPRESSED_INT_ONE_BYTE) ?
288               2 :
289           (id <= CompressedNumber.MAX_COMPRESSED_INT_TWO_BYTES) ?
290               3 : 5;
291
292         if ((status & (RECORD_OVERFLOW | RECORD_HAS_FIRST_FIELD)) == 0)
293         {
294             // usual case, not a record overflow and does not have first field
295
len +=
296               (numberFields <= CompressedNumber.MAX_COMPRESSED_INT_ONE_BYTE) ?
297                   1 :
298               (numberFields <= CompressedNumber.MAX_COMPRESSED_INT_TWO_BYTES) ?
299                   2 : 4;
300         }
301         else if ((status & RECORD_OVERFLOW) == 0)
302         {
303             // not overflow, and has first field set.
304

305             // account for size of the numberFields field + size fo the
306
// firstField field.
307
//
308
// len += (CompressedNumber.sizeInt(numberFields) +
309
// CompressedNumber.sizeInt(firstField);
310
//
311
len +=
312               ((numberFields <= CompressedNumber.MAX_COMPRESSED_INT_ONE_BYTE) ?
313                   1 :
314                (numberFields <= CompressedNumber.MAX_COMPRESSED_INT_TWO_BYTES) ?
315                   2 : 4) +
316
317               ((firstField <= CompressedNumber.MAX_COMPRESSED_INT_ONE_BYTE) ?
318                   1 :
319                (firstField <= CompressedNumber.MAX_COMPRESSED_INT_TWO_BYTES) ?
320                   2 : 4);
321         }
322         else
323         {
324             // is an overflow field
325

326             len += CompressedNumber.sizeLong(overflowPage);
327             len += CompressedNumber.sizeInt(overflowId);
328
329             if (hasFirstField())
330             {
331                 len += CompressedNumber.sizeInt(firstField);
332                 len += CompressedNumber.sizeInt(numberFields);
333             }
334         }
335
336         return len;
337     }
338
339     /**************************************************************************
340      * Public Accessor "Set" Methods of This class:
341      **************************************************************************
342      */

343
344     /**
345      * Set the deleted state of the record.
346      * <p>
347      * return 1, if delete status from not deleted to deleted
348      * return -1, if delete status from deleted to not deleted
349      * return 0, if status unchanged.
350      *
351      * <BR> MT - single thread required
352      **/

353     public int setDeleted(boolean deleteTrue)
354     {
355
356         int retCode = 0;
357
358         if (deleteTrue)
359         {
360             if (!isDeleted())
361             {
362                 // setting the bit from not deleted to deleted
363
retCode = 1;
364                 status |= RECORD_DELETED;
365             }
366         }
367         else
368         {
369             if (isDeleted())
370             {
371                 // setting the bit from deleted to not deleted
372
retCode = -1;
373                 status &= ~RECORD_DELETED;
374             }
375         }
376
377         return(retCode);
378     }
379
380     public void setFirstField(int firstField)
381     {
382         this.firstField = firstField;
383         status |= RECORD_HAS_FIRST_FIELD;
384     }
385
386     public final void setId(int id)
387     {
388         this.id = id;
389     }
390
391     public void setOverflowDetails(RecordHandle overflowHandle)
392     {
393         this.overflowPage = overflowHandle.getPageNumber();
394         this.overflowId = overflowHandle.getId();
395     }
396
397     public void setOverflowFields(StoredRecordHeader loadFromTarget)
398     {
399         this.status = (loadFromTarget.status | RECORD_OVERFLOW);
400         this.id = loadFromTarget.id;
401         this.numberFields = loadFromTarget.numberFields;
402         this.firstField = loadFromTarget.firstField;
403         handle = null;
404     }
405
406
407     public final void setNumberFields(int numberFields)
408     {
409         this.numberFields = numberFields;
410     }
411
412     /**************************************************************************
413      * Public Methods implmenting read/write of Storable Interface:
414      **************************************************************************
415      */

416     public int write(OutputStream JavaDoc out)
417         throws IOException JavaDoc
418     {
419         // check consistency of the status field - this has caught
420
// byte writing corruptions in StoredPage in the past.
421
if (SanityManager.DEBUG)
422         {
423             if ((status & ~RECORD_VALID_MASK) != 0)
424                 SanityManager.THROWASSERT(
425                     "Invalid status in StoredRecordHeaader = " + status);
426         }
427
428         // write status
429
int len = 1;
430         out.write(status);
431
432         // write id
433
len += CompressedNumber.writeInt(out, id);
434         
435
436         // write overflow information for overflow record headers
437
if (hasOverflow())
438         {
439             // if overflow bit is set, then write the overflow pointer info.
440
len += CompressedNumber.writeLong(out, overflowPage);
441             len += CompressedNumber.writeInt(out, overflowId);
442         }
443
444         // write first field info for long row parts
445
if (hasFirstField())
446         {
447             len += CompressedNumber.writeInt(out, firstField);
448         }
449
450         // write number of fields, except in the case of a record header
451
// which is solely a pointer to another row portion.
452
//
453
// see read
454
if (!hasOverflow() || hasFirstField())
455             len += CompressedNumber.writeInt(out, numberFields);
456
457         return len;
458     }
459
460     public void read(java.io.ObjectInput JavaDoc in)
461         throws IOException JavaDoc
462     {
463
464         // read status
465
status = in.read();
466         if (status < 0)
467             throw new EOFException JavaDoc();
468
469         // check consistency of the status field - this has caught
470
// byte writing corruptions in StoredPage in the past.
471
if (SanityManager.DEBUG)
472         {
473             if ((status & ~RECORD_VALID_MASK) != 0)
474                 SanityManager.THROWASSERT(
475                     "Invalid status in StoredRecordHeader = " + status);
476         }
477
478         // read the record id
479
id = CompressedNumber.readInt(in);
480
481         // initialize the overflow pointer based on status.
482
if (hasOverflow())
483         {
484             overflowPage = CompressedNumber.readLong(in);
485             overflowId = CompressedNumber.readInt(in);
486
487         }
488         else
489         {
490             overflowPage = 0;
491             overflowId = 0;
492         }
493
494         // initialize the 1st field overflow pointer based on status.
495
if (hasFirstField())
496         {
497             firstField = CompressedNumber.readInt(in);
498         }
499         else
500         {
501             firstField = 0;
502         }
503     
504         // In releases prior to 1.3 an overflow record was handled
505
// by an overflow header pointing to a complete record on
506
// another page. This header had the has overflow bit set but not
507
// the has first field bit. This header also did not have the
508
// number of fields written out, but it can be seen as
509
// a header with 0 fields and a first field of 0.
510
if (!hasOverflow() || hasFirstField())
511             numberFields = CompressedNumber.readInt(in);
512         else
513             numberFields = 0;
514
515         handle = null;
516     }
517
518     private int readId(
519     byte[] data,
520     int offset)
521     {
522         int value = data[offset++];
523
524         if ((value & ~0x3f) == 0)
525         {
526             // value stored in this byte.
527
id = value;
528
529             return(1);
530         }
531         else if ((value & 0x80) == 0)
532         {
533             // value is stored in 2 bytes. only use low 6 bits from 1st byte.
534

535             id = (((value & 0x3f) << 8) | (data[offset] & 0xff));
536
537             return(2);
538         }
539         else
540         {
541             // value is stored in 4 bytes. only use low 7 bits from 1st byte.
542
id =
543                 ((value & 0x7f) << 24) |
544                 ((data[offset++] & 0xff) << 16) |
545                 ((data[offset++] & 0xff) << 8) |
546                 ((data[offset] & 0xff) );
547
548             return(4);
549         }
550     }
551     private int readOverFlowPage(
552     byte[] data,
553     int offset)
554     {
555         int int_value = data[offset++];
556
557         if ((int_value & ~0x3f) == 0)
558         {
559             // test for small case first - assuming this is usual case.
560
// this is stored in 2 bytes.
561

562             overflowPage = ((int_value << 8) | (data[offset] & 0xff));
563
564             return(2);
565         }
566         else if ((int_value & 0x80) == 0)
567         {
568             // value is stored in 4 bytes. only use low 6 bits from 1st byte.
569

570             overflowPage =
571                 ((int_value & 0x3f) << 24) |
572                 ((data[offset++] & 0xff) << 16) |
573                 ((data[offset++] & 0xff) << 8) |
574                 ((data[offset] & 0xff) );
575
576             return(4);
577
578         }
579         else
580         {
581             // value is stored in 8 bytes. only use low 6 bits from 1st byte.
582
overflowPage =
583                 (((long) (int_value & 0x7f)) << 56) |
584                 (((long) (data[offset++] & 0xff)) << 48) |
585                 (((long) (data[offset++] & 0xff)) << 40) |
586                 (((long) (data[offset++] & 0xff)) << 32) |
587                 (((long) (data[offset++] & 0xff)) << 24) |
588                 (((long) (data[offset++] & 0xff)) << 16) |
589                 (((long) (data[offset++] & 0xff)) << 8) |
590                 (((long) (data[offset] & 0xff)) );
591
592             return(8);
593         }
594     }
595     private int readOverFlowId(
596     byte[] data,
597     int offset)
598     {
599         int value = data[offset++];
600
601         if ((value & ~0x3f) == 0)
602         {
603             // length stored in this byte.
604
overflowId = value;
605
606             return(1);
607         }
608         else if ((value & 0x80) == 0)
609         {
610             // length is stored in 2 bytes. only use low 6 bits from 1st byte.
611

612             overflowId = (((value & 0x3f) << 8) | (data[offset] & 0xff));
613
614             return(2);
615         }
616         else
617         {
618             // length is stored in 4 bytes. only use low 7 bits from 1st byte.
619
overflowId =
620                 ((value & 0x7f) << 24) |
621                 ((data[offset++] & 0xff) << 16) |
622                 ((data[offset++] & 0xff) << 8) |
623                 ((data[offset] & 0xff) );
624
625             return(4);
626         }
627     }
628     private int readFirstField(
629     byte[] data,
630     int offset)
631     {
632         int value = data[offset++];
633
634         if ((value & ~0x3f) == 0)
635         {
636             // length stored in this byte.
637
firstField = value;
638
639             return(1);
640         }
641         else if ((value & 0x80) == 0)
642         {
643             // length is stored in 2 bytes. only use low 6 bits from 1st byte.
644

645             firstField = (((value & 0x3f) << 8) | (data[offset] & 0xff));
646
647             return(2);
648         }
649         else
650         {
651             // length is stored in 4 bytes. only use low 7 bits from 1st byte.
652
firstField =
653                 ((value & 0x7f) << 24) |
654                 ((data[offset++] & 0xff) << 16) |
655                 ((data[offset++] & 0xff) << 8) |
656                 ((data[offset] & 0xff) );
657
658             return(4);
659         }
660     }
661     private void readNumberFields(
662     byte[] data,
663     int offset)
664     {
665         int value = data[offset++];
666
667         if ((value & ~0x3f) == 0)
668         {
669             // length stored in this byte.
670
numberFields = value;
671         }
672         else if ((value & 0x80) == 0)
673         {
674             // length is stored in 2 bytes. only use low 6 bits from 1st byte.
675

676             numberFields = (((value & 0x3f) << 8) | (data[offset] & 0xff));
677         }
678         else
679         {
680             // length is stored in 4 bytes. only use low 7 bits from 1st byte.
681
numberFields =
682                 ((value & 0x7f) << 24) |
683                 ((data[offset++] & 0xff) << 16) |
684                 ((data[offset++] & 0xff) << 8) |
685                 ((data[offset] & 0xff) );
686         }
687     }
688
689
690     private void read(
691     byte[] data,
692     int offset)
693     {
694         status = data[offset++];
695
696         int value = data[offset++];
697
698         if ((value & ~0x3f) == 0)
699         {
700             // value stored in this byte.
701
id = value;
702         }
703         else if ((value & 0x80) == 0)
704         {
705             // value is stored in 2 bytes. only use low 6 bits from 1st byte.
706

707             id = (((value & 0x3f) << 8) | (data[offset++] & 0xff));
708         }
709         else
710         {
711             // value is stored in 4 bytes. only use low 7 bits from 1st byte.
712
id =
713                 ((value & 0x7f) << 24) |
714                 ((data[offset++] & 0xff) << 16) |
715                 ((data[offset++] & 0xff) << 8) |
716                 ((data[offset++] & 0xff) );
717         }
718
719         if ((status & (RECORD_OVERFLOW | RECORD_HAS_FIRST_FIELD)) == 0)
720         {
721             // usual case, not a record overflow and does not have first field
722
overflowPage = 0;
723             overflowId = 0;
724             firstField = 0;
725
726             readNumberFields(data, offset);
727         }
728         else if ((status & RECORD_OVERFLOW) == 0)
729         {
730             // not overflow, and has first field set.
731
overflowPage = 0;
732             overflowId = 0;
733
734             offset += readFirstField(data, offset);
735
736             readNumberFields(data, offset);
737         }
738         else
739         {
740             // is an overflow field
741

742             offset += readOverFlowPage(data, offset);
743             offset += readOverFlowId(data, offset);
744
745             if (hasFirstField())
746             {
747                 offset += readFirstField(data, offset);
748                 readNumberFields(data, offset);
749             }
750             else
751             {
752                 firstField = 0;
753                 numberFields = 0;
754             }
755         }
756
757         handle = null;
758
759         return;
760     }
761
762
763     public String JavaDoc toString()
764     {
765         if (SanityManager.DEBUG)
766         {
767             String JavaDoc str = "recordHeader: Id=" + getId();
768             
769             str += "\n isDeleted = " + isDeleted();
770             str += "\n hasOverflow = " + hasOverflow();
771             str += "\n hasFirstField = " + hasFirstField();
772             str += "\n numberFields = " + getNumberFields();
773             str += "\n firstField = " + getFirstField();
774             str += "\n overflowPage = " + getOverflowPage();
775             str += "\n overflowId = " + getOverflowId();
776
777             return str;
778         }
779         else
780         {
781             return null;
782         }
783     }
784 }
785
Popular Tags