1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase;
21
22 import java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.nio.ByteBuffer;
26 import java.util.Comparator;
27
28 import com.google.common.primitives.Longs;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.hadoop.hbase.io.HeapSize;
32 import org.apache.hadoop.hbase.io.hfile.HFile;
33 import org.apache.hadoop.hbase.util.Bytes;
34 import org.apache.hadoop.hbase.util.ClassSize;
35 import org.apache.hadoop.io.RawComparator;
36 import org.apache.hadoop.io.Writable;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class KeyValue implements Writable, HeapSize {
67 static final Log LOG = LogFactory.getLog(KeyValue.class);
68
69
70
71
72 public static final char COLUMN_FAMILY_DELIMITER = ':';
73
74 public static final byte[] COLUMN_FAMILY_DELIM_ARRAY =
75 new byte[]{COLUMN_FAMILY_DELIMITER};
76
77
78
79
80 public static KVComparator COMPARATOR = new KVComparator();
81
82
83
84
85
86 public static KeyComparator KEY_COMPARATOR = new KeyComparator();
87
88
89
90
91
92 public static KVComparator META_COMPARATOR = new MetaComparator();
93
94
95
96
97
98 public static KeyComparator META_KEY_COMPARATOR = new MetaKeyComparator();
99
100
101
102
103
104 public static KVComparator ROOT_COMPARATOR = new RootComparator();
105
106
107
108
109
110 public static KeyComparator ROOT_KEY_COMPARATOR = new RootKeyComparator();
111
112
113
114
115
116
117
118
119
120
121 public static KeyComparator getRowComparator(byte [] tableName) {
122 if(Bytes.equals(HTableDescriptor.ROOT_TABLEDESC.getName(),tableName)) {
123 return ROOT_COMPARATOR.getRawComparator();
124 }
125 if(Bytes.equals(HTableDescriptor.META_TABLEDESC.getName(), tableName)) {
126 return META_COMPARATOR.getRawComparator();
127 }
128 return COMPARATOR.getRawComparator();
129 }
130
131
132 public static final int TIMESTAMP_TYPE_SIZE =
133 Bytes.SIZEOF_LONG
134 Bytes.SIZEOF_BYTE
135
136
137 public static final int KEY_INFRASTRUCTURE_SIZE =
138 Bytes.SIZEOF_SHORT
139 Bytes.SIZEOF_BYTE
140 TIMESTAMP_TYPE_SIZE;
141
142
143
144 public static final int ROW_OFFSET =
145 Bytes.SIZEOF_INT
146 Bytes.SIZEOF_INT
147
148
149 public static final int KEYVALUE_INFRASTRUCTURE_SIZE = ROW_OFFSET;
150
151
152
153
154
155
156 public static enum Type {
157 Minimum((byte)0),
158 Put((byte)4),
159
160 Delete((byte)8),
161 DeleteColumn((byte)12),
162 DeleteFamily((byte)14),
163
164
165 Maximum((byte)255);
166
167 private final byte code;
168
169 Type(final byte c) {
170 this.code = c;
171 }
172
173 public byte getCode() {
174 return this.code;
175 }
176
177
178
179
180
181
182
183 public static Type codeToType(final byte b) {
184 for (Type t : Type.values()) {
185 if (t.getCode() == b) {
186 return t;
187 }
188 }
189 throw new RuntimeException("Unknown code " + b);
190 }
191 }
192
193
194
195
196
197
198 public static final KeyValue LOWESTKEY =
199 new KeyValue(HConstants.EMPTY_BYTE_ARRAY, HConstants.LATEST_TIMESTAMP);
200
201 private byte [] bytes = null;
202 private int offset = 0;
203 private int length = 0;
204
205
206 private byte [] rowCache = null;
207
208
209
210
211
212 public long getMemstoreTS() {
213 return memstoreTS;
214 }
215
216 public void setMemstoreTS(long memstoreTS) {
217 this.memstoreTS = memstoreTS;
218 }
219
220
221 private long memstoreTS = 0;
222
223
224
225
226
227 public KeyValue() {}
228
229
230
231
232
233
234 public KeyValue(final byte [] bytes) {
235 this(bytes, 0);
236 }
237
238
239
240
241
242
243
244
245 public KeyValue(final byte [] bytes, final int offset) {
246 this(bytes, offset, getLength(bytes, offset));
247 }
248
249
250
251
252
253
254
255
256 public KeyValue(final byte [] bytes, final int offset, final int length) {
257 this.bytes = bytes;
258 this.offset = offset;
259 this.length = length;
260 }
261
262
263
264
265
266
267
268
269
270 public KeyValue(final byte [] row, final long timestamp) {
271 this(row, timestamp, Type.Maximum);
272 }
273
274
275
276
277
278
279 public KeyValue(final byte [] row, final long timestamp, Type type) {
280 this(row, null, null, timestamp, type, null);
281 }
282
283
284
285
286
287
288
289
290 public KeyValue(final byte [] row, final byte [] family,
291 final byte [] qualifier) {
292 this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Maximum);
293 }
294
295
296
297
298
299
300
301 public KeyValue(final byte [] row, final byte [] family,
302 final byte [] qualifier, final byte [] value) {
303 this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Put, value);
304 }
305
306
307
308
309
310
311
312
313
314
315 public KeyValue(final byte[] row, final byte[] family,
316 final byte[] qualifier, final long timestamp, Type type) {
317 this(row, family, qualifier, timestamp, type, null);
318 }
319
320
321
322
323
324
325
326
327
328
329 public KeyValue(final byte[] row, final byte[] family,
330 final byte[] qualifier, final long timestamp, final byte[] value) {
331 this(row, family, qualifier, timestamp, Type.Put, value);
332 }
333
334
335
336
337
338
339
340
341
342
343
344 public KeyValue(final byte[] row, final byte[] family,
345 final byte[] qualifier, final long timestamp, Type type,
346 final byte[] value) {
347 this(row, family, qualifier, 0, qualifier==null ? 0 : qualifier.length,
348 timestamp, type, value, 0, value==null ? 0 : value.length);
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365 public KeyValue(byte [] row, byte [] family,
366 byte [] qualifier, int qoffset, int qlength, long timestamp, Type type,
367 byte [] value, int voffset, int vlength) {
368 this(row, 0, row==null ? 0 : row.length,
369 family, 0, family==null ? 0 : family.length,
370 qualifier, qoffset, qlength, timestamp, type,
371 value, voffset, vlength);
372 }
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394 public KeyValue(final byte [] row, final int roffset, final int rlength,
395 final byte [] family, final int foffset, final int flength,
396 final byte [] qualifier, final int qoffset, final int qlength,
397 final long timestamp, final Type type,
398 final byte [] value, final int voffset, final int vlength) {
399 this.bytes = createByteArray(row, roffset, rlength,
400 family, foffset, flength, qualifier, qoffset, qlength,
401 timestamp, type, value, voffset, vlength);
402 this.length = bytes.length;
403 this.offset = 0;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425 static byte [] createByteArray(final byte [] row, final int roffset,
426 final int rlength, final byte [] family, final int foffset, int flength,
427 final byte [] qualifier, final int qoffset, int qlength,
428 final long timestamp, final Type type,
429 final byte [] value, final int voffset, int vlength) {
430 if (rlength > Short.MAX_VALUE) {
431 throw new IllegalArgumentException("Row > " + Short.MAX_VALUE);
432 }
433 if (row == null) {
434 throw new IllegalArgumentException("Row is null");
435 }
436
437 flength = family == null ? 0 : flength;
438 if (flength > Byte.MAX_VALUE) {
439 throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
440 }
441
442 qlength = qualifier == null ? 0 : qlength;
443 if (qlength > Integer.MAX_VALUE - rlength - flength) {
444 throw new IllegalArgumentException("Qualifier > " + Integer.MAX_VALUE);
445 }
446
447 long longkeylength = KEY_INFRASTRUCTURE_SIZE + rlength + flength + qlength;
448 if (longkeylength > Integer.MAX_VALUE) {
449 throw new IllegalArgumentException("keylength " + longkeylength + " > " +
450 Integer.MAX_VALUE);
451 }
452 int keylength = (int)longkeylength;
453
454 vlength = value == null? 0 : vlength;
455 if (vlength > HConstants.MAXIMUM_VALUE_LENGTH) {
456 throw new IllegalArgumentException("Valuer > " +
457 HConstants.MAXIMUM_VALUE_LENGTH);
458 }
459
460
461 byte [] bytes = new byte[KEYVALUE_INFRASTRUCTURE_SIZE + keylength + vlength];
462
463 int pos = 0;
464 pos = Bytes.putInt(bytes, pos, keylength);
465 pos = Bytes.putInt(bytes, pos, vlength);
466 pos = Bytes.putShort(bytes, pos, (short)(rlength & 0x0000ffff));
467 pos = Bytes.putBytes(bytes, pos, row, roffset, rlength);
468 pos = Bytes.putByte(bytes, pos, (byte)(flength & 0x0000ff));
469 if(flength != 0) {
470 pos = Bytes.putBytes(bytes, pos, family, foffset, flength);
471 }
472 if(qlength != 0) {
473 pos = Bytes.putBytes(bytes, pos, qualifier, qoffset, qlength);
474 }
475 pos = Bytes.putLong(bytes, pos, timestamp);
476 pos = Bytes.putByte(bytes, pos, type.getCode());
477 if (value != null && value.length > 0) {
478 pos = Bytes.putBytes(bytes, pos, value, voffset, vlength);
479 }
480 return bytes;
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500 static byte [] createByteArray(final byte [] row, final int roffset,
501 final int rlength,
502 final byte [] column, final int coffset, int clength,
503 final long timestamp, final Type type,
504 final byte [] value, final int voffset, int vlength) {
505
506 int delimiteroffset = 0;
507 if (column != null && column.length > 0) {
508 delimiteroffset = getFamilyDelimiterIndex(column, coffset, clength);
509 if (delimiteroffset > Byte.MAX_VALUE) {
510 throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
511 }
512 } else {
513 return createByteArray(row,roffset,rlength,null,0,0,null,0,0,timestamp,
514 type,value,voffset,vlength);
515 }
516 int flength = delimiteroffset-coffset;
517 int qlength = clength - flength - 1;
518 return createByteArray(row, roffset, rlength, column, coffset,
519 flength, column, delimiteroffset+1, qlength, timestamp, type,
520 value, voffset, vlength);
521 }
522
523
524
525 public boolean equals(Object other) {
526 if (!(other instanceof KeyValue)) {
527 return false;
528 }
529 KeyValue kv = (KeyValue)other;
530
531
532 boolean result = Bytes.BYTES_RAWCOMPARATOR.compare(getBuffer(),
533 getKeyOffset(), getKeyLength(),
534 kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength()) == 0;
535 return result;
536 }
537
538 public int hashCode() {
539 byte[] b = getBuffer();
540 int start = getOffset(), end = getOffset() + getLength();
541 int h = b[start++];
542 for (int i = start; i < end; i++) {
543 h = (h * 13) ^ b[i];
544 }
545 return h;
546 }
547
548
549
550
551
552
553
554
555
556
557
558 public KeyValue clone() {
559 byte [] b = new byte[this.length];
560 System.arraycopy(this.bytes, this.offset, b, 0, this.length);
561 KeyValue ret = new KeyValue(b, 0, b.length);
562
563
564
565 ret.setMemstoreTS(memstoreTS);
566 return ret;
567 }
568
569
570
571
572
573
574
575 public String toString() {
576 if (this.bytes == null || this.bytes.length == 0) {
577 return "empty";
578 }
579 return keyToString(this.bytes, this.offset + ROW_OFFSET, getKeyLength()) +
580 "/vlen=" + getValueLength();
581 }
582
583
584
585
586
587 public static String keyToString(final byte [] k) {
588 return keyToString(k, 0, k.length);
589 }
590
591
592
593
594
595
596
597
598 public static String keyToString(final byte [] b, final int o, final int l) {
599 if (b == null) return "";
600 int rowlength = Bytes.toShort(b, o);
601 String row = Bytes.toStringBinary(b, o + Bytes.SIZEOF_SHORT, rowlength);
602 int columnoffset = o + Bytes.SIZEOF_SHORT + 1 + rowlength;
603 int familylength = b[columnoffset - 1];
604 int columnlength = l - ((columnoffset - o) + TIMESTAMP_TYPE_SIZE);
605 String family = familylength == 0? "":
606 Bytes.toStringBinary(b, columnoffset, familylength);
607 String qualifier = columnlength == 0? "":
608 Bytes.toStringBinary(b, columnoffset + familylength,
609 columnlength - familylength);
610 long timestamp = Bytes.toLong(b, o + (l - TIMESTAMP_TYPE_SIZE));
611 byte type = b[o + l - 1];
612
613
614
615 return row + "/" + family +
616 (family != null && family.length() > 0? ":" :"") +
617 qualifier + "/" + timestamp + "/" + Type.codeToType(type);
618 }
619
620
621
622
623
624
625
626
627
628
629 public byte [] getBuffer() {
630 return this.bytes;
631 }
632
633
634
635
636 public int getOffset() {
637 return this.offset;
638 }
639
640
641
642
643 public int getLength() {
644 return length;
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660 private static int getLength(byte [] bytes, int offset) {
661 return (2 * Bytes.SIZEOF_INT) +
662 Bytes.toInt(bytes, offset) +
663 Bytes.toInt(bytes, offset + Bytes.SIZEOF_INT);
664 }
665
666
667
668
669 public int getKeyOffset() {
670 return this.offset + ROW_OFFSET;
671 }
672
673 public String getKeyString() {
674 return Bytes.toStringBinary(getBuffer(), getKeyOffset(), getKeyLength());
675 }
676
677
678
679
680 private int keyLength = 0;
681
682 public int getKeyLength() {
683 if (keyLength == 0) {
684 keyLength = Bytes.toInt(this.bytes, this.offset);
685 }
686 return keyLength;
687 }
688
689
690
691
692 public int getValueOffset() {
693 return getKeyOffset() + getKeyLength();
694 }
695
696
697
698
699 public int getValueLength() {
700 return Bytes.toInt(this.bytes, this.offset + Bytes.SIZEOF_INT);
701 }
702
703
704
705
706 public int getRowOffset() {
707 return getKeyOffset() + Bytes.SIZEOF_SHORT;
708 }
709
710
711
712
713 public short getRowLength() {
714 return Bytes.toShort(this.bytes, getKeyOffset());
715 }
716
717
718
719
720 public int getFamilyOffset() {
721 return getFamilyOffset(getRowLength());
722 }
723
724
725
726
727 public int getFamilyOffset(int rlength) {
728 return this.offset + ROW_OFFSET + Bytes.SIZEOF_SHORT + rlength + Bytes.SIZEOF_BYTE;
729 }
730
731
732
733
734 public byte getFamilyLength() {
735 return getFamilyLength(getFamilyOffset());
736 }
737
738
739
740
741 public byte getFamilyLength(int foffset) {
742 return this.bytes[foffset-1];
743 }
744
745
746
747
748 public int getQualifierOffset() {
749 return getQualifierOffset(getFamilyOffset());
750 }
751
752
753
754
755 public int getQualifierOffset(int foffset) {
756 return foffset + getFamilyLength(foffset);
757 }
758
759
760
761
762 public int getQualifierLength() {
763 return getQualifierLength(getRowLength(),getFamilyLength());
764 }
765
766
767
768
769 public int getQualifierLength(int rlength, int flength) {
770 return getKeyLength() -
771 (KEY_INFRASTRUCTURE_SIZE + rlength + flength);
772 }
773
774
775
776
777 public int getTotalColumnLength() {
778 int rlength = getRowLength();
779 int foffset = getFamilyOffset(rlength);
780 return getTotalColumnLength(rlength,foffset);
781 }
782
783
784
785
786 public int getTotalColumnLength(int rlength, int foffset) {
787 int flength = getFamilyLength(foffset);
788 int qlength = getQualifierLength(rlength,flength);
789 return flength + qlength;
790 }
791
792
793
794
795 public int getTimestampOffset() {
796 return getTimestampOffset(getKeyLength());
797 }
798
799
800
801
802
803 public int getTimestampOffset(final int keylength) {
804 return getKeyOffset() + keylength - TIMESTAMP_TYPE_SIZE;
805 }
806
807
808
809
810 public boolean isLatestTimestamp() {
811 return Bytes.compareTo(getBuffer(), getTimestampOffset(), Bytes.SIZEOF_LONG,
812 HConstants.LATEST_TIMESTAMP_BYTES, 0, Bytes.SIZEOF_LONG) == 0;
813 }
814
815
816
817
818
819
820 public boolean updateLatestStamp(final byte [] now) {
821 if (this.isLatestTimestamp()) {
822 int tsOffset = getTimestampOffset();
823 System.arraycopy(now, 0, this.bytes, tsOffset, Bytes.SIZEOF_LONG);
824 return true;
825 }
826 return false;
827 }
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842 public byte [] getKey() {
843 int keylength = getKeyLength();
844 byte [] key = new byte[keylength];
845 System.arraycopy(getBuffer(), getKeyOffset(), key, 0, keylength);
846 return key;
847 }
848
849
850
851
852
853
854
855
856 public byte [] getValue() {
857 int o = getValueOffset();
858 int l = getValueLength();
859 byte [] result = new byte[l];
860 System.arraycopy(getBuffer(), o, result, 0, l);
861 return result;
862 }
863
864
865
866
867
868
869
870
871
872 public byte [] getRow() {
873 if (rowCache == null) {
874 int o = getRowOffset();
875 short l = getRowLength();
876 rowCache = new byte[l];
877 System.arraycopy(getBuffer(), o, rowCache, 0, l);
878 }
879 return rowCache;
880 }
881
882
883
884
885
886 private long timestampCache = -1;
887 public long getTimestamp() {
888 if (timestampCache == -1) {
889 timestampCache = getTimestamp(getKeyLength());
890 }
891 return timestampCache;
892 }
893
894
895
896
897
898 long getTimestamp(final int keylength) {
899 int tsOffset = getTimestampOffset(keylength);
900 return Bytes.toLong(this.bytes, tsOffset);
901 }
902
903
904
905
906 public byte getType() {
907 return getType(getKeyLength());
908 }
909
910
911
912
913
914 byte getType(final int keylength) {
915 return this.bytes[this.offset + keylength - 1 + ROW_OFFSET];
916 }
917
918
919
920
921
922
923 public boolean isDelete() {
924 int t = getType();
925 return Type.Delete.getCode() <= t && t <= Type.DeleteFamily.getCode();
926 }
927
928
929
930
931 public boolean isDeleteType() {
932 return getType() == Type.Delete.getCode();
933 }
934
935
936
937
938 public boolean isDeleteFamily() {
939 return getType() == Type.DeleteFamily.getCode();
940 }
941
942
943
944
945
946 public boolean isDeleteColumnOrFamily() {
947 int t = getType();
948 return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode();
949 }
950
951
952
953
954
955
956
957
958
959 public byte [] getFamily() {
960 int o = getFamilyOffset();
961 int l = getFamilyLength(o);
962 byte [] result = new byte[l];
963 System.arraycopy(this.bytes, o, result, 0, l);
964 return result;
965 }
966
967
968
969
970
971
972
973
974
975
976 public byte [] getQualifier() {
977 int o = getQualifierOffset();
978 int l = getQualifierLength();
979 byte [] result = new byte[l];
980 System.arraycopy(this.bytes, o, result, 0, l);
981 return result;
982 }
983
984
985
986
987
988
989
990
991
992
993
994
995 public static class SplitKeyValue {
996 private byte [][] split;
997 SplitKeyValue() {
998 this.split = new byte[6][];
999 }
1000 public void setRow(byte [] value) { this.split[0] = value; }
1001 public void setFamily(byte [] value) { this.split[1] = value; }
1002 public void setQualifier(byte [] value) { this.split[2] = value; }
1003 public void setTimestamp(byte [] value) { this.split[3] = value; }
1004 public void setType(byte [] value) { this.split[4] = value; }
1005 public void setValue(byte [] value) { this.split[5] = value; }
1006 public byte [] getRow() { return this.split[0]; }
1007 public byte [] getFamily() { return this.split[1]; }
1008 public byte [] getQualifier() { return this.split[2]; }
1009 public byte [] getTimestamp() { return this.split[3]; }
1010 public byte [] getType() { return this.split[4]; }
1011 public byte [] getValue() { return this.split[5]; }
1012 }
1013
1014 public SplitKeyValue split() {
1015 SplitKeyValue split = new SplitKeyValue();
1016 int splitOffset = this.offset;
1017 int keyLen = Bytes.toInt(bytes, splitOffset);
1018 splitOffset += Bytes.SIZEOF_INT;
1019 int valLen = Bytes.toInt(bytes, splitOffset);
1020 splitOffset += Bytes.SIZEOF_INT;
1021 short rowLen = Bytes.toShort(bytes, splitOffset);
1022 splitOffset += Bytes.SIZEOF_SHORT;
1023 byte [] row = new byte[rowLen];
1024 System.arraycopy(bytes, splitOffset, row, 0, rowLen);
1025 splitOffset += rowLen;
1026 split.setRow(row);
1027 byte famLen = bytes[splitOffset];
1028 splitOffset += Bytes.SIZEOF_BYTE;
1029 byte [] family = new byte[famLen];
1030 System.arraycopy(bytes, splitOffset, family, 0, famLen);
1031 splitOffset += famLen;
1032 split.setFamily(family);
1033 int colLen = keyLen -
1034 (rowLen + famLen + Bytes.SIZEOF_SHORT + Bytes.SIZEOF_BYTE +
1035 Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE);
1036 byte [] qualifier = new byte[colLen];
1037 System.arraycopy(bytes, splitOffset, qualifier, 0, colLen);
1038 splitOffset += colLen;
1039 split.setQualifier(qualifier);
1040 byte [] timestamp = new byte[Bytes.SIZEOF_LONG];
1041 System.arraycopy(bytes, splitOffset, timestamp, 0, Bytes.SIZEOF_LONG);
1042 splitOffset += Bytes.SIZEOF_LONG;
1043 split.setTimestamp(timestamp);
1044 byte [] type = new byte[1];
1045 type[0] = bytes[splitOffset];
1046 splitOffset += Bytes.SIZEOF_BYTE;
1047 split.setType(type);
1048 byte [] value = new byte[valLen];
1049 System.arraycopy(bytes, splitOffset, value, 0, valLen);
1050 split.setValue(value);
1051 return split;
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 public boolean matchingFamily(final byte [] family) {
1065 return matchingFamily(family, 0, family.length);
1066 }
1067
1068 public boolean matchingFamily(final byte[] family, int offset, int length) {
1069 if (this.length == 0 || this.bytes.length == 0) {
1070 return false;
1071 }
1072 return Bytes.compareTo(family, offset, length,
1073 this.bytes, getFamilyOffset(), getFamilyLength()) == 0;
1074 }
1075
1076 public boolean matchingFamily(final KeyValue other) {
1077 return matchingFamily(other.getBuffer(), other.getFamilyOffset(),
1078 other.getFamilyLength());
1079 }
1080
1081
1082
1083
1084
1085 public boolean matchingQualifier(final byte [] qualifier) {
1086 return matchingQualifier(qualifier, 0, qualifier.length);
1087 }
1088
1089 public boolean matchingQualifier(final byte [] qualifier, int offset, int length) {
1090 return Bytes.compareTo(qualifier, offset, length,
1091 this.bytes, getQualifierOffset(), getQualifierLength()) == 0;
1092 }
1093
1094 public boolean matchingQualifier(final KeyValue other) {
1095 return matchingQualifier(other.getBuffer(), other.getQualifierOffset(),
1096 other.getQualifierLength());
1097 }
1098
1099 public boolean matchingRow(final byte [] row) {
1100 return matchingRow(row, 0, row.length);
1101 }
1102
1103 public boolean matchingRow(final byte[] row, int offset, int length) {
1104 return Bytes.compareTo(row, offset, length,
1105 this.bytes, getRowOffset(), getRowLength()) == 0;
1106 }
1107
1108 public boolean matchingRow(KeyValue other) {
1109 return matchingRow(other.getBuffer(), other.getRowOffset(),
1110 other.getRowLength());
1111 }
1112
1113
1114
1115
1116
1117 public boolean matchingColumnNoDelimiter(final byte [] column) {
1118 int rl = getRowLength();
1119 int o = getFamilyOffset(rl);
1120 int fl = getFamilyLength(o);
1121 int l = fl + getQualifierLength(rl,fl);
1122 return Bytes.compareTo(column, 0, column.length, this.bytes, o, l) == 0;
1123 }
1124
1125
1126
1127
1128
1129
1130
1131 public boolean matchingColumn(final byte[] family, final byte[] qualifier) {
1132 int rl = getRowLength();
1133 int o = getFamilyOffset(rl);
1134 int fl = getFamilyLength(o);
1135 int ql = getQualifierLength(rl,fl);
1136 if (Bytes.compareTo(family, 0, family.length, this.bytes, o, family.length)
1137 != 0) {
1138 return false;
1139 }
1140 if (qualifier == null || qualifier.length == 0) {
1141 if (ql == 0) {
1142 return true;
1143 }
1144 return false;
1145 }
1146 return Bytes.compareTo(qualifier, 0, qualifier.length,
1147 this.bytes, o + fl, ql) == 0;
1148 }
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 static int compareColumns(final byte [] left, final int loffset,
1162 final int llength, final int lfamilylength,
1163 final byte [] right, final int roffset, final int rlength,
1164 final int rfamilylength) {
1165
1166 int diff = Bytes.compareTo(left, loffset, lfamilylength,
1167 right, roffset, rfamilylength);
1168 if (diff != 0) {
1169 return diff;
1170 }
1171
1172 return Bytes.compareTo(left, loffset + lfamilylength,
1173 llength - lfamilylength,
1174 right, roffset + rfamilylength, rlength - rfamilylength);
1175 }
1176
1177
1178
1179
1180 public boolean nonNullRowAndColumn() {
1181 return getRowLength() > 0 && !isEmptyColumn();
1182 }
1183
1184
1185
1186
1187 public boolean isEmptyColumn() {
1188 return getQualifierLength() == 0;
1189 }
1190
1191
1192
1193
1194
1195
1196
1197
1198 public static byte [][] parseColumn(byte [] c) {
1199 final int index = getDelimiter(c, 0, c.length, COLUMN_FAMILY_DELIMITER);
1200 if (index == -1) {
1201
1202 return new byte [][] { c };
1203 } else if(index == c.length - 1) {
1204
1205 byte [] family = new byte[c.length-1];
1206 System.arraycopy(c, 0, family, 0, family.length);
1207 return new byte [][] { family };
1208 }
1209
1210 final byte [][] result = new byte [2][];
1211 result[0] = new byte [index];
1212 System.arraycopy(c, 0, result[0], 0, index);
1213 final int len = c.length - (index + 1);
1214 result[1] = new byte[len];
1215 System.arraycopy(c, index + 1
1216 len);
1217 return result;
1218 }
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228 public static byte [] makeColumn(byte [] family, byte [] qualifier) {
1229 return Bytes.add(family, COLUMN_FAMILY_DELIM_ARRAY, qualifier);
1230 }
1231
1232
1233
1234
1235
1236
1237 public static int getFamilyDelimiterIndex(final byte [] b, final int offset,
1238 final int length) {
1239 return getRequiredDelimiter(b, offset, length, COLUMN_FAMILY_DELIMITER);
1240 }
1241
1242 private static int getRequiredDelimiter(final byte [] b,
1243 final int offset, final int length, final int delimiter) {
1244 int index = getDelimiter(b, offset, length, delimiter);
1245 if (index < 0) {
1246 throw new IllegalArgumentException("No " + (char)delimiter + " in <" +
1247 Bytes.toString(b) + ">" + ", length=" + length + ", offset=" + offset);
1248 }
1249 return index;
1250 }
1251
1252 static int getRequiredDelimiterInReverse(final byte [] b,
1253 final int offset, final int length, final int delimiter) {
1254 int index = getDelimiterInReverse(b, offset, length, delimiter);
1255 if (index < 0) {
1256 throw new IllegalArgumentException("No " + delimiter + " in <" +
1257 Bytes.toString(b) + ">" + ", length=" + length + ", offset=" + offset);
1258 }
1259 return index;
1260 }
1261
1262
1263
1264
1265
1266
1267
1268 public static int getDelimiter(final byte [] b, int offset, final int length,
1269 final int delimiter) {
1270 if (b == null) {
1271 throw new NullPointerException();
1272 }
1273 int result = -1;
1274 for (int i = offset; i < length + offset; i++) {
1275 if (b[i] == delimiter) {
1276 result = i;
1277 break;
1278 }
1279 }
1280 return result;
1281 }
1282
1283
1284
1285
1286
1287
1288
1289 public static int getDelimiterInReverse(final byte [] b, final int offset,
1290 final int length, final int delimiter) {
1291 if (b == null) {
1292 throw new NullPointerException();
1293 }
1294 int result = -1;
1295 for (int i = (offset + length) - 1; i >= offset; i--) {
1296 if (b[i] == delimiter) {
1297 result = i;
1298 break;
1299 }
1300 }
1301 return result;
1302 }
1303
1304
1305
1306
1307
1308 public static class RootComparator extends MetaComparator {
1309 private final KeyComparator rawcomparator = new RootKeyComparator();
1310
1311 public KeyComparator getRawComparator() {
1312 return this.rawcomparator;
1313 }
1314
1315 @Override
1316 protected Object clone() throws CloneNotSupportedException {
1317 return new RootComparator();
1318 }
1319 }
1320
1321
1322
1323
1324
1325 public static class MetaComparator extends KVComparator {
1326 private final KeyComparator rawcomparator = new MetaKeyComparator();
1327
1328 public KeyComparator getRawComparator() {
1329 return this.rawcomparator;
1330 }
1331
1332 @Override
1333 protected Object clone() throws CloneNotSupportedException {
1334 return new MetaComparator();
1335 }
1336 }
1337
1338
1339
1340
1341
1342
1343
1344 public static class KVComparator implements java.util.Comparator<KeyValue> {
1345 private final KeyComparator rawcomparator = new KeyComparator();
1346
1347
1348
1349
1350
1351 public KeyComparator getRawComparator() {
1352 return this.rawcomparator;
1353 }
1354
1355 public int compare(final KeyValue left, final KeyValue right) {
1356 int ret = getRawComparator().compare(left.getBuffer(),
1357 left.getOffset() + ROW_OFFSET, left.getKeyLength(),
1358 right.getBuffer(), right.getOffset() + ROW_OFFSET,
1359 right.getKeyLength());
1360 if (ret != 0) return ret;
1361
1362 return -Longs.compare(left.getMemstoreTS(), right.getMemstoreTS());
1363 }
1364
1365 public int compareTimestamps(final KeyValue left, final KeyValue right) {
1366 return compareTimestamps(left, left.getKeyLength(), right,
1367 right.getKeyLength());
1368 }
1369
1370 int compareTimestamps(final KeyValue left, final int lkeylength,
1371 final KeyValue right, final int rkeylength) {
1372
1373 long ltimestamp = left.getTimestamp(lkeylength);
1374 long rtimestamp = right.getTimestamp(rkeylength);
1375 return getRawComparator().compareTimestamps(ltimestamp, rtimestamp);
1376 }
1377
1378
1379
1380
1381
1382
1383 public int compareRows(final KeyValue left, final KeyValue right) {
1384 return compareRows(left, left.getRowLength(), right,
1385 right.getRowLength());
1386 }
1387
1388
1389
1390
1391
1392
1393
1394
1395 public int compareRows(final KeyValue left, final short lrowlength,
1396 final KeyValue right, final short rrowlength) {
1397 return getRawComparator().compareRows(left.getBuffer(),
1398 left.getRowOffset(), lrowlength,
1399 right.getBuffer(), right.getRowOffset(), rrowlength);
1400 }
1401
1402
1403
1404
1405
1406
1407 public int compareRows(final KeyValue left, final byte [] row) {
1408 return getRawComparator().compareRows(left.getBuffer(),
1409 left.getRowOffset(), left.getRowLength(), row, 0, row.length);
1410 }
1411
1412 public int compareRows(byte [] left, int loffset, int llength,
1413 byte [] right, int roffset, int rlength) {
1414 return getRawComparator().compareRows(left, loffset, llength,
1415 right, roffset, rlength);
1416 }
1417
1418 public int compareColumns(final KeyValue left, final byte [] right,
1419 final int roffset, final int rlength, final int rfamilyoffset) {
1420 int offset = left.getFamilyOffset();
1421 int length = left.getFamilyLength() + left.getQualifierLength();
1422 return getRawComparator().compareColumns(left.getBuffer(), offset, length,
1423 left.getFamilyLength(offset),
1424 right, roffset, rlength, rfamilyoffset);
1425 }
1426
1427 int compareColumns(final KeyValue left, final short lrowlength,
1428 final KeyValue right, final short rrowlength) {
1429 int lfoffset = left.getFamilyOffset(lrowlength);
1430 int rfoffset = right.getFamilyOffset(rrowlength);
1431 int lclength = left.getTotalColumnLength(lrowlength,lfoffset);
1432 int rclength = right.getTotalColumnLength(rrowlength, rfoffset);
1433 int lfamilylength = left.getFamilyLength(lfoffset);
1434 int rfamilylength = right.getFamilyLength(rfoffset);
1435 return getRawComparator().compareColumns(left.getBuffer(), lfoffset,
1436 lclength, lfamilylength,
1437 right.getBuffer(), rfoffset, rclength, rfamilylength);
1438 }
1439
1440
1441
1442
1443
1444
1445
1446 public boolean matchingRowColumn(final KeyValue left,
1447 final KeyValue right) {
1448 short lrowlength = left.getRowLength();
1449 short rrowlength = right.getRowLength();
1450
1451 return left.getTimestampOffset() == right.getTimestampOffset() &&
1452 matchingRows(left, lrowlength, right, rrowlength) &&
1453 compareColumns(left, lrowlength, right, rrowlength) == 0;
1454 }
1455
1456
1457
1458
1459
1460
1461 public boolean matchingRows(final KeyValue left, final byte [] right) {
1462 return compareRows(left, right) == 0;
1463 }
1464
1465
1466
1467
1468
1469
1470
1471 public boolean matchingRows(final KeyValue left, final KeyValue right) {
1472 short lrowlength = left.getRowLength();
1473 short rrowlength = right.getRowLength();
1474 return matchingRows(left, lrowlength, right, rrowlength);
1475 }
1476
1477
1478
1479
1480
1481
1482
1483
1484 public boolean matchingRows(final KeyValue left, final short lrowlength,
1485 final KeyValue right, final short rrowlength) {
1486 return lrowlength == rrowlength &&
1487 compareRows(left, lrowlength, right, rrowlength) == 0;
1488 }
1489
1490 public boolean matchingRows(final byte [] left, final int loffset,
1491 final int llength,
1492 final byte [] right, final int roffset, final int rlength) {
1493 int compare = compareRows(left, loffset, llength,
1494 right, roffset, rlength);
1495 if (compare != 0) {
1496 return false;
1497 }
1498 return true;
1499 }
1500
1501
1502
1503
1504
1505
1506
1507
1508 public boolean matchingRowsGreaterTimestamp(final KeyValue left,
1509 final KeyValue right) {
1510 short lrowlength = left.getRowLength();
1511 short rrowlength = right.getRowLength();
1512 if (!matchingRows(left, lrowlength, right, rrowlength)) {
1513 return false;
1514 }
1515 return left.getTimestamp() >= right.getTimestamp();
1516 }
1517
1518 @Override
1519 protected Object clone() throws CloneNotSupportedException {
1520 return new KVComparator();
1521 }
1522
1523
1524
1525
1526 public KVComparator getComparatorIgnoringTimestamps() {
1527 KVComparator c = null;
1528 try {
1529 c = (KVComparator)this.clone();
1530 c.getRawComparator().ignoreTimestamp = true;
1531 } catch (CloneNotSupportedException e) {
1532 LOG.error("Not supported", e);
1533 }
1534 return c;
1535 }
1536
1537
1538
1539
1540 public KVComparator getComparatorIgnoringType() {
1541 KVComparator c = null;
1542 try {
1543 c = (KVComparator)this.clone();
1544 c.getRawComparator().ignoreType = true;
1545 } catch (CloneNotSupportedException e) {
1546 LOG.error("Not supported", e);
1547 }
1548 return c;
1549 }
1550 }
1551
1552
1553
1554
1555
1556
1557
1558
1559 public static KeyValue createLastOnRow(final byte[] row) {
1560 return new KeyValue(row, null, null, HConstants.LATEST_TIMESTAMP, Type.Minimum);
1561 }
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571 public static KeyValue createFirstOnRow(final byte [] row) {
1572 return createFirstOnRow(row, HConstants.LATEST_TIMESTAMP);
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582 public static KeyValue createFirstOnRow(final byte [] row,
1583 final long ts) {
1584 return new KeyValue(row, null, null, ts, Type.Maximum);
1585 }
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595 public static KeyValue createFirstOnRow(final byte [] row, final byte [] c,
1596 final long ts) {
1597 byte [][] split = parseColumn(c);
1598 return new KeyValue(row, split[0], split[1], ts, Type.Maximum);
1599 }
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610 public static KeyValue createFirstOnRow(final byte [] row, final byte [] family,
1611 final byte [] qualifier) {
1612 return new KeyValue(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Maximum);
1613 }
1614
1615
1616
1617
1618
1619
1620
1621
1622 public static KeyValue createFirstOnRow(final byte [] row, final byte [] f,
1623 final byte [] q, final long ts) {
1624 return new KeyValue(row, f, q, ts, Type.Maximum);
1625 }
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643 public static KeyValue createFirstOnRow(final byte [] row,
1644 final int roffset, final int rlength, final byte [] family,
1645 final int foffset, final int flength, final byte [] qualifier,
1646 final int qoffset, final int qlength) {
1647 return new KeyValue(row, roffset, rlength, family,
1648 foffset, flength, qualifier, qoffset, qlength,
1649 HConstants.LATEST_TIMESTAMP, Type.Maximum, null, 0, 0);
1650 }
1651
1652
1653
1654
1655
1656
1657 public static KeyValue createKeyValueFromKey(final byte [] b) {
1658 return createKeyValueFromKey(b, 0, b.length);
1659 }
1660
1661
1662
1663
1664
1665
1666 public static KeyValue createKeyValueFromKey(final ByteBuffer bb) {
1667 return createKeyValueFromKey(bb.array(), bb.arrayOffset(), bb.limit());
1668 }
1669
1670
1671
1672
1673
1674
1675
1676
1677 public static KeyValue createKeyValueFromKey(final byte [] b, final int o,
1678 final int l) {
1679 byte [] newb = new byte[b.length + ROW_OFFSET];
1680 System.arraycopy(b, o, newb, ROW_OFFSET, l);
1681 Bytes.putInt(newb, 0, b.length);
1682 Bytes.putInt(newb, Bytes.SIZEOF_INT, 0);
1683 return new KeyValue(newb);
1684 }
1685
1686
1687
1688
1689
1690 public static class RootKeyComparator extends MetaKeyComparator {
1691 public int compareRows(byte [] left, int loffset, int llength,
1692 byte [] right, int roffset, int rlength) {
1693
1694
1695
1696 final int metalength = 7;
1697 int lmetaOffsetPlusDelimiter = loffset + metalength;
1698 int leftFarDelimiter = getDelimiterInReverse(left,
1699 lmetaOffsetPlusDelimiter,
1700 llength - metalength, HRegionInfo.DELIMITER);
1701 int rmetaOffsetPlusDelimiter = roffset + metalength;
1702 int rightFarDelimiter = getDelimiterInReverse(right,
1703 rmetaOffsetPlusDelimiter, rlength - metalength,
1704 HRegionInfo.DELIMITER);
1705 if (leftFarDelimiter < 0 && rightFarDelimiter >= 0) {
1706
1707 return -1;
1708 } else if (rightFarDelimiter < 0 && leftFarDelimiter >= 0) {
1709 return 1;
1710 } else if (leftFarDelimiter < 0 && rightFarDelimiter < 0) {
1711 return 0;
1712 }
1713 int result = super.compareRows(left, lmetaOffsetPlusDelimiter,
1714 leftFarDelimiter - lmetaOffsetPlusDelimiter,
1715 right, rmetaOffsetPlusDelimiter,
1716 rightFarDelimiter - rmetaOffsetPlusDelimiter);
1717 if (result != 0) {
1718 return result;
1719 }
1720
1721 leftFarDelimiter++;
1722 rightFarDelimiter++;
1723 result = compareRowid(left, leftFarDelimiter,
1724 llength - (leftFarDelimiter - loffset),
1725 right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
1726 return result;
1727 }
1728 }
1729
1730
1731
1732
1733 public static class RowComparator implements Comparator<KeyValue> {
1734 final KVComparator comparator;
1735
1736 public RowComparator(final KVComparator c) {
1737 this.comparator = c;
1738 }
1739
1740 public int compare(KeyValue left, KeyValue right) {
1741 return comparator.compareRows(left, right);
1742 }
1743 }
1744
1745
1746
1747
1748
1749 public static class MetaKeyComparator extends KeyComparator {
1750 public int compareRows(byte [] left, int loffset, int llength,
1751 byte [] right, int roffset, int rlength) {
1752
1753
1754 int leftDelimiter = getDelimiter(left, loffset, llength,
1755 HRegionInfo.DELIMITER);
1756 int rightDelimiter = getDelimiter(right, roffset, rlength,
1757 HRegionInfo.DELIMITER);
1758 if (leftDelimiter < 0 && rightDelimiter >= 0) {
1759
1760 return -1;
1761 } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
1762 return 1;
1763 } else if (leftDelimiter < 0 && rightDelimiter < 0) {
1764 return 0;
1765 }
1766
1767 int result = Bytes.compareTo(left, loffset, leftDelimiter - loffset,
1768 right, roffset, rightDelimiter - roffset);
1769 if (result != 0) {
1770 return result;
1771 }
1772
1773
1774 leftDelimiter++;
1775 rightDelimiter++;
1776 int leftFarDelimiter = getRequiredDelimiterInReverse(left, leftDelimiter,
1777 llength - (leftDelimiter - loffset), HRegionInfo.DELIMITER);
1778 int rightFarDelimiter = getRequiredDelimiterInReverse(right,
1779 rightDelimiter, rlength - (rightDelimiter - roffset),
1780 HRegionInfo.DELIMITER);
1781
1782 result = super.compareRows(left, leftDelimiter,
1783 leftFarDelimiter - leftDelimiter, right, rightDelimiter,
1784 rightFarDelimiter - rightDelimiter);
1785 if (result != 0) {
1786 return result;
1787 }
1788
1789 leftFarDelimiter++;
1790 rightFarDelimiter++;
1791 result = compareRowid(left, leftFarDelimiter,
1792 llength - (leftFarDelimiter - loffset),
1793 right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
1794 return result;
1795 }
1796
1797 protected int compareRowid(byte[] left, int loffset, int llength,
1798 byte[] right, int roffset, int rlength) {
1799 return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
1800 }
1801 }
1802
1803
1804
1805
1806 public static class KeyComparator implements RawComparator<byte []> {
1807 volatile boolean ignoreTimestamp = false;
1808 volatile boolean ignoreType = false;
1809
1810 public int compare(byte[] left, int loffset, int llength, byte[] right,
1811 int roffset, int rlength) {
1812
1813 short lrowlength = Bytes.toShort(left, loffset);
1814 short rrowlength = Bytes.toShort(right, roffset);
1815 int compare = compareRows(left, loffset + Bytes.SIZEOF_SHORT,
1816 lrowlength,
1817 right, roffset + Bytes.SIZEOF_SHORT, rrowlength);
1818 if (compare != 0) {
1819 return compare;
1820 }
1821
1822
1823 int lcolumnoffset = Bytes.SIZEOF_SHORT + lrowlength + 1 + loffset;
1824 int rcolumnoffset = Bytes.SIZEOF_SHORT + rrowlength + 1 + roffset;
1825 int lcolumnlength = llength - TIMESTAMP_TYPE_SIZE -
1826 (lcolumnoffset - loffset);
1827 int rcolumnlength = rlength - TIMESTAMP_TYPE_SIZE -
1828 (rcolumnoffset - roffset);
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838 byte ltype = left[loffset + (llength - 1)];
1839 byte rtype = right[roffset + (rlength - 1)];
1840
1841 if (lcolumnlength == 0 && ltype == Type.Minimum.getCode()) {
1842 return 1;
1843 }
1844 if (rcolumnlength == 0 && rtype == Type.Minimum.getCode()) {
1845 return -1;
1846 }
1847
1848
1849 compare = Bytes.compareTo(left, lcolumnoffset, lcolumnlength, right,
1850 rcolumnoffset, rcolumnlength);
1851 if (compare != 0) {
1852 return compare;
1853 }
1854
1855 if (!this.ignoreTimestamp) {
1856
1857 long ltimestamp = Bytes.toLong(left,
1858 loffset + (llength - TIMESTAMP_TYPE_SIZE));
1859 long rtimestamp = Bytes.toLong(right,
1860 roffset + (rlength - TIMESTAMP_TYPE_SIZE));
1861 compare = compareTimestamps(ltimestamp, rtimestamp);
1862 if (compare != 0) {
1863 return compare;
1864 }
1865 }
1866
1867 if (!this.ignoreType) {
1868
1869
1870 return (0xff & rtype) - (0xff & ltype);
1871 }
1872 return 0;
1873 }
1874
1875 public int compare(byte[] left, byte[] right) {
1876 return compare(left, 0, left.length, right, 0, right.length);
1877 }
1878
1879 public int compareRows(byte [] left, int loffset, int llength,
1880 byte [] right, int roffset, int rlength) {
1881 return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
1882 }
1883
1884 protected int compareColumns(
1885 byte [] left, int loffset, int llength, final int lfamilylength,
1886 byte [] right, int roffset, int rlength, final int rfamilylength) {
1887 return KeyValue.compareColumns(left, loffset, llength, lfamilylength,
1888 right, roffset, rlength, rfamilylength);
1889 }
1890
1891 int compareTimestamps(final long ltimestamp, final long rtimestamp) {
1892
1893
1894
1895
1896 if (ltimestamp < rtimestamp) {
1897 return 1;
1898 } else if (ltimestamp > rtimestamp) {
1899 return -1;
1900 }
1901 return 0;
1902 }
1903 }
1904
1905
1906 public long heapSize() {
1907 return ClassSize.align(ClassSize.OBJECT + (2 * ClassSize.REFERENCE) +
1908 ClassSize.align(ClassSize.ARRAY + length) +
1909 (3 * Bytes.SIZEOF_INT) +
1910 ClassSize.align(ClassSize.ARRAY + (rowCache == null ? 0 : rowCache.length)) +
1911 (2 * Bytes.SIZEOF_LONG));
1912 }
1913
1914
1915
1916
1917 public void readFields(int length, final DataInput in) throws IOException {
1918 this.length = length;
1919 this.offset = 0;
1920 this.bytes = new byte[this.length];
1921 in.readFully(this.bytes, 0, this.length);
1922 }
1923
1924
1925 public void readFields(final DataInput in) throws IOException {
1926 int length = in.readInt();
1927 readFields(length, in);
1928 }
1929
1930 public void write(final DataOutput out) throws IOException {
1931 out.writeInt(this.length);
1932 out.write(this.bytes, this.offset, this.length);
1933 }
1934 }