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