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