View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase;
20  
21  import static org.apache.hadoop.hbase.HConstants.EMPTY_BYTE_ARRAY;
22  import static org.apache.hadoop.hbase.Tag.TAG_LENGTH_SIZE;
23  
24  import java.io.DataOutputStream;
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.math.BigDecimal;
28  import java.nio.ByteBuffer;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map.Entry;
34  import java.util.NavigableMap;
35
36  import org.apache.hadoop.hbase.KeyValue.Type;
37  import org.apache.hadoop.hbase.classification.InterfaceAudience;
38  import org.apache.hadoop.hbase.classification.InterfaceAudience.Private;
39  import org.apache.hadoop.hbase.classification.InterfaceStability;
40  import org.apache.hadoop.hbase.io.HeapSize;
41  import org.apache.hadoop.hbase.io.TagCompressionContext;
42  import org.apache.hadoop.hbase.util.ByteBufferUtils;
43  import org.apache.hadoop.hbase.util.ByteRange;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.apache.hadoop.hbase.util.ClassSize;
46
47  /**
48   * Utility methods helpful slinging {@link Cell} instances.
49   * Some methods below are for internal use only and are marked InterfaceAudience.Private at the
50   * method level.
51   */
52  @InterfaceAudience.Public
53  @InterfaceStability.Evolving
54  public final class CellUtil {
55
56    /**
57     * Private constructor to keep this class from being instantiated.
58     */
59    private CellUtil(){}
60
61    /******************* ByteRange *******************************/
62
63    public static ByteRange fillRowRange(Cell cell, ByteRange range) {
64      return range.set(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
65    }
66
67    public static ByteRange fillFamilyRange(Cell cell, ByteRange range) {
68      return range.set(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());
69    }
70
71    public static ByteRange fillQualifierRange(Cell cell, ByteRange range) {
72      return range.set(cell.getQualifierArray(), cell.getQualifierOffset(),
73        cell.getQualifierLength());
74    }
75
76    public static ByteRange fillValueRange(Cell cell, ByteRange range) {
77      return range.set(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
78    }
79
80    public static ByteRange fillTagRange(Cell cell, ByteRange range) {
81      return range.set(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
82    }
83
84    /***************** get individual arrays for tests ************/
85
86    public static byte[] cloneRow(Cell cell){
87      byte[] output = new byte[cell.getRowLength()];
88      copyRowTo(cell, output, 0);
89      return output;
90    }
91
92    public static byte[] cloneFamily(Cell cell){
93      byte[] output = new byte[cell.getFamilyLength()];
94      copyFamilyTo(cell, output, 0);
95      return output;
96    }
97
98    public static byte[] cloneQualifier(Cell cell){
99      byte[] output = new byte[cell.getQualifierLength()];
100     copyQualifierTo(cell, output, 0);
101     return output;
102   }
103
104   public static byte[] cloneValue(Cell cell){
105     byte[] output = new byte[cell.getValueLength()];
106     copyValueTo(cell, output, 0);
107     return output;
108   }
109
110   public static byte[] cloneTags(Cell cell) {
111     byte[] output = new byte[cell.getTagsLength()];
112     copyTagTo(cell, output, 0);
113     return output;
114   }
115
116   /**
117    * Returns tag value in a new byte array. If server-side, use
118    * {@link Tag#getValueArray()} with appropriate {@link Tag#getValueOffset()} and
119    * {@link Tag#getValueLength()} instead to save on allocations.
120    * @param cell
121    * @return tag value in a new byte array.
122    */
123   public static byte[] getTagArray(Cell cell){
124     byte[] output = new byte[cell.getTagsLength()];
125     copyTagTo(cell, output, 0);
126     return output;
127   }
128
129
130   /******************** copyTo **********************************/
131
132   public static int copyRowTo(Cell cell, byte[] destination, int destinationOffset) {
133     short rowLen = cell.getRowLength();
134     if (cell instanceof ByteBufferedCell) {
135       ByteBufferUtils.copyFromBufferToArray(destination,
136           ((ByteBufferedCell) cell).getRowByteBuffer(),
137           ((ByteBufferedCell) cell).getRowPosition(), destinationOffset, rowLen);
138     } else {
139       System.arraycopy(cell.getRowArray(), cell.getRowOffset(), destination, destinationOffset,
140           rowLen);
141     }
142     return destinationOffset + rowLen;
143   }
144
145   /**
146    * Copies the row to a new byte[]
147    * @param cell the cell from which row has to copied
148    * @return the byte[] containing the row
149    */
150   public static byte[] copyRow(Cell cell) {
151     if (cell instanceof ByteBufferedCell) {
152       return ByteBufferUtils.copyOfRange(((ByteBufferedCell) cell).getRowByteBuffer(),
153         ((ByteBufferedCell) cell).getRowPosition(),
154         ((ByteBufferedCell) cell).getRowPosition() + cell.getRowLength());
155     } else {
156       return Arrays.copyOfRange(cell.getRowArray(), cell.getRowOffset(),
157         cell.getRowOffset() + cell.getRowLength());
158     }
159   }
160
161   public static int copyFamilyTo(Cell cell, byte[] destination, int destinationOffset) {
162     byte fLen = cell.getFamilyLength();
163     if (cell instanceof ByteBufferedCell) {
164       ByteBufferUtils.copyFromBufferToArray(destination,
165           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
166           ((ByteBufferedCell) cell).getFamilyPosition(), destinationOffset, fLen);
167     } else {
168       System.arraycopy(cell.getFamilyArray(), cell.getFamilyOffset(), destination,
169           destinationOffset, fLen);
170     }
171     return destinationOffset + fLen;
172   }
173
174   public static int copyQualifierTo(Cell cell, byte[] destination, int destinationOffset) {
175     int qlen = cell.getQualifierLength();
176     if (cell instanceof ByteBufferedCell) {
177       ByteBufferUtils.copyFromBufferToArray(destination,
178           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
179           ((ByteBufferedCell) cell).getQualifierPosition(), destinationOffset, qlen);
180     } else {
181       System.arraycopy(cell.getQualifierArray(), cell.getQualifierOffset(), destination,
182           destinationOffset, qlen);
183     }
184     return destinationOffset + qlen;
185   }
186
187   public static int copyValueTo(Cell cell, byte[] destination, int destinationOffset) {
188     int vlen = cell.getValueLength();
189     if (cell instanceof ByteBufferedCell) {
190       ByteBufferUtils.copyFromBufferToArray(destination,
191           ((ByteBufferedCell) cell).getValueByteBuffer(),
192           ((ByteBufferedCell) cell).getValuePosition(), destinationOffset, vlen);
193     } else {
194       System.arraycopy(cell.getValueArray(), cell.getValueOffset(), destination, destinationOffset,
195           vlen);
196     }
197     return destinationOffset + vlen;
198   }
199
200   /**
201    * Copies the tags info into the tag portion of the cell
202    * @param cell
203    * @param destination
204    * @param destinationOffset
205    * @return position after tags
206    */
207   public static int copyTagTo(Cell cell, byte[] destination, int destinationOffset) {
208     int tlen = cell.getTagsLength();
209     if (cell instanceof ByteBufferedCell) {
210       ByteBufferUtils.copyFromBufferToArray(destination,
211           ((ByteBufferedCell) cell).getTagsByteBuffer(),
212           ((ByteBufferedCell) cell).getTagsPosition(), destinationOffset, tlen);
213     } else {
214       System.arraycopy(cell.getTagsArray(), cell.getTagsOffset(), destination, destinationOffset,
215           tlen);
216     }
217     return destinationOffset + tlen;
218   }
219
220   /********************* misc *************************************/
221
222   @Private
223   public static byte getRowByte(Cell cell, int index) {
224     if (cell instanceof ByteBufferedCell) {
225       return ((ByteBufferedCell) cell).getRowByteBuffer().get(
226           ((ByteBufferedCell) cell).getRowPosition() + index);
227     }
228     return cell.getRowArray()[cell.getRowOffset() + index];
229   }
230
231   @Private
232   public static byte getQualifierByte(Cell cell, int index) {
233     if (cell instanceof ByteBufferedCell) {
234       return ((ByteBufferedCell) cell).getQualifierByteBuffer().get(
235           ((ByteBufferedCell) cell).getQualifierPosition() + index);
236     }
237     return cell.getQualifierArray()[cell.getQualifierOffset() + index];
238   }
239
240   public static ByteBuffer getValueBufferShallowCopy(Cell cell) {
241     ByteBuffer buffer = ByteBuffer.wrap(cell.getValueArray(), cell.getValueOffset(),
242       cell.getValueLength());
243     return buffer;
244   }
245
246   /**
247    * @param cell
248    * @return cell's qualifier wrapped into a ByteBuffer.
249    * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
250    */
251   @Deprecated
252   public static ByteBuffer getQualifierBufferShallowCopy(Cell cell) {
253     // No usage of this in code.
254     ByteBuffer buffer = ByteBuffer.wrap(cell.getQualifierArray(), cell.getQualifierOffset(),
255         cell.getQualifierLength());
256     return buffer;
257   }
258
259   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier,
260       final long timestamp, final byte type, final byte [] value) {
261     // I need a Cell Factory here.  Using KeyValue for now. TODO.
262     // TODO: Make a new Cell implementation that just carries these
263     // byte arrays.
264     // TODO: Call factory to create Cell
265     return new KeyValue(row, family, qualifier, timestamp, KeyValue.Type.codeToType(type), value);
266   }
267
268   public static Cell createCell(final byte [] rowArray, final int rowOffset, final int rowLength,
269       final byte [] familyArray, final int familyOffset, final int familyLength,
270       final byte [] qualifierArray, final int qualifierOffset, final int qualifierLength) {
271     // See createCell(final byte [] row, final byte [] value) for why we default Maximum type.
272     return new KeyValue(rowArray, rowOffset, rowLength,
273         familyArray, familyOffset, familyLength,
274         qualifierArray, qualifierOffset, qualifierLength,
275         HConstants.LATEST_TIMESTAMP,
276         KeyValue.Type.Maximum,
277         HConstants.EMPTY_BYTE_ARRAY, 0, HConstants.EMPTY_BYTE_ARRAY.length);
278   }
279
280   /**
281    * Marked as audience Private as of 1.2.0.
282    * Creating a Cell with a memstoreTS/mvcc is an internal implementation detail not for
283    * public use.
284    */
285   @InterfaceAudience.Private
286   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
287       final long timestamp, final byte type, final byte[] value, final long memstoreTS) {
288     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
289         KeyValue.Type.codeToType(type), value);
290     keyValue.setSequenceId(memstoreTS);
291     return keyValue;
292   }
293
294   /**
295    * Marked as audience Private as of 1.2.0.
296    * Creating a Cell with tags and a memstoreTS/mvcc is an internal implementation detail not for
297    * public use.
298    */
299   @InterfaceAudience.Private
300   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
301       final long timestamp, final byte type, final byte[] value, byte[] tags,
302       final long memstoreTS) {
303     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp,
304         KeyValue.Type.codeToType(type), value, tags);
305     keyValue.setSequenceId(memstoreTS);
306     return keyValue;
307   }
308
309   /**
310    * Marked as audience Private as of 1.2.0.
311    * Creating a Cell with tags is an internal implementation detail not for
312    * public use.
313    */
314   @InterfaceAudience.Private
315   public static Cell createCell(final byte[] row, final byte[] family, final byte[] qualifier,
316       final long timestamp, Type type, final byte[] value, byte[] tags) {
317     KeyValue keyValue = new KeyValue(row, family, qualifier, timestamp, type, value, tags);
318     return keyValue;
319   }
320
321   /**
322    * Create a Cell with specific row.  Other fields defaulted.
323    * @param row
324    * @return Cell with passed row but all other fields are arbitrary
325    */
326   public static Cell createCell(final byte [] row) {
327     return createCell(row, HConstants.EMPTY_BYTE_ARRAY);
328   }
329
330   /**
331    * Create a Cell with specific row and value.  Other fields are defaulted.
332    * @param row
333    * @param value
334    * @return Cell with passed row and value but all other fields are arbitrary
335    */
336   public static Cell createCell(final byte [] row, final byte [] value) {
337     // An empty family + empty qualifier + Type.Minimum is used as flag to indicate last on row.
338     // See the CellComparator and KeyValue comparator.  Search for compareWithoutRow.
339     // Lets not make a last-on-row key as default but at same time, if you are making a key
340     // without specifying type, etc., flag it as weird by setting type to be Maximum.
341     return createCell(row, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
342       HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), value);
343   }
344
345   /**
346    * Create a Cell with specific row.  Other fields defaulted.
347    * @param row
348    * @param family
349    * @param qualifier
350    * @return Cell with passed row but all other fields are arbitrary
351    */
352   public static Cell createCell(final byte [] row, final byte [] family, final byte [] qualifier) {
353     // See above in createCell(final byte [] row, final byte [] value) why we set type to Maximum.
354     return createCell(row, family, qualifier,
355         HConstants.LATEST_TIMESTAMP, KeyValue.Type.Maximum.getCode(), HConstants.EMPTY_BYTE_ARRAY);
356   }
357
358   /**
359    * @return A new cell which is having the extra tags also added to it.
360    */
361   public static Cell createCell(Cell cell, List<Tag> tags) {
362     return createCell(cell, TagUtil.fromList(tags));
363   }
364
365   /**
366    * @return A new cell which is having the extra tags also added to it.
367    */
368   public static Cell createCell(Cell cell, byte[] tags) {
369     if (cell instanceof ShareableMemory) {
370       return new ShareableMemoryTagRewriteCell(cell, tags);
371     }
372     return new TagRewriteCell(cell, tags);
373   }
374
375   /**
376    * This can be used when a Cell has to change with addition/removal of one or more tags. This is an
377    * efficient way to do so in which only the tags bytes part need to recreated and copied. All other
378    * parts, refer to the original Cell.
379    */
380   @InterfaceAudience.Private
381   private static class TagRewriteCell implements ExtendedCell {
382     protected Cell cell;
383     protected byte[] tags;
384
385     /**
386      * @param cell The original Cell which it rewrites
387      * @param tags the tags bytes. The array suppose to contain the tags bytes alone.
388      */
389     public TagRewriteCell(Cell cell, byte[] tags) {
390       assert cell instanceof ExtendedCell;
391       assert tags != null;
392       this.cell = cell;
393       this.tags = tags;
394       // tag offset will be treated as 0 and length this.tags.length
395       if (this.cell instanceof TagRewriteCell) {
396         // Cleaning the ref so that the byte[] can be GCed
397         ((TagRewriteCell) this.cell).tags = null;
398       }
399     }
400
401     @Override
402     public byte[] getRowArray() {
403       return cell.getRowArray();
404     }
405
406     @Override
407     public int getRowOffset() {
408       return cell.getRowOffset();
409     }
410
411     @Override
412     public short getRowLength() {
413       return cell.getRowLength();
414     }
415
416     @Override
417     public byte[] getFamilyArray() {
418       return cell.getFamilyArray();
419     }
420
421     @Override
422     public int getFamilyOffset() {
423       return cell.getFamilyOffset();
424     }
425
426     @Override
427     public byte getFamilyLength() {
428       return cell.getFamilyLength();
429     }
430
431     @Override
432     public byte[] getQualifierArray() {
433       return cell.getQualifierArray();
434     }
435
436     @Override
437     public int getQualifierOffset() {
438       return cell.getQualifierOffset();
439     }
440
441     @Override
442     public int getQualifierLength() {
443       return cell.getQualifierLength();
444     }
445
446     @Override
447     public long getTimestamp() {
448       return cell.getTimestamp();
449     }
450
451     @Override
452     public byte getTypeByte() {
453       return cell.getTypeByte();
454     }
455
456     @Override
457     public long getSequenceId() {
458       return cell.getSequenceId();
459     }
460
461     @Override
462     public byte[] getValueArray() {
463       return cell.getValueArray();
464     }
465
466     @Override
467     public int getValueOffset() {
468       return cell.getValueOffset();
469     }
470
471     @Override
472     public int getValueLength() {
473       return cell.getValueLength();
474     }
475
476     @Override
477     public byte[] getTagsArray() {
478       return this.tags;
479     }
480
481     @Override
482     public int getTagsOffset() {
483       return 0;
484     }
485
486     @Override
487     public int getTagsLength() {
488       if (null == this.tags) {
489         // Nulled out tags array optimization in constructor
490         return 0;
491       }
492       return this.tags.length;
493     }
494
495     @Override
496     public long heapSize() {
497       long sum = CellUtil.estimatedHeapSizeOf(cell) - cell.getTagsLength();
498       sum += ClassSize.OBJECT;// this object itself
499       sum += (2 * ClassSize.REFERENCE);// pointers to cell and tags array
500       if (this.tags != null) {
501         sum += ClassSize.align(ClassSize.ARRAY);// "tags"
502         sum += this.tags.length;
503       }
504       return sum;
505     }
506
507     @Override
508     public void setTimestamp(long ts) throws IOException {
509       // The incoming cell is supposed to be SettableTimestamp type.
510       CellUtil.setTimestamp(cell, ts);
511     }
512
513     @Override
514     public void setTimestamp(byte[] ts, int tsOffset) throws IOException {
515       // The incoming cell is supposed to be SettableTimestamp type.
516       CellUtil.setTimestamp(cell, ts, tsOffset);
517     }
518
519     @Override
520     public void setSequenceId(long seqId) throws IOException {
521       // The incoming cell is supposed to be SettableSequenceId type.
522       CellUtil.setSequenceId(cell, seqId);
523     }
524
525     @Override
526     public int write(OutputStream out, boolean withTags) throws IOException {
527       int len = ((ExtendedCell) this.cell).write(out, false);
528       if (withTags && this.tags != null) {
529         // Write the tagsLength 2 bytes
530         out.write((byte) (0xff & (this.tags.length >> 8)));
531         out.write((byte) (0xff & this.tags.length));
532         out.write(this.tags);
533         len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
534       }
535       return len;
536     }
537
538     @Override
539     public int getSerializedSize(boolean withTags) {
540       int len = ((ExtendedCell) this.cell).getSerializedSize(false);
541       if (withTags && this.tags != null) {
542         len += KeyValue.TAGS_LENGTH_SIZE + this.tags.length;
543       }
544       return len;
545     }
546   }
547
548   /**
549    * Version of TagRewriteCell where the original Cell is ShareableMemory type.
550    */
551   private static class ShareableMemoryTagRewriteCell extends TagRewriteCell implements
552       ShareableMemory {
553
554     public ShareableMemoryTagRewriteCell(Cell cell, byte[] tags) {
555       super(cell, tags);
556       assert cell instanceof ShareableMemory;
557     }
558
559     @Override
560     public Cell cloneToCell() {
561       Cell clonedBaseCell = ((ShareableMemory) this.cell).cloneToCell();
562       return new TagRewriteCell(clonedBaseCell, this.tags);
563     }
564   }
565
566   /**
567    * @param cellScannerables
568    * @return CellScanner interface over <code>cellIterables</code>
569    */
570   public static CellScanner createCellScanner(
571       final List<? extends CellScannable> cellScannerables) {
572     return new CellScanner() {
573       private final Iterator<? extends CellScannable> iterator = cellScannerables.iterator();
574       private CellScanner cellScanner = null;
575
576       @Override
577       public Cell current() {
578         return this.cellScanner != null? this.cellScanner.current(): null;
579       }
580
581       @Override
582       public boolean advance() throws IOException {
583         while (true) {
584           if (this.cellScanner == null) {
585             if (!this.iterator.hasNext()) return false;
586             this.cellScanner = this.iterator.next().cellScanner();
587           }
588           if (this.cellScanner.advance()) return true;
589           this.cellScanner = null;
590         }
591       }
592     };
593   }
594
595   /**
596    * @param cellIterable
597    * @return CellScanner interface over <code>cellIterable</code>
598    */
599   public static CellScanner createCellScanner(final Iterable<Cell> cellIterable) {
600     if (cellIterable == null) return null;
601     return createCellScanner(cellIterable.iterator());
602   }
603
604   /**
605    * @param cells
606    * @return CellScanner interface over <code>cellIterable</code> or null if <code>cells</code> is
607    * null
608    */
609   public static CellScanner createCellScanner(final Iterator<Cell> cells) {
610     if (cells == null) return null;
611     return new CellScanner() {
612       private final Iterator<Cell> iterator = cells;
613       private Cell current = null;
614
615       @Override
616       public Cell current() {
617         return this.current;
618       }
619
620       @Override
621       public boolean advance() {
622         boolean hasNext = this.iterator.hasNext();
623         this.current = hasNext? this.iterator.next(): null;
624         return hasNext;
625       }
626     };
627   }
628
629   /**
630    * @param cellArray
631    * @return CellScanner interface over <code>cellArray</code>
632    */
633   public static CellScanner createCellScanner(final Cell[] cellArray) {
634     return new CellScanner() {
635       private final Cell [] cells = cellArray;
636       private int index = -1;
637
638       @Override
639       public Cell current() {
640         if (cells == null) return null;
641         return (index < 0)? null: this.cells[index];
642       }
643
644       @Override
645       public boolean advance() {
646         if (cells == null) return false;
647         return ++index < this.cells.length;
648       }
649     };
650   }
651
652   /**
653    * Flatten the map of cells out under the CellScanner
654    * @param map Map of Cell Lists; for example, the map of families to Cells that is used
655    * inside Put, etc., keeping Cells organized by family.
656    * @return CellScanner interface over <code>cellIterable</code>
657    */
658   public static CellScanner createCellScanner(final NavigableMap<byte [], List<Cell>> map) {
659     return new CellScanner() {
660       private final Iterator<Entry<byte[], List<Cell>>> entries = map.entrySet().iterator();
661       private Iterator<Cell> currentIterator = null;
662       private Cell currentCell;
663
664       @Override
665       public Cell current() {
666         return this.currentCell;
667       }
668
669       @Override
670       public boolean advance() {
671         while(true) {
672           if (this.currentIterator == null) {
673             if (!this.entries.hasNext()) return false;
674             this.currentIterator = this.entries.next().getValue().iterator();
675           }
676           if (this.currentIterator.hasNext()) {
677             this.currentCell = this.currentIterator.next();
678             return true;
679           }
680           this.currentCell = null;
681           this.currentIterator = null;
682         }
683       }
684     };
685   }
686
687   /**
688    * @param left
689    * @param right
690    * @return True if the rows in <code>left</code> and <code>right</code> Cells match
691    * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
692    *             Instead use {@link #matchingRows(Cell, Cell)}
693    */
694   @Deprecated
695   public static boolean matchingRow(final Cell left, final Cell right) {
696     return matchingRows(left, right);
697   }
698
699   public static boolean matchingRow(final Cell left, final byte[] buf) {
700     if (buf == null) {
701       return left.getRowLength() == 0;
702     }
703     return matchingRow(left, buf, 0, buf.length);
704   }
705
706   public static boolean matchingRow(final Cell left, final byte[] buf, final int offset,
707       final int length) {
708     if (left instanceof ByteBufferedCell) {
709       return ByteBufferUtils.equals(((ByteBufferedCell) left).getRowByteBuffer(),
710           ((ByteBufferedCell) left).getRowPosition(), left.getRowLength(), buf, offset,
711           length);
712     }
713     return Bytes.equals(left.getRowArray(), left.getRowOffset(), left.getRowLength(), buf, offset,
714         length);
715   }
716
717   public static boolean matchingFamily(final Cell left, final Cell right) {
718     byte lfamlength = left.getFamilyLength();
719     byte rfamlength = right.getFamilyLength();
720     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
721       return ByteBufferUtils.equals(((ByteBufferedCell) left).getFamilyByteBuffer(),
722           ((ByteBufferedCell) left).getFamilyPosition(), lfamlength,
723           ((ByteBufferedCell) right).getFamilyByteBuffer(),
724           ((ByteBufferedCell) right).getFamilyPosition(), rfamlength);
725     }
726     if (left instanceof ByteBufferedCell) {
727       return ByteBufferUtils.equals(((ByteBufferedCell) left).getFamilyByteBuffer(),
728           ((ByteBufferedCell) left).getFamilyPosition(), lfamlength,
729           right.getFamilyArray(), right.getFamilyOffset(), rfamlength);
730     }
731     if (right instanceof ByteBufferedCell) {
732       return ByteBufferUtils.equals(((ByteBufferedCell) right).getFamilyByteBuffer(),
733           ((ByteBufferedCell) right).getFamilyPosition(), rfamlength,
734           left.getFamilyArray(), left.getFamilyOffset(), lfamlength);
735     }
736     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), lfamlength,
737         right.getFamilyArray(), right.getFamilyOffset(), rfamlength);
738   }
739
740   public static boolean matchingFamily(final Cell left, final byte[] buf) {
741     if (buf == null) {
742       return left.getFamilyLength() == 0;
743     }
744     return matchingFamily(left, buf, 0, buf.length);
745   }
746
747   public static boolean matchingFamily(final Cell left, final byte[] buf, final int offset,
748       final int length) {
749     if (left instanceof ByteBufferedCell) {
750       return ByteBufferUtils.equals(((ByteBufferedCell) left).getFamilyByteBuffer(),
751           ((ByteBufferedCell) left).getFamilyPosition(), left.getFamilyLength(), buf,
752           offset, length);
753     }
754     return Bytes.equals(left.getFamilyArray(), left.getFamilyOffset(), left.getFamilyLength(), buf,
755         offset, length);
756   }
757
758   public static boolean matchingQualifier(final Cell left, final Cell right) {
759     int lqlength = left.getQualifierLength();
760     int rqlength = right.getQualifierLength();
761     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
762       return ByteBufferUtils.equals(((ByteBufferedCell) left).getQualifierByteBuffer(),
763           ((ByteBufferedCell) left).getQualifierPosition(), lqlength,
764           ((ByteBufferedCell) right).getQualifierByteBuffer(),
765           ((ByteBufferedCell) right).getQualifierPosition(), rqlength);
766     }
767     if (left instanceof ByteBufferedCell) {
768       return ByteBufferUtils.equals(((ByteBufferedCell) left).getQualifierByteBuffer(),
769           ((ByteBufferedCell) left).getQualifierPosition(), lqlength,
770           right.getQualifierArray(), right.getQualifierOffset(), rqlength);
771     }
772     if (right instanceof ByteBufferedCell) {
773       return ByteBufferUtils.equals(((ByteBufferedCell) right).getQualifierByteBuffer(),
774           ((ByteBufferedCell) right).getQualifierPosition(), rqlength,
775           left.getQualifierArray(), left.getQualifierOffset(), lqlength);
776     }
777     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
778         lqlength, right.getQualifierArray(), right.getQualifierOffset(),
779         rqlength);
780   }
781
782   /**
783    * Finds if the qualifier part of the cell and the KV serialized
784    * byte[] are equal
785    * @param left
786    * @param buf the serialized keyvalue format byte[]
787    * @return true if the qualifier matches, false otherwise
788    */
789   public static boolean matchingQualifier(final Cell left, final byte[] buf) {
790     if (buf == null) {
791       return left.getQualifierLength() == 0;
792     }
793     return matchingQualifier(left, buf, 0, buf.length);
794   }
795
796   /**
797    * Finds if the qualifier part of the cell and the KV serialized
798    * byte[] are equal
799    * @param left
800    * @param buf the serialized keyvalue format byte[]
801    * @param offset the offset of the qualifier in the byte[]
802    * @param length the length of the qualifier in the byte[]
803    * @return true if the qualifier matches, false otherwise
804    */
805   public static boolean matchingQualifier(final Cell left, final byte[] buf, final int offset,
806       final int length) {
807     if (buf == null) {
808       return left.getQualifierLength() == 0;
809     }
810     if (left instanceof ByteBufferedCell) {
811       return ByteBufferUtils.equals(((ByteBufferedCell) left).getQualifierByteBuffer(),
812           ((ByteBufferedCell) left).getQualifierPosition(), left.getQualifierLength(),
813           buf, offset, length);
814     }
815     return Bytes.equals(left.getQualifierArray(), left.getQualifierOffset(),
816         left.getQualifierLength(), buf, offset, length);
817   }
818
819   public static boolean matchingColumn(final Cell left, final byte[] fam, final byte[] qual) {
820     if (!matchingFamily(left, fam))
821       return false;
822     return matchingQualifier(left, qual);
823   }
824
825   public static boolean matchingColumn(final Cell left, final byte[] fam, final int foffset,
826       final int flength, final byte[] qual, final int qoffset, final int qlength) {
827     if (!matchingFamily(left, fam, foffset, flength))
828       return false;
829     return matchingQualifier(left, qual, qoffset, qlength);
830   }
831
832   public static boolean matchingColumn(final Cell left, final Cell right) {
833     if (!matchingFamily(left, right))
834       return false;
835     return matchingQualifier(left, right);
836   }
837
838   public static boolean matchingValue(final Cell left, final Cell right) {
839     return matchingValue(left, right, left.getValueLength(), right.getValueLength());
840   }
841
842   public static boolean matchingValue(final Cell left, final Cell right, int lvlength,
843       int rvlength) {
844     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
845       return ByteBufferUtils.equals(((ByteBufferedCell) left).getValueByteBuffer(),
846         ((ByteBufferedCell) left).getValuePosition(), lvlength,
847         ((ByteBufferedCell) right).getValueByteBuffer(),
848         ((ByteBufferedCell) right).getValuePosition(), rvlength);
849     }
850     if (left instanceof ByteBufferedCell) {
851       return ByteBufferUtils.equals(((ByteBufferedCell) left).getValueByteBuffer(),
852         ((ByteBufferedCell) left).getValuePosition(), lvlength, right.getValueArray(),
853         right.getValueOffset(), rvlength);
854     }
855     if (right instanceof ByteBufferedCell) {
856       return ByteBufferUtils.equals(((ByteBufferedCell) right).getValueByteBuffer(),
857         ((ByteBufferedCell) right).getValuePosition(), rvlength, left.getValueArray(),
858         left.getValueOffset(), lvlength);
859     }
860     return Bytes.equals(left.getValueArray(), left.getValueOffset(), lvlength,
861       right.getValueArray(), right.getValueOffset(), rvlength);
862   }
863
864   public static boolean matchingValue(final Cell left, final byte[] buf) {
865     if (left instanceof ByteBufferedCell) {
866       return ByteBufferUtils.compareTo(((ByteBufferedCell) left).getValueByteBuffer(),
867           ((ByteBufferedCell) left).getValuePosition(), left.getValueLength(), buf, 0,
868           buf.length) == 0;
869     }
870     return Bytes.equals(left.getValueArray(), left.getValueOffset(), left.getValueLength(), buf, 0,
871         buf.length);
872   }
873
874   /**
875    * @return True if a delete type, a {@link KeyValue.Type#Delete} or a
876    *         {KeyValue.Type#DeleteFamily} or a
877    *         {@link KeyValue.Type#DeleteColumn} KeyValue type.
878    */
879   public static boolean isDelete(final Cell cell) {
880     return isDelete(cell.getTypeByte());
881   }
882
883   /**
884    * @return True if a delete type, a {@link KeyValue.Type#Delete} or a
885    *         {KeyValue.Type#DeleteFamily} or a
886    *         {@link KeyValue.Type#DeleteColumn} KeyValue type.
887    */
888   public static boolean isDelete(final byte type) {
889     return Type.Delete.getCode() <= type
890         && type <= Type.DeleteFamily.getCode();
891   }
892
893   /**
894    * @return True if this cell is a {@link KeyValue.Type#Delete} type.
895    */
896   public static boolean isDeleteType(Cell cell) {
897     return cell.getTypeByte() == Type.Delete.getCode();
898   }
899
900   public static boolean isDeleteFamily(final Cell cell) {
901     return cell.getTypeByte() == Type.DeleteFamily.getCode();
902   }
903
904   public static boolean isDeleteFamilyVersion(final Cell cell) {
905     return cell.getTypeByte() == Type.DeleteFamilyVersion.getCode();
906   }
907
908   public static boolean isDeleteColumns(final Cell cell) {
909     return cell.getTypeByte() == Type.DeleteColumn.getCode();
910   }
911
912   public static boolean isDeleteColumnVersion(final Cell cell) {
913     return cell.getTypeByte() == Type.Delete.getCode();
914   }
915
916   /**
917    *
918    * @return True if this cell is a delete family or column type.
919    */
920   public static boolean isDeleteColumnOrFamily(Cell cell) {
921     int t = cell.getTypeByte();
922     return t == Type.DeleteColumn.getCode() || t == Type.DeleteFamily.getCode();
923   }
924
925   /**
926    * Estimate based on keyvalue's serialization format.
927    * @param cell
928    * @return Estimate of the <code>cell</code> size in bytes.
929    */
930   public static int estimatedSerializedSizeOf(final Cell cell) {
931     // If a KeyValue, we can give a good estimate of size.
932     if (cell instanceof KeyValue) {
933       return ((KeyValue)cell).getLength() + Bytes.SIZEOF_INT;
934     }
935     // TODO: Should we add to Cell a sizeOf?  Would it help? Does it make sense if Cell is
936     // prefix encoded or compressed?
937     return getSumOfCellElementLengths(cell) +
938       // Use the KeyValue's infrastructure size presuming that another implementation would have
939       // same basic cost.
940       KeyValue.ROW_LENGTH_SIZE + KeyValue.FAMILY_LENGTH_SIZE +
941       // Serialization is probably preceded by a length (it is in the KeyValueCodec at least).
942       Bytes.SIZEOF_INT;
943   }
944
945   /**
946    * @param cell
947    * @return Sum of the lengths of all the elements in a Cell; does not count in any infrastructure
948    */
949   private static int getSumOfCellElementLengths(final Cell cell) {
950     return getSumOfCellKeyElementLengths(cell) + cell.getValueLength() + cell.getTagsLength();
951   }
952
953   /**
954    * @param cell
955    * @return Sum of all elements that make up a key; does not include infrastructure, tags or
956    * values.
957    */
958   private static int getSumOfCellKeyElementLengths(final Cell cell) {
959     return cell.getRowLength() + cell.getFamilyLength() +
960     cell.getQualifierLength() +
961     KeyValue.TIMESTAMP_TYPE_SIZE;
962   }
963
964   /**
965    * Calculates the serialized key size. We always serialize in the KeyValue's serialization
966    * format.
967    * @param cell the cell for which the key size has to be calculated.
968    * @return the key size
969    */
970   public static int estimatedSerializedSizeOfKey(final Cell cell) {
971     if (cell instanceof KeyValue) return ((KeyValue)cell).getKeyLength();
972     return cell.getRowLength() + cell.getFamilyLength() +
973         cell.getQualifierLength() +
974         KeyValue.KEY_INFRASTRUCTURE_SIZE;
975   }
976
977   /**
978    * This is an estimate of the heap space occupied by a cell. When the cell is of type
979    * {@link HeapSize} we call {@link HeapSize#heapSize()} so cell can give a correct value. In other
980    * cases we just consider the bytes occupied by the cell components ie. row, CF, qualifier,
981    * timestamp, type, value and tags.
982    * @param cell
983    * @return estimate of the heap space
984    */
985   public static long estimatedHeapSizeOf(final Cell cell) {
986     if (cell instanceof HeapSize) {
987       return ((HeapSize) cell).heapSize();
988     }
989     // TODO: Add sizing of references that hold the row, family, etc., arrays.
990     return estimatedSerializedSizeOf(cell);
991   }
992
993   /********************* tags *************************************/
994   /**
995    * Util method to iterate through the tags
996    *
997    * @param tags
998    * @param offset
999    * @param length
1000    * @return iterator for the tags
1001    * @deprecated As of 2.0.0 and will be removed in 3.0.0
1002    *             Instead use {@link #tagsIterator(Cell)}
1003    */
1004   @Deprecated
1005   public static Iterator<Tag> tagsIterator(final byte[] tags, final int offset, final int length) {
1006     return new Iterator<Tag>() {
1007       private int pos = offset;
1008       private int endOffset = offset + length - 1;
1009
1010       @Override
1011       public boolean hasNext() {
1012         return this.pos < endOffset;
1013       }
1014
1015       @Override
1016       public Tag next() {
1017         if (hasNext()) {
1018           int curTagLen = Bytes.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
1019           Tag tag = new ArrayBackedTag(tags, pos, curTagLen + TAG_LENGTH_SIZE);
1020           this.pos += Bytes.SIZEOF_SHORT + curTagLen;
1021           return tag;
1022         }
1023         return null;
1024       }
1025
1026       @Override
1027       public void remove() {
1028         throw new UnsupportedOperationException();
1029       }
1030     };
1031   }
1032
1033   private static Iterator<Tag> tagsIterator(final ByteBuffer tags, final int offset,
1034       final int length) {
1035     return new Iterator<Tag>() {
1036       private int pos = offset;
1037       private int endOffset = offset + length - 1;
1038
1039       @Override
1040       public boolean hasNext() {
1041         return this.pos < endOffset;
1042       }
1043
1044       @Override
1045       public Tag next() {
1046         if (hasNext()) {
1047           int curTagLen = ByteBufferUtils.readAsInt(tags, this.pos, Tag.TAG_LENGTH_SIZE);
1048           Tag tag = new OffheapTag(tags, pos, curTagLen + Tag.TAG_LENGTH_SIZE);
1049           this.pos += Bytes.SIZEOF_SHORT + curTagLen;
1050           return tag;
1051         }
1052         return null;
1053       }
1054
1055       @Override
1056       public void remove() {
1057         throw new UnsupportedOperationException();
1058       }
1059     };
1060   }
1061
1062   private static final Iterator<Tag> EMPTY_TAGS_ITR = new Iterator<Tag>() {
1063     @Override
1064     public boolean hasNext() {
1065       return false;
1066     }
1067
1068     @Override
1069     @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="IT_NO_SUCH_ELEMENT",
1070       justification="Intentional")
1071     public Tag next() {
1072       return null;
1073     }
1074
1075     @Override
1076     public void remove() {
1077       throw new UnsupportedOperationException();
1078     }
1079   };
1080
1081   /**
1082    * Util method to iterate through the tags in the given cell.
1083    *
1084    * @param cell The Cell over which tags iterator is needed.
1085    * @return iterator for the tags
1086    */
1087   public static Iterator<Tag> tagsIterator(final Cell cell) {
1088     final int tagsLength = cell.getTagsLength();
1089     // Save an object allocation where we can
1090     if (tagsLength == 0) {
1091       return TagUtil.EMPTY_TAGS_ITR;
1092     }
1093     if (cell instanceof ByteBufferedCell) {
1094       return tagsIterator(((ByteBufferedCell) cell).getTagsByteBuffer(),
1095           ((ByteBufferedCell) cell).getTagsPosition(), tagsLength);
1096     }
1097     return tagsIterator(cell.getTagsArray(), cell.getTagsOffset(), tagsLength);
1098   }
1099
1100   /**
1101    * @param cell The Cell
1102    * @return Tags in the given Cell as a List
1103    */
1104   public static List<Tag> getTags(Cell cell) {
1105     List<Tag> tags = new ArrayList<Tag>();
1106     Iterator<Tag> tagsItr = tagsIterator(cell);
1107     while (tagsItr.hasNext()) {
1108       tags.add(tagsItr.next());
1109     }
1110     return tags;
1111   }
1112
1113   /**
1114    * Retrieve Cell's first tag, matching the passed in type
1115    *
1116    * @param cell The Cell
1117    * @param type Type of the Tag to retrieve
1118    * @return null if there is no tag of the passed in tag type
1119    */
1120   public static Tag getTag(Cell cell, byte type){
1121     boolean bufferBacked = cell instanceof ByteBufferedCell;
1122     int length = cell.getTagsLength();
1123     int offset = bufferBacked? ((ByteBufferedCell)cell).getTagsPosition():cell.getTagsOffset();
1124     int pos = offset;
1125     while (pos < offset + length) {
1126       int tagLen;
1127       if (bufferBacked) {
1128         ByteBuffer tagsBuffer = ((ByteBufferedCell)cell).getTagsByteBuffer();
1129         tagLen = ByteBufferUtils.readAsInt(tagsBuffer, pos, TAG_LENGTH_SIZE);
1130         if (ByteBufferUtils.toByte(tagsBuffer, pos + TAG_LENGTH_SIZE) == type) {
1131           return new OffheapTag(tagsBuffer, pos, tagLen + TAG_LENGTH_SIZE);
1132         }
1133       } else {
1134         tagLen = Bytes.readAsInt(cell.getTagsArray(), pos, TAG_LENGTH_SIZE);
1135         if (cell.getTagsArray()[pos + TAG_LENGTH_SIZE] == type) {
1136           return new ArrayBackedTag(cell.getTagsArray(), pos, tagLen + TAG_LENGTH_SIZE);
1137         }
1138       }
1139       pos += TAG_LENGTH_SIZE + tagLen;
1140     }
1141     return null;
1142   }
1143
1144   /**
1145    * Returns true if the first range start1...end1 overlaps with the second range
1146    * start2...end2, assuming the byte arrays represent row keys
1147    */
1148   public static boolean overlappingKeys(final byte[] start1, final byte[] end1,
1149       final byte[] start2, final byte[] end2) {
1150     return (end2.length == 0 || start1.length == 0 || Bytes.compareTo(start1,
1151         end2) < 0)
1152         && (end1.length == 0 || start2.length == 0 || Bytes.compareTo(start2,
1153             end1) < 0);
1154   }
1155
1156   /**
1157    * Sets the given seqId to the cell.
1158    * Marked as audience Private as of 1.2.0.
1159    * Setting a Cell sequenceid is an internal implementation detail not for general public use.
1160    * @param cell
1161    * @param seqId
1162    * @throws IOException when the passed cell is not of type {@link SettableSequenceId}
1163    */
1164   @InterfaceAudience.Private
1165   public static void setSequenceId(Cell cell, long seqId) throws IOException {
1166     if (cell instanceof SettableSequenceId) {
1167       ((SettableSequenceId) cell).setSequenceId(seqId);
1168     } else {
1169       throw new IOException(new UnsupportedOperationException("Cell is not of type "
1170           + SettableSequenceId.class.getName()));
1171     }
1172   }
1173
1174   /**
1175    * Sets the given timestamp to the cell.
1176    * @param cell
1177    * @param ts
1178    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
1179    */
1180   public static void setTimestamp(Cell cell, long ts) throws IOException {
1181     if (cell instanceof SettableTimestamp) {
1182       ((SettableTimestamp) cell).setTimestamp(ts);
1183     } else {
1184       throw new IOException(new UnsupportedOperationException("Cell is not of type "
1185           + SettableTimestamp.class.getName()));
1186     }
1187   }
1188
1189   /**
1190    * Sets the given timestamp to the cell.
1191    * @param cell
1192    * @param ts buffer containing the timestamp value
1193    * @param tsOffset offset to the new timestamp
1194    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
1195    */
1196   public static void setTimestamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
1197     if (cell instanceof SettableTimestamp) {
1198       ((SettableTimestamp) cell).setTimestamp(ts, tsOffset);
1199     } else {
1200       throw new IOException(new UnsupportedOperationException("Cell is not of type "
1201           + SettableTimestamp.class.getName()));
1202     }
1203   }
1204
1205   /**
1206    * Sets the given timestamp to the cell iff current timestamp is
1207    * {@link HConstants#LATEST_TIMESTAMP}.
1208    * @param cell
1209    * @param ts
1210    * @return True if cell timestamp is modified.
1211    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
1212    */
1213   public static boolean updateLatestStamp(Cell cell, long ts) throws IOException {
1214     if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
1215       setTimestamp(cell, ts);
1216       return true;
1217     }
1218     return false;
1219   }
1220
1221   /**
1222    * Sets the given timestamp to the cell iff current timestamp is
1223    * {@link HConstants#LATEST_TIMESTAMP}.
1224    * @param cell
1225    * @param ts buffer containing the timestamp value
1226    * @param tsOffset offset to the new timestamp
1227    * @return True if cell timestamp is modified.
1228    * @throws IOException when the passed cell is not of type {@link SettableTimestamp}
1229    */
1230   public static boolean updateLatestStamp(Cell cell, byte[] ts, int tsOffset) throws IOException {
1231     if (cell.getTimestamp() == HConstants.LATEST_TIMESTAMP) {
1232       setTimestamp(cell, ts, tsOffset);
1233       return true;
1234     }
1235     return false;
1236   }
1237
1238   /**
1239    * Writes the Cell's key part as it would have serialized in a KeyValue. The format is &lt;2 bytes
1240    * rk len&gt;&lt;rk&gt;&lt;1 byte cf len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes
1241    * timestamp&gt;&lt;1 byte type&gt;
1242    * @param cell
1243    * @param out
1244    * @throws IOException
1245    */
1246   public static void writeFlatKey(Cell cell, DataOutputStream out) throws IOException {
1247     short rowLen = cell.getRowLength();
1248     byte fLen = cell.getFamilyLength();
1249     int qLen = cell.getQualifierLength();
1250     // Using just one if/else loop instead of every time checking before writing every
1251     // component of cell
1252     if (cell instanceof ByteBufferedCell) {
1253       out.writeShort(rowLen);
1254       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getRowByteBuffer(),
1255         ((ByteBufferedCell) cell).getRowPosition(), rowLen);
1256       out.writeByte(fLen);
1257       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1258         ((ByteBufferedCell) cell).getFamilyPosition(), fLen);
1259       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1260         ((ByteBufferedCell) cell).getQualifierPosition(), qLen);
1261     } else {
1262       out.writeShort(rowLen);
1263       out.write(cell.getRowArray(), cell.getRowOffset(), rowLen);
1264       out.writeByte(fLen);
1265       out.write(cell.getFamilyArray(), cell.getFamilyOffset(), fLen);
1266       out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qLen);
1267     }
1268     out.writeLong(cell.getTimestamp());
1269     out.writeByte(cell.getTypeByte());
1270   }
1271
1272   /**
1273    * Writes the row from the given cell to the output stream
1274    * @param out The dataoutputstream to which the data has to be written
1275    * @param cell The cell whose contents has to be written
1276    * @param rlength the row length
1277    * @throws IOException
1278    */
1279   public static void writeRow(DataOutputStream out, Cell cell, short rlength) throws IOException {
1280     if (cell instanceof ByteBufferedCell) {
1281       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getRowByteBuffer(),
1282         ((ByteBufferedCell) cell).getRowPosition(), rlength);
1283     } else {
1284       out.write(cell.getRowArray(), cell.getRowOffset(), rlength);
1285     }
1286   }
1287
1288   /**
1289    * Writes the row from the given cell to the output stream excluding the common prefix
1290    * @param out The dataoutputstream to which the data has to be written
1291    * @param cell The cell whose contents has to be written
1292    * @param rlength the row length
1293    * @throws IOException
1294    */
1295   public static void writeRowSkippingBytes(DataOutputStream out, Cell cell, short rlength,
1296       int commonPrefix) throws IOException {
1297     if (cell instanceof ByteBufferedCell) {
1298       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getRowByteBuffer(),
1299         ((ByteBufferedCell) cell).getRowPosition() + commonPrefix, rlength - commonPrefix);
1300     } else {
1301       out.write(cell.getRowArray(), cell.getRowOffset() + commonPrefix, rlength - commonPrefix);
1302     }
1303   }
1304
1305   /**
1306    * Writes the family from the given cell to the output stream
1307    * @param out The dataoutputstream to which the data has to be written
1308    * @param cell The cell whose contents has to be written
1309    * @param flength the family length
1310    * @throws IOException
1311    */
1312   public static void writeFamily(DataOutputStream out, Cell cell, byte flength) throws IOException {
1313     if (cell instanceof ByteBufferedCell) {
1314       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1315         ((ByteBufferedCell) cell).getFamilyPosition(), flength);
1316     } else {
1317       out.write(cell.getFamilyArray(), cell.getFamilyOffset(), flength);
1318     }
1319   }
1320
1321   /**
1322    * Writes the qualifier from the given cell to the output stream
1323    * @param out The dataoutputstream to which the data has to be written
1324    * @param cell The cell whose contents has to be written
1325    * @param qlength the qualifier length
1326    * @throws IOException
1327    */
1328   public static void writeQualifier(DataOutputStream out, Cell cell, int qlength)
1329       throws IOException {
1330     if (cell instanceof ByteBufferedCell) {
1331       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1332         ((ByteBufferedCell) cell).getQualifierPosition(), qlength);
1333     } else {
1334       out.write(cell.getQualifierArray(), cell.getQualifierOffset(), qlength);
1335     }
1336   }
1337
1338   /**
1339    * Writes the qualifier from the given cell to the output stream excluding the common prefix
1340    * @param out The dataoutputstream to which the data has to be written
1341    * @param cell The cell whose contents has to be written
1342    * @param qlength the qualifier length
1343    * @throws IOException
1344    */
1345   public static void writeQualifierSkippingBytes(DataOutputStream out, Cell cell,
1346       int qlength, int commonPrefix) throws IOException {
1347     if (cell instanceof ByteBufferedCell) {
1348       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1349         ((ByteBufferedCell) cell).getQualifierPosition() + commonPrefix, qlength - commonPrefix);
1350     } else {
1351       out.write(cell.getQualifierArray(), cell.getQualifierOffset() + commonPrefix,
1352         qlength - commonPrefix);
1353     }
1354   }
1355
1356   /**
1357    * Writes the value from the given cell to the output stream
1358    * @param out The dataoutputstream to which the data has to be written
1359    * @param cell The cell whose contents has to be written
1360    * @param vlength the value length
1361    * @throws IOException
1362    */
1363   public static void writeValue(DataOutputStream out, Cell cell, int vlength) throws IOException {
1364     if (cell instanceof ByteBufferedCell) {
1365       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getValueByteBuffer(),
1366         ((ByteBufferedCell) cell).getValuePosition(), vlength);
1367     } else {
1368       out.write(cell.getValueArray(), cell.getValueOffset(), vlength);
1369     }
1370   }
1371
1372   /**
1373    * Writes the tag from the given cell to the output stream
1374    * @param out The dataoutputstream to which the data has to be written
1375    * @param cell The cell whose contents has to be written
1376    * @param tagsLength the tag length
1377    * @throws IOException
1378    */
1379   public static void writeTags(DataOutputStream out, Cell cell, int tagsLength) throws IOException {
1380     if (cell instanceof ByteBufferedCell) {
1381       ByteBufferUtils.copyBufferToStream(out, ((ByteBufferedCell) cell).getTagsByteBuffer(),
1382         ((ByteBufferedCell) cell).getTagsPosition(), tagsLength);
1383     } else {
1384       out.write(cell.getTagsArray(), cell.getTagsOffset(), tagsLength);
1385     }
1386   }
1387
1388   /**
1389    * @param cell
1390    * @return The Key portion of the passed <code>cell</code> as a String.
1391    */
1392   public static String getCellKeyAsString(Cell cell) {
1393     StringBuilder sb = new StringBuilder(Bytes.toStringBinary(
1394       cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
1395     sb.append('/');
1396     sb.append(cell.getFamilyLength() == 0? "":
1397       Bytes.toStringBinary(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
1398     // KeyValue only added ':' if family is non-null.  Do same.
1399     if (cell.getFamilyLength() > 0) sb.append(':');
1400     sb.append(cell.getQualifierLength() == 0? "":
1401       Bytes.toStringBinary(cell.getQualifierArray(), cell.getQualifierOffset(),
1402         cell.getQualifierLength()));
1403     sb.append('/');
1404     sb.append(KeyValue.humanReadableTimestamp(cell.getTimestamp()));
1405     sb.append('/');
1406     sb.append(Type.codeToType(cell.getTypeByte()));
1407     if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
1408       sb.append("/vlen=");
1409       sb.append(cell.getValueLength());
1410     }
1411     sb.append("/seqid=");
1412     sb.append(cell.getSequenceId());
1413     return sb.toString();
1414   }
1415
1416   /**
1417    * This method exists just to encapsulate how we serialize keys.  To be replaced by a factory
1418    * that we query to figure what the Cell implementation is and then, what serialization engine
1419    * to use and further, how to serialize the key for inclusion in hfile index. TODO.
1420    * @param cell
1421    * @return The key portion of the Cell serialized in the old-school KeyValue way or null if
1422    * passed a null <code>cell</code>
1423    */
1424   public static byte [] getCellKeySerializedAsKeyValueKey(final Cell cell) {
1425     if (cell == null) return null;
1426     byte [] b = new byte[KeyValueUtil.keyLength(cell)];
1427     KeyValueUtil.appendKeyTo(cell, b, 0);
1428     return b;
1429   }
1430
1431   /**
1432    * Write rowkey excluding the common part.
1433    * @param cell
1434    * @param rLen
1435    * @param commonPrefix
1436    * @param out
1437    * @throws IOException
1438    */
1439   public static void writeRowKeyExcludingCommon(Cell cell, short rLen, int commonPrefix,
1440       DataOutputStream out) throws IOException {
1441     if (commonPrefix == 0) {
1442       out.writeShort(rLen);
1443     } else if (commonPrefix == 1) {
1444       out.writeByte((byte) rLen);
1445       commonPrefix--;
1446     } else {
1447       commonPrefix -= KeyValue.ROW_LENGTH_SIZE;
1448     }
1449     if (rLen > commonPrefix) {
1450       writeRowSkippingBytes(out, cell, rLen, commonPrefix);
1451     }
1452   }
1453
1454   /**
1455    * Find length of common prefix in keys of the cells, considering key as byte[] if serialized in
1456    * {@link KeyValue}. The key format is &lt;2 bytes rk len&gt;&lt;rk&gt;&lt;1 byte cf
1457    * len&gt;&lt;cf&gt;&lt;qualifier&gt;&lt;8 bytes timestamp&gt;&lt;1 byte type&gt;
1458    * @param c1
1459    *          the cell
1460    * @param c2
1461    *          the cell
1462    * @param bypassFamilyCheck
1463    *          when true assume the family bytes same in both cells. Pass it as true when dealing
1464    *          with Cells in same CF so as to avoid some checks
1465    * @param withTsType
1466    *          when true check timestamp and type bytes also.
1467    * @return length of common prefix
1468    */
1469   public static int findCommonPrefixInFlatKey(Cell c1, Cell c2, boolean bypassFamilyCheck,
1470       boolean withTsType) {
1471     // Compare the 2 bytes in RK length part
1472     short rLen1 = c1.getRowLength();
1473     short rLen2 = c2.getRowLength();
1474     int commonPrefix = KeyValue.ROW_LENGTH_SIZE;
1475     if (rLen1 != rLen2) {
1476       // early out when the RK length itself is not matching
1477       return ByteBufferUtils.findCommonPrefix(Bytes.toBytes(rLen1), 0, KeyValue.ROW_LENGTH_SIZE,
1478           Bytes.toBytes(rLen2), 0, KeyValue.ROW_LENGTH_SIZE);
1479     }
1480     // Compare the RKs
1481     int rkCommonPrefix = 0;
1482     if (c1 instanceof ByteBufferedCell && c2 instanceof ByteBufferedCell) {
1483       rkCommonPrefix = ByteBufferUtils.findCommonPrefix(((ByteBufferedCell) c1).getRowByteBuffer(),
1484         ((ByteBufferedCell) c1).getRowPosition(), rLen1, ((ByteBufferedCell) c2).getRowByteBuffer(),
1485         ((ByteBufferedCell) c2).getRowPosition(), rLen2);
1486     } else {
1487       // There cannot be a case where one cell is BBCell and other is KeyValue. This flow comes either
1488       // in flush or compactions. In flushes both cells are KV and in case of compaction it will be either
1489       // KV or BBCell
1490       rkCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getRowArray(), c1.getRowOffset(),
1491         rLen1, c2.getRowArray(), c2.getRowOffset(), rLen2);
1492     }
1493     commonPrefix += rkCommonPrefix;
1494     if (rkCommonPrefix != rLen1) {
1495       // Early out when RK is not fully matching.
1496       return commonPrefix;
1497     }
1498     // Compare 1 byte CF length part
1499     byte fLen1 = c1.getFamilyLength();
1500     if (bypassFamilyCheck) {
1501       // This flag will be true when caller is sure that the family will be same for both the cells
1502       // Just make commonPrefix to increment by the family part
1503       commonPrefix += KeyValue.FAMILY_LENGTH_SIZE + fLen1;
1504     } else {
1505       byte fLen2 = c2.getFamilyLength();
1506       if (fLen1 != fLen2) {
1507         // early out when the CF length itself is not matching
1508         return commonPrefix;
1509       }
1510       // CF lengths are same so there is one more byte common in key part
1511       commonPrefix += KeyValue.FAMILY_LENGTH_SIZE;
1512       // Compare the CF names
1513       int fCommonPrefix;
1514       if (c1 instanceof ByteBufferedCell && c2 instanceof ByteBufferedCell) {
1515         fCommonPrefix =
1516             ByteBufferUtils.findCommonPrefix(((ByteBufferedCell) c1).getFamilyByteBuffer(),
1517               ((ByteBufferedCell) c1).getFamilyPosition(), fLen1,
1518               ((ByteBufferedCell) c2).getFamilyByteBuffer(),
1519               ((ByteBufferedCell) c2).getFamilyPosition(), fLen2);
1520       } else {
1521         fCommonPrefix = ByteBufferUtils.findCommonPrefix(c1.getFamilyArray(), c1.getFamilyOffset(),
1522           fLen1, c2.getFamilyArray(), c2.getFamilyOffset(), fLen2);
1523       }
1524       commonPrefix += fCommonPrefix;
1525       if (fCommonPrefix != fLen1) {
1526         return commonPrefix;
1527       }
1528     }
1529     // Compare the Qualifiers
1530     int qLen1 = c1.getQualifierLength();
1531     int qLen2 = c2.getQualifierLength();
1532     int qCommon;
1533     if (c1 instanceof ByteBufferedCell && c2 instanceof ByteBufferedCell) {
1534       qCommon = ByteBufferUtils.findCommonPrefix(((ByteBufferedCell) c1).getQualifierByteBuffer(),
1535         ((ByteBufferedCell) c1).getQualifierPosition(), qLen1,
1536         ((ByteBufferedCell) c2).getQualifierByteBuffer(),
1537         ((ByteBufferedCell) c2).getQualifierPosition(), qLen2);
1538     } else {
1539       qCommon = ByteBufferUtils.findCommonPrefix(c1.getQualifierArray(), c1.getQualifierOffset(),
1540         qLen1, c2.getQualifierArray(), c2.getQualifierOffset(), qLen2);
1541     }
1542     commonPrefix += qCommon;
1543     if (!withTsType || Math.max(qLen1, qLen2) != qCommon) {
1544       return commonPrefix;
1545     }
1546     // Compare the timestamp parts
1547     int tsCommonPrefix = ByteBufferUtils.findCommonPrefix(Bytes.toBytes(c1.getTimestamp()), 0,
1548         KeyValue.TIMESTAMP_SIZE, Bytes.toBytes(c2.getTimestamp()), 0, KeyValue.TIMESTAMP_SIZE);
1549     commonPrefix += tsCommonPrefix;
1550     if (tsCommonPrefix != KeyValue.TIMESTAMP_SIZE) {
1551       return commonPrefix;
1552     }
1553     // Compare the type
1554     if (c1.getTypeByte() == c2.getTypeByte()) {
1555       commonPrefix += KeyValue.TYPE_SIZE;
1556     }
1557     return commonPrefix;
1558   }
1559
1560   /** Returns a string representation of the cell */
1561   public static String toString(Cell cell, boolean verbose) {
1562     if (cell == null) {
1563       return "";
1564     }
1565     StringBuilder builder = new StringBuilder();
1566     String keyStr = getCellKeyAsString(cell);
1567
1568     String tag = null;
1569     String value = null;
1570     if (verbose) {
1571       // TODO: pretty print tags as well
1572       if (cell.getTagsLength() > 0) {
1573         tag = Bytes.toStringBinary(cell.getTagsArray(), cell.getTagsOffset(), cell.getTagsLength());
1574       }
1575       if (!(cell instanceof KeyValue.KeyOnlyKeyValue)) {
1576         value = Bytes.toStringBinary(cell.getValueArray(), cell.getValueOffset(),
1577             cell.getValueLength());
1578       }
1579     }
1580
1581     builder
1582       .append(keyStr);
1583     if (tag != null && !tag.isEmpty()) {
1584       builder.append("/").append(tag);
1585     }
1586     if (value != null) {
1587       builder.append("/").append(value);
1588     }
1589
1590     return builder.toString();
1591   }
1592
1593   /***************** special cases ****************************/
1594
1595   /**
1596    * special case for Cell.equals
1597    */
1598   public static boolean equalsIgnoreMvccVersion(Cell a, Cell b) {
1599     // row
1600     boolean res = matchingRow(a, b);
1601     if (!res)
1602       return res;
1603
1604     // family
1605     res = matchingColumn(a, b);
1606     if (!res)
1607       return res;
1608
1609     // timestamp: later sorts first
1610     if (!matchingTimestamp(a, b))
1611       return false;
1612
1613     // type
1614     int c = (0xff & b.getTypeByte()) - (0xff & a.getTypeByte());
1615     if (c != 0)
1616       return false;
1617     else return true;
1618   }
1619
1620   /**************** equals ****************************/
1621
1622   public static boolean equals(Cell a, Cell b) {
1623     return matchingRow(a, b) && matchingFamily(a, b) && matchingQualifier(a, b)
1624         && matchingTimestamp(a, b) && matchingType(a, b);
1625   }
1626
1627   public static boolean matchingTimestamp(Cell a, Cell b) {
1628     return CellComparator.compareTimestamps(a.getTimestamp(), b.getTimestamp()) == 0;
1629   }
1630
1631   public static boolean matchingType(Cell a, Cell b) {
1632     return a.getTypeByte() == b.getTypeByte();
1633   }
1634
1635   /**
1636    * Compares the row of two keyvalues for equality
1637    *
1638    * @param left
1639    * @param right
1640    * @return True if rows match.
1641    */
1642   public static boolean matchingRows(final Cell left, final Cell right) {
1643     short lrowlength = left.getRowLength();
1644     short rrowlength = right.getRowLength();
1645     if (lrowlength != rrowlength) return false;
1646     if (left instanceof ByteBufferedCell && right instanceof ByteBufferedCell) {
1647       return ByteBufferUtils.equals(((ByteBufferedCell) left).getRowByteBuffer(),
1648           ((ByteBufferedCell) left).getRowPosition(), lrowlength,
1649           ((ByteBufferedCell) right).getRowByteBuffer(),
1650           ((ByteBufferedCell) right).getRowPosition(), rrowlength);
1651     }
1652     if (left instanceof ByteBufferedCell) {
1653       return ByteBufferUtils.equals(((ByteBufferedCell) left).getRowByteBuffer(),
1654           ((ByteBufferedCell) left).getRowPosition(), lrowlength, right.getRowArray(),
1655           right.getRowOffset(), rrowlength);
1656     }
1657     if (right instanceof ByteBufferedCell) {
1658       return ByteBufferUtils.equals(((ByteBufferedCell) right).getRowByteBuffer(),
1659           ((ByteBufferedCell) right).getRowPosition(), rrowlength, left.getRowArray(),
1660           left.getRowOffset(), lrowlength);
1661     }
1662     return Bytes.equals(left.getRowArray(), left.getRowOffset(), lrowlength,
1663         right.getRowArray(), right.getRowOffset(), rrowlength);
1664   }
1665
1666   /**
1667    * Compares the row and column of two keyvalues for equality
1668    *
1669    * @param left
1670    * @param right
1671    * @return True if same row and column.
1672    */
1673   public static boolean matchingRowColumn(final Cell left, final Cell right) {
1674     if ((left.getRowLength() + left.getFamilyLength() + left.getQualifierLength()) != (right
1675         .getRowLength() + right.getFamilyLength() + right.getQualifierLength())) {
1676       return false;
1677     }
1678
1679     if (!matchingRows(left, right)) {
1680       return false;
1681     }
1682     return matchingColumn(left, right);
1683   }
1684
1685   /**
1686    * Converts the rowkey bytes of the given cell into an int value
1687    *
1688    * @param cell
1689    * @return rowkey as int
1690    */
1691   public static int getRowAsInt(Cell cell) {
1692     if (cell instanceof ByteBufferedCell) {
1693       return ByteBufferUtils.toInt(((ByteBufferedCell) cell).getRowByteBuffer(),
1694           ((ByteBufferedCell) cell).getRowPosition());
1695     }
1696     return Bytes.toInt(cell.getRowArray(), cell.getRowOffset());
1697   }
1698
1699   /**
1700    * Converts the value bytes of the given cell into a long value
1701    *
1702    * @param cell
1703    * @return value as long
1704    */
1705   public static long getValueAsLong(Cell cell) {
1706     if (cell instanceof ByteBufferedCell) {
1707       return ByteBufferUtils.toLong(((ByteBufferedCell) cell).getValueByteBuffer(),
1708           ((ByteBufferedCell) cell).getValuePosition());
1709     }
1710     return Bytes.toLong(cell.getValueArray(), cell.getValueOffset());
1711   }
1712
1713   /**
1714    * Converts the value bytes of the given cell into a double value
1715    *
1716    * @param cell
1717    * @return value as double
1718    */
1719   public static double getValueAsDouble(Cell cell) {
1720     if (cell instanceof ByteBufferedCell) {
1721       return ByteBufferUtils.toDouble(((ByteBufferedCell) cell).getValueByteBuffer(),
1722           ((ByteBufferedCell) cell).getValuePosition());
1723     }
1724     return Bytes.toDouble(cell.getValueArray(), cell.getValueOffset());
1725   }
1726
1727   /**
1728    * Converts the value bytes of the given cell into a BigDecimal
1729    *
1730    * @param cell
1731    * @return value as BigDecimal
1732    */
1733   public static BigDecimal getValueAsBigDecimal(Cell cell) {
1734     if (cell instanceof ByteBufferedCell) {
1735       return ByteBufferUtils.toBigDecimal(((ByteBufferedCell) cell).getValueByteBuffer(),
1736           ((ByteBufferedCell) cell).getValuePosition(), cell.getValueLength());
1737     }
1738     return Bytes.toBigDecimal(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
1739   }
1740
1741   /**
1742    * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
1743    *
1744    * @param cell
1745    * @return First possible Cell on passed Cell's row.
1746    */
1747   public static Cell createFirstOnRow(final Cell cell) {
1748     if (cell instanceof ByteBufferedCell) {
1749       return new FirstOnRowByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1750         ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength());
1751     }
1752     return new FirstOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1753   }
1754
1755   public static Cell createFirstOnRow(final byte [] row, int roffset, short rlength) {
1756     return new FirstOnRowCell(row, roffset, rlength);
1757   }
1758
1759   public static Cell createFirstOnRow(final byte[] row, final byte[] family, final byte[] col) {
1760     return createFirstOnRow(row, 0, (short)row.length,
1761         family, 0, (byte)family.length,
1762         col, 0, col.length);
1763   }
1764
1765   public static Cell createFirstOnRow(final byte[] row, int roffset, short rlength,
1766                                       final byte[] family, int foffset, byte flength,
1767                                       final byte[] col, int coffset, int clength) {
1768     return new FirstOnRowColCell(row, roffset, rlength,
1769         family, foffset, flength,
1770         col, coffset, clength);
1771   }
1772
1773   public static Cell createFirstOnRow(final byte[] row) {
1774     return createFirstOnRow(row, 0, (short)row.length);
1775   }
1776
1777   /**
1778    * Create a Cell that is smaller than all other possible Cells for the given Cell's row.
1779    * The family length is considered to be 0
1780    * @param cell
1781    * @return First possible Cell on passed Cell's row.
1782    */
1783   public static Cell createFirstOnRowCol(final Cell cell) {
1784     if (cell instanceof ByteBufferedCell) {
1785       return new FirstOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1786           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1787           HConstants.EMPTY_BYTE_BUFFER, 0, (byte) 0,
1788           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1789           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength());
1790     }
1791     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1792         cell.getRowLength(), HConstants.EMPTY_BYTE_ARRAY, 0, (byte)0, cell.getQualifierArray(),
1793         cell.getQualifierOffset(), cell.getQualifierLength());
1794   }
1795   /**
1796    * Create a Cell that is smaller than all other possible Cells for the given Cell row's next row.
1797    * Makes the next row's rowkey by appending single byte 0x00 to the end of current row key.
1798    */
1799   public static Cell createFirstOnNextRow(final Cell cell) {
1800     byte[] nextRow = new byte[cell.getRowLength() + 1];
1801     copyRowTo(cell, nextRow, 0);
1802     nextRow[nextRow.length - 1] = 0;// maybe not necessary
1803     return new FirstOnRowCell(nextRow, 0, (short) nextRow.length);
1804   }
1805
1806   /**
1807    * Create a Cell that is smaller than all other possible Cells for the given Cell's rk:cf and
1808    * passed qualifier.
1809    *
1810    * @param cell
1811    * @param qArray
1812    * @param qoffest
1813    * @param qlength
1814    * @return Last possible Cell on passed Cell's rk:cf and passed qualifier.
1815    */
1816   public static Cell createFirstOnRowCol(final Cell cell, byte[] qArray, int qoffest, int qlength) {
1817     if(cell instanceof ByteBufferedCell) {
1818       return new FirstOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1819           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1820           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1821           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1822           ByteBuffer.wrap(qArray), qoffest, qlength);
1823     }
1824     return new FirstOnRowColCell(cell.getRowArray(), cell.getRowOffset(),
1825         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1826         qArray, qoffest, qlength);
1827   }
1828
1829   /**
1830    * Creates the first cell with the row/family/qualifier of this cell and the given timestamp.
1831    * Uses the "maximum" type that guarantees that the new cell is the lowest possible for this
1832    * combination of row, family, qualifier, and timestamp. This cell's own timestamp is ignored.
1833    *
1834    * @param cell - cell
1835    * @param ts
1836    */
1837   public static Cell createFirstOnRowColTS(Cell cell, long ts) {
1838     if(cell instanceof ByteBufferedCell) {
1839       return new FirstOnRowColTSByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1840           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1841           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1842           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1843           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1844           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength(),
1845           ts);
1846     }
1847     return new FirstOnRowColTSCell(cell.getRowArray(), cell.getRowOffset(),
1848         cell.getRowLength(), cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1849         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength(), ts);
1850   }
1851
1852   /**
1853    * Create a Cell that is larger than all other possible Cells for the given Cell's row.
1854    *
1855    * @param cell
1856    * @return Last possible Cell on passed Cell's row.
1857    */
1858   public static Cell createLastOnRow(final Cell cell) {
1859     if (cell instanceof ByteBufferedCell) {
1860       return new LastOnRowByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1861         ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength());
1862     }
1863     return new LastOnRowCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
1864   }
1865
1866   public static Cell createLastOnRow(final byte[] row) {
1867     return new LastOnRowCell(row, 0, (short)row.length);
1868   }
1869
1870   /**
1871    * Create a Cell that is larger than all other possible Cells for the given Cell's rk:cf:q. Used
1872    * in creating "fake keys" for the multi-column Bloom filter optimization to skip the row/column
1873    * we already know is not in the file.
1874    *
1875    * @param cell
1876    * @return Last possible Cell on passed Cell's rk:cf:q.
1877    */
1878   public static Cell createLastOnRowCol(final Cell cell) {
1879     if (cell instanceof ByteBufferedCell) {
1880       return new LastOnRowColByteBufferedCell(((ByteBufferedCell) cell).getRowByteBuffer(),
1881           ((ByteBufferedCell) cell).getRowPosition(), cell.getRowLength(),
1882           ((ByteBufferedCell) cell).getFamilyByteBuffer(),
1883           ((ByteBufferedCell) cell).getFamilyPosition(), cell.getFamilyLength(),
1884           ((ByteBufferedCell) cell).getQualifierByteBuffer(),
1885           ((ByteBufferedCell) cell).getQualifierPosition(), cell.getQualifierLength());
1886     }
1887     return new LastOnRowColCell(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength(),
1888         cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength(),
1889         cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
1890   }
1891
1892   /**
1893    * Create a Delete Family Cell for the specified row and family that would
1894    * be smaller than all other possible Delete Family KeyValues that have the
1895    * same row and family.
1896    * Used for seeking.
1897    * @param row - row key (arbitrary byte array)
1898    * @param fam - family name
1899    * @return First Delete Family possible key on passed <code>row</code>.
1900    */
1901   public static Cell createFirstDeleteFamilyCellOnRow(final byte[] row, final byte[] fam) {
1902     return new FirstOnRowDeleteFamilyCell(row, fam);
1903   }
1904
1905   /**
1906    * Compresses the tags to the given outputstream using the TagcompressionContext
1907    * @param out the outputstream to which the compression should happen
1908    * @param cell the cell which has tags
1909    * @param tagCompressionContext the TagCompressionContext
1910    * @throws IOException can throw IOException if the compression encounters issue
1911    */
1912   public static void compressTags(DataOutputStream out, Cell cell,
1913       TagCompressionContext tagCompressionContext) throws IOException {
1914     if (cell instanceof ByteBufferedCell) {
1915       tagCompressionContext.compressTags(out, ((ByteBufferedCell) cell).getTagsByteBuffer(),
1916           ((ByteBufferedCell) cell).getTagsPosition(), cell.getTagsLength());
1917     } else {
1918       tagCompressionContext.compressTags(out, cell.getTagsArray(), cell.getTagsOffset(),
1919           cell.getTagsLength());
1920     }
1921   }
1922
1923   @InterfaceAudience.Private
1924   /**
1925    * These cells are used in reseeks/seeks to improve the read performance.
1926    * They are not real cells that are returned back to the clients
1927    */
1928   private static abstract class EmptyCell implements Cell, SettableSequenceId {
1929
1930     @Override
1931     public void setSequenceId(long seqId) {
1932       // Fake cells don't need seqId, so leaving it as a noop.
1933     }
1934     @Override
1935     public byte[] getRowArray() {
1936       return EMPTY_BYTE_ARRAY;
1937     }
1938
1939     @Override
1940     public int getRowOffset() {
1941       return 0;
1942     }
1943
1944     @Override
1945     public short getRowLength() {
1946       return 0;
1947     }
1948
1949     @Override
1950     public byte[] getFamilyArray() {
1951       return EMPTY_BYTE_ARRAY;
1952     }
1953
1954     @Override
1955     public int getFamilyOffset() {
1956       return 0;
1957     }
1958
1959     @Override
1960     public byte getFamilyLength() {
1961       return 0;
1962     }
1963
1964     @Override
1965     public byte[] getQualifierArray() {
1966       return EMPTY_BYTE_ARRAY;
1967     }
1968
1969     @Override
1970     public int getQualifierOffset() {
1971       return 0;
1972     }
1973
1974     @Override
1975     public int getQualifierLength() {
1976       return 0;
1977     }
1978
1979     @Override
1980     public long getSequenceId() {
1981       return 0;
1982     }
1983
1984     @Override
1985     public byte[] getValueArray() {
1986       return EMPTY_BYTE_ARRAY;
1987     }
1988
1989     @Override
1990     public int getValueOffset() {
1991       return 0;
1992     }
1993
1994     @Override
1995     public int getValueLength() {
1996       return 0;
1997     }
1998
1999     @Override
2000     public byte[] getTagsArray() {
2001       return EMPTY_BYTE_ARRAY;
2002     }
2003
2004     @Override
2005     public int getTagsOffset() {
2006       return 0;
2007     }
2008
2009     @Override
2010     public int getTagsLength() {
2011       return 0;
2012     }
2013   }
2014
2015   @InterfaceAudience.Private
2016   /**
2017    * These cells are used in reseeks/seeks to improve the read performance.
2018    * They are not real cells that are returned back to the clients
2019    */
2020   private static abstract class EmptyByteBufferedCell extends ByteBufferedCell
2021       implements SettableSequenceId {
2022
2023     @Override
2024     public void setSequenceId(long seqId) {
2025       // Fake cells don't need seqId, so leaving it as a noop.
2026     }
2027
2028     @Override
2029     public byte[] getRowArray() {
2030       return CellUtil.cloneRow(this);
2031     }
2032
2033     @Override
2034     public int getRowOffset() {
2035       return 0;
2036     }
2037
2038     @Override
2039     public short getRowLength() {
2040       return 0;
2041     }
2042
2043     @Override
2044     public byte[] getFamilyArray() {
2045       return CellUtil.cloneFamily(this);
2046     }
2047
2048     @Override
2049     public int getFamilyOffset() {
2050       return 0;
2051     }
2052
2053     @Override
2054     public byte getFamilyLength() {
2055       return 0;
2056     }
2057
2058     @Override
2059     public byte[] getQualifierArray() {
2060       return CellUtil.cloneQualifier(this);
2061     }
2062
2063     @Override
2064     public int getQualifierOffset() {
2065       return 0;
2066     }
2067
2068     @Override
2069     public int getQualifierLength() {
2070       return 0;
2071     }
2072
2073     @Override
2074     public long getSequenceId() {
2075       return 0;
2076     }
2077
2078     @Override
2079     public byte[] getValueArray() {
2080       return CellUtil.cloneValue(this);
2081     }
2082
2083     @Override
2084     public int getValueOffset() {
2085       return 0;
2086     }
2087
2088     @Override
2089     public int getValueLength() {
2090       return 0;
2091     }
2092
2093     @Override
2094     public byte[] getTagsArray() {
2095       return CellUtil.cloneTags(this);
2096     }
2097
2098     @Override
2099     public int getTagsOffset() {
2100       return 0;
2101     }
2102
2103     @Override
2104     public int getTagsLength() {
2105       return 0;
2106     }
2107
2108     @Override
2109     public ByteBuffer getRowByteBuffer() {
2110       return HConstants.EMPTY_BYTE_BUFFER;
2111     }
2112
2113     @Override
2114     public int getRowPosition() {
2115       return 0;
2116     }
2117
2118     @Override
2119     public ByteBuffer getFamilyByteBuffer() {
2120       return HConstants.EMPTY_BYTE_BUFFER;
2121     }
2122
2123     @Override
2124     public int getFamilyPosition() {
2125       return 0;
2126     }
2127
2128     @Override
2129     public ByteBuffer getQualifierByteBuffer() {
2130       return HConstants.EMPTY_BYTE_BUFFER;
2131     }
2132
2133     @Override
2134     public int getQualifierPosition() {
2135       return 0;
2136     }
2137
2138     @Override
2139     public ByteBuffer getTagsByteBuffer() {
2140       return HConstants.EMPTY_BYTE_BUFFER;
2141     }
2142
2143     @Override
2144     public int getTagsPosition() {
2145       return 0;
2146     }
2147
2148     @Override
2149     public ByteBuffer getValueByteBuffer() {
2150       return HConstants.EMPTY_BYTE_BUFFER;
2151     }
2152
2153     @Override
2154     public int getValuePosition() {
2155       return 0;
2156     }
2157   }
2158
2159   @InterfaceAudience.Private
2160   private static class FirstOnRowCell extends EmptyCell {
2161     private final byte[] rowArray;
2162     private final int roffset;
2163     private final short rlength;
2164
2165     public FirstOnRowCell(final byte[] row, int roffset, short rlength) {
2166       this.rowArray = row;
2167       this.roffset = roffset;
2168       this.rlength = rlength;
2169     }
2170
2171     @Override
2172     public byte[] getRowArray() {
2173       return this.rowArray;
2174     }
2175
2176     @Override
2177     public int getRowOffset() {
2178       return this.roffset;
2179     }
2180
2181     @Override
2182     public short getRowLength() {
2183       return this.rlength;
2184     }
2185
2186     @Override
2187     public long getTimestamp() {
2188       return HConstants.LATEST_TIMESTAMP;
2189     }
2190
2191     @Override
2192     public byte getTypeByte() {
2193       return Type.Maximum.getCode();
2194     }
2195   }
2196
2197   @InterfaceAudience.Private
2198   private static class FirstOnRowByteBufferedCell extends EmptyByteBufferedCell {
2199     private final ByteBuffer rowBuff;
2200     private final int roffset;
2201     private final short rlength;
2202
2203     public FirstOnRowByteBufferedCell(final ByteBuffer row, int roffset, short rlength) {
2204       this.rowBuff = row;
2205       this.roffset = roffset;
2206       this.rlength = rlength;
2207     }
2208
2209     @Override
2210     public ByteBuffer getRowByteBuffer() {
2211       return this.rowBuff;
2212     }
2213
2214     @Override
2215     public int getRowPosition() {
2216       return this.roffset;
2217     }
2218
2219     @Override
2220     public short getRowLength() {
2221       return this.rlength;
2222     }
2223
2224     @Override
2225     public long getTimestamp() {
2226       return HConstants.LATEST_TIMESTAMP;
2227     }
2228
2229     @Override
2230     public byte getTypeByte() {
2231       return Type.Maximum.getCode();
2232     }
2233   }
2234
2235   @InterfaceAudience.Private
2236   private static class LastOnRowByteBufferedCell extends EmptyByteBufferedCell {
2237     private final ByteBuffer rowBuff;
2238     private final int roffset;
2239     private final short rlength;
2240
2241     public LastOnRowByteBufferedCell(final ByteBuffer row, int roffset, short rlength) {
2242       this.rowBuff = row;
2243       this.roffset = roffset;
2244       this.rlength = rlength;
2245     }
2246
2247     @Override
2248     public ByteBuffer getRowByteBuffer() {
2249       return this.rowBuff;
2250     }
2251
2252     @Override
2253     public int getRowPosition() {
2254       return this.roffset;
2255     }
2256
2257     @Override
2258     public short getRowLength() {
2259       return this.rlength;
2260     }
2261
2262     @Override
2263     public long getTimestamp() {
2264       return HConstants.OLDEST_TIMESTAMP;
2265     }
2266
2267     @Override
2268     public byte getTypeByte() {
2269       return Type.Minimum.getCode();
2270     }
2271   }
2272
2273   @InterfaceAudience.Private
2274   private static class FirstOnRowColByteBufferedCell extends FirstOnRowByteBufferedCell {
2275     private final ByteBuffer famBuff;
2276     private final int famOffset;
2277     private final byte famLength;
2278     private final ByteBuffer colBuff;
2279     private final int colOffset;
2280     private final int colLength;
2281
2282     public FirstOnRowColByteBufferedCell(final ByteBuffer row, int roffset, short rlength,
2283         final ByteBuffer famBuff, final int famOffset, final byte famLength, final ByteBuffer col,
2284         final int colOffset, final int colLength) {
2285       super(row, roffset, rlength);
2286       this.famBuff = famBuff;
2287       this.famOffset = famOffset;
2288       this.famLength = famLength;
2289       this.colBuff = col;
2290       this.colOffset = colOffset;
2291       this.colLength = colLength;
2292     }
2293
2294     @Override
2295     public ByteBuffer getFamilyByteBuffer() {
2296       return this.famBuff;
2297     }
2298
2299     @Override
2300     public int getFamilyPosition() {
2301       return this.famOffset;
2302     }
2303
2304     @Override
2305     public byte getFamilyLength() {
2306       return famLength;
2307     }
2308
2309     @Override
2310     public ByteBuffer getQualifierByteBuffer() {
2311       return this.colBuff;
2312     }
2313
2314     @Override
2315     public int getQualifierPosition() {
2316       return this.colOffset;
2317     }
2318
2319     @Override
2320     public int getQualifierLength() {
2321       return this.colLength;
2322     }
2323   }
2324
2325   @InterfaceAudience.Private
2326   private static class FirstOnRowColCell extends FirstOnRowCell {
2327     private final byte[] fArray;
2328     private final int foffset;
2329     private final byte flength;
2330     private final byte[] qArray;
2331     private final int qoffset;
2332     private final int qlength;
2333
2334     public FirstOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2335         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
2336       super(rArray, roffset, rlength);
2337       this.fArray = fArray;
2338       this.foffset = foffset;
2339       this.flength = flength;
2340       this.qArray = qArray;
2341       this.qoffset = qoffset;
2342       this.qlength = qlength;
2343     }
2344
2345     @Override
2346     public byte[] getFamilyArray() {
2347       return this.fArray;
2348     }
2349
2350     @Override
2351     public int getFamilyOffset() {
2352       return this.foffset;
2353     }
2354
2355     @Override
2356     public byte getFamilyLength() {
2357       return this.flength;
2358     }
2359
2360     @Override
2361     public byte[] getQualifierArray() {
2362       return this.qArray;
2363     }
2364
2365     @Override
2366     public int getQualifierOffset() {
2367       return this.qoffset;
2368     }
2369
2370     @Override
2371     public int getQualifierLength() {
2372       return this.qlength;
2373     }
2374   }
2375
2376   @InterfaceAudience.Private
2377   private static class FirstOnRowColTSCell extends FirstOnRowColCell {
2378
2379     private long ts;
2380
2381     public FirstOnRowColTSCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2382         int foffset, byte flength, byte[] qArray, int qoffset, int qlength, long ts) {
2383       super(rArray, roffset, rlength, fArray, foffset, flength, qArray, qoffset, qlength);
2384       this.ts = ts;
2385     }
2386
2387     @Override
2388     public long getTimestamp() {
2389       return this.ts;
2390     }
2391   }
2392
2393   @InterfaceAudience.Private
2394   private static class FirstOnRowColTSByteBufferedCell extends FirstOnRowColByteBufferedCell {
2395
2396     private long ts;
2397
2398     public FirstOnRowColTSByteBufferedCell(ByteBuffer rBuffer, int roffset, short rlength,
2399         ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset, int qlength,
2400         long ts) {
2401       super(rBuffer, roffset, rlength, fBuffer, foffset, flength, qBuffer, qoffset, qlength);
2402       this.ts = ts;
2403     }
2404
2405     @Override
2406     public long getTimestamp() {
2407       return this.ts;
2408     }
2409   }
2410
2411   @InterfaceAudience.Private
2412   private static class LastOnRowCell extends EmptyCell {
2413     private final byte[] rowArray;
2414     private final int roffset;
2415     private final short rlength;
2416
2417     public LastOnRowCell(byte[] row, int roffset, short rlength) {
2418       this.rowArray = row;
2419       this.roffset = roffset;
2420       this.rlength = rlength;
2421     }
2422
2423     @Override
2424     public byte[] getRowArray() {
2425       return this.rowArray;
2426     }
2427
2428     @Override
2429     public int getRowOffset() {
2430       return this.roffset;
2431     }
2432
2433     @Override
2434     public short getRowLength() {
2435       return this.rlength;
2436     }
2437
2438     @Override
2439     public long getTimestamp() {
2440       return HConstants.OLDEST_TIMESTAMP;
2441     }
2442
2443     @Override
2444     public byte getTypeByte() {
2445       return Type.Minimum.getCode();
2446     }
2447   }
2448
2449   @InterfaceAudience.Private
2450   private static class LastOnRowColCell extends LastOnRowCell {
2451     private final byte[] fArray;
2452     private final int foffset;
2453     private final byte flength;
2454     private final byte[] qArray;
2455     private final int qoffset;
2456     private final int qlength;
2457
2458     public LastOnRowColCell(byte[] rArray, int roffset, short rlength, byte[] fArray,
2459         int foffset, byte flength, byte[] qArray, int qoffset, int qlength) {
2460       super(rArray, roffset, rlength);
2461       this.fArray = fArray;
2462       this.foffset = foffset;
2463       this.flength = flength;
2464       this.qArray = qArray;
2465       this.qoffset = qoffset;
2466       this.qlength = qlength;
2467     }
2468
2469     @Override
2470     public byte[] getFamilyArray() {
2471       return this.fArray;
2472     }
2473
2474     @Override
2475     public int getFamilyOffset() {
2476       return this.foffset;
2477     }
2478
2479     @Override
2480     public byte getFamilyLength() {
2481       return this.flength;
2482     }
2483
2484     @Override
2485     public byte[] getQualifierArray() {
2486       return this.qArray;
2487     }
2488
2489     @Override
2490     public int getQualifierOffset() {
2491       return this.qoffset;
2492     }
2493
2494     @Override
2495     public int getQualifierLength() {
2496       return this.qlength;
2497     }
2498   }
2499
2500   @InterfaceAudience.Private
2501   private static class LastOnRowColByteBufferedCell extends LastOnRowByteBufferedCell {
2502     private final ByteBuffer fBuffer;
2503     private final int foffset;
2504     private final byte flength;
2505     private final ByteBuffer qBuffer;
2506     private final int qoffset;
2507     private final int qlength;
2508
2509     public LastOnRowColByteBufferedCell(ByteBuffer rBuffer, int roffset, short rlength,
2510         ByteBuffer fBuffer, int foffset, byte flength, ByteBuffer qBuffer, int qoffset,
2511         int qlength) {
2512       super(rBuffer, roffset, rlength);
2513       this.fBuffer = fBuffer;
2514       this.foffset = foffset;
2515       this.flength = flength;
2516       this.qBuffer = qBuffer;
2517       this.qoffset = qoffset;
2518       this.qlength = qlength;
2519     }
2520
2521     @Override
2522     public ByteBuffer getFamilyByteBuffer() {
2523       return this.fBuffer;
2524     }
2525
2526     @Override
2527     public int getFamilyPosition() {
2528       return this.foffset;
2529     }
2530
2531     @Override
2532     public byte getFamilyLength() {
2533       return this.flength;
2534     }
2535
2536     @Override
2537     public ByteBuffer getQualifierByteBuffer() {
2538       return this.qBuffer;
2539     }
2540
2541     @Override
2542     public int getQualifierPosition() {
2543       return this.qoffset;
2544     }
2545
2546     @Override
2547     public int getQualifierLength() {
2548       return this.qlength;
2549     }
2550   }
2551
2552   @InterfaceAudience.Private
2553   private static class FirstOnRowDeleteFamilyCell extends EmptyCell {
2554     private final byte[] row;
2555     private final byte[] fam;
2556
2557     public FirstOnRowDeleteFamilyCell(byte[] row, byte[] fam) {
2558       this.row = row;
2559       this.fam = fam;
2560     }
2561
2562     @Override
2563     public byte[] getRowArray() {
2564       return this.row;
2565     }
2566
2567     @Override
2568     public short getRowLength() {
2569       return (short) this.row.length;
2570     }
2571
2572     @Override
2573     public byte[] getFamilyArray() {
2574       return this.fam;
2575     }
2576
2577     @Override
2578     public byte getFamilyLength() {
2579       return (byte) this.fam.length;
2580     }
2581
2582     @Override
2583     public long getTimestamp() {
2584       return HConstants.LATEST_TIMESTAMP;
2585     }
2586
2587     @Override
2588     public byte getTypeByte() {
2589       return Type.DeleteFamily.getCode();
2590     }
2591   }
2592 }