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.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.NavigableMap;
27 import java.util.TreeMap;
28 import java.util.UUID;
29
30 import org.apache.hadoop.classification.InterfaceAudience;
31 import org.apache.hadoop.classification.InterfaceStability;
32 import org.apache.hadoop.hbase.Cell;
33 import org.apache.hadoop.hbase.CellScannable;
34 import org.apache.hadoop.hbase.CellScanner;
35 import org.apache.hadoop.hbase.CellUtil;
36 import org.apache.hadoop.hbase.HConstants;
37 import org.apache.hadoop.hbase.KeyValue;
38 import org.apache.hadoop.hbase.KeyValueUtil;
39 import org.apache.hadoop.hbase.io.HeapSize;
40 import org.apache.hadoop.hbase.util.Bytes;
41 import org.apache.hadoop.hbase.util.ClassSize;
42
43 import com.google.common.collect.Lists;
44 import com.google.common.io.ByteArrayDataInput;
45 import com.google.common.io.ByteArrayDataOutput;
46 import com.google.common.io.ByteStreams;
47
48 @InterfaceAudience.Public
49 @InterfaceStability.Evolving
50 public abstract class Mutation extends OperationWithAttributes implements Row, CellScannable,
51 HeapSize {
52 public static final long MUTATION_OVERHEAD = ClassSize.align(
53
54 ClassSize.OBJECT +
55
56 2 * ClassSize.REFERENCE +
57
58 1 * Bytes.SIZEOF_LONG +
59
60 ClassSize.REFERENCE +
61
62 ClassSize.REFERENCE +
63
64 ClassSize.TREEMAP);
65
66
67
68
69 private static final String CONSUMED_CLUSTER_IDS = "_cs.id";
70
71 protected byte [] row = null;
72 protected long ts = HConstants.LATEST_TIMESTAMP;
73 protected Durability durability = Durability.USE_DEFAULT;
74
75
76 protected NavigableMap<byte [], List<Cell>> familyMap =
77 new TreeMap<byte [], List<Cell>>(Bytes.BYTES_COMPARATOR);
78
79 @Override
80 public CellScanner cellScanner() {
81 return CellUtil.createCellScanner(getFamilyCellMap());
82 }
83
84
85
86
87
88
89
90
91 List<Cell> getCellList(byte[] family) {
92 List<Cell> list = this.familyMap.get(family);
93 if (list == null) {
94 list = new ArrayList<Cell>();
95 }
96 return list;
97 }
98
99
100
101
102
103
104 KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts, byte[] value) {
105 return new KeyValue(this.row, family, qualifier, ts, KeyValue.Type.Put, value);
106 }
107
108
109
110
111
112
113 KeyValue createPutKeyValue(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
114 return new KeyValue(this.row, 0, this.row == null ? 0 : this.row.length,
115 family, 0, family == null ? 0 : family.length,
116 qualifier, ts, KeyValue.Type.Put, value);
117 }
118
119
120
121
122
123
124
125 @Override
126 public Map<String, Object> getFingerprint() {
127 Map<String, Object> map = new HashMap<String, Object>();
128 List<String> families = new ArrayList<String>();
129
130
131 map.put("families", families);
132 for (Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
133 families.add(Bytes.toStringBinary(entry.getKey()));
134 }
135 return map;
136 }
137
138
139
140
141
142
143
144
145 @Override
146 public Map<String, Object> toMap(int maxCols) {
147
148 Map<String, Object> map = getFingerprint();
149
150
151 Map<String, List<Map<String, Object>>> columns =
152 new HashMap<String, List<Map<String, Object>>>();
153 map.put("families", columns);
154 map.put("row", Bytes.toStringBinary(this.row));
155 int colCount = 0;
156
157 for (Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
158
159 List<Map<String, Object>> qualifierDetails = new ArrayList<Map<String, Object>>();
160 columns.put(Bytes.toStringBinary(entry.getKey()), qualifierDetails);
161 colCount += entry.getValue().size();
162 if (maxCols <= 0) {
163 continue;
164 }
165
166 for (Cell cell: entry.getValue()) {
167 if (--maxCols <= 0 ) {
168 continue;
169 }
170
171 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
172 Map<String, Object> kvMap = kv.toStringMap();
173
174 kvMap.remove("row");
175 kvMap.remove("family");
176 qualifierDetails.add(kvMap);
177 }
178 }
179 map.put("totalColumns", colCount);
180
181 if (getId() != null) {
182 map.put("id", getId());
183 }
184 return map;
185 }
186
187
188
189
190
191 public void setDurability(Durability d) {
192 this.durability = d;
193 }
194
195
196 public Durability getDurability() {
197 return this.durability;
198 }
199
200
201
202
203
204
205 @Deprecated
206 public void setWriteToWAL(boolean writeToWal) {
207 if(!writeToWal) {
208 setDurability(Durability.SKIP_WAL);
209 } else {
210
211
212
213 setDurability(Durability.USE_DEFAULT);
214 }
215 }
216
217
218
219
220
221
222
223 @Deprecated
224 public boolean getWriteToWAL() {
225 return Durability.SKIP_WAL != getDurability();
226 }
227
228
229
230
231
232
233
234 @Deprecated
235 public Map<byte[], List<KeyValue>> getFamilyMap() {
236 Map<byte[], List<KeyValue>> fm = new TreeMap<byte[], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
237 for (Map.Entry<byte[], List<Cell>> e : this.familyMap.entrySet()) {
238 byte[] family = e.getKey();
239 List<Cell> cells = e.getValue();
240 List<KeyValue> kvs = new ArrayList<KeyValue>(cells.size());
241 for (Cell c : cells) {
242 KeyValue kv = KeyValueUtil.ensureKeyValue(c);
243 kvs.add(kv);
244 }
245 fm.put(family, kvs);
246 }
247 return fm;
248 }
249
250
251
252
253
254 public NavigableMap<byte [], List<Cell>> getFamilyCellMap() {
255 return this.familyMap;
256 }
257
258
259
260
261 public void setFamilyCellMap(NavigableMap<byte [], List<Cell>> map) {
262
263
264 this.familyMap = map;
265 }
266
267
268
269
270
271 @Deprecated
272 public void setFamilyMap(NavigableMap<byte [], List<KeyValue>> map) {
273 TreeMap<byte[], List<Cell>> fm = new TreeMap<byte[], List<Cell>>(Bytes.BYTES_COMPARATOR);
274 for (Map.Entry<byte[], List<KeyValue>> e : map.entrySet()) {
275 fm.put(e.getKey(), Lists.<Cell>newArrayList(e.getValue()));
276 }
277 this.familyMap = fm;
278 }
279
280
281
282
283
284 public boolean isEmpty() {
285 return familyMap.isEmpty();
286 }
287
288
289
290
291
292 @Override
293 public byte [] getRow() {
294 return this.row;
295 }
296
297 public int compareTo(final Row d) {
298 return Bytes.compareTo(this.getRow(), d.getRow());
299 }
300
301
302
303
304
305 public long getTimeStamp() {
306 return this.ts;
307 }
308
309
310
311
312
313 public void setClusterIds(List<UUID> clusterIds) {
314 ByteArrayDataOutput out = ByteStreams.newDataOutput();
315 out.writeInt(clusterIds.size());
316 for (UUID clusterId : clusterIds) {
317 out.writeLong(clusterId.getMostSignificantBits());
318 out.writeLong(clusterId.getLeastSignificantBits());
319 }
320 setAttribute(CONSUMED_CLUSTER_IDS, out.toByteArray());
321 }
322
323
324
325
326 public List<UUID> getClusterIds() {
327 List<UUID> clusterIds = new ArrayList<UUID>();
328 byte[] bytes = getAttribute(CONSUMED_CLUSTER_IDS);
329 if(bytes != null) {
330 ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
331 int numClusters = in.readInt();
332 for(int i=0; i<numClusters; i++){
333 clusterIds.add(new UUID(in.readLong(), in.readLong()));
334 }
335 }
336 return clusterIds;
337 }
338
339
340
341
342
343 public int size() {
344 int size = 0;
345 for (List<Cell> cells : this.familyMap.values()) {
346 size += cells.size();
347 }
348 return size;
349 }
350
351
352
353
354 public int numFamilies() {
355 return familyMap.size();
356 }
357
358
359
360
361 @Override
362 public long heapSize() {
363 long heapsize = MUTATION_OVERHEAD;
364
365 heapsize += ClassSize.align(ClassSize.ARRAY + this.row.length);
366
367
368 heapsize +=
369 ClassSize.align(this.familyMap.size() * ClassSize.MAP_ENTRY);
370 for(Map.Entry<byte [], List<Cell>> entry : this.familyMap.entrySet()) {
371
372 heapsize +=
373 ClassSize.align(ClassSize.ARRAY + entry.getKey().length);
374
375
376
377
378 heapsize += ClassSize.align(ClassSize.ARRAYLIST);
379 int size = entry.getValue().size();
380 heapsize += ClassSize.align(ClassSize.ARRAY +
381 size * ClassSize.REFERENCE);
382
383 for(Cell cell : entry.getValue()) {
384 KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
385 heapsize += kv.heapSize();
386 }
387 }
388 heapsize += getAttributeSize();
389 heapsize += extraHeapSize();
390 return ClassSize.align(heapsize);
391 }
392
393
394
395
396
397 protected long extraHeapSize(){
398 return 0L;
399 }
400
401
402
403
404
405
406
407
408 static byte [] checkRow(final byte [] row) {
409 return checkRow(row, 0, row == null? 0: row.length);
410 }
411
412
413
414
415
416
417
418
419
420 static byte [] checkRow(final byte [] row, final int offset, final int length) {
421 if (row == null) {
422 throw new IllegalArgumentException("Row buffer is null");
423 }
424 if (length == 0) {
425 throw new IllegalArgumentException("Row length is 0");
426 }
427 if (length > HConstants.MAX_ROW_LENGTH) {
428 throw new IllegalArgumentException("Row length " + length + " is > " +
429 HConstants.MAX_ROW_LENGTH);
430 }
431 return row;
432 }
433
434 static void checkRow(ByteBuffer row) {
435 if (row == null) {
436 throw new IllegalArgumentException("Row buffer is null");
437 }
438 if (row.remaining() == 0) {
439 throw new IllegalArgumentException("Row length is 0");
440 }
441 if (row.remaining() > HConstants.MAX_ROW_LENGTH) {
442 throw new IllegalArgumentException("Row length " + row.remaining() + " is > " +
443 HConstants.MAX_ROW_LENGTH);
444 }
445 }
446 }