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 */ 018package org.apache.hadoop.hbase.client; 019 020import java.io.IOException; 021import java.nio.ByteBuffer; 022import java.util.ArrayList; 023import java.util.Arrays; 024import java.util.HashMap; 025import java.util.Iterator; 026import java.util.List; 027import java.util.Map; 028import java.util.NavigableMap; 029import java.util.Optional; 030import java.util.TreeMap; 031import java.util.UUID; 032import java.util.stream.Collectors; 033import org.apache.hadoop.hbase.Cell; 034import org.apache.hadoop.hbase.CellScannable; 035import org.apache.hadoop.hbase.CellScanner; 036import org.apache.hadoop.hbase.CellUtil; 037import org.apache.hadoop.hbase.ExtendedCell; 038import org.apache.hadoop.hbase.HConstants; 039import org.apache.hadoop.hbase.IndividualBytesFieldCell; 040import org.apache.hadoop.hbase.KeyValue; 041import org.apache.hadoop.hbase.PrivateCellUtil; 042import org.apache.hadoop.hbase.Tag; 043import org.apache.hadoop.hbase.exceptions.DeserializationException; 044import org.apache.hadoop.hbase.io.HeapSize; 045import org.apache.hadoop.hbase.protobuf.ProtobufUtil; 046import org.apache.hadoop.hbase.protobuf.generated.ClientProtos; 047import org.apache.hadoop.hbase.security.access.AccessControlConstants; 048import org.apache.hadoop.hbase.security.access.AccessControlUtil; 049import org.apache.hadoop.hbase.security.access.Permission; 050import org.apache.hadoop.hbase.security.visibility.CellVisibility; 051import org.apache.hadoop.hbase.security.visibility.VisibilityConstants; 052import org.apache.hadoop.hbase.util.Bytes; 053import org.apache.hadoop.hbase.util.ClassSize; 054import org.apache.yetus.audience.InterfaceAudience; 055 056import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 057import org.apache.hbase.thirdparty.com.google.common.collect.ArrayListMultimap; 058import org.apache.hbase.thirdparty.com.google.common.collect.ListMultimap; 059import org.apache.hbase.thirdparty.com.google.common.io.ByteArrayDataInput; 060import org.apache.hbase.thirdparty.com.google.common.io.ByteArrayDataOutput; 061import org.apache.hbase.thirdparty.com.google.common.io.ByteStreams; 062 063@InterfaceAudience.Public 064public abstract class Mutation extends OperationWithAttributes 065 implements Row, CellScannable, HeapSize { 066 public static final long MUTATION_OVERHEAD = ClassSize.align( 067 // This 068 ClassSize.OBJECT + 069 // row + OperationWithAttributes.attributes 070 2 * ClassSize.REFERENCE + 071 // Timestamp 072 1 * Bytes.SIZEOF_LONG + 073 // durability 074 ClassSize.REFERENCE + 075 // familyMap 076 ClassSize.REFERENCE + 077 // familyMap 078 ClassSize.TREEMAP + 079 // priority 080 ClassSize.INTEGER); 081 082 /** 083 * The attribute for storing the list of clusters that have consumed the change. 084 */ 085 private static final String CONSUMED_CLUSTER_IDS = "_cs.id"; 086 087 /** 088 * The attribute for storing TTL for the result of the mutation. 089 */ 090 private static final String OP_ATTRIBUTE_TTL = "_ttl"; 091 092 private static final String RETURN_RESULTS = "_rr_"; 093 094 // TODO: row should be final 095 protected byte[] row = null; 096 protected long ts = HConstants.LATEST_TIMESTAMP; 097 protected Durability durability = Durability.USE_DEFAULT; 098 099 // TODO: familyMap should be final 100 // A Map sorted by column family. 101 protected NavigableMap<byte[], List<Cell>> familyMap; 102 103 /** 104 * empty construction. We need this empty construction to keep binary compatibility. 105 */ 106 protected Mutation() { 107 this.familyMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 108 } 109 110 protected Mutation(Mutation clone) { 111 super(clone); 112 this.row = clone.getRow(); 113 this.ts = clone.getTimestamp(); 114 this.familyMap = clone.getFamilyCellMap().entrySet().stream() 115 .collect(Collectors.toMap(e -> e.getKey(), e -> new ArrayList<>(e.getValue()), (k, v) -> { 116 throw new RuntimeException("collisions!!!"); 117 }, () -> new TreeMap<>(Bytes.BYTES_COMPARATOR))); 118 } 119 120 /** 121 * Construct the mutation with user defined data. 122 * @param row row. CAN'T be null 123 * @param ts timestamp 124 * @param familyMap the map to collect all cells internally. CAN'T be null 125 */ 126 protected Mutation(byte[] row, long ts, NavigableMap<byte[], List<Cell>> familyMap) { 127 this.row = Preconditions.checkNotNull(row); 128 if (row.length == 0) { 129 throw new IllegalArgumentException("Row can't be empty"); 130 } 131 this.ts = ts; 132 this.familyMap = Preconditions.checkNotNull(familyMap); 133 } 134 135 @Override 136 public CellScanner cellScanner() { 137 return CellUtil.createCellScanner(getFamilyCellMap()); 138 } 139 140 /** 141 * Creates an empty list if one doesn't exist for the given column family or else it returns the 142 * associated list of Cell objects. 143 * @param family column family 144 * @return a list of Cell objects, returns an empty list if one doesn't exist. 145 */ 146 List<Cell> getCellList(byte[] family) { 147 List<Cell> list = getFamilyCellMap().get(family); 148 if (list == null) { 149 list = new ArrayList<>(); 150 getFamilyCellMap().put(family, list); 151 } 152 return list; 153 } 154 155 /* 156 * Create a KeyValue with this objects row key and the Put identifier. 157 * @return a KeyValue with this objects row key and the Put identifier. 158 */ 159 KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts, byte[] value) { 160 return new KeyValue(this.row, family, qualifier, ts, KeyValue.Type.Put, value); 161 } 162 163 /** 164 * Create a KeyValue with this objects row key and the Put identifier. 165 * @param tags - Specify the Tags as an Array 166 * @return a KeyValue with this objects row key and the Put identifier. 167 */ 168 KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tags) { 169 KeyValue kvWithTag = new KeyValue(this.row, family, qualifier, ts, value, tags); 170 return kvWithTag; 171 } 172 173 /* 174 * Create a KeyValue with this objects row key and the Put identifier. 175 * @return a KeyValue with this objects row key and the Put identifier. 176 */ 177 KeyValue createPutKeyValue(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value, 178 Tag[] tags) { 179 return new KeyValue(this.row, 0, this.row == null ? 0 : this.row.length, family, 0, 180 family == null ? 0 : family.length, qualifier, ts, KeyValue.Type.Put, value, 181 tags != null ? Arrays.asList(tags) : null); 182 } 183 184 /** 185 * Compile the column family (i.e. schema) information into a Map. Useful for parsing and 186 * aggregation by debugging, logging, and administration tools. 187 */ 188 @Override 189 public Map<String, Object> getFingerprint() { 190 Map<String, Object> map = new HashMap<>(); 191 List<String> families = new ArrayList<>(getFamilyCellMap().entrySet().size()); 192 // ideally, we would also include table information, but that information 193 // is not stored in each Operation instance. 194 map.put("families", families); 195 for (Map.Entry<byte[], List<Cell>> entry : getFamilyCellMap().entrySet()) { 196 families.add(Bytes.toStringBinary(entry.getKey())); 197 } 198 return map; 199 } 200 201 /** 202 * Compile the details beyond the scope of getFingerprint (row, columns, timestamps, etc.) into a 203 * Map along with the fingerprinted information. Useful for debugging, logging, and administration 204 * tools. 205 * @param maxCols a limit on the number of columns output prior to truncation 206 */ 207 @Override 208 public Map<String, Object> toMap(int maxCols) { 209 // we start with the fingerprint map and build on top of it. 210 Map<String, Object> map = getFingerprint(); 211 // replace the fingerprint's simple list of families with a 212 // map from column families to lists of qualifiers and kv details 213 Map<String, List<Map<String, Object>>> columns = new HashMap<>(); 214 map.put("families", columns); 215 map.put("row", Bytes.toStringBinary(this.row)); 216 int colCount = 0; 217 // iterate through all column families affected 218 for (Map.Entry<byte[], List<Cell>> entry : getFamilyCellMap().entrySet()) { 219 // map from this family to details for each cell affected within the family 220 List<Map<String, Object>> qualifierDetails = new ArrayList<>(); 221 columns.put(Bytes.toStringBinary(entry.getKey()), qualifierDetails); 222 colCount += entry.getValue().size(); 223 if (maxCols <= 0) { 224 continue; 225 } 226 // add details for each cell 227 for (Cell cell : entry.getValue()) { 228 if (--maxCols <= 0) { 229 continue; 230 } 231 Map<String, Object> cellMap = cellToStringMap(cell); 232 qualifierDetails.add(cellMap); 233 } 234 } 235 map.put("totalColumns", colCount); 236 // add the id if set 237 if (getId() != null) { 238 map.put("id", getId()); 239 } 240 // Add the TTL if set 241 // Long.MAX_VALUE is the default, and is interpreted to mean this attribute 242 // has not been set. 243 if (getTTL() != Long.MAX_VALUE) { 244 map.put("ttl", getTTL()); 245 } 246 map.put("ts", this.ts); 247 return map; 248 } 249 250 private static Map<String, Object> cellToStringMap(Cell c) { 251 Map<String, Object> stringMap = new HashMap<>(); 252 stringMap.put("qualifier", 253 Bytes.toStringBinary(c.getQualifierArray(), c.getQualifierOffset(), c.getQualifierLength())); 254 stringMap.put("timestamp", c.getTimestamp()); 255 stringMap.put("vlen", c.getValueLength()); 256 List<Tag> tags = PrivateCellUtil.getTags(c); 257 if (tags != null) { 258 List<String> tagsString = new ArrayList<>(tags.size()); 259 for (Tag t : tags) { 260 tagsString.add((t.getType()) + ":" + Bytes.toStringBinary(Tag.cloneValue(t))); 261 } 262 stringMap.put("tag", tagsString); 263 } 264 return stringMap; 265 } 266 267 /** 268 * Set the durability for this mutation 269 */ 270 public Mutation setDurability(Durability d) { 271 this.durability = d; 272 return this; 273 } 274 275 /** Get the current durability */ 276 public Durability getDurability() { 277 return this.durability; 278 } 279 280 /** 281 * Method for retrieving the put's familyMap 282 */ 283 public NavigableMap<byte[], List<Cell>> getFamilyCellMap() { 284 return this.familyMap; 285 } 286 287 /** 288 * Method for setting the mutation's familyMap 289 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 290 * {@link Mutation#Mutation(byte[], long, NavigableMap)} instead 291 */ 292 @Deprecated 293 public Mutation setFamilyCellMap(NavigableMap<byte[], List<Cell>> map) { 294 // TODO: Shut this down or move it up to be a Constructor. Get new object rather than change 295 // this internal data member. 296 this.familyMap = map; 297 return this; 298 } 299 300 /** 301 * Method to check if the familyMap is empty 302 * @return true if empty, false otherwise 303 */ 304 public boolean isEmpty() { 305 return getFamilyCellMap().isEmpty(); 306 } 307 308 /** 309 * Method for retrieving the delete's row 310 */ 311 @Override 312 public byte[] getRow() { 313 return this.row; 314 } 315 316 /** 317 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 318 * {@link Row#COMPARATOR} instead 319 */ 320 @Deprecated 321 @Override 322 public int compareTo(final Row d) { 323 return Bytes.compareTo(this.getRow(), d.getRow()); 324 } 325 326 /** 327 * Method for retrieving the timestamp 328 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0. Use 329 * {@link #getTimestamp()} instead 330 */ 331 @Deprecated 332 public long getTimeStamp() { 333 return this.getTimestamp(); 334 } 335 336 /** 337 * Method for retrieving the timestamp. 338 */ 339 public long getTimestamp() { 340 return this.ts; 341 } 342 343 /** 344 * Marks that the clusters with the given clusterIds have consumed the mutation 345 * @param clusterIds of the clusters that have consumed the mutation 346 */ 347 public Mutation setClusterIds(List<UUID> clusterIds) { 348 ByteArrayDataOutput out = ByteStreams.newDataOutput(); 349 out.writeInt(clusterIds.size()); 350 for (UUID clusterId : clusterIds) { 351 out.writeLong(clusterId.getMostSignificantBits()); 352 out.writeLong(clusterId.getLeastSignificantBits()); 353 } 354 setAttribute(CONSUMED_CLUSTER_IDS, out.toByteArray()); 355 return this; 356 } 357 358 /** Returns the set of clusterIds that have consumed the mutation */ 359 public List<UUID> getClusterIds() { 360 List<UUID> clusterIds = new ArrayList<>(); 361 byte[] bytes = getAttribute(CONSUMED_CLUSTER_IDS); 362 if (bytes != null) { 363 ByteArrayDataInput in = ByteStreams.newDataInput(bytes); 364 int numClusters = in.readInt(); 365 for (int i = 0; i < numClusters; i++) { 366 clusterIds.add(new UUID(in.readLong(), in.readLong())); 367 } 368 } 369 return clusterIds; 370 } 371 372 /** 373 * Sets the visibility expression associated with cells in this Mutation. 374 */ 375 public Mutation setCellVisibility(CellVisibility expression) { 376 this.setAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY, 377 toCellVisibility(expression).toByteArray()); 378 return this; 379 } 380 381 /** Returns CellVisibility associated with cells in this Mutation. n */ 382 public CellVisibility getCellVisibility() throws DeserializationException { 383 byte[] cellVisibilityBytes = this.getAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY); 384 if (cellVisibilityBytes == null) return null; 385 return toCellVisibility(cellVisibilityBytes); 386 } 387 388 /** 389 * Create a protocol buffer CellVisibility based on a client CellVisibility. 390 * @return a protocol buffer CellVisibility 391 */ 392 static ClientProtos.CellVisibility toCellVisibility(CellVisibility cellVisibility) { 393 ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder(); 394 builder.setExpression(cellVisibility.getExpression()); 395 return builder.build(); 396 } 397 398 /** 399 * Convert a protocol buffer CellVisibility to a client CellVisibility 400 * @return the converted client CellVisibility 401 */ 402 private static CellVisibility toCellVisibility(ClientProtos.CellVisibility proto) { 403 if (proto == null) return null; 404 return new CellVisibility(proto.getExpression()); 405 } 406 407 /** 408 * Convert a protocol buffer CellVisibility bytes to a client CellVisibility 409 * @return the converted client CellVisibility 410 */ 411 private static CellVisibility toCellVisibility(byte[] protoBytes) 412 throws DeserializationException { 413 if (protoBytes == null) return null; 414 ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder(); 415 ClientProtos.CellVisibility proto = null; 416 try { 417 ProtobufUtil.mergeFrom(builder, protoBytes); 418 proto = builder.build(); 419 } catch (IOException e) { 420 throw new DeserializationException(e); 421 } 422 return toCellVisibility(proto); 423 } 424 425 /** 426 * Number of KeyValues carried by this Mutation. 427 * @return the total number of KeyValues 428 */ 429 public int size() { 430 int size = 0; 431 for (List<Cell> cells : getFamilyCellMap().values()) { 432 size += cells.size(); 433 } 434 return size; 435 } 436 437 /** Returns the number of different families */ 438 public int numFamilies() { 439 return getFamilyCellMap().size(); 440 } 441 442 /** Returns Calculate what Mutation adds to class heap size. */ 443 @Override 444 public long heapSize() { 445 long heapsize = MUTATION_OVERHEAD; 446 // Adding row 447 heapsize += ClassSize.align(ClassSize.ARRAY + this.row.length); 448 449 // Adding map overhead 450 heapsize += ClassSize.align(getFamilyCellMap().size() * ClassSize.MAP_ENTRY); 451 for (Map.Entry<byte[], List<Cell>> entry : getFamilyCellMap().entrySet()) { 452 // Adding key overhead 453 heapsize += ClassSize.align(ClassSize.ARRAY + entry.getKey().length); 454 455 // This part is kinds tricky since the JVM can reuse references if you 456 // store the same value, but have a good match with SizeOf at the moment 457 // Adding value overhead 458 heapsize += ClassSize.align(ClassSize.ARRAYLIST); 459 int size = entry.getValue().size(); 460 heapsize += ClassSize.align(ClassSize.ARRAY + size * ClassSize.REFERENCE); 461 462 for (Cell cell : entry.getValue()) { 463 heapsize += cell.heapSize(); 464 } 465 } 466 heapsize += getAttributeSize(); 467 heapsize += extraHeapSize(); 468 return ClassSize.align(heapsize); 469 } 470 471 /** Returns The serialized ACL for this operation, or null if none */ 472 public byte[] getACL() { 473 return getAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL); 474 } 475 476 /** 477 * @param user User short name 478 * @param perms Permissions for the user 479 */ 480 public Mutation setACL(String user, Permission perms) { 481 setAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL, 482 AccessControlUtil.toUsersAndPermissions(user, perms).toByteArray()); 483 return this; 484 } 485 486 /** 487 * @param perms A map of permissions for a user or users 488 */ 489 public Mutation setACL(Map<String, Permission> perms) { 490 ListMultimap<String, Permission> permMap = ArrayListMultimap.create(); 491 for (Map.Entry<String, Permission> entry : perms.entrySet()) { 492 permMap.put(entry.getKey(), entry.getValue()); 493 } 494 setAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL, 495 AccessControlUtil.toUsersAndPermissions(permMap).toByteArray()); 496 return this; 497 } 498 499 /** 500 * Return the TTL requested for the result of the mutation, in milliseconds. 501 * @return the TTL requested for the result of the mutation, in milliseconds, or Long.MAX_VALUE if 502 * unset 503 */ 504 public long getTTL() { 505 byte[] ttlBytes = getAttribute(OP_ATTRIBUTE_TTL); 506 if (ttlBytes != null) { 507 return Bytes.toLong(ttlBytes); 508 } 509 return Long.MAX_VALUE; 510 } 511 512 /** 513 * Set the TTL desired for the result of the mutation, in milliseconds. 514 * @param ttl the TTL desired for the result of the mutation, in milliseconds 515 */ 516 public Mutation setTTL(long ttl) { 517 setAttribute(OP_ATTRIBUTE_TTL, Bytes.toBytes(ttl)); 518 return this; 519 } 520 521 /** Returns current value for returnResults */ 522 // Used by Increment and Append only. 523 @InterfaceAudience.Private 524 protected boolean isReturnResults() { 525 byte[] v = getAttribute(RETURN_RESULTS); 526 return v == null ? true : Bytes.toBoolean(v); 527 } 528 529 @InterfaceAudience.Private 530 // Used by Increment and Append only. 531 protected Mutation setReturnResults(boolean returnResults) { 532 setAttribute(RETURN_RESULTS, Bytes.toBytes(returnResults)); 533 return this; 534 } 535 536 /** 537 * Subclasses should override this method to add the heap size of their own fields. 538 * @return the heap size to add (will be aligned). 539 */ 540 protected long extraHeapSize() { 541 return 0L; 542 } 543 544 /** 545 * Set the timestamp of the delete. 546 */ 547 public Mutation setTimestamp(long timestamp) { 548 if (timestamp < 0) { 549 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + timestamp); 550 } 551 this.ts = timestamp; 552 return this; 553 } 554 555 /** 556 * A convenience method to determine if this object's familyMap contains a value assigned to the 557 * given family & qualifier. Both given arguments must match the KeyValue object to return 558 * true. 559 * @param family column family 560 * @param qualifier column qualifier 561 * @return returns true if the given family and qualifier already has an existing KeyValue object 562 * in the family map. 563 */ 564 public boolean has(byte[] family, byte[] qualifier) { 565 return has(family, qualifier, this.ts, HConstants.EMPTY_BYTE_ARRAY, true, true); 566 } 567 568 /** 569 * A convenience method to determine if this object's familyMap contains a value assigned to the 570 * given family, qualifier and timestamp. All 3 given arguments must match the KeyValue object to 571 * return true. 572 * @param family column family 573 * @param qualifier column qualifier 574 * @param ts timestamp 575 * @return returns true if the given family, qualifier and timestamp already has an existing 576 * KeyValue object in the family map. 577 */ 578 public boolean has(byte[] family, byte[] qualifier, long ts) { 579 return has(family, qualifier, ts, HConstants.EMPTY_BYTE_ARRAY, false, true); 580 } 581 582 /** 583 * A convenience method to determine if this object's familyMap contains a value assigned to the 584 * given family, qualifier and timestamp. All 3 given arguments must match the KeyValue object to 585 * return true. 586 * @param family column family 587 * @param qualifier column qualifier 588 * @param value value to check 589 * @return returns true if the given family, qualifier and value already has an existing KeyValue 590 * object in the family map. 591 */ 592 public boolean has(byte[] family, byte[] qualifier, byte[] value) { 593 return has(family, qualifier, this.ts, value, true, false); 594 } 595 596 /** 597 * A convenience method to determine if this object's familyMap contains the given value assigned 598 * to the given family, qualifier and timestamp. All 4 given arguments must match the KeyValue 599 * object to return true. 600 * @param family column family 601 * @param qualifier column qualifier 602 * @param ts timestamp 603 * @param value value to check 604 * @return returns true if the given family, qualifier timestamp and value already has an existing 605 * KeyValue object in the family map. 606 */ 607 public boolean has(byte[] family, byte[] qualifier, long ts, byte[] value) { 608 return has(family, qualifier, ts, value, false, false); 609 } 610 611 /** 612 * Returns a list of all KeyValue objects with matching column family and qualifier. 613 * @param family column family 614 * @param qualifier column qualifier 615 * @return a list of KeyValue objects with the matching family and qualifier, returns an empty 616 * list if one doesn't exist for the given family. 617 */ 618 public List<Cell> get(byte[] family, byte[] qualifier) { 619 List<Cell> filteredList = new ArrayList<>(); 620 for (Cell cell : getCellList(family)) { 621 if (CellUtil.matchingQualifier(cell, qualifier)) { 622 filteredList.add(cell); 623 } 624 } 625 return filteredList; 626 } 627 628 /* 629 * Private method to determine if this object's familyMap contains the given value assigned to the 630 * given family, qualifier and timestamp respecting the 2 boolean arguments 631 * @return returns true if the given family, qualifier timestamp and value already has an existing 632 * KeyValue object in the family map. 633 */ 634 protected boolean has(byte[] family, byte[] qualifier, long ts, byte[] value, boolean ignoreTS, 635 boolean ignoreValue) { 636 List<Cell> list = getCellList(family); 637 if (list.isEmpty()) { 638 return false; 639 } 640 // Boolean analysis of ignoreTS/ignoreValue. 641 // T T => 2 642 // T F => 3 (first is always true) 643 // F T => 2 644 // F F => 1 645 if (!ignoreTS && !ignoreValue) { 646 for (Cell cell : list) { 647 if ( 648 CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) 649 && CellUtil.matchingValue(cell, value) && cell.getTimestamp() == ts 650 ) { 651 return true; 652 } 653 } 654 } else if (ignoreValue && !ignoreTS) { 655 for (Cell cell : list) { 656 if ( 657 CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) 658 && cell.getTimestamp() == ts 659 ) { 660 return true; 661 } 662 } 663 } else if (!ignoreValue && ignoreTS) { 664 for (Cell cell : list) { 665 if ( 666 CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier) 667 && CellUtil.matchingValue(cell, value) 668 ) { 669 return true; 670 } 671 } 672 } else { 673 for (Cell cell : list) { 674 if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)) { 675 return true; 676 } 677 } 678 } 679 return false; 680 } 681 682 /** 683 * @param row Row to check 684 * @throws IllegalArgumentException Thrown if <code>row</code> is empty or null or > 685 * {@link HConstants#MAX_ROW_LENGTH} 686 * @return <code>row</code> 687 */ 688 static byte[] checkRow(final byte[] row) { 689 return checkRow(row, 0, row == null ? 0 : row.length); 690 } 691 692 /** 693 * @param row Row to check 694 * @throws IllegalArgumentException Thrown if <code>row</code> is empty or null or > 695 * {@link HConstants#MAX_ROW_LENGTH} 696 * @return <code>row</code> 697 */ 698 static byte[] checkRow(final byte[] row, final int offset, final int length) { 699 if (row == null) { 700 throw new IllegalArgumentException("Row buffer is null"); 701 } 702 if (length == 0) { 703 throw new IllegalArgumentException("Row length is 0"); 704 } 705 if (length > HConstants.MAX_ROW_LENGTH) { 706 throw new IllegalArgumentException( 707 "Row length " + length + " is > " + HConstants.MAX_ROW_LENGTH); 708 } 709 return row; 710 } 711 712 static void checkRow(ByteBuffer row) { 713 if (row == null) { 714 throw new IllegalArgumentException("Row buffer is null"); 715 } 716 if (row.remaining() == 0) { 717 throw new IllegalArgumentException("Row length is 0"); 718 } 719 if (row.remaining() > HConstants.MAX_ROW_LENGTH) { 720 throw new IllegalArgumentException( 721 "Row length " + row.remaining() + " is > " + HConstants.MAX_ROW_LENGTH); 722 } 723 } 724 725 Mutation add(Cell cell) throws IOException { 726 // Checking that the row of the kv is the same as the mutation 727 // TODO: It is fraught with risk if user pass the wrong row. 728 // Throwing the IllegalArgumentException is more suitable I'd say. 729 if (!CellUtil.matchingRows(cell, this.row)) { 730 throw new WrongRowIOException("The row in " + cell.toString() 731 + " doesn't match the original one " + Bytes.toStringBinary(this.row)); 732 } 733 734 byte[] family; 735 736 if (cell instanceof IndividualBytesFieldCell) { 737 family = cell.getFamilyArray(); 738 } else { 739 family = CellUtil.cloneFamily(cell); 740 } 741 742 if (family == null || family.length == 0) { 743 throw new IllegalArgumentException("Family cannot be null"); 744 } 745 746 if (cell instanceof ExtendedCell) { 747 getCellList(family).add(cell); 748 } else { 749 getCellList(family).add(new CellWrapper(cell)); 750 } 751 return this; 752 } 753 754 private static final class CellWrapper implements ExtendedCell { 755 private static final long FIXED_OVERHEAD = ClassSize.align(ClassSize.OBJECT // object header 756 + KeyValue.TIMESTAMP_SIZE // timestamp 757 + Bytes.SIZEOF_LONG // sequence id 758 + 1 * ClassSize.REFERENCE); // references to cell 759 private final Cell cell; 760 private long sequenceId; 761 private long timestamp; 762 763 CellWrapper(Cell cell) { 764 assert !(cell instanceof ExtendedCell); 765 this.cell = cell; 766 this.sequenceId = cell.getSequenceId(); 767 this.timestamp = cell.getTimestamp(); 768 } 769 770 @Override 771 public void setSequenceId(long seqId) { 772 sequenceId = seqId; 773 } 774 775 @Override 776 public void setTimestamp(long ts) { 777 timestamp = ts; 778 } 779 780 @Override 781 public void setTimestamp(byte[] ts) { 782 timestamp = Bytes.toLong(ts); 783 } 784 785 @Override 786 public long getSequenceId() { 787 return sequenceId; 788 } 789 790 @Override 791 public byte[] getValueArray() { 792 return cell.getValueArray(); 793 } 794 795 @Override 796 public int getValueOffset() { 797 return cell.getValueOffset(); 798 } 799 800 @Override 801 public int getValueLength() { 802 return cell.getValueLength(); 803 } 804 805 @Override 806 public byte[] getTagsArray() { 807 return cell.getTagsArray(); 808 } 809 810 @Override 811 public int getTagsOffset() { 812 return cell.getTagsOffset(); 813 } 814 815 @Override 816 public int getTagsLength() { 817 return cell.getTagsLength(); 818 } 819 820 @Override 821 public byte[] getRowArray() { 822 return cell.getRowArray(); 823 } 824 825 @Override 826 public int getRowOffset() { 827 return cell.getRowOffset(); 828 } 829 830 @Override 831 public short getRowLength() { 832 return cell.getRowLength(); 833 } 834 835 @Override 836 public byte[] getFamilyArray() { 837 return cell.getFamilyArray(); 838 } 839 840 @Override 841 public int getFamilyOffset() { 842 return cell.getFamilyOffset(); 843 } 844 845 @Override 846 public byte getFamilyLength() { 847 return cell.getFamilyLength(); 848 } 849 850 @Override 851 public byte[] getQualifierArray() { 852 return cell.getQualifierArray(); 853 } 854 855 @Override 856 public int getQualifierOffset() { 857 return cell.getQualifierOffset(); 858 } 859 860 @Override 861 public int getQualifierLength() { 862 return cell.getQualifierLength(); 863 } 864 865 @Override 866 public long getTimestamp() { 867 return timestamp; 868 } 869 870 @Override 871 public byte getTypeByte() { 872 return cell.getTypeByte(); 873 } 874 875 @Override 876 public Optional<Tag> getTag(byte type) { 877 return PrivateCellUtil.getTag(cell, type); 878 } 879 880 @Override 881 public Iterator<Tag> getTags() { 882 return PrivateCellUtil.tagsIterator(cell); 883 } 884 885 @Override 886 public byte[] cloneTags() { 887 return PrivateCellUtil.cloneTags(cell); 888 } 889 890 private long heapOverhead() { 891 return FIXED_OVERHEAD + ClassSize.ARRAY // row 892 + getFamilyLength() == 0 893 ? 0 894 : ClassSize.ARRAY + getQualifierLength() == 0 ? 0 895 : ClassSize.ARRAY + getValueLength() == 0 ? 0 896 : ClassSize.ARRAY + getTagsLength() == 0 ? 0 897 : ClassSize.ARRAY; 898 } 899 900 @Override 901 public long heapSize() { 902 return heapOverhead() + ClassSize.align(getRowLength()) + ClassSize.align(getFamilyLength()) 903 + ClassSize.align(getQualifierLength()) + ClassSize.align(getValueLength()) 904 + ClassSize.align(getTagsLength()); 905 } 906 } 907}