1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.client;
22
23 import org.apache.hadoop.hbase.HConstants;
24 import org.apache.hadoop.hbase.KeyValue;
25 import org.apache.hadoop.hbase.io.HeapSize;
26 import org.apache.hadoop.hbase.util.Bytes;
27 import org.apache.hadoop.hbase.util.ClassSize;
28 import org.apache.hadoop.io.Writable;
29
30 import java.io.DataInput;
31 import java.io.DataOutput;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.TreeMap;
38
39
40
41
42
43
44
45
46
47 public class Put implements HeapSize, Writable, Row, Comparable<Row> {
48 private static final byte PUT_VERSION = (byte)1;
49
50 private byte [] row = null;
51 private long timestamp = HConstants.LATEST_TIMESTAMP;
52 private long lockId = -1L;
53 private boolean writeToWAL = true;
54
55 private Map<byte [], List<KeyValue>> familyMap =
56 new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
57
58 private static final long OVERHEAD = ClassSize.align(
59 ClassSize.OBJECT + ClassSize.REFERENCE +
60 2 * Bytes.SIZEOF_LONG + Bytes.SIZEOF_BOOLEAN +
61 ClassSize.REFERENCE + ClassSize.TREEMAP);
62
63
64 public Put() {}
65
66
67
68
69
70 public Put(byte [] row) {
71 this(row, null);
72 }
73
74
75
76
77
78
79 public Put(byte [] row, RowLock rowLock) {
80 this(row, HConstants.LATEST_TIMESTAMP, rowLock);
81 }
82
83
84
85
86
87
88
89 public Put(byte[] row, long ts) {
90 this(row, ts, null);
91 }
92
93
94
95
96
97
98
99 public Put(byte [] row, long ts, RowLock rowLock) {
100 if(row == null || row.length > HConstants.MAX_ROW_LENGTH) {
101 throw new IllegalArgumentException("Row key is invalid");
102 }
103 this.row = Arrays.copyOf(row, row.length);
104 this.timestamp = ts;
105 if(rowLock != null) {
106 this.lockId = rowLock.getLockId();
107 }
108 }
109
110
111
112
113
114 public Put(Put putToCopy) {
115 this(putToCopy.getRow(), putToCopy.timestamp, putToCopy.getRowLock());
116 this.familyMap =
117 new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
118 for(Map.Entry<byte [], List<KeyValue>> entry :
119 putToCopy.getFamilyMap().entrySet()) {
120 this.familyMap.put(entry.getKey(), entry.getValue());
121 }
122 this.writeToWAL = putToCopy.writeToWAL;
123 }
124
125
126
127
128
129
130
131
132 public Put add(byte [] family, byte [] qualifier, byte [] value) {
133 return add(family, qualifier, this.timestamp, value);
134 }
135
136
137
138
139
140
141
142
143
144
145 public Put add(byte [] family, byte [] qualifier, long ts, byte [] value) {
146 List<KeyValue> list = getKeyValueList(family);
147 KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
148 list.add(kv);
149 familyMap.put(kv.getFamily(), list);
150 return this;
151 }
152
153
154
155
156
157
158
159
160
161 public Put add(KeyValue kv) throws IOException{
162 byte [] family = kv.getFamily();
163 List<KeyValue> list = getKeyValueList(family);
164
165 int res = Bytes.compareTo(this.row, 0, row.length,
166 kv.getBuffer(), kv.getRowOffset(), kv.getRowLength());
167 if(res != 0) {
168 throw new IOException("The row in the recently added KeyValue " +
169 Bytes.toStringBinary(kv.getBuffer(), kv.getRowOffset(),
170 kv.getRowLength()) + " doesn't match the original one " +
171 Bytes.toStringBinary(this.row));
172 }
173 list.add(kv);
174 familyMap.put(family, list);
175 return this;
176 }
177
178
179
180
181
182
183 private KeyValue createPutKeyValue(byte[] family, byte[] qualifier, long ts,
184 byte[] value) {
185 return new KeyValue(this.row, family, qualifier, ts, KeyValue.Type.Put,
186 value);
187 }
188
189
190
191
192
193
194
195
196
197
198
199 public boolean has(byte [] family, byte [] qualifier) {
200 return has(family, qualifier, this.timestamp, new byte[0], true, true);
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214 public boolean has(byte [] family, byte [] qualifier, long ts) {
215 return has(family, qualifier, ts, new byte[0], false, true);
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229 public boolean has(byte [] family, byte [] qualifier, byte [] value) {
230 return has(family, qualifier, this.timestamp, value, true, false);
231 }
232
233
234
235
236
237
238
239
240
241
242
243
244
245 public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
246 return has(family, qualifier, ts, value, false, false);
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 private boolean has(byte [] family, byte [] qualifier, long ts, byte [] value,
264 boolean ignoreTS, boolean ignoreValue) {
265 List<KeyValue> list = getKeyValueList(family);
266 if (list.size() == 0) {
267 return false;
268 }
269
270
271
272
273
274 if (!ignoreTS && !ignoreValue) {
275 KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
276 return (list.contains(kv));
277 } else if (ignoreValue) {
278 for (KeyValue kv: list) {
279 if (Arrays.equals(kv.getFamily(), family) && Arrays.equals(kv.getQualifier(), qualifier)
280 && kv.getTimestamp() == ts) {
281 return true;
282 }
283 }
284 } else {
285
286 for (KeyValue kv: list) {
287 if (Arrays.equals(kv.getFamily(), family) && Arrays.equals(kv.getQualifier(), qualifier)
288 && Arrays.equals(kv.getValue(), value)) {
289 return true;
290 }
291 }
292 }
293 return false;
294 }
295
296
297
298
299
300
301
302
303
304 public List<KeyValue> get(byte[] family, byte[] qualifier) {
305 List<KeyValue> filteredList = new ArrayList<KeyValue>();
306 for (KeyValue kv: getKeyValueList(family)) {
307 if (Arrays.equals(kv.getQualifier(), qualifier)) {
308 filteredList.add(kv);
309 }
310 }
311 return filteredList;
312 }
313
314
315
316
317
318
319
320
321 private List<KeyValue> getKeyValueList(byte[] family) {
322 List<KeyValue> list = familyMap.get(family);
323 if(list == null) {
324 list = new ArrayList<KeyValue>(0);
325 }
326 return list;
327 }
328
329
330
331
332
333 public Map<byte [], List<KeyValue>> getFamilyMap() {
334 return this.familyMap;
335 }
336
337
338
339
340
341 public byte [] getRow() {
342 return this.row;
343 }
344
345
346
347
348
349 public RowLock getRowLock() {
350 return new RowLock(this.row, this.lockId);
351 }
352
353
354
355
356
357 public long getLockId() {
358 return this.lockId;
359 }
360
361
362
363
364
365 public boolean isEmpty() {
366 return familyMap.isEmpty();
367 }
368
369
370
371
372 public long getTimeStamp() {
373 return this.timestamp;
374 }
375
376
377
378
379 public int numFamilies() {
380 return familyMap.size();
381 }
382
383
384
385
386 public int size() {
387 int size = 0;
388 for(List<KeyValue> kvList : this.familyMap.values()) {
389 size += kvList.size();
390 }
391 return size;
392 }
393
394
395
396
397 public boolean getWriteToWAL() {
398 return this.writeToWAL;
399 }
400
401
402
403
404
405
406 public void setWriteToWAL(boolean write) {
407 this.writeToWAL = write;
408 }
409
410
411
412
413 @Override
414 public String toString() {
415 StringBuilder sb = new StringBuilder();
416 sb.append("row=");
417 sb.append(Bytes.toStringBinary(this.row));
418 sb.append(", families={");
419 boolean moreThanOne = false;
420 for(Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
421 if(moreThanOne) {
422 sb.append(", ");
423 } else {
424 moreThanOne = true;
425 }
426 sb.append("(family=");
427 sb.append(Bytes.toString(entry.getKey()));
428 sb.append(", keyvalues=(");
429 boolean moreThanOneB = false;
430 for(KeyValue kv : entry.getValue()) {
431 if(moreThanOneB) {
432 sb.append(", ");
433 } else {
434 moreThanOneB = true;
435 }
436 sb.append(kv.toString());
437 }
438 sb.append(")");
439 }
440 sb.append("}");
441 return sb.toString();
442 }
443
444 public int compareTo(Row p) {
445 return Bytes.compareTo(this.getRow(), p.getRow());
446 }
447
448
449 public long heapSize() {
450 long heapsize = OVERHEAD;
451
452 heapsize += ClassSize.align(ClassSize.ARRAY + this.row.length);
453
454
455 heapsize +=
456 ClassSize.align(this.familyMap.size() * ClassSize.MAP_ENTRY);
457 for(Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
458
459 heapsize +=
460 ClassSize.align(ClassSize.ARRAY + entry.getKey().length);
461
462
463
464
465 heapsize += ClassSize.align(ClassSize.ARRAYLIST);
466 int size = entry.getValue().size();
467 heapsize += ClassSize.align(ClassSize.ARRAY +
468 size * ClassSize.REFERENCE);
469
470 for(KeyValue kv : entry.getValue()) {
471 heapsize += kv.heapSize();
472 }
473 }
474 return ClassSize.align((int)heapsize);
475 }
476
477
478 public void readFields(final DataInput in)
479 throws IOException {
480 int version = in.readByte();
481 if (version > PUT_VERSION) {
482 throw new IOException("version not supported");
483 }
484 this.row = Bytes.readByteArray(in);
485 this.timestamp = in.readLong();
486 this.lockId = in.readLong();
487 this.writeToWAL = in.readBoolean();
488 int numFamilies = in.readInt();
489 if (!this.familyMap.isEmpty()) this.familyMap.clear();
490 for(int i=0;i<numFamilies;i++) {
491 byte [] family = Bytes.readByteArray(in);
492 int numKeys = in.readInt();
493 List<KeyValue> keys = new ArrayList<KeyValue>(numKeys);
494 int totalLen = in.readInt();
495 byte [] buf = new byte[totalLen];
496 int offset = 0;
497 for (int j = 0; j < numKeys; j++) {
498 int keyLength = in.readInt();
499 in.readFully(buf, offset, keyLength);
500 keys.add(new KeyValue(buf, offset, keyLength));
501 offset += keyLength;
502 }
503 this.familyMap.put(family, keys);
504 }
505 }
506
507 public void write(final DataOutput out)
508 throws IOException {
509 out.writeByte(PUT_VERSION);
510 Bytes.writeByteArray(out, this.row);
511 out.writeLong(this.timestamp);
512 out.writeLong(this.lockId);
513 out.writeBoolean(this.writeToWAL);
514 out.writeInt(familyMap.size());
515 for (Map.Entry<byte [], List<KeyValue>> entry : familyMap.entrySet()) {
516 Bytes.writeByteArray(out, entry.getKey());
517 List<KeyValue> keys = entry.getValue();
518 out.writeInt(keys.size());
519 int totalLen = 0;
520 for(KeyValue kv : keys) {
521 totalLen += kv.getLength();
522 }
523 out.writeInt(totalLen);
524 for(KeyValue kv : keys) {
525 out.writeInt(kv.getLength());
526 out.write(kv.getBuffer(), kv.getOffset(), kv.getLength());
527 }
528 }
529 }
530
531
532
533
534
535
536
537
538
539
540
541 public Put add(byte [] column, long ts, byte [] value) {
542 byte [][] parts = KeyValue.parseColumn(column);
543 return add(parts[0], parts[1], ts, value);
544 }
545 }