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