1 /*
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 package org.apache.hadoop.hbase.client;
21
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.util.ArrayList;
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.CellUtil;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.KeyValue;
37 import org.apache.hadoop.hbase.Tag;
38 import org.apache.hadoop.hbase.io.HeapSize;
39 import org.apache.hadoop.hbase.security.access.Permission;
40 import org.apache.hadoop.hbase.security.visibility.CellVisibility;
41 import org.apache.hadoop.hbase.util.Bytes;
42
43 /**
44 * Used to perform Put operations for a single row.
45 * <p>
46 * To perform a Put, instantiate a Put object with the row to insert to and
47 * for eachumn to be inserted, execute {@link #add(byte[], byte[], byte[]) add} or
48 * {@link #add(byte[], byte[], long, byte[]) add} if setting the timestamp.
49 */
50 @InterfaceAudience.Public
51 @InterfaceStability.Stable
52 public class Put extends Mutation implements HeapSize, Comparable<Row> {
53 /**
54 * Create a Put operation for the specified row.
55 * @param row row key
56 */
57 public Put(byte [] row) {
58 this(row, HConstants.LATEST_TIMESTAMP);
59 }
60
61 /**
62 * Create a Put operation for the specified row, using a given timestamp.
63 *
64 * @param row row key; we make a copy of what we are passed to keep local.
65 * @param ts timestamp
66 */
67 public Put(byte[] row, long ts) {
68 this(row, 0, row.length, ts);
69 }
70
71 /**
72 * We make a copy of the passed in row key to keep local.
73 * @param rowArray
74 * @param rowOffset
75 * @param rowLength
76 */
77 public Put(byte [] rowArray, int rowOffset, int rowLength) {
78 this(rowArray, rowOffset, rowLength, HConstants.LATEST_TIMESTAMP);
79 }
80
81 /**
82 * @param row row key; we make a copy of what we are passed to keep local.
83 * @param ts timestamp
84 */
85 public Put(ByteBuffer row, long ts) {
86 if (ts < 0) {
87 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
88 }
89 checkRow(row);
90 this.row = new byte[row.remaining()];
91 row.get(this.row);
92 this.ts = ts;
93 }
94
95 /**
96 * @param row row key; we make a copy of what we are passed to keep local.
97 */
98 public Put(ByteBuffer row) {
99 this(row, HConstants.LATEST_TIMESTAMP);
100 }
101
102 /**
103 * We make a copy of the passed in row key to keep local.
104 * @param rowArray
105 * @param rowOffset
106 * @param rowLength
107 * @param ts
108 */
109 public Put(byte [] rowArray, int rowOffset, int rowLength, long ts) {
110 checkRow(rowArray, rowOffset, rowLength);
111 this.row = Bytes.copy(rowArray, rowOffset, rowLength);
112 this.ts = ts;
113 if (ts < 0) {
114 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
115 }
116 }
117
118 /**
119 * Copy constructor. Creates a Put operation cloned from the specified Put.
120 * @param putToCopy put to copy
121 */
122 public Put(Put putToCopy) {
123 this(putToCopy.getRow(), putToCopy.ts);
124 this.familyMap = new TreeMap<byte [], List<Cell>>(Bytes.BYTES_COMPARATOR);
125 for(Map.Entry<byte [], List<Cell>> entry: putToCopy.getFamilyCellMap().entrySet()) {
126 this.familyMap.put(entry.getKey(), new ArrayList<Cell>(entry.getValue()));
127 }
128 this.durability = putToCopy.durability;
129 for (Map.Entry<String, byte[]> entry : putToCopy.getAttributesMap().entrySet()) {
130 this.setAttribute(entry.getKey(), entry.getValue());
131 }
132 }
133
134 /**
135 * Add the specified column and value to this Put operation.
136 * @param family family name
137 * @param qualifier column qualifier
138 * @param value column value
139 * @return this
140 * @deprecated Since 1.0.0. Use {@link #addColumn(byte[], byte[], byte[])}
141 */
142 @Deprecated
143 public Put add(byte [] family, byte [] qualifier, byte [] value) {
144 return addColumn(family, qualifier, value);
145 }
146
147 /**
148 * Add the specified column and value to this Put operation.
149 * @param family family name
150 * @param qualifier column qualifier
151 * @param value column value
152 * @return this
153 */
154 public Put addColumn(byte [] family, byte [] qualifier, byte [] value) {
155 return addColumn(family, qualifier, this.ts, value);
156 }
157
158 /**
159 * See {@link #add(byte[], byte[], byte[])}. This version expects
160 * that the underlying arrays won't change. It's intended
161 * for usage internal HBase to and for advanced client applications.
162 */
163 public Put addImmutable(byte [] family, byte [] qualifier, byte [] value) {
164 return addImmutable(family, qualifier, this.ts, value);
165 }
166
167 /**
168 * This expects that the underlying arrays won't change. It's intended
169 * for usage internal HBase to and for advanced client applications.
170 * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
171 * that should not be exposed publicly.
172 */
173 @InterfaceAudience.Private
174 public Put addImmutable(byte[] family, byte [] qualifier, byte [] value, Tag[] tag) {
175 return addImmutable(family, qualifier, this.ts, value, tag);
176 }
177
178 /**
179 * Add the specified column and value, with the specified timestamp as
180 * its version to this Put operation.
181 * @param family family name
182 * @param qualifier column qualifier
183 * @param ts version timestamp
184 * @param value column value
185 * @return this
186 * @deprecated Since 1.0.0. Use {@link #addColumn(byte[], byte[], long, byte[])}
187 */
188 @Deprecated
189 public Put add(byte [] family, byte [] qualifier, long ts, byte [] value) {
190 return addColumn(family, qualifier, ts, value);
191 }
192
193 /**
194 * Add the specified column and value, with the specified timestamp as
195 * its version to this Put operation.
196 * @param family family name
197 * @param qualifier column qualifier
198 * @param ts version timestamp
199 * @param value column value
200 * @return this
201 */
202 public Put addColumn(byte [] family, byte [] qualifier, long ts, byte [] value) {
203 if (ts < 0) {
204 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
205 }
206 List<Cell> list = getCellList(family);
207 KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
208 list.add(kv);
209 familyMap.put(CellUtil.cloneFamily(kv), list);
210 return this;
211 }
212
213 /**
214 * See {@link #add(byte[], byte[], long, byte[])}. This version expects
215 * that the underlying arrays won't change. It's intended
216 * for usage internal HBase to and for advanced client applications.
217 */
218 public Put addImmutable(byte [] family, byte [] qualifier, long ts, byte [] value) {
219 if (ts < 0) {
220 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
221 }
222 List<Cell> list = getCellList(family);
223 KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
224 list.add(kv);
225 familyMap.put(family, list);
226 return this;
227 }
228
229 /**
230 * This expects that the underlying arrays won't change. It's intended
231 * for usage internal HBase to and for advanced client applications.
232 * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
233 * that should not be exposed publicly.
234 */
235 @InterfaceAudience.Private
236 public Put addImmutable(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tag) {
237 List<Cell> list = getCellList(family);
238 KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
239 list.add(kv);
240 familyMap.put(family, list);
241 return this;
242 }
243
244 /**
245 * This expects that the underlying arrays won't change. It's intended
246 * for usage internal HBase to and for advanced client applications.
247 * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
248 * that should not be exposed publicly.
249 */
250 @InterfaceAudience.Private
251 public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value,
252 Tag[] tag) {
253 if (ts < 0) {
254 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
255 }
256 List<Cell> list = getCellList(family);
257 KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
258 list.add(kv);
259 familyMap.put(family, list);
260 return this;
261 }
262
263
264 /**
265 * Add the specified column and value, with the specified timestamp as
266 * its version to this Put operation.
267 * @param family family name
268 * @param qualifier column qualifier
269 * @param ts version timestamp
270 * @param value column value
271 * @return this
272 * @deprecated Since 1.0.0. Use {@link Put#addColumn(byte[], ByteBuffer, long, ByteBuffer)}
273 */
274 @Deprecated
275 public Put add(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
276 return addColumn(family, qualifier, ts, value);
277 }
278
279 /**
280 * Add the specified column and value, with the specified timestamp as
281 * its version to this Put operation.
282 * @param family family name
283 * @param qualifier column qualifier
284 * @param ts version timestamp
285 * @param value column value
286 * @return this
287 */
288 public Put addColumn(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
289 if (ts < 0) {
290 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
291 }
292 List<Cell> list = getCellList(family);
293 KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
294 list.add(kv);
295 familyMap.put(CellUtil.cloneFamily(kv), list);
296 return this;
297 }
298
299 /**
300 * See {@link #add(byte[], ByteBuffer, long, ByteBuffer)}. This version expects
301 * that the underlying arrays won't change. It's intended
302 * for usage internal HBase to and for advanced client applications.
303 */
304 public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
305 if (ts < 0) {
306 throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
307 }
308 List<Cell> list = getCellList(family);
309 KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
310 list.add(kv);
311 familyMap.put(family, list);
312 return this;
313 }
314
315 /**
316 * Add the specified KeyValue to this Put operation. Operation assumes that
317 * the passed KeyValue is immutable and its backing array will not be modified
318 * for the duration of this Put.
319 * @param kv individual KeyValue
320 * @return this
321 * @throws java.io.IOException e
322 */
323 public Put add(Cell kv) throws IOException{
324 byte [] family = CellUtil.cloneFamily(kv);
325 List<Cell> list = getCellList(family);
326 //Checking that the row of the kv is the same as the put
327 int res = Bytes.compareTo(this.row, 0, row.length,
328 kv.getRowArray(), kv.getRowOffset(), kv.getRowLength());
329 if (res != 0) {
330 throw new WrongRowIOException("The row in " + kv.toString() +
331 " doesn't match the original one " + Bytes.toStringBinary(this.row));
332 }
333 list.add(kv);
334 familyMap.put(family, list);
335 return this;
336 }
337
338 /**
339 * A convenience method to determine if this object's familyMap contains
340 * a value assigned to the given family & qualifier.
341 * Both given arguments must match the KeyValue object to return true.
342 *
343 * @param family column family
344 * @param qualifier column qualifier
345 * @return returns true if the given family and qualifier already has an
346 * existing KeyValue object in the family map.
347 */
348 public boolean has(byte [] family, byte [] qualifier) {
349 return has(family, qualifier, this.ts, new byte[0], true, true);
350 }
351
352 /**
353 * A convenience method to determine if this object's familyMap contains
354 * a value assigned to the given family, qualifier and timestamp.
355 * All 3 given arguments must match the KeyValue object to return true.
356 *
357 * @param family column family
358 * @param qualifier column qualifier
359 * @param ts timestamp
360 * @return returns true if the given family, qualifier and timestamp already has an
361 * existing KeyValue object in the family map.
362 */
363 public boolean has(byte [] family, byte [] qualifier, long ts) {
364 return has(family, qualifier, ts, new byte[0], false, true);
365 }
366
367 /**
368 * A convenience method to determine if this object's familyMap contains
369 * a value assigned to the given family, qualifier and timestamp.
370 * All 3 given arguments must match the KeyValue object to return true.
371 *
372 * @param family column family
373 * @param qualifier column qualifier
374 * @param value value to check
375 * @return returns true if the given family, qualifier and value already has an
376 * existing KeyValue object in the family map.
377 */
378 public boolean has(byte [] family, byte [] qualifier, byte [] value) {
379 return has(family, qualifier, this.ts, value, true, false);
380 }
381
382 /**
383 * A convenience method to determine if this object's familyMap contains
384 * the given value assigned to the given family, qualifier and timestamp.
385 * All 4 given arguments must match the KeyValue object to return true.
386 *
387 * @param family column family
388 * @param qualifier column qualifier
389 * @param ts timestamp
390 * @param value value to check
391 * @return returns true if the given family, qualifier timestamp and value
392 * already has an existing KeyValue object in the family map.
393 */
394 public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
395 return has(family, qualifier, ts, value, false, false);
396 }
397
398 /*
399 * Private method to determine if this object's familyMap contains
400 * the given value assigned to the given family, qualifier and timestamp
401 * respecting the 2 boolean arguments
402 *
403 * @param family
404 * @param qualifier
405 * @param ts
406 * @param value
407 * @param ignoreTS
408 * @param ignoreValue
409 * @return returns true if the given family, qualifier timestamp and value
410 * already has an existing KeyValue object in the family map.
411 */
412 private boolean has(byte[] family, byte[] qualifier, long ts, byte[] value,
413 boolean ignoreTS, boolean ignoreValue) {
414 List<Cell> list = getCellList(family);
415 if (list.size() == 0) {
416 return false;
417 }
418 // Boolean analysis of ignoreTS/ignoreValue.
419 // T T => 2
420 // T F => 3 (first is always true)
421 // F T => 2
422 // F F => 1
423 if (!ignoreTS && !ignoreValue) {
424 for (Cell cell : list) {
425 if (CellUtil.matchingFamily(cell, family) &&
426 CellUtil.matchingQualifier(cell, qualifier) &&
427 CellUtil.matchingValue(cell, value) &&
428 cell.getTimestamp() == ts) {
429 return true;
430 }
431 }
432 } else if (ignoreValue && !ignoreTS) {
433 for (Cell cell : list) {
434 if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
435 && cell.getTimestamp() == ts) {
436 return true;
437 }
438 }
439 } else if (!ignoreValue && ignoreTS) {
440 for (Cell cell : list) {
441 if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
442 && CellUtil.matchingValue(cell, value)) {
443 return true;
444 }
445 }
446 } else {
447 for (Cell cell : list) {
448 if (CellUtil.matchingFamily(cell, family) &&
449 CellUtil.matchingQualifier(cell, qualifier)) {
450 return true;
451 }
452 }
453 }
454 return false;
455 }
456
457 /**
458 * Returns a list of all KeyValue objects with matching column family and qualifier.
459 *
460 * @param family column family
461 * @param qualifier column qualifier
462 * @return a list of KeyValue objects with the matching family and qualifier,
463 * returns an empty list if one doesn't exist for the given family.
464 */
465 public List<Cell> get(byte[] family, byte[] qualifier) {
466 List<Cell> filteredList = new ArrayList<Cell>();
467 for (Cell cell: getCellList(family)) {
468 if (CellUtil.matchingQualifier(cell, qualifier)) {
469 filteredList.add(cell);
470 }
471 }
472 return filteredList;
473 }
474 }