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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 package org
.apache
.hadoop
.hbase
.client
;
21 import java
.io
.IOException
;
22 import java
.nio
.ByteBuffer
;
23 import java
.util
.ArrayList
;
24 import java
.util
.Arrays
;
25 import java
.util
.HashMap
;
26 import java
.util
.Iterator
;
27 import java
.util
.List
;
29 import java
.util
.NavigableMap
;
30 import java
.util
.Optional
;
31 import java
.util
.TreeMap
;
32 import java
.util
.UUID
;
33 import java
.util
.stream
.Collectors
;
34 import org
.apache
.hadoop
.hbase
.Cell
;
35 import org
.apache
.hadoop
.hbase
.CellBuilder
;
36 import org
.apache
.hadoop
.hbase
.CellBuilderFactory
;
37 import org
.apache
.hadoop
.hbase
.CellBuilderType
;
38 import org
.apache
.hadoop
.hbase
.CellScannable
;
39 import org
.apache
.hadoop
.hbase
.CellScanner
;
40 import org
.apache
.hadoop
.hbase
.CellUtil
;
41 import org
.apache
.hadoop
.hbase
.ExtendedCell
;
42 import org
.apache
.hadoop
.hbase
.HConstants
;
43 import org
.apache
.hadoop
.hbase
.IndividualBytesFieldCell
;
44 import org
.apache
.hadoop
.hbase
.KeyValue
;
45 import org
.apache
.hadoop
.hbase
.PrivateCellUtil
;
46 import org
.apache
.hadoop
.hbase
.Tag
;
47 import org
.apache
.hadoop
.hbase
.exceptions
.DeserializationException
;
48 import org
.apache
.hadoop
.hbase
.io
.HeapSize
;
49 import org
.apache
.hadoop
.hbase
.security
.access
.AccessControlConstants
;
50 import org
.apache
.hadoop
.hbase
.security
.access
.AccessControlUtil
;
51 import org
.apache
.hadoop
.hbase
.security
.access
.Permission
;
52 import org
.apache
.hadoop
.hbase
.security
.visibility
.CellVisibility
;
53 import org
.apache
.hadoop
.hbase
.security
.visibility
.VisibilityConstants
;
54 import org
.apache
.hadoop
.hbase
.util
.Bytes
;
55 import org
.apache
.hadoop
.hbase
.util
.ClassSize
;
56 import org
.apache
.yetus
.audience
.InterfaceAudience
;
58 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.base
.Preconditions
;
59 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.collect
.ArrayListMultimap
;
60 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.collect
.ListMultimap
;
61 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.io
.ByteArrayDataInput
;
62 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.io
.ByteArrayDataOutput
;
63 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.io
.ByteStreams
;
65 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.ProtobufUtil
;
66 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.ClientProtos
;
68 @InterfaceAudience.Public
69 public abstract class Mutation
extends OperationWithAttributes
implements Row
, CellScannable
,
71 public static final long MUTATION_OVERHEAD
= ClassSize
.align(
74 // row + OperationWithAttributes.attributes
75 2 * ClassSize
.REFERENCE
+
77 1 * Bytes
.SIZEOF_LONG
+
89 * The attribute for storing the list of clusters that have consumed the change.
91 private static final String CONSUMED_CLUSTER_IDS
= "_cs.id";
94 * The attribute for storing TTL for the result of the mutation.
96 private static final String OP_ATTRIBUTE_TTL
= "_ttl";
98 private static final String RETURN_RESULTS
= "_rr_";
100 // TODO: row should be final
101 protected byte [] row
= null;
102 protected long ts
= HConstants
.LATEST_TIMESTAMP
;
103 protected Durability durability
= Durability
.USE_DEFAULT
;
105 // TODO: familyMap should be final
106 // A Map sorted by column family.
107 protected NavigableMap
<byte [], List
<Cell
>> familyMap
;
110 * empty construction.
111 * We need this empty construction to keep binary compatibility.
113 protected Mutation() {
114 this.familyMap
= new TreeMap
<>(Bytes
.BYTES_COMPARATOR
);
117 protected Mutation(Mutation clone
) {
119 this.row
= clone
.getRow();
120 this.ts
= clone
.getTimestamp();
121 this.familyMap
= clone
.getFamilyCellMap().entrySet().stream().
122 collect(Collectors
.toMap(e
-> e
.getKey(), e
-> new ArrayList
<>(e
.getValue()), (k
, v
) -> {
123 throw new RuntimeException("collisions!!!");
124 }, () -> new TreeMap
<>(Bytes
.BYTES_COMPARATOR
)));
128 * Construct the mutation with user defined data.
129 * @param row row. CAN'T be null
130 * @param ts timestamp
131 * @param familyMap the map to collect all cells internally. CAN'T be null
133 protected Mutation(byte[] row
, long ts
, NavigableMap
<byte [], List
<Cell
>> familyMap
) {
134 this.row
= Preconditions
.checkNotNull(row
);
135 if (row
.length
== 0) {
136 throw new IllegalArgumentException("Row can't be empty");
139 this.familyMap
= Preconditions
.checkNotNull(familyMap
);
143 public CellScanner
cellScanner() {
144 return CellUtil
.createCellScanner(getFamilyCellMap());
148 * Creates an empty list if one doesn't exist for the given column family
149 * or else it returns the associated list of Cell objects.
151 * @param family column family
152 * @return a list of Cell objects, returns an empty list if one doesn't exist.
154 List
<Cell
> getCellList(byte[] family
) {
155 List
<Cell
> list
= getFamilyCellMap().get(family
);
157 list
= new ArrayList
<>();
158 getFamilyCellMap().put(family
, list
);
164 * Create a KeyValue with this objects row key and the Put identifier.
166 * @return a KeyValue with this objects row key and the Put identifier.
168 KeyValue
createPutKeyValue(byte[] family
, byte[] qualifier
, long ts
, byte[] value
) {
169 return new KeyValue(this.row
, family
, qualifier
, ts
, KeyValue
.Type
.Put
, value
);
173 * Create a KeyValue with this objects row key and the Put identifier.
178 * @param tags - Specify the Tags as an Array
179 * @return a KeyValue with this objects row key and the Put identifier.
181 KeyValue
createPutKeyValue(byte[] family
, byte[] qualifier
, long ts
, byte[] value
, Tag
[] tags
) {
182 KeyValue kvWithTag
= new KeyValue(this.row
, family
, qualifier
, ts
, value
, tags
);
187 * Create a KeyValue with this objects row key and the Put identifier.
189 * @return a KeyValue with this objects row key and the Put identifier.
191 KeyValue
createPutKeyValue(byte[] family
, ByteBuffer qualifier
, long ts
, ByteBuffer value
,
193 return new KeyValue(this.row
, 0, this.row
== null ?
0 : this.row
.length
,
194 family
, 0, family
== null ?
0 : family
.length
,
195 qualifier
, ts
, KeyValue
.Type
.Put
, value
, tags
!= null ? Arrays
.asList(tags
) : null);
199 * Compile the column family (i.e. schema) information
200 * into a Map. Useful for parsing and aggregation by debugging,
201 * logging, and administration tools.
205 public Map
<String
, Object
> getFingerprint() {
206 Map
<String
, Object
> map
= new HashMap
<>();
207 List
<String
> families
= new ArrayList
<>(getFamilyCellMap().entrySet().size());
208 // ideally, we would also include table information, but that information
209 // is not stored in each Operation instance.
210 map
.put("families", families
);
211 for (Map
.Entry
<byte [], List
<Cell
>> entry
: getFamilyCellMap().entrySet()) {
212 families
.add(Bytes
.toStringBinary(entry
.getKey()));
218 * Compile the details beyond the scope of getFingerprint (row, columns,
219 * timestamps, etc.) into a Map along with the fingerprinted information.
220 * Useful for debugging, logging, and administration tools.
221 * @param maxCols a limit on the number of columns output prior to truncation
225 public Map
<String
, Object
> toMap(int maxCols
) {
226 // we start with the fingerprint map and build on top of it.
227 Map
<String
, Object
> map
= getFingerprint();
228 // replace the fingerprint's simple list of families with a
229 // map from column families to lists of qualifiers and kv details
230 Map
<String
, List
<Map
<String
, Object
>>> columns
= new HashMap
<>();
231 map
.put("families", columns
);
232 map
.put("row", Bytes
.toStringBinary(this.row
));
234 // iterate through all column families affected
235 for (Map
.Entry
<byte [], List
<Cell
>> entry
: getFamilyCellMap().entrySet()) {
236 // map from this family to details for each cell affected within the family
237 List
<Map
<String
, Object
>> qualifierDetails
= new ArrayList
<>();
238 columns
.put(Bytes
.toStringBinary(entry
.getKey()), qualifierDetails
);
239 colCount
+= entry
.getValue().size();
243 // add details for each cell
244 for (Cell cell
: entry
.getValue()) {
245 if (--maxCols
<= 0) {
248 Map
<String
, Object
> cellMap
= cellToStringMap(cell
);
249 qualifierDetails
.add(cellMap
);
252 map
.put("totalColumns", colCount
);
254 if (getId() != null) {
255 map
.put("id", getId());
257 // Add the TTL if set
258 // Long.MAX_VALUE is the default, and is interpreted to mean this attribute
260 if (getTTL() != Long
.MAX_VALUE
) {
261 map
.put("ttl", getTTL());
263 map
.put("ts", this.ts
);
267 private static Map
<String
, Object
> cellToStringMap(Cell c
) {
268 Map
<String
, Object
> stringMap
= new HashMap
<>();
269 stringMap
.put("qualifier", Bytes
.toStringBinary(c
.getQualifierArray(), c
.getQualifierOffset(),
270 c
.getQualifierLength()));
271 stringMap
.put("timestamp", c
.getTimestamp());
272 stringMap
.put("vlen", c
.getValueLength());
273 List
<Tag
> tags
= PrivateCellUtil
.getTags(c
);
275 List
<String
> tagsString
= new ArrayList
<>(tags
.size());
278 .add((t
.getType()) + ":" + Bytes
.toStringBinary(Tag
.cloneValue(t
)));
280 stringMap
.put("tag", tagsString
);
286 * Set the durability for this mutation
289 public Mutation
setDurability(Durability d
) {
294 /** Get the current durability */
295 public Durability
getDurability() {
296 return this.durability
;
300 * Method for retrieving the put's familyMap
303 public NavigableMap
<byte [], List
<Cell
>> getFamilyCellMap() {
304 return this.familyMap
;
308 * Method to check if the familyMap is empty
309 * @return true if empty, false otherwise
311 public boolean isEmpty() {
312 return getFamilyCellMap().isEmpty();
316 * Method for retrieving the delete's row
320 public byte [] getRow() {
325 * Method for retrieving the timestamp.
329 public long getTimestamp() {
334 * Marks that the clusters with the given clusterIds have consumed the mutation
335 * @param clusterIds of the clusters that have consumed the mutation
337 public Mutation
setClusterIds(List
<UUID
> clusterIds
) {
338 ByteArrayDataOutput out
= ByteStreams
.newDataOutput();
339 out
.writeInt(clusterIds
.size());
340 for (UUID clusterId
: clusterIds
) {
341 out
.writeLong(clusterId
.getMostSignificantBits());
342 out
.writeLong(clusterId
.getLeastSignificantBits());
344 setAttribute(CONSUMED_CLUSTER_IDS
, out
.toByteArray());
349 * @return the set of clusterIds that have consumed the mutation
351 public List
<UUID
> getClusterIds() {
352 List
<UUID
> clusterIds
= new ArrayList
<>();
353 byte[] bytes
= getAttribute(CONSUMED_CLUSTER_IDS
);
355 ByteArrayDataInput in
= ByteStreams
.newDataInput(bytes
);
356 int numClusters
= in
.readInt();
357 for(int i
=0; i
<numClusters
; i
++){
358 clusterIds
.add(new UUID(in
.readLong(), in
.readLong()));
365 * Sets the visibility expression associated with cells in this Mutation.
368 public Mutation
setCellVisibility(CellVisibility expression
) {
369 this.setAttribute(VisibilityConstants
.VISIBILITY_LABELS_ATTR_KEY
,
370 toCellVisibility(expression
).toByteArray());
375 * @return CellVisibility associated with cells in this Mutation.
376 * @throws DeserializationException
378 public CellVisibility
getCellVisibility() throws DeserializationException
{
379 byte[] cellVisibilityBytes
= this.getAttribute(VisibilityConstants
.VISIBILITY_LABELS_ATTR_KEY
);
380 if (cellVisibilityBytes
== null) return null;
381 return toCellVisibility(cellVisibilityBytes
);
385 * Create a protocol buffer CellVisibility based on a client CellVisibility.
387 * @param cellVisibility
388 * @return a protocol buffer CellVisibility
390 static ClientProtos
.CellVisibility
toCellVisibility(CellVisibility cellVisibility
) {
391 ClientProtos
.CellVisibility
.Builder builder
= ClientProtos
.CellVisibility
.newBuilder();
392 builder
.setExpression(cellVisibility
.getExpression());
393 return builder
.build();
397 * Convert a protocol buffer CellVisibility to a client CellVisibility
400 * @return the converted client CellVisibility
402 private static CellVisibility
toCellVisibility(ClientProtos
.CellVisibility proto
) {
403 if (proto
== null) return null;
404 return new CellVisibility(proto
.getExpression());
408 * Convert a protocol buffer CellVisibility bytes to a client CellVisibility
411 * @return the converted client CellVisibility
412 * @throws DeserializationException
414 private static CellVisibility
toCellVisibility(byte[] protoBytes
) throws DeserializationException
{
415 if (protoBytes
== null) return null;
416 ClientProtos
.CellVisibility
.Builder builder
= ClientProtos
.CellVisibility
.newBuilder();
417 ClientProtos
.CellVisibility proto
= null;
419 ProtobufUtil
.mergeFrom(builder
, protoBytes
);
420 proto
= builder
.build();
421 } catch (IOException e
) {
422 throw new DeserializationException(e
);
424 return toCellVisibility(proto
);
428 * Number of KeyValues carried by this Mutation.
429 * @return the total number of KeyValues
433 for (List
<Cell
> cells
: getFamilyCellMap().values()) {
434 size
+= cells
.size();
440 * @return the number of different families
442 public int numFamilies() {
443 return getFamilyCellMap().size();
447 * @return Calculate what Mutation adds to class heap size.
450 public long heapSize() {
451 long heapsize
= MUTATION_OVERHEAD
;
453 heapsize
+= ClassSize
.align(ClassSize
.ARRAY
+ this.row
.length
);
455 // Adding map overhead
457 ClassSize
.align(getFamilyCellMap().size() * ClassSize
.MAP_ENTRY
);
458 for(Map
.Entry
<byte [], List
<Cell
>> entry
: getFamilyCellMap().entrySet()) {
459 //Adding key overhead
461 ClassSize
.align(ClassSize
.ARRAY
+ entry
.getKey().length
);
463 //This part is kinds tricky since the JVM can reuse references if you
464 //store the same value, but have a good match with SizeOf at the moment
465 //Adding value overhead
466 heapsize
+= ClassSize
.align(ClassSize
.ARRAYLIST
);
467 int size
= entry
.getValue().size();
468 heapsize
+= ClassSize
.align(ClassSize
.ARRAY
+
469 size
* ClassSize
.REFERENCE
);
471 for (Cell cell
: entry
.getValue()) {
472 heapsize
+= cell
.heapSize();
475 heapsize
+= getAttributeSize();
476 heapsize
+= extraHeapSize();
477 return ClassSize
.align(heapsize
);
481 * @return The serialized ACL for this operation, or null if none
483 public byte[] getACL() {
484 return getAttribute(AccessControlConstants
.OP_ATTRIBUTE_ACL
);
488 * @param user User short name
489 * @param perms Permissions for the user
491 public Mutation
setACL(String user
, Permission perms
) {
492 setAttribute(AccessControlConstants
.OP_ATTRIBUTE_ACL
,
493 AccessControlUtil
.toUsersAndPermissions(user
, perms
).toByteArray());
498 * @param perms A map of permissions for a user or users
500 public Mutation
setACL(Map
<String
, Permission
> perms
) {
501 ListMultimap
<String
, Permission
> permMap
= ArrayListMultimap
.create();
502 for (Map
.Entry
<String
, Permission
> entry
: perms
.entrySet()) {
503 permMap
.put(entry
.getKey(), entry
.getValue());
505 setAttribute(AccessControlConstants
.OP_ATTRIBUTE_ACL
,
506 AccessControlUtil
.toUsersAndPermissions(permMap
).toByteArray());
511 * Return the TTL requested for the result of the mutation, in milliseconds.
512 * @return the TTL requested for the result of the mutation, in milliseconds,
513 * or Long.MAX_VALUE if unset
515 public long getTTL() {
516 byte[] ttlBytes
= getAttribute(OP_ATTRIBUTE_TTL
);
517 if (ttlBytes
!= null) {
518 return Bytes
.toLong(ttlBytes
);
520 return Long
.MAX_VALUE
;
524 * Set the TTL desired for the result of the mutation, in milliseconds.
525 * @param ttl the TTL desired for the result of the mutation, in milliseconds
528 public Mutation
setTTL(long ttl
) {
529 setAttribute(OP_ATTRIBUTE_TTL
, Bytes
.toBytes(ttl
));
534 * @return current value for returnResults
536 // Used by Increment and Append only.
537 @InterfaceAudience.Private
538 protected boolean isReturnResults() {
539 byte[] v
= getAttribute(RETURN_RESULTS
);
540 return v
== null ?
true : Bytes
.toBoolean(v
);
543 @InterfaceAudience.Private
544 // Used by Increment and Append only.
545 protected Mutation
setReturnResults(boolean returnResults
) {
546 setAttribute(RETURN_RESULTS
, Bytes
.toBytes(returnResults
));
551 * Subclasses should override this method to add the heap size of their own fields.
552 * @return the heap size to add (will be aligned).
554 protected long extraHeapSize(){
559 * Set the timestamp of the delete.
561 public Mutation
setTimestamp(long timestamp
) {
563 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + timestamp
);
570 * A convenience method to determine if this object's familyMap contains
571 * a value assigned to the given family & qualifier.
572 * Both given arguments must match the KeyValue object to return true.
574 * @param family column family
575 * @param qualifier column qualifier
576 * @return returns true if the given family and qualifier already has an
577 * existing KeyValue object in the family map.
579 public boolean has(byte [] family
, byte [] qualifier
) {
580 return has(family
, qualifier
, this.ts
, HConstants
.EMPTY_BYTE_ARRAY
, true, true);
584 * A convenience method to determine if this object's familyMap contains
585 * a value assigned to the given family, qualifier and timestamp.
586 * All 3 given arguments must match the KeyValue object to return true.
588 * @param family column family
589 * @param qualifier column qualifier
590 * @param ts timestamp
591 * @return returns true if the given family, qualifier and timestamp already has an
592 * existing KeyValue object in the family map.
594 public boolean has(byte [] family
, byte [] qualifier
, long ts
) {
595 return has(family
, qualifier
, ts
, HConstants
.EMPTY_BYTE_ARRAY
, false, true);
599 * A convenience method to determine if this object's familyMap contains
600 * a value assigned to the given family, qualifier and timestamp.
601 * All 3 given arguments must match the KeyValue object to return true.
603 * @param family column family
604 * @param qualifier column qualifier
605 * @param value value to check
606 * @return returns true if the given family, qualifier and value already has an
607 * existing KeyValue object in the family map.
609 public boolean has(byte [] family
, byte [] qualifier
, byte [] value
) {
610 return has(family
, qualifier
, this.ts
, value
, true, false);
614 * A convenience method to determine if this object's familyMap contains
615 * the given value assigned to the given family, qualifier and timestamp.
616 * All 4 given arguments must match the KeyValue object to return true.
618 * @param family column family
619 * @param qualifier column qualifier
620 * @param ts timestamp
621 * @param value value to check
622 * @return returns true if the given family, qualifier timestamp and value
623 * already has an existing KeyValue object in the family map.
625 public boolean has(byte [] family
, byte [] qualifier
, long ts
, byte [] value
) {
626 return has(family
, qualifier
, ts
, value
, false, false);
630 * Returns a list of all KeyValue objects with matching column family and qualifier.
632 * @param family column family
633 * @param qualifier column qualifier
634 * @return a list of KeyValue objects with the matching family and qualifier,
635 * returns an empty list if one doesn't exist for the given family.
637 public List
<Cell
> get(byte[] family
, byte[] qualifier
) {
638 List
<Cell
> filteredList
= new ArrayList
<>();
639 for (Cell cell
: getCellList(family
)) {
640 if (CellUtil
.matchingQualifier(cell
, qualifier
)) {
641 filteredList
.add(cell
);
648 * Private method to determine if this object's familyMap contains
649 * the given value assigned to the given family, qualifier and timestamp
650 * respecting the 2 boolean arguments
658 * @return returns true if the given family, qualifier timestamp and value
659 * already has an existing KeyValue object in the family map.
661 protected boolean has(byte[] family
, byte[] qualifier
, long ts
, byte[] value
,
662 boolean ignoreTS
, boolean ignoreValue
) {
663 List
<Cell
> list
= getCellList(family
);
664 if (list
.isEmpty()) {
667 // Boolean analysis of ignoreTS/ignoreValue.
669 // T F => 3 (first is always true)
672 if (!ignoreTS
&& !ignoreValue
) {
673 for (Cell cell
: list
) {
674 if (CellUtil
.matchingFamily(cell
, family
) &&
675 CellUtil
.matchingQualifier(cell
, qualifier
) &&
676 CellUtil
.matchingValue(cell
, value
) &&
677 cell
.getTimestamp() == ts
) {
681 } else if (ignoreValue
&& !ignoreTS
) {
682 for (Cell cell
: list
) {
683 if (CellUtil
.matchingFamily(cell
, family
) && CellUtil
.matchingQualifier(cell
, qualifier
)
684 && cell
.getTimestamp() == ts
) {
688 } else if (!ignoreValue
&& ignoreTS
) {
689 for (Cell cell
: list
) {
690 if (CellUtil
.matchingFamily(cell
, family
) && CellUtil
.matchingQualifier(cell
, qualifier
)
691 && CellUtil
.matchingValue(cell
, value
)) {
696 for (Cell cell
: list
) {
697 if (CellUtil
.matchingFamily(cell
, family
) &&
698 CellUtil
.matchingQualifier(cell
, qualifier
)) {
707 * @param row Row to check
708 * @throws IllegalArgumentException Thrown if <code>row</code> is empty or null or
709 * > {@link HConstants#MAX_ROW_LENGTH}
710 * @return <code>row</code>
712 static byte [] checkRow(final byte [] row
) {
713 return checkRow(row
, 0, row
== null?
0: row
.length
);
717 * @param row Row to check
720 * @throws IllegalArgumentException Thrown if <code>row</code> is empty or null or
721 * > {@link HConstants#MAX_ROW_LENGTH}
722 * @return <code>row</code>
724 static byte [] checkRow(final byte [] row
, final int offset
, final int length
) {
726 throw new IllegalArgumentException("Row buffer is null");
729 throw new IllegalArgumentException("Row length is 0");
731 if (length
> HConstants
.MAX_ROW_LENGTH
) {
732 throw new IllegalArgumentException("Row length " + length
+ " is > " +
733 HConstants
.MAX_ROW_LENGTH
);
738 static void checkRow(ByteBuffer row
) {
740 throw new IllegalArgumentException("Row buffer is null");
742 if (row
.remaining() == 0) {
743 throw new IllegalArgumentException("Row length is 0");
745 if (row
.remaining() > HConstants
.MAX_ROW_LENGTH
) {
746 throw new IllegalArgumentException("Row length " + row
.remaining() + " is > " +
747 HConstants
.MAX_ROW_LENGTH
);
751 Mutation
add(Cell cell
) throws IOException
{
752 //Checking that the row of the kv is the same as the mutation
753 // TODO: It is fraught with risk if user pass the wrong row.
754 // Throwing the IllegalArgumentException is more suitable I'd say.
755 if (!CellUtil
.matchingRows(cell
, this.row
)) {
756 throw new WrongRowIOException("The row in " + cell
.toString() +
757 " doesn't match the original one " + Bytes
.toStringBinary(this.row
));
762 if (cell
instanceof IndividualBytesFieldCell
) {
763 family
= cell
.getFamilyArray();
765 family
= CellUtil
.cloneFamily(cell
);
768 if (family
== null || family
.length
== 0) {
769 throw new IllegalArgumentException("Family cannot be null");
772 if (cell
instanceof ExtendedCell
) {
773 getCellList(family
).add(cell
);
775 getCellList(family
).add(new CellWrapper(cell
));
781 * get a CellBuilder instance that already has relevant Type and Row set.
782 * @param cellBuilderType e.g CellBuilderType.SHALLOW_COPY
783 * @return CellBuilder which already has relevant Type and Row set.
785 public abstract CellBuilder
getCellBuilder(CellBuilderType cellBuilderType
);
788 * get a CellBuilder instance that already has relevant Type and Row set.
789 * the default CellBuilderType is CellBuilderType.SHALLOW_COPY
790 * @return CellBuilder which already has relevant Type and Row set.
792 public CellBuilder
getCellBuilder() {
793 return getCellBuilder(CellBuilderType
.SHALLOW_COPY
);
797 * get a CellBuilder instance that already has relevant Type and Row set.
798 * @param cellBuilderType e.g CellBuilderType.SHALLOW_COPY
799 * @param cellType e.g Cell.Type.Put
800 * @return CellBuilder which already has relevant Type and Row set.
802 protected CellBuilder
getCellBuilder(CellBuilderType cellBuilderType
, Cell
.Type cellType
) {
803 CellBuilder builder
= CellBuilderFactory
.create(cellBuilderType
).setRow(row
).setType(cellType
);
804 return new CellBuilder() {
806 public CellBuilder
setRow(byte[] row
) {
811 public CellBuilder
setType(Cell
.Type type
) {
816 public CellBuilder
setRow(byte[] row
, int rOffset
, int rLength
) {
821 public CellBuilder
setFamily(byte[] family
) {
822 builder
.setFamily(family
);
827 public CellBuilder
setFamily(byte[] family
, int fOffset
, int fLength
) {
828 builder
.setFamily(family
, fOffset
, fLength
);
833 public CellBuilder
setQualifier(byte[] qualifier
) {
834 builder
.setQualifier(qualifier
);
839 public CellBuilder
setQualifier(byte[] qualifier
, int qOffset
, int qLength
) {
840 builder
.setQualifier(qualifier
, qOffset
, qLength
);
845 public CellBuilder
setTimestamp(long timestamp
) {
846 builder
.setTimestamp(timestamp
);
851 public CellBuilder
setValue(byte[] value
) {
852 builder
.setValue(value
);
857 public CellBuilder
setValue(byte[] value
, int vOffset
, int vLength
) {
858 builder
.setValue(value
, vOffset
, vLength
);
863 public Cell
build() {
864 return builder
.build();
868 public CellBuilder
clear() {
870 // reset the row and type
872 builder
.setType(cellType
);
878 private static final class CellWrapper
implements ExtendedCell
{
879 private static final long FIXED_OVERHEAD
= ClassSize
.align(
880 ClassSize
.OBJECT
// object header
881 + KeyValue
.TIMESTAMP_SIZE
// timestamp
882 + Bytes
.SIZEOF_LONG
// sequence id
883 + 1 * ClassSize
.REFERENCE
); // references to cell
884 private final Cell cell
;
885 private long sequenceId
;
886 private long timestamp
;
888 CellWrapper(Cell cell
) {
889 assert !(cell
instanceof ExtendedCell
);
891 this.sequenceId
= cell
.getSequenceId();
892 this.timestamp
= cell
.getTimestamp();
896 public void setSequenceId(long seqId
) {
901 public void setTimestamp(long ts
) {
906 public void setTimestamp(byte[] ts
) {
907 timestamp
= Bytes
.toLong(ts
);
911 public long getSequenceId() {
916 public byte[] getValueArray() {
917 return cell
.getValueArray();
921 public int getValueOffset() {
922 return cell
.getValueOffset();
926 public int getValueLength() {
927 return cell
.getValueLength();
931 public byte[] getTagsArray() {
932 return cell
.getTagsArray();
936 public int getTagsOffset() {
937 return cell
.getTagsOffset();
941 public int getTagsLength() {
942 return cell
.getTagsLength();
946 public byte[] getRowArray() {
947 return cell
.getRowArray();
951 public int getRowOffset() {
952 return cell
.getRowOffset();
956 public short getRowLength() {
957 return cell
.getRowLength();
961 public byte[] getFamilyArray() {
962 return cell
.getFamilyArray();
966 public int getFamilyOffset() {
967 return cell
.getFamilyOffset();
971 public byte getFamilyLength() {
972 return cell
.getFamilyLength();
976 public byte[] getQualifierArray() {
977 return cell
.getQualifierArray();
981 public int getQualifierOffset() {
982 return cell
.getQualifierOffset();
986 public int getQualifierLength() {
987 return cell
.getQualifierLength();
991 public long getTimestamp() {
996 public byte getTypeByte() {
997 return cell
.getTypeByte();
1001 public Optional
<Tag
> getTag(byte type
) {
1002 return PrivateCellUtil
.getTag(cell
, type
);
1006 public Iterator
<Tag
> getTags() {
1007 return PrivateCellUtil
.tagsIterator(cell
);
1011 public byte[] cloneTags() {
1012 return PrivateCellUtil
.cloneTags(cell
);
1015 private long heapOverhead() {
1016 return FIXED_OVERHEAD
1017 + ClassSize
.ARRAY
// row
1018 + getFamilyLength() == 0 ?
0 : ClassSize
.ARRAY
1019 + getQualifierLength() == 0 ?
0 : ClassSize
.ARRAY
1020 + getValueLength() == 0 ?
0 : ClassSize
.ARRAY
1021 + getTagsLength() == 0 ?
0 : ClassSize
.ARRAY
;
1025 public long heapSize() {
1026 return heapOverhead()
1027 + ClassSize
.align(getRowLength())
1028 + ClassSize
.align(getFamilyLength())
1029 + ClassSize
.align(getQualifierLength())
1030 + ClassSize
.align(getValueLength())
1031 + ClassSize
.align(getTagsLength());