View Javadoc

1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with 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  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  import java.util.HashMap;
28  import java.util.Map;
29  
30  import com.google.common.primitives.Longs;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.apache.hadoop.hbase.io.HeapSize;
34  import org.apache.hadoop.hbase.io.hfile.HFile;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.apache.hadoop.hbase.util.ClassSize;
37  import org.apache.hadoop.io.RawComparator;
38  import org.apache.hadoop.io.Writable;
39  
40  /**
41   * An HBase Key/Value.  This is the fundamental HBase Type.
42   *
43   * <p>If being used client-side, the primary methods to access individual fields
44   * are {@link #getRow()}, {@link #getFamily()}, {@link #getQualifier()},
45   * {@link #getTimestamp()}, and {@link #getValue()}.  These methods allocate new
46   * byte arrays and return copies. Avoid their use server-side.
47   *
48   * <p>Instances of this class are immutable.  They do not implement Comparable
49   * but Comparators are provided.  Comparators change with context,
50   * whether user table or a catalog table comparison.  Its critical you use the
51   * appropriate comparator.  There are Comparators for KeyValue instances and
52   * then for just the Key portion of a KeyValue used mostly by {@link HFile}.
53   *
54   * <p>KeyValue wraps a byte array and takes offsets and lengths into passed
55   * array at where to start interpreting the content as KeyValue.  The KeyValue
56   * format inside a byte array is:
57   * <code>&lt;keylength> &lt;valuelength> &lt;key> &lt;value></code>
58   * Key is further decomposed as:
59   * <code>&lt;rowlength> &lt;row> &lt;columnfamilylength> &lt;columnfamily> &lt;columnqualifier> &lt;timestamp> &lt;keytype></code>
60   * The <code>rowlength</code> maximum is <code>Short.MAX_SIZE</code>,
61   * column family length maximum is
62   * <code>Byte.MAX_SIZE</code>, and column qualifier + key length must
63   * be < <code>Integer.MAX_SIZE</code>.
64   * The column does not contain the family/qualifier delimiter, {@link #COLUMN_FAMILY_DELIMITER}
65   */
66  public class KeyValue implements Writable, HeapSize {
67    static final Log LOG = LogFactory.getLog(KeyValue.class);
68    // TODO: Group Key-only comparators and operations into a Key class, just
69    // for neatness sake, if can figure what to call it.
70  
71    /**
72     * Colon character in UTF-8
73     */
74    public static final char COLUMN_FAMILY_DELIMITER = ':';
75  
76    public static final byte[] COLUMN_FAMILY_DELIM_ARRAY =
77      new byte[]{COLUMN_FAMILY_DELIMITER};
78  
79    /**
80     * Comparator for plain key/values; i.e. non-catalog table key/values.
81     */
82    public static KVComparator COMPARATOR = new KVComparator();
83  
84    /**
85     * Comparator for plain key; i.e. non-catalog table key.  Works on Key portion
86     * of KeyValue only.
87     */
88    public static KeyComparator KEY_COMPARATOR = new KeyComparator();
89  
90    /**
91     * A {@link KVComparator} for <code>.META.</code> catalog table
92     * {@link KeyValue}s.
93     */
94    public static KVComparator META_COMPARATOR = new MetaComparator();
95  
96    /**
97     * A {@link KVComparator} for <code>.META.</code> catalog table
98     * {@link KeyValue} keys.
99     */
100   public static KeyComparator META_KEY_COMPARATOR = new MetaKeyComparator();
101 
102   /**
103    * A {@link KVComparator} for <code>-ROOT-</code> catalog table
104    * {@link KeyValue}s.
105    */
106   public static KVComparator ROOT_COMPARATOR = new RootComparator();
107 
108   /**
109    * A {@link KVComparator} for <code>-ROOT-</code> catalog table
110    * {@link KeyValue} keys.
111    */
112   public static KeyComparator ROOT_KEY_COMPARATOR = new RootKeyComparator();
113 
114   /**
115    * Get the appropriate row comparator for the specified table.
116    *
117    * Hopefully we can get rid of this, I added this here because it's replacing
118    * something in HSK.  We should move completely off of that.
119    *
120    * @param tableName  The table name.
121    * @return The comparator.
122    */
123   public static KeyComparator getRowComparator(byte [] tableName) {
124     if(Bytes.equals(HTableDescriptor.ROOT_TABLEDESC.getName(),tableName)) {
125       return ROOT_COMPARATOR.getRawComparator();
126     }
127     if(Bytes.equals(HTableDescriptor.META_TABLEDESC.getName(), tableName)) {
128       return META_COMPARATOR.getRawComparator();
129     }
130     return COMPARATOR.getRawComparator();
131   }
132 
133   // Size of the timestamp and type byte on end of a key -- a long + a byte.
134   public static final int TIMESTAMP_TYPE_SIZE =
135     Bytes.SIZEOF_LONG /* timestamp */ +
136     Bytes.SIZEOF_BYTE /*keytype*/;
137 
138   // Size of the length shorts and bytes in key.
139   public static final int KEY_INFRASTRUCTURE_SIZE =
140     Bytes.SIZEOF_SHORT /*rowlength*/ +
141     Bytes.SIZEOF_BYTE /*columnfamilylength*/ +
142     TIMESTAMP_TYPE_SIZE;
143 
144   // How far into the key the row starts at. First thing to read is the short
145   // that says how long the row is.
146   public static final int ROW_OFFSET =
147     Bytes.SIZEOF_INT /*keylength*/ +
148     Bytes.SIZEOF_INT /*valuelength*/;
149 
150   // Size of the length ints in a KeyValue datastructure.
151   public static final int KEYVALUE_INFRASTRUCTURE_SIZE = ROW_OFFSET;
152 
153   /**
154    * Key type.
155    * Has space for other key types to be added later.  Cannot rely on
156    * enum ordinals . They change if item is removed or moved.  Do our own codes.
157    */
158   public static enum Type {
159     Minimum((byte)0),
160     Put((byte)4),
161 
162     Delete((byte)8),
163     DeleteColumn((byte)12),
164     DeleteFamily((byte)14),
165 
166     // Maximum is used when searching; you look from maximum on down.
167     Maximum((byte)255);
168 
169     private final byte code;
170 
171     Type(final byte c) {
172       this.code = c;
173     }
174 
175     public byte getCode() {
176       return this.code;
177     }
178 
179     /**
180      * Cannot rely on enum ordinals . They change if item is removed or moved.
181      * Do our own codes.
182      * @param b
183      * @return Type associated with passed code.
184      */
185     public static Type codeToType(final byte b) {
186       for (Type t : Type.values()) {
187         if (t.getCode() == b) {
188           return t;
189         }
190       }
191       throw new RuntimeException("Unknown code " + b);
192     }
193   }
194 
195   /**
196    * Lowest possible key.
197    * Makes a Key with highest possible Timestamp, empty row and column.  No
198    * key can be equal or lower than this one in memstore or in store file.
199    */
200   public static final KeyValue LOWESTKEY =
201     new KeyValue(HConstants.EMPTY_BYTE_ARRAY, HConstants.LATEST_TIMESTAMP);
202 
203   private byte [] bytes = null;
204   private int offset = 0;
205   private int length = 0;
206 
207   // the row cached
208   private volatile byte [] rowCache = null;
209 
210 
211   /** Here be dragons **/
212 
213   // used to achieve atomic operations in the memstore.
214   public long getMemstoreTS() {
215     return memstoreTS;
216   }
217 
218   public void setMemstoreTS(long memstoreTS) {
219     this.memstoreTS = memstoreTS;
220   }
221 
222   // default value is 0, aka DNC
223   private long memstoreTS = 0;
224 
225   /** Dragon time over, return to normal business */
226 
227 
228   /** Writable Constructor -- DO NOT USE */
229   public KeyValue() {}
230 
231   /**
232    * Creates a KeyValue from the start of the specified byte array.
233    * Presumes <code>bytes</code> content is formatted as a KeyValue blob.
234    * @param bytes byte array
235    */
236   public KeyValue(final byte [] bytes) {
237     this(bytes, 0);
238   }
239 
240   /**
241    * Creates a KeyValue from the specified byte array and offset.
242    * Presumes <code>bytes</code> content starting at <code>offset</code> is
243    * formatted as a KeyValue blob.
244    * @param bytes byte array
245    * @param offset offset to start of KeyValue
246    */
247   public KeyValue(final byte [] bytes, final int offset) {
248     this(bytes, offset, getLength(bytes, offset));
249   }
250 
251   /**
252    * Creates a KeyValue from the specified byte array, starting at offset, and
253    * for length <code>length</code>.
254    * @param bytes byte array
255    * @param offset offset to start of the KeyValue
256    * @param length length of the KeyValue
257    */
258   public KeyValue(final byte [] bytes, final int offset, final int length) {
259     this.bytes = bytes;
260     this.offset = offset;
261     this.length = length;
262   }
263 
264   /** Constructors that build a new backing byte array from fields */
265 
266   /**
267    * Constructs KeyValue structure filled with null value.
268    * Sets type to {@link KeyValue.Type#Maximum}
269    * @param row - row key (arbitrary byte array)
270    * @param timestamp
271    */
272   public KeyValue(final byte [] row, final long timestamp) {
273     this(row, timestamp, Type.Maximum);
274   }
275 
276   /**
277    * Constructs KeyValue structure filled with null value.
278    * @param row - row key (arbitrary byte array)
279    * @param timestamp
280    */
281   public KeyValue(final byte [] row, final long timestamp, Type type) {
282     this(row, null, null, timestamp, type, null);
283   }
284 
285   /**
286    * Constructs KeyValue structure filled with null value.
287    * Sets type to {@link KeyValue.Type#Maximum}
288    * @param row - row key (arbitrary byte array)
289    * @param family family name
290    * @param qualifier column qualifier
291    */
292   public KeyValue(final byte [] row, final byte [] family,
293       final byte [] qualifier) {
294     this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Maximum);
295   }
296 
297   /**
298    * Constructs KeyValue structure filled with null value.
299    * @param row - row key (arbitrary byte array)
300    * @param family family name
301    * @param qualifier column qualifier
302    */
303   public KeyValue(final byte [] row, final byte [] family,
304       final byte [] qualifier, final byte [] value) {
305     this(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Put, value);
306   }
307 
308   /**
309    * Constructs KeyValue structure filled with specified values.
310    * @param row row key
311    * @param family family name
312    * @param qualifier column qualifier
313    * @param timestamp version timestamp
314    * @param type key type
315    * @throws IllegalArgumentException
316    */
317   public KeyValue(final byte[] row, final byte[] family,
318       final byte[] qualifier, final long timestamp, Type type) {
319     this(row, family, qualifier, timestamp, type, null);
320   }
321 
322   /**
323    * Constructs KeyValue structure filled with specified values.
324    * @param row row key
325    * @param family family name
326    * @param qualifier column qualifier
327    * @param timestamp version timestamp
328    * @param value column value
329    * @throws IllegalArgumentException
330    */
331   public KeyValue(final byte[] row, final byte[] family,
332       final byte[] qualifier, final long timestamp, final byte[] value) {
333     this(row, family, qualifier, timestamp, Type.Put, value);
334   }
335 
336   /**
337    * Constructs KeyValue structure filled with specified values.
338    * @param row row key
339    * @param family family name
340    * @param qualifier column qualifier
341    * @param timestamp version timestamp
342    * @param type key type
343    * @param value column value
344    * @throws IllegalArgumentException
345    */
346   public KeyValue(final byte[] row, final byte[] family,
347       final byte[] qualifier, final long timestamp, Type type,
348       final byte[] value) {
349     this(row, family, qualifier, 0, qualifier==null ? 0 : qualifier.length,
350         timestamp, type, value, 0, value==null ? 0 : value.length);
351   }
352 
353   /**
354    * Constructs KeyValue structure filled with specified values.
355    * @param row row key
356    * @param family family name
357    * @param qualifier column qualifier
358    * @param qoffset qualifier offset
359    * @param qlength qualifier length
360    * @param timestamp version timestamp
361    * @param type key type
362    * @param value column value
363    * @param voffset value offset
364    * @param vlength value length
365    * @throws IllegalArgumentException
366    */
367   public KeyValue(byte [] row, byte [] family,
368       byte [] qualifier, int qoffset, int qlength, long timestamp, Type type,
369       byte [] value, int voffset, int vlength) {
370     this(row, 0, row==null ? 0 : row.length,
371         family, 0, family==null ? 0 : family.length,
372         qualifier, qoffset, qlength, timestamp, type,
373         value, voffset, vlength);
374   }
375 
376   /**
377    * Constructs KeyValue structure filled with specified values.
378    * <p>
379    * Column is split into two fields, family and qualifier.
380    * @param row row key
381    * @param roffset row offset
382    * @param rlength row length
383    * @param family family name
384    * @param foffset family offset
385    * @param flength family length
386    * @param qualifier column qualifier
387    * @param qoffset qualifier offset
388    * @param qlength qualifier length
389    * @param timestamp version timestamp
390    * @param type key type
391    * @param value column value
392    * @param voffset value offset
393    * @param vlength value length
394    * @throws IllegalArgumentException
395    */
396   public KeyValue(final byte [] row, final int roffset, final int rlength,
397       final byte [] family, final int foffset, final int flength,
398       final byte [] qualifier, final int qoffset, final int qlength,
399       final long timestamp, final Type type,
400       final byte [] value, final int voffset, final int vlength) {
401     this.bytes = createByteArray(row, roffset, rlength,
402         family, foffset, flength, qualifier, qoffset, qlength,
403         timestamp, type, value, voffset, vlength);
404     this.length = bytes.length;
405     this.offset = 0;
406   }
407 
408   /**
409    * Write KeyValue format into a byte array.
410    *
411    * @param row row key
412    * @param roffset row offset
413    * @param rlength row length
414    * @param family family name
415    * @param foffset family offset
416    * @param flength family length
417    * @param qualifier column qualifier
418    * @param qoffset qualifier offset
419    * @param qlength qualifier length
420    * @param timestamp version timestamp
421    * @param type key type
422    * @param value column value
423    * @param voffset value offset
424    * @param vlength value length
425    * @return The newly created byte array.
426    */
427   static byte [] createByteArray(final byte [] row, final int roffset,
428       final int rlength, final byte [] family, final int foffset, int flength,
429       final byte [] qualifier, final int qoffset, int qlength,
430       final long timestamp, final Type type,
431       final byte [] value, final int voffset, int vlength) {
432     if (rlength > Short.MAX_VALUE) {
433       throw new IllegalArgumentException("Row > " + Short.MAX_VALUE);
434     }
435     if (row == null) {
436       throw new IllegalArgumentException("Row is null");
437     }
438     // Family length
439     flength = family == null ? 0 : flength;
440     if (flength > Byte.MAX_VALUE) {
441       throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
442     }
443     // Qualifier length
444     qlength = qualifier == null ? 0 : qlength;
445     if (qlength > Integer.MAX_VALUE - rlength - flength) {
446       throw new IllegalArgumentException("Qualifier > " + Integer.MAX_VALUE);
447     }
448     // Key length
449     long longkeylength = KEY_INFRASTRUCTURE_SIZE + rlength + flength + qlength;
450     if (longkeylength > Integer.MAX_VALUE) {
451       throw new IllegalArgumentException("keylength " + longkeylength + " > " +
452         Integer.MAX_VALUE);
453     }
454     int keylength = (int)longkeylength;
455     // Value length
456     vlength = value == null? 0 : vlength;
457     if (vlength > HConstants.MAXIMUM_VALUE_LENGTH) { // FindBugs INT_VACUOUS_COMPARISON
458       throw new IllegalArgumentException("Valuer > " +
459           HConstants.MAXIMUM_VALUE_LENGTH);
460     }
461 
462     // Allocate right-sized byte array.
463     byte [] bytes = new byte[KEYVALUE_INFRASTRUCTURE_SIZE + keylength + vlength];
464     // Write key, value and key row length.
465     int pos = 0;
466     pos = Bytes.putInt(bytes, pos, keylength);
467     pos = Bytes.putInt(bytes, pos, vlength);
468     pos = Bytes.putShort(bytes, pos, (short)(rlength & 0x0000ffff));
469     pos = Bytes.putBytes(bytes, pos, row, roffset, rlength);
470     pos = Bytes.putByte(bytes, pos, (byte)(flength & 0x0000ff));
471     if(flength != 0) {
472       pos = Bytes.putBytes(bytes, pos, family, foffset, flength);
473     }
474     if(qlength != 0) {
475       pos = Bytes.putBytes(bytes, pos, qualifier, qoffset, qlength);
476     }
477     pos = Bytes.putLong(bytes, pos, timestamp);
478     pos = Bytes.putByte(bytes, pos, type.getCode());
479     if (value != null && value.length > 0) {
480       pos = Bytes.putBytes(bytes, pos, value, voffset, vlength);
481     }
482     return bytes;
483   }
484 
485   /**
486    * Write KeyValue format into a byte array.
487    * <p>
488    * Takes column in the form <code>family:qualifier</code>
489    * @param row - row key (arbitrary byte array)
490    * @param roffset
491    * @param rlength
492    * @param column
493    * @param coffset
494    * @param clength
495    * @param timestamp
496    * @param type
497    * @param value
498    * @param voffset
499    * @param vlength
500    * @return The newly created byte array.
501    */
502   static byte [] createByteArray(final byte [] row, final int roffset,
503         final int rlength,
504       final byte [] column, final int coffset, int clength,
505       final long timestamp, final Type type,
506       final byte [] value, final int voffset, int vlength) {
507     // If column is non-null, figure where the delimiter is at.
508     int delimiteroffset = 0;
509     if (column != null && column.length > 0) {
510       delimiteroffset = getFamilyDelimiterIndex(column, coffset, clength);
511       if (delimiteroffset > Byte.MAX_VALUE) {
512         throw new IllegalArgumentException("Family > " + Byte.MAX_VALUE);
513       }
514     } else {
515       return createByteArray(row,roffset,rlength,null,0,0,null,0,0,timestamp,
516           type,value,voffset,vlength);
517     }
518     int flength = delimiteroffset-coffset;
519     int qlength = clength - flength - 1;
520     return createByteArray(row, roffset, rlength, column, coffset,
521         flength, column, delimiteroffset+1, qlength, timestamp, type,
522         value, voffset, vlength);
523   }
524 
525   // Needed doing 'contains' on List.  Only compares the key portion, not the
526   // value.
527   public boolean equals(Object other) {
528     if (!(other instanceof KeyValue)) {
529       return false;
530     }
531     KeyValue kv = (KeyValue)other;
532     // Comparing bytes should be fine doing equals test.  Shouldn't have to
533     // worry about special .META. comparators doing straight equals.
534     return Bytes.equals(getBuffer(), getKeyOffset(), getKeyLength(),
535       kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength());
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   //  KeyValue cloning
551   //
552   //---------------------------------------------------------------------------
553 
554   /**
555    * Clones a KeyValue.  This creates a copy, re-allocating the buffer.
556    * @return Fully copied clone of this KeyValue
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     // Important to clone the memstoreTS as well - otherwise memstore's
563     // update-in-place methods (eg increment) will end up creating
564     // new entries
565     ret.setMemstoreTS(memstoreTS);
566     return ret;
567   }
568 
569   /**
570    * Creates a deep copy of this KeyValue, re-allocating the buffer.
571    * Same function as {@link #clone()}.  Added for clarity vs shallowCopy()
572    * @return Deep copy of this KeyValue
573    */
574   public KeyValue deepCopy() {
575     return clone();
576   }
577 
578   /**
579    * Creates a shallow copy of this KeyValue, reusing the data byte buffer.
580    * http://en.wikipedia.org/wiki/Object_copy
581    * @return Shallow copy of this KeyValue
582    */
583   public KeyValue shallowCopy() {
584     KeyValue shallowCopy = new KeyValue(this.bytes, this.offset, this.length);
585     shallowCopy.setMemstoreTS(this.memstoreTS);
586     return shallowCopy;
587   }
588 
589   //---------------------------------------------------------------------------
590   //
591   //  String representation
592   //
593   //---------------------------------------------------------------------------
594 
595   public String toString() {
596     if (this.bytes == null || this.bytes.length == 0) {
597       return "empty";
598     }
599     return keyToString(this.bytes, this.offset + ROW_OFFSET, getKeyLength()) +
600       "/vlen=" + getValueLength();
601   }
602 
603   /**
604    * @param k Key portion of a KeyValue.
605    * @return Key as a String.
606    */
607   public static String keyToString(final byte [] k) {
608     return keyToString(k, 0, k.length);
609   }
610 
611   /**
612    * Use for logging.
613    * @param b Key portion of a KeyValue.
614    * @param o Offset to start of key
615    * @param l Length of key.
616    * @return Key as a String.
617    */
618   /**
619    * Produces a string map for this key/value pair. Useful for programmatic use
620    * and manipulation of the data stored in an HLogKey, for example, printing 
621    * as JSON. Values are left out due to their tendency to be large. If needed, 
622    * they can be added manually.
623    * 
624    * @return the Map<String,?> containing data from this key
625    */
626   public Map<String, Object> toStringMap() {
627     Map<String, Object> stringMap = new HashMap<String, Object>();
628     stringMap.put("row", Bytes.toStringBinary(getRow()));
629     stringMap.put("family", Bytes.toStringBinary(getFamily()));
630     stringMap.put("qualifier", Bytes.toStringBinary(getQualifier()));
631     stringMap.put("timestamp", getTimestamp());
632     stringMap.put("vlen", getValueLength());
633     return stringMap;
634   }
635 
636   public static String keyToString(final byte [] b, final int o, final int l) {
637     if (b == null) return "";
638     int rowlength = Bytes.toShort(b, o);
639     String row = Bytes.toStringBinary(b, o + Bytes.SIZEOF_SHORT, rowlength);
640     int columnoffset = o + Bytes.SIZEOF_SHORT + 1 + rowlength;
641     int familylength = b[columnoffset - 1];
642     int columnlength = l - ((columnoffset - o) + TIMESTAMP_TYPE_SIZE);
643     String family = familylength == 0? "":
644       Bytes.toStringBinary(b, columnoffset, familylength);
645     String qualifier = columnlength == 0? "":
646       Bytes.toStringBinary(b, columnoffset + familylength,
647       columnlength - familylength);
648     long timestamp = Bytes.toLong(b, o + (l - TIMESTAMP_TYPE_SIZE));
649     byte type = b[o + l - 1];
650 //    return row + "/" + family +
651 //      (family != null && family.length() > 0? COLUMN_FAMILY_DELIMITER: "") +
652 //      qualifier + "/" + timestamp + "/" + Type.codeToType(type);
653     return row + "/" + family +
654       (family != null && family.length() > 0? ":" :"") +
655       qualifier + "/" + timestamp + "/" + Type.codeToType(type);
656   }
657 
658   //---------------------------------------------------------------------------
659   //
660   //  Public Member Accessors
661   //
662   //---------------------------------------------------------------------------
663 
664   /**
665    * @return The byte array backing this KeyValue.
666    */
667   public byte [] getBuffer() {
668     return this.bytes;
669   }
670 
671   /**
672    * @return Offset into {@link #getBuffer()} at which this KeyValue starts.
673    */
674   public int getOffset() {
675     return this.offset;
676   }
677 
678   /**
679    * @return Length of bytes this KeyValue occupies in {@link #getBuffer()}.
680    */
681   public int getLength() {
682     return length;
683   }
684 
685   //---------------------------------------------------------------------------
686   //
687   //  Length and Offset Calculators
688   //
689   //---------------------------------------------------------------------------
690 
691   /**
692    * Determines the total length of the KeyValue stored in the specified
693    * byte array and offset.  Includes all headers.
694    * @param bytes byte array
695    * @param offset offset to start of the KeyValue
696    * @return length of entire KeyValue, in bytes
697    */
698   private static int getLength(byte [] bytes, int offset) {
699     return (2 * Bytes.SIZEOF_INT) +
700         Bytes.toInt(bytes, offset) +
701         Bytes.toInt(bytes, offset + Bytes.SIZEOF_INT);
702   }
703 
704   /**
705    * @return Key offset in backing buffer..
706    */
707   public int getKeyOffset() {
708     return this.offset + ROW_OFFSET;
709   }
710 
711   public String getKeyString() {
712     return Bytes.toStringBinary(getBuffer(), getKeyOffset(), getKeyLength());
713   }
714 
715   /**
716    * @return Length of key portion.
717    */
718   private int keyLength = 0;
719 
720   public int getKeyLength() {
721     if (keyLength == 0) {
722       keyLength = Bytes.toInt(this.bytes, this.offset);
723     }
724     return keyLength;
725   }
726 
727   /**
728    * @return Value offset
729    */
730   public int getValueOffset() {
731     return getKeyOffset() + getKeyLength();
732   }
733 
734   /**
735    * @return Value length
736    */
737   public int getValueLength() {
738     return Bytes.toInt(this.bytes, this.offset + Bytes.SIZEOF_INT);
739   }
740 
741   /**
742    * @return Row offset
743    */
744   public int getRowOffset() {
745     return getKeyOffset() + Bytes.SIZEOF_SHORT;
746   }
747 
748   /**
749    * @return Row length
750    */
751   public short getRowLength() {
752     return Bytes.toShort(this.bytes, getKeyOffset());
753   }
754 
755   /**
756    * @return Family offset
757    */
758   public int getFamilyOffset() {
759     return getFamilyOffset(getRowLength());
760   }
761 
762   /**
763    * @return Family offset
764    */
765   public int getFamilyOffset(int rlength) {
766     return this.offset + ROW_OFFSET + Bytes.SIZEOF_SHORT + rlength + Bytes.SIZEOF_BYTE;
767   }
768 
769   /**
770    * @return Family length
771    */
772   public byte getFamilyLength() {
773     return getFamilyLength(getFamilyOffset());
774   }
775 
776   /**
777    * @return Family length
778    */
779   public byte getFamilyLength(int foffset) {
780     return this.bytes[foffset-1];
781   }
782 
783   /**
784    * @return Qualifier offset
785    */
786   public int getQualifierOffset() {
787     return getQualifierOffset(getFamilyOffset());
788   }
789 
790   /**
791    * @return Qualifier offset
792    */
793   public int getQualifierOffset(int foffset) {
794     return foffset + getFamilyLength(foffset);
795   }
796 
797   /**
798    * @return Qualifier length
799    */
800   public int getQualifierLength() {
801     return getQualifierLength(getRowLength(),getFamilyLength());
802   }
803 
804   /**
805    * @return Qualifier length
806    */
807   public int getQualifierLength(int rlength, int flength) {
808     return getKeyLength() -
809       (KEY_INFRASTRUCTURE_SIZE + rlength + flength);
810   }
811 
812   /**
813    * @return Column (family + qualifier) length
814    */
815   public int getTotalColumnLength() {
816     int rlength = getRowLength();
817     int foffset = getFamilyOffset(rlength);
818     return getTotalColumnLength(rlength,foffset);
819   }
820 
821   /**
822    * @return Column (family + qualifier) length
823    */
824   public int getTotalColumnLength(int rlength, int foffset) {
825     int flength = getFamilyLength(foffset);
826     int qlength = getQualifierLength(rlength,flength);
827     return flength + qlength;
828   }
829 
830   /**
831    * @return Timestamp offset
832    */
833   public int getTimestampOffset() {
834     return getTimestampOffset(getKeyLength());
835   }
836 
837   /**
838    * @param keylength Pass if you have it to save on a int creation.
839    * @return Timestamp offset
840    */
841   public int getTimestampOffset(final int keylength) {
842     return getKeyOffset() + keylength - TIMESTAMP_TYPE_SIZE;
843   }
844 
845   /**
846    * @return True if this KeyValue has a LATEST_TIMESTAMP timestamp.
847    */
848   public boolean isLatestTimestamp() {
849     return Bytes.equals(getBuffer(), getTimestampOffset(), Bytes.SIZEOF_LONG,
850       HConstants.LATEST_TIMESTAMP_BYTES, 0, Bytes.SIZEOF_LONG);
851   }
852 
853   /**
854    * @param now Time to set into <code>this</code> IFF timestamp ==
855    * {@link HConstants#LATEST_TIMESTAMP} (else, its a noop).
856    * @return True is we modified this.
857    */
858   public boolean updateLatestStamp(final byte [] now) {
859     if (this.isLatestTimestamp()) {
860       int tsOffset = getTimestampOffset();
861       System.arraycopy(now, 0, this.bytes, tsOffset, Bytes.SIZEOF_LONG);
862       return true;
863     }
864     return false;
865   }
866 
867   //---------------------------------------------------------------------------
868   //
869   //  Methods that return copies of fields
870   //
871   //---------------------------------------------------------------------------
872 
873   /**
874    * Do not use unless you have to.  Used internally for compacting and testing.
875    *
876    * Use {@link #getRow()}, {@link #getFamily()}, {@link #getQualifier()}, and
877    * {@link #getValue()} if accessing a KeyValue client-side.
878    * @return Copy of the key portion only.
879    */
880   public byte [] getKey() {
881     int keylength = getKeyLength();
882     byte [] key = new byte[keylength];
883     System.arraycopy(getBuffer(), getKeyOffset(), key, 0, keylength);
884     return key;
885   }
886 
887   /**
888    * Returns value in a new byte array.
889    * Primarily for use client-side. If server-side, use
890    * {@link #getBuffer()} with appropriate offsets and lengths instead to
891    * save on allocations.
892    * @return Value in a new byte array.
893    */
894   public byte [] getValue() {
895     int o = getValueOffset();
896     int l = getValueLength();
897     byte [] result = new byte[l];
898     System.arraycopy(getBuffer(), o, result, 0, l);
899     return result;
900   }
901 
902   /**
903    * Primarily for use client-side.  Returns the row of this KeyValue in a new
904    * byte array.<p>
905    *
906    * If server-side, use {@link #getBuffer()} with appropriate offsets and
907    * lengths instead.
908    * @return Row in a new byte array.
909    */
910   public byte [] getRow() {
911     if (rowCache == null) {
912       int o = getRowOffset();
913       short l = getRowLength();
914       // initialize and copy the data into a local variable
915       // in case multiple threads race here.
916       byte local[] = new byte[l];
917       System.arraycopy(getBuffer(), o, local, 0, l);
918       rowCache = local; // volatile assign
919     }
920     return rowCache;
921   }
922 
923   /**
924    *
925    * @return Timestamp
926    */
927   private long timestampCache = -1;
928   public long getTimestamp() {
929     if (timestampCache == -1) {
930       timestampCache = getTimestamp(getKeyLength());
931     }
932     return timestampCache;
933   }
934 
935   /**
936    * @param keylength Pass if you have it to save on a int creation.
937    * @return Timestamp
938    */
939   long getTimestamp(final int keylength) {
940     int tsOffset = getTimestampOffset(keylength);
941     return Bytes.toLong(this.bytes, tsOffset);
942   }
943 
944   /**
945    * @return Type of this KeyValue.
946    */
947   public byte getType() {
948     return getType(getKeyLength());
949   }
950 
951   /**
952    * @param keylength Pass if you have it to save on a int creation.
953    * @return Type of this KeyValue.
954    */
955   byte getType(final int keylength) {
956     return this.bytes[this.offset + keylength - 1 + ROW_OFFSET];
957   }
958 
959   /**
960    * @return True if a delete type, a {@link KeyValue.Type#Delete} or
961    * a {KeyValue.Type#DeleteFamily} or a {@link KeyValue.Type#DeleteColumn}
962    * KeyValue type.
963    */
964   public boolean isDelete() {
965     int t = getType();
966     return Type.Delete.getCode() <= t && t <= Type.DeleteFamily.getCode();
967   }
968 
969   /**
970    * @return True if this KV is a {@link KeyValue.Type#Delete} type.
971    */
972   public boolean isDeleteType() {
973     // TODO: Fix this method name vis-a-vis isDelete!
974     return getType() == Type.Delete.getCode();
975   }
976 
977   /**
978    * @return True if this KV is a delete family type.
979    */
980   public boolean isDeleteFamily() {
981     return getType() == Type.DeleteFamily.getCode();
982   }
983 
984   /**
985    *
986    * @return True if this KV is a delete family or column type.
987    */
988   public boolean isDeleteColumnOrFamily() {
989     int t = getType();
990     return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode();
991   }
992 
993   /**
994    * Primarily for use client-side.  Returns the family of this KeyValue in a
995    * new byte array.<p>
996    *
997    * If server-side, use {@link #getBuffer()} with appropriate offsets and
998    * lengths instead.
999    * @return Returns family. Makes a copy.
1000    */
1001   public byte [] getFamily() {
1002     int o = getFamilyOffset();
1003     int l = getFamilyLength(o);
1004     byte [] result = new byte[l];
1005     System.arraycopy(this.bytes, o, result, 0, l);
1006     return result;
1007   }
1008 
1009   /**
1010    * Primarily for use client-side.  Returns the column qualifier of this
1011    * KeyValue in a new byte array.<p>
1012    *
1013    * If server-side, use {@link #getBuffer()} with appropriate offsets and
1014    * lengths instead.
1015    * Use {@link #getBuffer()} with appropriate offsets and lengths instead.
1016    * @return Returns qualifier. Makes a copy.
1017    */
1018   public byte [] getQualifier() {
1019     int o = getQualifierOffset();
1020     int l = getQualifierLength();
1021     byte [] result = new byte[l];
1022     System.arraycopy(this.bytes, o, result, 0, l);
1023     return result;
1024   }
1025 
1026   //---------------------------------------------------------------------------
1027   //
1028   //  KeyValue splitter
1029   //
1030   //---------------------------------------------------------------------------
1031 
1032   /**
1033    * Utility class that splits a KeyValue buffer into separate byte arrays.
1034    * <p>
1035    * Should get rid of this if we can, but is very useful for debugging.
1036    */
1037   public static class SplitKeyValue {
1038     private byte [][] split;
1039     SplitKeyValue() {
1040       this.split = new byte[6][];
1041     }
1042     public void setRow(byte [] value) { this.split[0] = value; }
1043     public void setFamily(byte [] value) { this.split[1] = value; }
1044     public void setQualifier(byte [] value) { this.split[2] = value; }
1045     public void setTimestamp(byte [] value) { this.split[3] = value; }
1046     public void setType(byte [] value) { this.split[4] = value; }
1047     public void setValue(byte [] value) { this.split[5] = value; }
1048     public byte [] getRow() { return this.split[0]; }
1049     public byte [] getFamily() { return this.split[1]; }
1050     public byte [] getQualifier() { return this.split[2]; }
1051     public byte [] getTimestamp() { return this.split[3]; }
1052     public byte [] getType() { return this.split[4]; }
1053     public byte [] getValue() { return this.split[5]; }
1054   }
1055 
1056   public SplitKeyValue split() {
1057     SplitKeyValue split = new SplitKeyValue();
1058     int splitOffset = this.offset;
1059     int keyLen = Bytes.toInt(bytes, splitOffset);
1060     splitOffset += Bytes.SIZEOF_INT;
1061     int valLen = Bytes.toInt(bytes, splitOffset);
1062     splitOffset += Bytes.SIZEOF_INT;
1063     short rowLen = Bytes.toShort(bytes, splitOffset);
1064     splitOffset += Bytes.SIZEOF_SHORT;
1065     byte [] row = new byte[rowLen];
1066     System.arraycopy(bytes, splitOffset, row, 0, rowLen);
1067     splitOffset += rowLen;
1068     split.setRow(row);
1069     byte famLen = bytes[splitOffset];
1070     splitOffset += Bytes.SIZEOF_BYTE;
1071     byte [] family = new byte[famLen];
1072     System.arraycopy(bytes, splitOffset, family, 0, famLen);
1073     splitOffset += famLen;
1074     split.setFamily(family);
1075     int colLen = keyLen -
1076       (rowLen + famLen + Bytes.SIZEOF_SHORT + Bytes.SIZEOF_BYTE +
1077       Bytes.SIZEOF_LONG + Bytes.SIZEOF_BYTE);
1078     byte [] qualifier = new byte[colLen];
1079     System.arraycopy(bytes, splitOffset, qualifier, 0, colLen);
1080     splitOffset += colLen;
1081     split.setQualifier(qualifier);
1082     byte [] timestamp = new byte[Bytes.SIZEOF_LONG];
1083     System.arraycopy(bytes, splitOffset, timestamp, 0, Bytes.SIZEOF_LONG);
1084     splitOffset += Bytes.SIZEOF_LONG;
1085     split.setTimestamp(timestamp);
1086     byte [] type = new byte[1];
1087     type[0] = bytes[splitOffset];
1088     splitOffset += Bytes.SIZEOF_BYTE;
1089     split.setType(type);
1090     byte [] value = new byte[valLen];
1091     System.arraycopy(bytes, splitOffset, value, 0, valLen);
1092     split.setValue(value);
1093     return split;
1094   }
1095 
1096   //---------------------------------------------------------------------------
1097   //
1098   //  Compare specified fields against those contained in this KeyValue
1099   //
1100   //---------------------------------------------------------------------------
1101 
1102   /**
1103    * @param family
1104    * @return True if matching families.
1105    */
1106   public boolean matchingFamily(final byte [] family) {
1107     return matchingFamily(family, 0, family.length);
1108   }
1109 
1110   public boolean matchingFamily(final byte[] family, int offset, int length) {
1111     if (this.length == 0 || this.bytes.length == 0) {
1112       return false;
1113     }
1114     return Bytes.equals(family, offset, length,
1115         this.bytes, getFamilyOffset(), getFamilyLength());
1116   }
1117 
1118   public boolean matchingFamily(final KeyValue other) {
1119     return matchingFamily(other.getBuffer(), other.getFamilyOffset(),
1120         other.getFamilyLength());
1121   }
1122 
1123   /**
1124    * @param qualifier
1125    * @return True if matching qualifiers.
1126    */
1127   public boolean matchingQualifier(final byte [] qualifier) {
1128     return matchingQualifier(qualifier, 0, qualifier.length);
1129   }
1130 
1131   public boolean matchingQualifier(final byte [] qualifier, int offset, int length) {
1132     return Bytes.equals(qualifier, offset, length,
1133         this.bytes, getQualifierOffset(), getQualifierLength());
1134   }
1135 
1136   public boolean matchingQualifier(final KeyValue other) {
1137     return matchingQualifier(other.getBuffer(), other.getQualifierOffset(),
1138         other.getQualifierLength());
1139   }
1140 
1141   public boolean matchingRow(final byte [] row) {
1142     return matchingRow(row, 0, row.length);
1143   }
1144 
1145   public boolean matchingRow(final byte[] row, int offset, int length) {
1146     return Bytes.equals(row, offset, length,
1147         this.bytes, getRowOffset(), getRowLength());
1148   }
1149 
1150   public boolean matchingRow(KeyValue other) {
1151     return matchingRow(other.getBuffer(), other.getRowOffset(),
1152         other.getRowLength());
1153   }
1154 
1155   /**
1156    * @param column Column minus its delimiter
1157    * @return True if column matches.
1158    */
1159   public boolean matchingColumnNoDelimiter(final byte [] column) {
1160     int rl = getRowLength();
1161     int o = getFamilyOffset(rl);
1162     int fl = getFamilyLength(o);
1163     int l = fl + getQualifierLength(rl,fl);
1164     return Bytes.equals(column, 0, column.length, this.bytes, o, l);
1165   }
1166 
1167   /**
1168    *
1169    * @param family column family
1170    * @param qualifier column qualifier
1171    * @return True if column matches
1172    */
1173   public boolean matchingColumn(final byte[] family, final byte[] qualifier) {
1174     int rl = getRowLength();
1175     int o = getFamilyOffset(rl);
1176     int fl = getFamilyLength(o);
1177     int ql = getQualifierLength(rl,fl);
1178     if (!Bytes.equals(family, 0, family.length, this.bytes, o, family.length)) {
1179       return false;
1180     }
1181     if (qualifier == null || qualifier.length == 0) {
1182       if (ql == 0) {
1183         return true;
1184       }
1185       return false;
1186     }
1187     return Bytes.equals(qualifier, 0, qualifier.length,
1188         this.bytes, o + fl, ql);
1189   }
1190 
1191   /**
1192    * @param left
1193    * @param loffset
1194    * @param llength
1195    * @param lfamilylength Offset of family delimiter in left column.
1196    * @param right
1197    * @param roffset
1198    * @param rlength
1199    * @param rfamilylength Offset of family delimiter in right column.
1200    * @return The result of the comparison.
1201    */
1202   static int compareColumns(final byte [] left, final int loffset,
1203       final int llength, final int lfamilylength,
1204       final byte [] right, final int roffset, final int rlength,
1205       final int rfamilylength) {
1206     // Compare family portion first.
1207     int diff = Bytes.compareTo(left, loffset, lfamilylength,
1208       right, roffset, rfamilylength);
1209     if (diff != 0) {
1210       return diff;
1211     }
1212     // Compare qualifier portion
1213     return Bytes.compareTo(left, loffset + lfamilylength,
1214       llength - lfamilylength,
1215       right, roffset + rfamilylength, rlength - rfamilylength);
1216   }
1217 
1218   /**
1219    * @return True if non-null row and column.
1220    */
1221   public boolean nonNullRowAndColumn() {
1222     return getRowLength() > 0 && !isEmptyColumn();
1223   }
1224 
1225   /**
1226    * @return True if column is empty.
1227    */
1228   public boolean isEmptyColumn() {
1229     return getQualifierLength() == 0;
1230   }
1231 
1232   /**
1233    * Creates a new KeyValue that only contains the key portion (the value is
1234    * set to be null).
1235    * @param lenAsVal replace value with the actual value length (false=empty)
1236    */
1237   public KeyValue createKeyOnly(boolean lenAsVal) {
1238     // KV format:  <keylen:4><valuelen:4><key:keylen><value:valuelen>
1239     // Rebuild as: <keylen:4><0:4><key:keylen>
1240     int dataLen = lenAsVal? Bytes.SIZEOF_INT : 0;
1241     byte [] newBuffer = new byte[getKeyLength() + (2 * Bytes.SIZEOF_INT) + dataLen];
1242     System.arraycopy(this.bytes, this.offset, newBuffer, 0, 
1243         Math.min(newBuffer.length,this.length));
1244     Bytes.putInt(newBuffer, Bytes.SIZEOF_INT, dataLen);
1245     if (lenAsVal) {
1246       Bytes.putInt(newBuffer, newBuffer.length - dataLen, this.getValueLength());
1247     }
1248     return new KeyValue(newBuffer);
1249   }
1250 
1251   /**
1252    * Splits a column in family:qualifier form into separate byte arrays.
1253    * <p>
1254    * Not recommend to be used as this is old-style API.
1255    * @param c  The column.
1256    * @return The parsed column.
1257    */
1258   public static byte [][] parseColumn(byte [] c) {
1259     final int index = getDelimiter(c, 0, c.length, COLUMN_FAMILY_DELIMITER);
1260     if (index == -1) {
1261       // If no delimiter, return array of size 1
1262       return new byte [][] { c };
1263     } else if(index == c.length - 1) {
1264       // Only a family, return array size 1
1265       byte [] family = new byte[c.length-1];
1266       System.arraycopy(c, 0, family, 0, family.length);
1267       return new byte [][] { family };
1268     }
1269     // Family and column, return array size 2
1270     final byte [][] result = new byte [2][];
1271     result[0] = new byte [index];
1272     System.arraycopy(c, 0, result[0], 0, index);
1273     final int len = c.length - (index + 1);
1274     result[1] = new byte[len];
1275     System.arraycopy(c, index + 1 /*Skip delimiter*/, result[1], 0,
1276       len);
1277     return result;
1278   }
1279 
1280   /**
1281    * Makes a column in family:qualifier form from separate byte arrays.
1282    * <p>
1283    * Not recommended for usage as this is old-style API.
1284    * @param family
1285    * @param qualifier
1286    * @return family:qualifier
1287    */
1288   public static byte [] makeColumn(byte [] family, byte [] qualifier) {
1289     return Bytes.add(family, COLUMN_FAMILY_DELIM_ARRAY, qualifier);
1290   }
1291 
1292   /**
1293    * @param b
1294    * @return Index of the family-qualifier colon delimiter character in passed
1295    * buffer.
1296    */
1297   public static int getFamilyDelimiterIndex(final byte [] b, final int offset,
1298       final int length) {
1299     return getRequiredDelimiter(b, offset, length, COLUMN_FAMILY_DELIMITER);
1300   }
1301 
1302   private static int getRequiredDelimiter(final byte [] b,
1303       final int offset, final int length, final int delimiter) {
1304     int index = getDelimiter(b, offset, length, delimiter);
1305     if (index < 0) {
1306       throw new IllegalArgumentException("No " + (char)delimiter + " in <" +
1307         Bytes.toString(b) + ">" + ", length=" + length + ", offset=" + offset);
1308     }
1309     return index;
1310   }
1311 
1312   /**
1313    * This function is only used in Meta key comparisons so its error message 
1314    * is specific for meta key errors.
1315    */
1316   static int getRequiredDelimiterInReverse(final byte [] b,
1317       final int offset, final int length, final int delimiter) {
1318     int index = getDelimiterInReverse(b, offset, length, delimiter);
1319     if (index < 0) {
1320       throw new IllegalArgumentException(".META. key must have two '" + (char)delimiter + "' "
1321         + "delimiters and have the following format: '<table>,<key>,<etc>'");
1322     }
1323     return index;
1324   }
1325 
1326   /**
1327    * @param b
1328    * @param delimiter
1329    * @return Index of delimiter having started from start of <code>b</code>
1330    * moving rightward.
1331    */
1332   public static int getDelimiter(final byte [] b, int offset, final int length,
1333       final int delimiter) {
1334     if (b == null) {
1335       throw new IllegalArgumentException("Passed buffer is null");
1336     }
1337     int result = -1;
1338     for (int i = offset; i < length + offset; i++) {
1339       if (b[i] == delimiter) {
1340         result = i;
1341         break;
1342       }
1343     }
1344     return result;
1345   }
1346 
1347   /**
1348    * Find index of passed delimiter walking from end of buffer backwards.
1349    * @param b
1350    * @param delimiter
1351    * @return Index of delimiter
1352    */
1353   public static int getDelimiterInReverse(final byte [] b, final int offset,
1354       final int length, final int delimiter) {
1355     if (b == null) {
1356       throw new IllegalArgumentException("Passed buffer is null");
1357     }
1358     int result = -1;
1359     for (int i = (offset + length) - 1; i >= offset; i--) {
1360       if (b[i] == delimiter) {
1361         result = i;
1362         break;
1363       }
1364     }
1365     return result;
1366   }
1367 
1368   /**
1369    * A {@link KVComparator} for <code>-ROOT-</code> catalog table
1370    * {@link KeyValue}s.
1371    */
1372   public static class RootComparator extends MetaComparator {
1373     private final KeyComparator rawcomparator = new RootKeyComparator();
1374 
1375     public KeyComparator getRawComparator() {
1376       return this.rawcomparator;
1377     }
1378 
1379     @Override
1380     protected Object clone() throws CloneNotSupportedException {
1381       return new RootComparator();
1382     }
1383   }
1384 
1385   /**
1386    * A {@link KVComparator} for <code>.META.</code> catalog table
1387    * {@link KeyValue}s.
1388    */
1389   public static class MetaComparator extends KVComparator {
1390     private final KeyComparator rawcomparator = new MetaKeyComparator();
1391 
1392     public KeyComparator getRawComparator() {
1393       return this.rawcomparator;
1394     }
1395 
1396     @Override
1397     protected Object clone() throws CloneNotSupportedException {
1398       return new MetaComparator();
1399     }
1400   }
1401 
1402   /**
1403    * Compare KeyValues.  When we compare KeyValues, we only compare the Key
1404    * portion.  This means two KeyValues with same Key but different Values are
1405    * considered the same as far as this Comparator is concerned.
1406    * Hosts a {@link KeyComparator}.
1407    */
1408   public static class KVComparator implements java.util.Comparator<KeyValue> {
1409     private final KeyComparator rawcomparator = new KeyComparator();
1410 
1411     /**
1412      * @return RawComparator that can compare the Key portion of a KeyValue.
1413      * Used in hfile where indices are the Key portion of a KeyValue.
1414      */
1415     public KeyComparator getRawComparator() {
1416       return this.rawcomparator;
1417     }
1418 
1419     public int compare(final KeyValue left, final KeyValue right) {
1420       int ret = getRawComparator().compare(left.getBuffer(),
1421           left.getOffset() + ROW_OFFSET, left.getKeyLength(),
1422           right.getBuffer(), right.getOffset() + ROW_OFFSET,
1423           right.getKeyLength());
1424       if (ret != 0) return ret;
1425       // Negate this comparison so later edits show up first
1426       return -Longs.compare(left.getMemstoreTS(), right.getMemstoreTS());
1427     }
1428 
1429     public int compareTimestamps(final KeyValue left, final KeyValue right) {
1430       return compareTimestamps(left, left.getKeyLength(), right,
1431         right.getKeyLength());
1432     }
1433 
1434     int compareTimestamps(final KeyValue left, final int lkeylength,
1435         final KeyValue right, final int rkeylength) {
1436       // Compare timestamps
1437       long ltimestamp = left.getTimestamp(lkeylength);
1438       long rtimestamp = right.getTimestamp(rkeylength);
1439       return getRawComparator().compareTimestamps(ltimestamp, rtimestamp);
1440     }
1441 
1442     /**
1443      * @param left
1444      * @param right
1445      * @return Result comparing rows.
1446      */
1447     public int compareRows(final KeyValue left, final KeyValue right) {
1448       return compareRows(left, left.getRowLength(), right,
1449           right.getRowLength());
1450     }
1451 
1452     /**
1453      * @param left
1454      * @param lrowlength Length of left row.
1455      * @param right
1456      * @param rrowlength Length of right row.
1457      * @return Result comparing rows.
1458      */
1459     public int compareRows(final KeyValue left, final short lrowlength,
1460         final KeyValue right, final short rrowlength) {
1461       return getRawComparator().compareRows(left.getBuffer(),
1462           left.getRowOffset(), lrowlength,
1463         right.getBuffer(), right.getRowOffset(), rrowlength);
1464     }
1465 
1466     /**
1467      * @param left
1468      * @param row - row key (arbitrary byte array)
1469      * @return RawComparator
1470      */
1471     public int compareRows(final KeyValue left, final byte [] row) {
1472       return getRawComparator().compareRows(left.getBuffer(),
1473           left.getRowOffset(), left.getRowLength(), row, 0, row.length);
1474     }
1475 
1476     public int compareRows(byte [] left, int loffset, int llength,
1477         byte [] right, int roffset, int rlength) {
1478       return getRawComparator().compareRows(left, loffset, llength,
1479         right, roffset, rlength);
1480     }
1481     
1482     public int compareColumns(final KeyValue left, final byte [] right,
1483         final int roffset, final int rlength, final int rfamilyoffset) {
1484       int offset = left.getFamilyOffset();
1485       int length = left.getFamilyLength() + left.getQualifierLength();
1486       return getRawComparator().compareColumns(left.getBuffer(), offset, length,
1487         left.getFamilyLength(offset),
1488         right, roffset, rlength, rfamilyoffset);
1489     }
1490 
1491     int compareColumns(final KeyValue left, final short lrowlength,
1492         final KeyValue right, final short rrowlength) {
1493       int lfoffset = left.getFamilyOffset(lrowlength);
1494       int rfoffset = right.getFamilyOffset(rrowlength);
1495       int lclength = left.getTotalColumnLength(lrowlength,lfoffset);
1496       int rclength = right.getTotalColumnLength(rrowlength, rfoffset);
1497       int lfamilylength = left.getFamilyLength(lfoffset);
1498       int rfamilylength = right.getFamilyLength(rfoffset);
1499       return getRawComparator().compareColumns(left.getBuffer(), lfoffset,
1500           lclength, lfamilylength,
1501         right.getBuffer(), rfoffset, rclength, rfamilylength);
1502     }
1503 
1504     /**
1505      * Compares the row and column of two keyvalues for equality
1506      * @param left
1507      * @param right
1508      * @return True if same row and column.
1509      */
1510     public boolean matchingRowColumn(final KeyValue left,
1511         final KeyValue right) {
1512       short lrowlength = left.getRowLength();
1513       short rrowlength = right.getRowLength();
1514       // TsOffset = end of column data. just comparing Row+CF length of each
1515       return ((left.getTimestampOffset() - left.getOffset()) == 
1516               (right.getTimestampOffset() - right.getOffset())) &&
1517         matchingRows(left, lrowlength, right, rrowlength) &&
1518         compareColumns(left, lrowlength, right, rrowlength) == 0;
1519     }
1520 
1521     /**
1522      * @param left
1523      * @param right
1524      * @return True if rows match.
1525      */
1526     public boolean matchingRows(final KeyValue left, final byte [] right) {
1527       return Bytes.equals(left.getBuffer(), left.getRowOffset(), left.getRowLength(),
1528           right, 0, right.length);
1529     }
1530 
1531     /**
1532      * Compares the row of two keyvalues for equality
1533      * @param left
1534      * @param right
1535      * @return True if rows match.
1536      */
1537     public boolean matchingRows(final KeyValue left, final KeyValue right) {
1538       short lrowlength = left.getRowLength();
1539       short rrowlength = right.getRowLength();
1540       return matchingRows(left, lrowlength, right, rrowlength);
1541     }
1542 
1543     /**
1544      * @param left
1545      * @param lrowlength
1546      * @param right
1547      * @param rrowlength
1548      * @return True if rows match.
1549      */
1550     public boolean matchingRows(final KeyValue left, final short lrowlength,
1551         final KeyValue right, final short rrowlength) {
1552       return lrowlength == rrowlength &&
1553           Bytes.equals(left.getBuffer(), left.getRowOffset(), lrowlength,
1554               right.getBuffer(), right.getRowOffset(), rrowlength);
1555     }
1556 
1557     public boolean matchingRows(final byte [] left, final int loffset,
1558         final int llength,
1559         final byte [] right, final int roffset, final int rlength) {
1560       return Bytes.equals(left, loffset, llength,
1561           right, roffset, rlength);
1562     }
1563 
1564     /**
1565      * Compares the row and timestamp of two keys
1566      * Was called matchesWithoutColumn in HStoreKey.
1567      * @param right Key to compare against.
1568      * @return True if same row and timestamp is greater than the timestamp in
1569      * <code>right</code>
1570      */
1571     public boolean matchingRowsGreaterTimestamp(final KeyValue left,
1572         final KeyValue right) {
1573       short lrowlength = left.getRowLength();
1574       short rrowlength = right.getRowLength();
1575       if (!matchingRows(left, lrowlength, right, rrowlength)) {
1576         return false;
1577       }
1578       return left.getTimestamp() >= right.getTimestamp();
1579     }
1580 
1581     @Override
1582     protected Object clone() throws CloneNotSupportedException {
1583       return new KVComparator();
1584     }
1585 
1586     /**
1587      * @return Comparator that ignores timestamps; useful counting versions.
1588      */
1589     public KVComparator getComparatorIgnoringTimestamps() {
1590       KVComparator c = null;
1591       try {
1592         c = (KVComparator)this.clone();
1593         c.getRawComparator().ignoreTimestamp = true;
1594       } catch (CloneNotSupportedException e) {
1595         LOG.error("Not supported", e);
1596       }
1597       return c;
1598     }
1599 
1600     /**
1601      * @return Comparator that ignores key type; useful checking deletes
1602      */
1603     public KVComparator getComparatorIgnoringType() {
1604       KVComparator c = null;
1605       try {
1606         c = (KVComparator)this.clone();
1607         c.getRawComparator().ignoreType = true;
1608       } catch (CloneNotSupportedException e) {
1609         LOG.error("Not supported", e);
1610       }
1611       return c;
1612     }
1613   }
1614 
1615   /**
1616    * Creates a KeyValue that is last on the specified row id. That is,
1617    * every other possible KeyValue for the given row would compareTo()
1618    * less than the result of this call.
1619    * @param row row key
1620    * @return Last possible KeyValue on passed <code>row</code>
1621    */
1622   public static KeyValue createLastOnRow(final byte[] row) {
1623     return new KeyValue(row, null, null, HConstants.LATEST_TIMESTAMP, Type.Minimum);
1624   }
1625 
1626   /**
1627    * Create a KeyValue that is smaller than all other possible KeyValues
1628    * for the given row. That is any (valid) KeyValue on 'row' would sort
1629    * _after_ the result.
1630    *
1631    * @param row - row key (arbitrary byte array)
1632    * @return First possible KeyValue on passed <code>row</code>
1633    */
1634   public static KeyValue createFirstOnRow(final byte [] row) {
1635     return createFirstOnRow(row, HConstants.LATEST_TIMESTAMP);
1636   }
1637 
1638   /**
1639    * Creates a KeyValue that is smaller than all other KeyValues that
1640    * are older than the passed timestamp.
1641    * @param row - row key (arbitrary byte array)
1642    * @param ts - timestamp
1643    * @return First possible key on passed <code>row</code> and timestamp.
1644    */
1645   public static KeyValue createFirstOnRow(final byte [] row,
1646       final long ts) {
1647     return new KeyValue(row, null, null, ts, Type.Maximum);
1648   }
1649 
1650   /**
1651    * Create a KeyValue for the specified row, family and qualifier that would be
1652    * smaller than all other possible KeyValues that have the same row,family,qualifier.
1653    * Used for seeking.
1654    * @param row - row key (arbitrary byte array)
1655    * @param family - family name
1656    * @param qualifier - column qualifier
1657    * @return First possible key on passed <code>row</code>, and column.
1658    */
1659   public static KeyValue createFirstOnRow(final byte [] row, final byte [] family,
1660       final byte [] qualifier) {
1661     return new KeyValue(row, family, qualifier, HConstants.LATEST_TIMESTAMP, Type.Maximum);
1662   }
1663 
1664   /**
1665    * @param row - row key (arbitrary byte array)
1666    * @param f - family name
1667    * @param q - column qualifier
1668    * @param ts - timestamp
1669    * @return First possible key on passed <code>row</code>, column and timestamp
1670    */
1671   public static KeyValue createFirstOnRow(final byte [] row, final byte [] f,
1672       final byte [] q, final long ts) {
1673     return new KeyValue(row, f, q, ts, Type.Maximum);
1674   }
1675 
1676   /**
1677    * Create a KeyValue for the specified row, family and qualifier that would be
1678    * smaller than all other possible KeyValues that have the same row,
1679    * family, qualifier.
1680    * Used for seeking.
1681    * @param row row key
1682    * @param roffset row offset
1683    * @param rlength row length
1684    * @param family family name
1685    * @param foffset family offset
1686    * @param flength family length
1687    * @param qualifier column qualifier
1688    * @param qoffset qualifier offset
1689    * @param qlength qualifier length
1690    * @return First possible key on passed Row, Family, Qualifier.
1691    */
1692   public static KeyValue createFirstOnRow(final byte [] row,
1693       final int roffset, final int rlength, final byte [] family,
1694       final int foffset, final int flength, final byte [] qualifier,
1695       final int qoffset, final int qlength) {
1696     return new KeyValue(row, roffset, rlength, family,
1697         foffset, flength, qualifier, qoffset, qlength,
1698         HConstants.LATEST_TIMESTAMP, Type.Maximum, null, 0, 0);
1699   }
1700 
1701   /**
1702    * Create a KeyValue for the specified row, family and qualifier that would be
1703    * larger than or equal to all other possible KeyValues that have the same
1704    * row, family, qualifier.
1705    * Used for reseeking.
1706    * @param row row key
1707    * @param roffset row offset
1708    * @param rlength row length
1709    * @param family family name
1710    * @param foffset family offset
1711    * @param flength family length
1712    * @param qualifier column qualifier
1713    * @param qoffset qualifier offset
1714    * @param qlength qualifier length
1715    * @return Last possible key on passed row, family, qualifier.
1716    */
1717   public static KeyValue createLastOnRow(final byte [] row,
1718       final int roffset, final int rlength, final byte [] family,
1719       final int foffset, final int flength, final byte [] qualifier,
1720       final int qoffset, final int qlength) {
1721     return new KeyValue(row, roffset, rlength, family,
1722         foffset, flength, qualifier, qoffset, qlength,
1723         HConstants.OLDEST_TIMESTAMP, Type.Minimum, null, 0, 0);
1724   }
1725 
1726   /**
1727    * Similar to {@link #createLastOnRow(byte[], int, int, byte[], int, int,
1728    * byte[], int, int)} but creates the last key on the row/column of this KV
1729    * (the value part of the returned KV is always empty). Used in creating
1730    * "fake keys" for the multi-column Bloom filter optimization to skip the
1731    * row/column we already know is not in the file.
1732    * @return the last key on the row/column of the given key-value pair
1733    */
1734   public KeyValue createLastOnRowCol() {
1735     return new KeyValue(
1736         bytes, getRowOffset(), getRowLength(),
1737         bytes, getFamilyOffset(), getFamilyLength(),
1738         bytes, getQualifierOffset(), getQualifierLength(),
1739         HConstants.OLDEST_TIMESTAMP, Type.Minimum, null, 0, 0);
1740   }
1741 
1742   /**
1743    * @param b
1744    * @return A KeyValue made of a byte array that holds the key-only part.
1745    * Needed to convert hfile index members to KeyValues.
1746    */
1747   public static KeyValue createKeyValueFromKey(final byte [] b) {
1748     return createKeyValueFromKey(b, 0, b.length);
1749   }
1750 
1751   /**
1752    * @param bb
1753    * @return A KeyValue made of a byte buffer that holds the key-only part.
1754    * Needed to convert hfile index members to KeyValues.
1755    */
1756   public static KeyValue createKeyValueFromKey(final ByteBuffer bb) {
1757     return createKeyValueFromKey(bb.array(), bb.arrayOffset(), bb.limit());
1758   }
1759 
1760   /**
1761    * @param b
1762    * @param o
1763    * @param l
1764    * @return A KeyValue made of a byte array that holds the key-only part.
1765    * Needed to convert hfile index members to KeyValues.
1766    */
1767   public static KeyValue createKeyValueFromKey(final byte [] b, final int o,
1768       final int l) {
1769     byte [] newb = new byte[b.length + ROW_OFFSET];
1770     System.arraycopy(b, o, newb, ROW_OFFSET, l);
1771     Bytes.putInt(newb, 0, b.length);
1772     Bytes.putInt(newb, Bytes.SIZEOF_INT, 0);
1773     return new KeyValue(newb);
1774   }
1775 
1776   /**
1777    * Compare key portion of a {@link KeyValue} for keys in <code>-ROOT-<code>
1778    * table.
1779    */
1780   public static class RootKeyComparator extends MetaKeyComparator {
1781     public int compareRows(byte [] left, int loffset, int llength,
1782         byte [] right, int roffset, int rlength) {
1783       // Rows look like this: .META.,ROW_FROM_META,RID
1784       //        LOG.info("ROOT " + Bytes.toString(left, loffset, llength) +
1785       //          "---" + Bytes.toString(right, roffset, rlength));
1786       final int metalength = 7; // '.META.' length
1787       int lmetaOffsetPlusDelimiter = loffset + metalength;
1788       int leftFarDelimiter = getDelimiterInReverse(left,
1789           lmetaOffsetPlusDelimiter,
1790           llength - metalength, HRegionInfo.DELIMITER);
1791       int rmetaOffsetPlusDelimiter = roffset + metalength;
1792       int rightFarDelimiter = getDelimiterInReverse(right,
1793           rmetaOffsetPlusDelimiter, rlength - metalength,
1794           HRegionInfo.DELIMITER);
1795       if (leftFarDelimiter < 0 && rightFarDelimiter >= 0) {
1796         // Nothing between .META. and regionid.  Its first key.
1797         return -1;
1798       } else if (rightFarDelimiter < 0 && leftFarDelimiter >= 0) {
1799         return 1;
1800       } else if (leftFarDelimiter < 0 && rightFarDelimiter < 0) {
1801         return 0;
1802       }
1803       int result = super.compareRows(left, lmetaOffsetPlusDelimiter,
1804           leftFarDelimiter - lmetaOffsetPlusDelimiter,
1805           right, rmetaOffsetPlusDelimiter,
1806           rightFarDelimiter - rmetaOffsetPlusDelimiter);
1807       if (result != 0) {
1808         return result;
1809       }
1810       // Compare last part of row, the rowid.
1811       leftFarDelimiter++;
1812       rightFarDelimiter++;
1813       result = compareRowid(left, leftFarDelimiter,
1814           llength - (leftFarDelimiter - loffset),
1815           right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
1816       return result;
1817     }
1818   }
1819 
1820   /**
1821    * Comparator that compares row component only of a KeyValue.
1822    */
1823   public static class RowComparator implements Comparator<KeyValue> {
1824     final KVComparator comparator;
1825 
1826     public RowComparator(final KVComparator c) {
1827       this.comparator = c;
1828     }
1829 
1830     public int compare(KeyValue left, KeyValue right) {
1831       return comparator.compareRows(left, right);
1832     }
1833   }
1834 
1835   /**
1836    * Compare key portion of a {@link KeyValue} for keys in <code>.META.</code>
1837    * table.
1838    */
1839   public static class MetaKeyComparator extends KeyComparator {
1840     public int compareRows(byte [] left, int loffset, int llength,
1841         byte [] right, int roffset, int rlength) {
1842       //        LOG.info("META " + Bytes.toString(left, loffset, llength) +
1843       //          "---" + Bytes.toString(right, roffset, rlength));
1844       int leftDelimiter = getDelimiter(left, loffset, llength,
1845           HRegionInfo.DELIMITER);
1846       int rightDelimiter = getDelimiter(right, roffset, rlength,
1847           HRegionInfo.DELIMITER);
1848       if (leftDelimiter < 0 && rightDelimiter >= 0) {
1849         // Nothing between .META. and regionid.  Its first key.
1850         return -1;
1851       } else if (rightDelimiter < 0 && leftDelimiter >= 0) {
1852         return 1;
1853       } else if (leftDelimiter < 0 && rightDelimiter < 0) {
1854         return 0;
1855       }
1856       // Compare up to the delimiter
1857       int result = Bytes.compareTo(left, loffset, leftDelimiter - loffset,
1858           right, roffset, rightDelimiter - roffset);
1859       if (result != 0) {
1860         return result;
1861       }
1862       // Compare middle bit of the row.
1863       // Move past delimiter
1864       leftDelimiter++;
1865       rightDelimiter++;
1866       int leftFarDelimiter = getRequiredDelimiterInReverse(left, leftDelimiter,
1867           llength - (leftDelimiter - loffset), HRegionInfo.DELIMITER);
1868       int rightFarDelimiter = getRequiredDelimiterInReverse(right,
1869           rightDelimiter, rlength - (rightDelimiter - roffset),
1870           HRegionInfo.DELIMITER);
1871       // Now compare middlesection of row.
1872       result = super.compareRows(left, leftDelimiter,
1873           leftFarDelimiter - leftDelimiter, right, rightDelimiter,
1874           rightFarDelimiter - rightDelimiter);
1875       if (result != 0) {
1876         return result;
1877       }
1878       // Compare last part of row, the rowid.
1879       leftFarDelimiter++;
1880       rightFarDelimiter++;
1881       result = compareRowid(left, leftFarDelimiter,
1882           llength - (leftFarDelimiter - loffset),
1883           right, rightFarDelimiter, rlength - (rightFarDelimiter - roffset));
1884       return result;
1885     }
1886 
1887     protected int compareRowid(byte[] left, int loffset, int llength,
1888         byte[] right, int roffset, int rlength) {
1889       return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
1890     }
1891   }
1892 
1893   /**
1894    * Compare key portion of a {@link KeyValue}.
1895    */
1896   public static class KeyComparator implements RawComparator<byte []> {
1897     volatile boolean ignoreTimestamp = false;
1898     volatile boolean ignoreType = false;
1899 
1900     public int compare(byte[] left, int loffset, int llength, byte[] right,
1901         int roffset, int rlength) {
1902       // Compare row
1903       short lrowlength = Bytes.toShort(left, loffset);
1904       short rrowlength = Bytes.toShort(right, roffset);
1905       int compare = compareRows(left, loffset + Bytes.SIZEOF_SHORT,
1906           lrowlength,
1907           right, roffset + Bytes.SIZEOF_SHORT, rrowlength);
1908       if (compare != 0) {
1909         return compare;
1910       }
1911 
1912       // Compare column family.  Start compare past row and family length.
1913       int lcolumnoffset = Bytes.SIZEOF_SHORT + lrowlength + 1 + loffset;
1914       int rcolumnoffset = Bytes.SIZEOF_SHORT + rrowlength + 1 + roffset;
1915       int lcolumnlength = llength - TIMESTAMP_TYPE_SIZE -
1916         (lcolumnoffset - loffset);
1917       int rcolumnlength = rlength - TIMESTAMP_TYPE_SIZE -
1918         (rcolumnoffset - roffset);
1919 
1920       // if row matches, and no column in the 'left' AND put type is 'minimum',
1921       // then return that left is larger than right.
1922 
1923       // This supports 'last key on a row' - the magic is if there is no column in the
1924       // left operand, and the left operand has a type of '0' - magical value,
1925       // then we say the left is bigger.  This will let us seek to the last key in
1926       // a row.
1927 
1928       byte ltype = left[loffset + (llength - 1)];
1929       byte rtype = right[roffset + (rlength - 1)];
1930 
1931       if (lcolumnlength == 0 && ltype == Type.Minimum.getCode()) {
1932         return 1; // left is bigger.
1933       }
1934       if (rcolumnlength == 0 && rtype == Type.Minimum.getCode()) {
1935         return -1;
1936       }
1937 
1938       // TODO the family and qualifier should be compared separately
1939       compare = Bytes.compareTo(left, lcolumnoffset, lcolumnlength, right,
1940           rcolumnoffset, rcolumnlength);
1941       if (compare != 0) {
1942         return compare;
1943       }
1944 
1945       if (!this.ignoreTimestamp) {
1946         // Get timestamps.
1947         long ltimestamp = Bytes.toLong(left,
1948             loffset + (llength - TIMESTAMP_TYPE_SIZE));
1949         long rtimestamp = Bytes.toLong(right,
1950             roffset + (rlength - TIMESTAMP_TYPE_SIZE));
1951         compare = compareTimestamps(ltimestamp, rtimestamp);
1952         if (compare != 0) {
1953           return compare;
1954         }
1955       }
1956 
1957       if (!this.ignoreType) {
1958         // Compare types. Let the delete types sort ahead of puts; i.e. types
1959         // of higher numbers sort before those of lesser numbers
1960         return (0xff & rtype) - (0xff & ltype);
1961       }
1962       return 0;
1963     }
1964 
1965     public int compare(byte[] left, byte[] right) {
1966       return compare(left, 0, left.length, right, 0, right.length);
1967     }
1968 
1969     public int compareRows(byte [] left, int loffset, int llength,
1970         byte [] right, int roffset, int rlength) {
1971       return Bytes.compareTo(left, loffset, llength, right, roffset, rlength);
1972     }
1973 
1974     protected int compareColumns(
1975         byte [] left, int loffset, int llength, final int lfamilylength,
1976         byte [] right, int roffset, int rlength, final int rfamilylength) {
1977       return KeyValue.compareColumns(left, loffset, llength, lfamilylength,
1978         right, roffset, rlength, rfamilylength);
1979     }
1980 
1981     int compareTimestamps(final long ltimestamp, final long rtimestamp) {
1982       // The below older timestamps sorting ahead of newer timestamps looks
1983       // wrong but it is intentional. This way, newer timestamps are first
1984       // found when we iterate over a memstore and newer versions are the
1985       // first we trip over when reading from a store file.
1986       if (ltimestamp < rtimestamp) {
1987         return 1;
1988       } else if (ltimestamp > rtimestamp) {
1989         return -1;
1990       }
1991       return 0;
1992     }
1993   }
1994 
1995   // HeapSize
1996   public long heapSize() {
1997     return ClassSize.align(ClassSize.OBJECT + (2 * ClassSize.REFERENCE) +
1998         ClassSize.align(ClassSize.ARRAY) + ClassSize.align(length) +
1999         (3 * Bytes.SIZEOF_INT) +
2000         ClassSize.align(ClassSize.ARRAY) +
2001         (2 * Bytes.SIZEOF_LONG));
2002   }
2003 
2004   // this overload assumes that the length bytes have already been read,
2005   // and it expects the length of the KeyValue to be explicitly passed
2006   // to it.
2007   public void readFields(int length, final DataInput in) throws IOException {
2008     this.length = length;
2009     this.offset = 0;
2010     this.bytes = new byte[this.length];
2011     in.readFully(this.bytes, 0, this.length);
2012   }
2013 
2014   // Writable
2015   public void readFields(final DataInput in) throws IOException {
2016     int length = in.readInt();
2017     readFields(length, in);
2018   }
2019 
2020   public void write(final DataOutput out) throws IOException {
2021     out.writeInt(this.length);
2022     out.write(this.bytes, this.offset, this.length);
2023   }
2024 }