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