001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.hbase;
020
021import org.apache.commons.lang3.ArrayUtils;
022import org.apache.hadoop.hbase.util.Bytes;
023import org.apache.hadoop.hbase.util.ClassSize;
024import org.apache.yetus.audience.InterfaceAudience;
025
026@InterfaceAudience.Private
027public class IndividualBytesFieldCell implements ExtendedCell, Cloneable {
028
029  private static final long FIXED_OVERHEAD = ClassSize.align(  // do alignment(padding gap)
030        ClassSize.OBJECT              // object header
031      + KeyValue.TIMESTAMP_TYPE_SIZE  // timestamp and type
032      + Bytes.SIZEOF_LONG             // sequence id
033      + 5 * ClassSize.REFERENCE);     // references to all byte arrays: row, family, qualifier, value, tags
034
035  // The following fields are backed by individual byte arrays
036  private final byte[] row;
037  private final int rOffset;
038  private final int rLength;
039  private final byte[] family;
040  private final int fOffset;
041  private final int fLength;
042  private final byte[] qualifier;
043  private final int qOffset;
044  private final int qLength;
045  private final byte[] value;
046  private final int vOffset;
047  private final int vLength;
048  private final byte[] tags;  // A byte array, rather than an array of org.apache.hadoop.hbase.Tag
049  private final int tagsOffset;
050  private final int tagsLength;
051
052  // Other fields
053  private long timestamp;
054  private final byte type;  // A byte, rather than org.apache.hadoop.hbase.KeyValue.Type
055  private long seqId;
056
057  public IndividualBytesFieldCell(byte[] row, byte[] family, byte[] qualifier,
058                                  long timestamp, KeyValue.Type type,  byte[] value) {
059    this(row, family, qualifier, timestamp, type, 0L /* sequence id */, value, null /* tags */);
060  }
061
062  public IndividualBytesFieldCell(byte[] row, byte[] family, byte[] qualifier,
063                                  long timestamp, KeyValue.Type type, long seqId, byte[] value, byte[] tags) {
064    this(row, 0, ArrayUtils.getLength(row),
065            family, 0, ArrayUtils.getLength(family),
066            qualifier, 0, ArrayUtils.getLength(qualifier),
067            timestamp, type, seqId,
068            value, 0, ArrayUtils.getLength(value),
069            tags, 0, ArrayUtils.getLength(tags));
070  }
071
072  public IndividualBytesFieldCell(byte[] row, int rOffset, int rLength,
073                                  byte[] family, int fOffset, int fLength,
074                                  byte[] qualifier, int qOffset, int qLength,
075                                  long timestamp, KeyValue.Type type, long seqId,
076                                  byte[] value, int vOffset, int vLength,
077                                  byte[] tags, int tagsOffset, int tagsLength) {
078
079    // Check row, family, qualifier and value
080    KeyValue.checkParameters(row, rLength,     // row and row length
081                             family, fLength,  // family and family length
082                             qLength,          // qualifier length
083                             vLength);         // value length
084
085    // Check timestamp
086    if (timestamp < 0) {
087      throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + timestamp);
088    }
089
090    // Check tags
091    RawCell.checkForTagsLength(tagsLength);
092    checkArrayBounds(row, rOffset, rLength);
093    checkArrayBounds(family, fOffset, fLength);
094    checkArrayBounds(qualifier, qOffset, qLength);
095    checkArrayBounds(value, vOffset, vLength);
096    checkArrayBounds(tags, tagsOffset, tagsLength);
097    // No local copy is made, but reference to the input directly
098    this.row        = row;
099    this.rOffset    = rOffset;
100    this.rLength    = rLength;
101    this.family     = family;
102    this.fOffset    = fOffset;
103    this.fLength    = fLength;
104    this.qualifier  = qualifier;
105    this.qOffset    = qOffset;
106    this.qLength    = qLength;
107    this.value      = value;
108    this.vOffset    = vOffset;
109    this.vLength    = vLength;
110    this.tags       = tags;
111    this.tagsOffset = tagsOffset;
112    this.tagsLength = tagsLength;
113
114    // Set others
115    this.timestamp  = timestamp;
116    this.type       = type.getCode();
117    this.seqId      = seqId;
118  }
119
120  private void checkArrayBounds(byte[] bytes, int offset, int length) {
121    if (offset < 0 || length < 0) {
122      throw new IllegalArgumentException("Negative number! offset=" + offset + "and length=" + length);
123    }
124    if (bytes == null && (offset != 0 || length != 0)) {
125      throw new IllegalArgumentException("Null bytes array but offset=" + offset + "and length=" + length);
126    }
127    if (bytes != null && bytes.length < offset + length) {
128      throw new IllegalArgumentException("Out of bounds! bytes.length=" + bytes.length
129        + ", offset=" + offset + ", length=" + length);
130    }
131  }
132
133  private long heapOverhead() {
134    return   FIXED_OVERHEAD
135           + ClassSize.ARRAY                               // row      , can not be null
136           + ((family    == null) ? 0 : ClassSize.ARRAY)   // family   , can be null
137           + ((qualifier == null) ? 0 : ClassSize.ARRAY)   // qualifier, can be null
138           + ((value     == null) ? 0 : ClassSize.ARRAY)   // value    , can be null
139           + ((tags      == null) ? 0 : ClassSize.ARRAY);  // tags     , can be null
140  }
141
142  /**
143   * Implement Cell interface
144   */
145  // 1) Row
146  @Override
147  public byte[] getRowArray() {
148    // If row is null, the constructor will reject it, by {@link KeyValue#checkParameters()},
149    // so it is safe to return row without checking.
150    return row;
151  }
152
153  @Override
154  public int getRowOffset() {
155        return rOffset;
156    }
157
158  @Override
159  public short getRowLength() {
160    // If row is null or rLength is invalid, the constructor will reject it, by {@link KeyValue#checkParameters()},
161    // so it is safe to call rLength and make the type conversion.
162    return (short)(rLength);
163  }
164
165  // 2) Family
166  @Override
167  public byte[] getFamilyArray() {
168    // Family could be null
169    return (family == null) ? HConstants.EMPTY_BYTE_ARRAY : family;
170  }
171
172  @Override
173  public int getFamilyOffset() {
174    return fOffset;
175  }
176
177  @Override
178  public byte getFamilyLength() {
179    // If fLength is invalid, the constructor will reject it, by {@link KeyValue#checkParameters()},
180    // so it is safe to make the type conversion.
181    return (byte)(fLength);
182  }
183
184  // 3) Qualifier
185  @Override
186  public byte[] getQualifierArray() {
187    // Qualifier could be null
188    return (qualifier == null) ? HConstants.EMPTY_BYTE_ARRAY : qualifier;
189  }
190
191  @Override
192  public int getQualifierOffset() {
193    return qOffset;
194  }
195
196  @Override
197  public int getQualifierLength() {
198    return qLength;
199  }
200
201  // 4) Timestamp
202  @Override
203  public long getTimestamp() {
204    return timestamp;
205  }
206
207  //5) Type
208  @Override
209  public byte getTypeByte() {
210    return type;
211  }
212
213  //6) Sequence id
214  @Override
215  public long getSequenceId() {
216    return seqId;
217  }
218
219  //7) Value
220  @Override
221  public byte[] getValueArray() {
222    // Value could be null
223    return (value == null) ? HConstants.EMPTY_BYTE_ARRAY : value;
224  }
225
226  @Override
227  public int getValueOffset() {
228    return vOffset;
229  }
230
231  @Override
232  public int getValueLength() {
233    return vLength;
234  }
235
236  // 8) Tags
237  @Override
238  public byte[] getTagsArray() {
239    // Tags can could null
240    return (tags == null) ? HConstants.EMPTY_BYTE_ARRAY : tags;
241  }
242
243  @Override
244  public int getTagsOffset() {
245    return tagsOffset;
246  }
247
248  @Override
249  public int getTagsLength() {
250    return tagsLength;
251  }
252
253  /**
254   * Implement HeapSize interface
255   */
256  @Override
257  public long heapSize() {
258    // Size of array headers are already included into overhead, so do not need to include it for each byte array
259    return   heapOverhead()                         // overhead, with array headers included
260           + ClassSize.align(getRowLength())        // row
261           + ClassSize.align(getFamilyLength())     // family
262           + ClassSize.align(getQualifierLength())  // qualifier
263           + ClassSize.align(getValueLength())      // value
264           + ClassSize.align(getTagsLength());      // tags
265  }
266
267  /**
268   * Implement Cloneable interface
269   */
270  @Override
271  public Object clone() throws CloneNotSupportedException {
272    return super.clone();  // only a shadow copy
273  }
274
275  @Override
276  public void setSequenceId(long seqId) {
277    if (seqId < 0) {
278      throw new IllegalArgumentException("Sequence Id cannot be negative. ts=" + seqId);
279    }
280    this.seqId = seqId;
281  }
282
283  @Override
284  public void setTimestamp(long ts) {
285    if (ts < 0) {
286      throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
287    }
288    this.timestamp = ts;
289  }
290
291  @Override
292  public void setTimestamp(byte[] ts) {
293    setTimestamp(Bytes.toLong(ts, 0));
294  }
295
296  @Override
297  public String toString() {
298    return CellUtil.toString(this, true);
299  }
300}