1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import java.nio.ByteBuffer;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.NavigableMap;
28 import java.util.TreeMap;
29 import java.util.UUID;
30
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.classification.InterfaceStability;
33 import org.apache.hadoop.hbase.Cell;
34 import org.apache.hadoop.hbase.CellScannable;
35 import org.apache.hadoop.hbase.CellScanner;
36 import org.apache.hadoop.hbase.CellUtil;
37 import org.apache.hadoop.hbase.HConstants;
38 import org.apache.hadoop.hbase.KeyValue;
39 import org.apache.hadoop.hbase.KeyValueUtil;
40 import org.apache.hadoop.hbase.Tag;
41 import org.apache.hadoop.hbase.exceptions.DeserializationException;
42 import org.apache.hadoop.hbase.io.HeapSize;
43 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
44 import org.apache.hadoop.hbase.security.access.AccessControlConstants;
45 import org.apache.hadoop.hbase.security.access.Permission;
46 import org.apache.hadoop.hbase.security.visibility.CellVisibility;
47 import org.apache.hadoop.hbase.security.visibility.VisibilityConstants;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.ClassSize;
50
51 import com.google.common.collect.ArrayListMultimap;
52 import com.google.common.collect.ListMultimap;
53 import com.google.common.collect.Lists;
54 import com.google.common.io.ByteArrayDataInput;
55 import com.google.common.io.ByteArrayDataOutput;
56 import com.google.common.io.ByteStreams;
57
58 @InterfaceAudience.Public
59 @InterfaceStability.Evolving
60 public abstract class Mutation extends OperationWithAttributes implements Row, CellScannable,
61 HeapSize {
62 public static final long MUTATION_OVERHEAD = ClassSize.align(
63
64 ClassSize.OBJECT +
65
66 2 * ClassSize.REFERENCE +
67
68 1 * Bytes.SIZEOF_LONG +
69
70 ClassSize.REFERENCE +
71
72 ClassSize.REFERENCE +
73
74 ClassSize.TREEMAP +
75
76 ClassSize.INTEGER
77 );
78
79
80
81
82 private static final String CONSUMED_CLUSTER_IDS = "_cs.id";
83
84
85
86
87 private static final String OP_ATTRIBUTE_TTL = "_ttl";
88
89
90
91
92 @Deprecated
93 protected static final String RETURN_RESULTS = "_rr_";
94
95 protected byte [] row = null;
96 protected long ts = HConstants.LATEST_TIMESTAMP;
97 protected Durability durability = Durability.USE_DEFAULT;
98
99
100 protected NavigableMap<byte [], List<Cell>> familyMap =
101 new TreeMap<byte [], List<Cell>>(Bytes.BYTES_COMPARATOR);
102
103 @Override
104 public CellScanner cellScanner() {
105 return CellUtil.createCellScanner(getFamilyCellMap());
106 }
107
108
109
110
111
112
113
114
115 List<Cell> getCellList(byte[] family) {
116 List<Cell> list = this.familyMap.get(family);
117 if (list == null) {
118 list = new ArrayList<Cell>();
119 this.familyMap.put(family, list);
120 }
121 return list;
122 }
123
124
125
126
127
128
129 KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts, byte[] value) {
130 return new KeyValue(this.row, family, qualifier, ts, KeyValue.Type.Put, value);
131 }
132
133
134
135
136
137
138
139
140
141
142 KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tags) {
143 KeyValue kvWithTag = new KeyValue(this.row, family, qualifier, ts, value, tags);
144 return kvWithTag;
145 }
146
147
148
149
150
151
152 KeyValue createPutKeyValue(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value,
153 Tag[] tags) {
154 return new KeyValue(this.row, 0, this.row == null ? 0 : this.row.length,
155 family, 0, family == null ? 0 : family.length,
156 qualifier, ts, KeyValue.Type.Put, value, tags != null ? Arrays.asList(tags) : null);
157 }
158
159
160
161
162
163
164
165 @Override
166 public Map<String, Object> getFingerprint() {
167 Map<String, Object> map = new HashMap<String, Object>();
168 List<String> families = new ArrayList<String>();
169
170
171 map.put("families", families);
172 for (Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
173 families.add(Bytes.toStringBinary(entry.getKey()));
174 }
175 return map;
176 }
177
178
179
180
181
182
183
184
185 @Override
186 public Map<String, Object> toMap(int maxCols) {
187
188 Map<String, Object> map = getFingerprint();
189
190
191 Map<String, List<Map<String, Object>>> columns =
192 new HashMap<String, List<Map<String, Object>>>();
193 map.put("families", columns);
194 map.put("row", Bytes.toStringBinary(this.row));
195 int colCount = 0;
196
197 for (Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
198
199 List<Map<String, Object>> qualifierDetails = new ArrayList<Map<String, Object>>();
200 columns.put(Bytes.toStringBinary(entry.getKey()), qualifierDetails);
201 colCount += entry.getValue().size();
202 if (maxCols <= 0) {
203 continue;
204 }
205
206 for (Cell cell: entry.getValue()) {
207 if (--maxCols <= 0 ) {
208 continue;
209 }
210 Map<String, Object> cellMap = cellToStringMap(cell);
211 qualifierDetails.add(cellMap);
212 }
213 }
214 map.put("totalColumns", colCount);
215
216 if (getId() != null) {
217 map.put("id", getId());
218 }
219
220
221
222 if (getTTL() != Long.MAX_VALUE) {
223 map.put("ttl", getTTL());
224 }
225 return map;
226 }
227
228 private static Map<String, Object> cellToStringMap(Cell c) {
229 Map<String, Object> stringMap = new HashMap<String, Object>();
230 stringMap.put("qualifier", Bytes.toStringBinary(c.getQualifierArray(), c.getQualifierOffset(),
231 c.getQualifierLength()));
232 stringMap.put("timestamp", c.getTimestamp());
233 stringMap.put("vlen", c.getValueLength());
234 List<Tag> tags = Tag.asList(c.getTagsArray(), c.getTagsOffset(), c.getTagsLength());
235 if (tags != null) {
236 List<String> tagsString = new ArrayList<String>();
237 for (Tag t : tags) {
238 tagsString.add((t.getType()) + ":" + Bytes.toStringBinary(t.getValue()));
239 }
240 stringMap.put("tag", tagsString);
241 }
242 return stringMap;
243 }
244
245
246
247
248
249 @Deprecated
250 public boolean getWriteToWAL() {
251 return this.durability != Durability.SKIP_WAL;
252 }
253
254
255
256
257
258
259
260
261 @Deprecated
262 public Mutation setWriteToWAL(boolean write) {
263 setDurability(write ? Durability.USE_DEFAULT : Durability.SKIP_WAL);
264 return this;
265 }
266
267
268
269
270
271 public Mutation setDurability(Durability d) {
272 this.durability = d;
273 return this;
274 }
275
276
277 public Durability getDurability() {
278 return this.durability;
279 }
280
281
282
283
284
285 public NavigableMap<byte [], List<Cell>> getFamilyCellMap() {
286 return this.familyMap;
287 }
288
289
290
291
292 public Mutation setFamilyCellMap(NavigableMap<byte [], List<Cell>> map) {
293
294
295 this.familyMap = map;
296 return this;
297 }
298
299
300
301
302
303
304 @Deprecated
305 public NavigableMap<byte [], List<KeyValue>> getFamilyMap() {
306 TreeMap<byte[], List<KeyValue>> fm =
307 new TreeMap<byte[], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
308 for (Map.Entry<byte[], List<Cell>> e : familyMap.entrySet()) {
309 List<KeyValue> kvl = new ArrayList<KeyValue>(e.getValue().size());
310 for (Cell c : e.getValue()) {
311 kvl.add(KeyValueUtil.ensureKeyValue(c));
312 }
313 fm.put(e.getKey(), kvl);
314 }
315 return fm;
316 }
317
318
319
320
321
322 @Deprecated
323 public Mutation setFamilyMap(NavigableMap<byte [], List<KeyValue>> map) {
324 TreeMap<byte[], List<Cell>> fm = new TreeMap<byte[], List<Cell>>(Bytes.BYTES_COMPARATOR);
325 for (Map.Entry<byte[], List<KeyValue>> e : map.entrySet()) {
326 fm.put(e.getKey(), Lists.<Cell>newArrayList(e.getValue()));
327 }
328 this.familyMap = fm;
329 return this;
330 }
331
332
333
334
335
336 public boolean isEmpty() {
337 return familyMap.isEmpty();
338 }
339
340
341
342
343
344 @Override
345 public byte [] getRow() {
346 return this.row;
347 }
348
349 @Override
350 public int compareTo(final Row d) {
351 return Bytes.compareTo(this.getRow(), d.getRow());
352 }
353
354
355
356
357
358 public long getTimeStamp() {
359 return this.ts;
360 }
361
362
363
364
365
366 public Mutation setClusterIds(List<UUID> clusterIds) {
367 ByteArrayDataOutput out = ByteStreams.newDataOutput();
368 out.writeInt(clusterIds.size());
369 for (UUID clusterId : clusterIds) {
370 out.writeLong(clusterId.getMostSignificantBits());
371 out.writeLong(clusterId.getLeastSignificantBits());
372 }
373 setAttribute(CONSUMED_CLUSTER_IDS, out.toByteArray());
374 return this;
375 }
376
377
378
379
380 public List<UUID> getClusterIds() {
381 List<UUID> clusterIds = new ArrayList<UUID>();
382 byte[] bytes = getAttribute(CONSUMED_CLUSTER_IDS);
383 if(bytes != null) {
384 ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
385 int numClusters = in.readInt();
386 for(int i=0; i<numClusters; i++){
387 clusterIds.add(new UUID(in.readLong(), in.readLong()));
388 }
389 }
390 return clusterIds;
391 }
392
393
394
395
396
397 public Mutation setCellVisibility(CellVisibility expression) {
398 this.setAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY, ProtobufUtil
399 .toCellVisibility(expression).toByteArray());
400 return this;
401 }
402
403
404
405
406
407 public CellVisibility getCellVisibility() throws DeserializationException {
408 byte[] cellVisibilityBytes = this.getAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY);
409 if (cellVisibilityBytes == null) return null;
410 return ProtobufUtil.toCellVisibility(cellVisibilityBytes);
411 }
412
413
414
415
416
417 public int size() {
418 int size = 0;
419 for (List<Cell> cells : this.familyMap.values()) {
420 size += cells.size();
421 }
422 return size;
423 }
424
425
426
427
428 public int numFamilies() {
429 return familyMap.size();
430 }
431
432
433
434
435 @Override
436 public long heapSize() {
437 long heapsize = MUTATION_OVERHEAD;
438
439 heapsize += ClassSize.align(ClassSize.ARRAY + this.row.length);
440
441
442 heapsize +=
443 ClassSize.align(this.familyMap.size() * ClassSize.MAP_ENTRY);
444 for(Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
445
446 heapsize +=
447 ClassSize.align(ClassSize.ARRAY + entry.getKey().length);
448
449
450
451
452 heapsize += ClassSize.align(ClassSize.ARRAYLIST);
453 int size = entry.getValue().size();
454 heapsize += ClassSize.align(ClassSize.ARRAY +
455 size * ClassSize.REFERENCE);
456
457 for(Cell cell : entry.getValue()) {
458 heapsize += CellUtil.estimatedHeapSizeOf(cell);
459 }
460 }
461 heapsize += getAttributeSize();
462 heapsize += extraHeapSize();
463 return ClassSize.align(heapsize);
464 }
465
466
467
468
469 public byte[] getACL() {
470 return getAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL);
471 }
472
473
474
475
476
477 public Mutation setACL(String user, Permission perms) {
478 setAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL,
479 ProtobufUtil.toUsersAndPermissions(user, perms).toByteArray());
480 return this;
481 }
482
483
484
485
486 public Mutation setACL(Map<String, Permission> perms) {
487 ListMultimap<String, Permission> permMap = ArrayListMultimap.create();
488 for (Map.Entry<String, Permission> entry : perms.entrySet()) {
489 permMap.put(entry.getKey(), entry.getValue());
490 }
491 setAttribute(AccessControlConstants.OP_ATTRIBUTE_ACL,
492 ProtobufUtil.toUsersAndPermissions(permMap).toByteArray());
493 return this;
494 }
495
496
497
498
499
500
501 public long getTTL() {
502 byte[] ttlBytes = getAttribute(OP_ATTRIBUTE_TTL);
503 if (ttlBytes != null) {
504 return Bytes.toLong(ttlBytes);
505 }
506 return Long.MAX_VALUE;
507 }
508
509
510
511
512
513
514 public Mutation setTTL(long ttl) {
515 setAttribute(OP_ATTRIBUTE_TTL, Bytes.toBytes(ttl));
516 return this;
517 }
518
519
520
521
522
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
531 protected Mutation setReturnResults(boolean returnResults) {
532 setAttribute(RETURN_RESULTS, Bytes.toBytes(returnResults));
533 return this;
534 }
535
536
537
538
539
540 protected long extraHeapSize(){
541 return 0L;
542 }
543
544
545
546
547
548
549
550
551 static byte [] checkRow(final byte [] row) {
552 return checkRow(row, 0, row == null? 0: row.length);
553 }
554
555
556
557
558
559
560
561
562
563 static byte [] checkRow(final byte [] row, final int offset, final int length) {
564 if (row == null) {
565 throw new IllegalArgumentException("Row buffer is null");
566 }
567 if (length == 0) {
568 throw new IllegalArgumentException("Row length is 0");
569 }
570 if (length > HConstants.MAX_ROW_LENGTH) {
571 throw new IllegalArgumentException("Row length " + length + " is > " +
572 HConstants.MAX_ROW_LENGTH);
573 }
574 return row;
575 }
576
577 static void checkRow(ByteBuffer row) {
578 if (row == null) {
579 throw new IllegalArgumentException("Row buffer is null");
580 }
581 if (row.remaining() == 0) {
582 throw new IllegalArgumentException("Row length is 0");
583 }
584 if (row.remaining() > HConstants.MAX_ROW_LENGTH) {
585 throw new IllegalArgumentException("Row length " + row.remaining() + " is > " +
586 HConstants.MAX_ROW_LENGTH);
587 }
588 }
589 }