View Javadoc

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.Cell;
32  import org.apache.hadoop.hbase.CellUtil;
33  import org.apache.hadoop.hbase.HConstants;
34  import org.apache.hadoop.hbase.KeyValue;
35  import org.apache.hadoop.hbase.Tag;
36  import org.apache.hadoop.hbase.classification.InterfaceAudience;
37  import org.apache.hadoop.hbase.classification.InterfaceStability;
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 each column to be inserted, execute {@link #addColumn(byte[], byte[],
48   * byte[]) add} or {@link #addColumn(byte[], byte[], long, byte[]) add} if
49   * setting the timestamp.
50   */
51  @InterfaceAudience.Public
52  @InterfaceStability.Stable
53  public class Put extends Mutation implements HeapSize, Comparable<Row> {
54    /**
55     * Create a Put operation for the specified row.
56     * @param row row key
57     */
58    public Put(byte [] row) {
59      this(row, HConstants.LATEST_TIMESTAMP);
60    }
61
62    /**
63     * Create a Put operation for the specified row, using a given timestamp.
64     *
65     * @param row row key; we make a copy of what we are passed to keep local.
66     * @param ts timestamp
67     */
68    public Put(byte[] row, long ts) {
69      this(row, 0, row.length, ts);
70    }
71
72    /**
73     * We make a copy of the passed in row key to keep local.
74     * @param rowArray
75     * @param rowOffset
76     * @param rowLength
77     */
78    public Put(byte [] rowArray, int rowOffset, int rowLength) {
79      this(rowArray, rowOffset, rowLength, HConstants.LATEST_TIMESTAMP);
80    }
81
82    /**
83     * @param row row key; we make a copy of what we are passed to keep local.
84     * @param ts  timestamp
85     */
86    public Put(ByteBuffer row, long ts) {
87      if (ts < 0) {
88        throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
89      }
90      checkRow(row);
91      this.row = new byte[row.remaining()];
92      row.get(this.row);
93      this.ts = ts;
94    }
95
96    /**
97     * @param row row key; we make a copy of what we are passed to keep local.
98     */
99    public Put(ByteBuffer row) {
100     this(row, HConstants.LATEST_TIMESTAMP);
101   }
102
103   /**
104    * We make a copy of the passed in row key to keep local.
105    * @param rowArray
106    * @param rowOffset
107    * @param rowLength
108    * @param ts
109    */
110   public Put(byte [] rowArray, int rowOffset, int rowLength, long ts) {
111     checkRow(rowArray, rowOffset, rowLength);
112     this.row = Bytes.copy(rowArray, rowOffset, rowLength);
113     this.ts = ts;
114     if (ts < 0) {
115       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
116     }
117   }
118
119   /**
120    * Create a Put operation for an immutable row key.
121    *
122    * @param row row key
123    * @param rowIsImmutable whether the input row is immutable.
124    *                       Set to true if the caller can guarantee that
125    *                       the row will not be changed for the Put duration.
126    */
127   public Put(byte [] row, boolean rowIsImmutable) {
128     this(row, HConstants.LATEST_TIMESTAMP, rowIsImmutable);
129   }
130
131   /**
132    * Create a Put operation for an immutable row key, using a given timestamp.
133    *
134    * @param row row key
135    * @param ts timestamp
136    * @param rowIsImmutable whether the input row is immutable.
137    *                       Set to true if the caller can guarantee that
138    *                       the row will not be changed for the Put duration.
139    */
140   public Put(byte[] row, long ts, boolean rowIsImmutable) {
141     // Check and set timestamp
142     if (ts < 0) {
143       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
144     }
145     this.ts = ts;
146
147     // Deal with row according to rowIsImmutable
148     checkRow(row);
149     if (rowIsImmutable) {  // Row is immutable
150       this.row = row;  // Do not make a local copy, but point to the provided byte array directly
151     } else {  // Row is not immutable
152       this.row = Bytes.copy(row, 0, row.length);  // Make a local copy
153     }
154   }
155
156   /**
157    * Copy constructor.  Creates a Put operation cloned from the specified Put.
158    * @param putToCopy put to copy
159    */
160   public Put(Put putToCopy) {
161     this(putToCopy.getRow(), putToCopy.ts);
162     this.familyMap = new TreeMap<byte [], List<Cell>>(Bytes.BYTES_COMPARATOR);
163     for(Map.Entry<byte [], List<Cell>> entry: putToCopy.getFamilyCellMap().entrySet()) {
164       this.familyMap.put(entry.getKey(), new ArrayList<Cell>(entry.getValue()));
165     }
166     this.durability = putToCopy.durability;
167     for (Map.Entry<String, byte[]> entry : putToCopy.getAttributesMap().entrySet()) {
168       this.setAttribute(entry.getKey(), entry.getValue());
169     }
170   }
171
172   /**
173    * Add the specified column and value to this Put operation.
174    * @param family family name
175    * @param qualifier column qualifier
176    * @param value column value
177    * @return this
178    */
179   public Put addColumn(byte [] family, byte [] qualifier, byte [] value) {
180     return addColumn(family, qualifier, this.ts, value);
181   }
182
183   /**
184    * See {@link #addColumn(byte[], byte[], byte[])}. This version expects
185    * that the underlying arrays won't change. It's intended
186    * for usage internal HBase to and for advanced client applications.
187    */
188   public Put addImmutable(byte [] family, byte [] qualifier, byte [] value) {
189     return addImmutable(family, qualifier, this.ts, value);
190   }
191
192   /**
193    * This expects that the underlying arrays won't change. It's intended
194    * for usage internal HBase to and for advanced client applications.
195    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
196    * that should not be exposed publicly.
197    */
198   @InterfaceAudience.Private
199   public Put addImmutable(byte[] family, byte [] qualifier, byte [] value, Tag[] tag) {
200     return addImmutable(family, qualifier, this.ts, value, tag);
201   }
202
203   /**
204    * Add the specified column and value, with the specified timestamp as
205    * its version to this Put operation.
206    * @param family family name
207    * @param qualifier column qualifier
208    * @param ts version timestamp
209    * @param value column value
210    * @return this
211    */
212   public Put addColumn(byte [] family, byte [] qualifier, long ts, byte [] value) {
213     if (ts < 0) {
214       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
215     }
216     List<Cell> list = getCellList(family);
217     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
218     list.add(kv);
219     familyMap.put(CellUtil.cloneFamily(kv), list);
220     return this;
221   }
222
223   /**
224    * See {@link #addColumn(byte[], byte[], long, byte[])}. This version expects
225    * that the underlying arrays won't change. It's intended
226    * for usage internal HBase to and for advanced client applications.
227    */
228   public Put addImmutable(byte [] family, byte [] qualifier, long ts, byte [] value) {
229     if (ts < 0) {
230       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
231     }
232     List<Cell> list = getCellList(family);
233     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
234     list.add(kv);
235     familyMap.put(family, list);
236     return this;
237   }
238
239   /**
240    * This expects that the underlying arrays won't change. It's intended
241    * for usage internal HBase to and for advanced client applications.
242    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
243    * that should not be exposed publicly.
244    */
245   @InterfaceAudience.Private
246   public Put addImmutable(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tag) {
247     List<Cell> list = getCellList(family);
248     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
249     list.add(kv);
250     familyMap.put(family, list);
251     return this;
252   }
253
254   /**
255    * This expects that the underlying arrays won't change. It's intended
256    * for usage internal HBase to and for advanced client applications.
257    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
258    * that should not be exposed publicly.
259    */
260   @InterfaceAudience.Private
261   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value,
262                           Tag[] tag) {
263     if (ts < 0) {
264       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
265     }
266     List<Cell> list = getCellList(family);
267     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
268     list.add(kv);
269     familyMap.put(family, list);
270     return this;
271   }
272
273
274   /**
275    * Add the specified column and value, with the specified timestamp as
276    * its version to this Put operation.
277    * @param family family name
278    * @param qualifier column qualifier
279    * @param ts version timestamp
280    * @param value column value
281    * @return this
282    */
283   public Put addColumn(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
284     if (ts < 0) {
285       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
286     }
287     List<Cell> list = getCellList(family);
288     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
289     list.add(kv);
290     familyMap.put(CellUtil.cloneFamily(kv), list);
291     return this;
292   }
293
294   /**
295    * See {@link #addColumn(byte[], ByteBuffer, long, ByteBuffer)}. This version expects
296    * that the underlying arrays won't change. It's intended
297    * for usage internal HBase to and for advanced client applications.
298    */
299   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
300     if (ts < 0) {
301       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
302     }
303     List<Cell> list = getCellList(family);
304     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
305     list.add(kv);
306     familyMap.put(family, list);
307     return this;
308   }
309
310   /**
311    * Add the specified KeyValue to this Put operation.  Operation assumes that
312    * the passed KeyValue is immutable and its backing array will not be modified
313    * for the duration of this Put.
314    * @param kv individual KeyValue
315    * @return this
316    * @throws java.io.IOException e
317    */
318   public Put add(Cell kv) throws IOException{
319     byte [] family = CellUtil.cloneFamily(kv);
320     List<Cell> list = getCellList(family);
321     //Checking that the row of the kv is the same as the put
322     int res = Bytes.compareTo(this.row, 0, row.length,
323         kv.getRowArray(), kv.getRowOffset(), kv.getRowLength());
324     if (res != 0) {
325       throw new WrongRowIOException("The row in " + kv.toString() +
326         " doesn't match the original one " +  Bytes.toStringBinary(this.row));
327     }
328     list.add(kv);
329     familyMap.put(family, list);
330     return this;
331   }
332
333   /**
334    * A convenience method to determine if this object's familyMap contains
335    * a value assigned to the given family &amp; qualifier.
336    * Both given arguments must match the KeyValue object to return true.
337    *
338    * @param family column family
339    * @param qualifier column qualifier
340    * @return returns true if the given family and qualifier already has an
341    * existing KeyValue object in the family map.
342    */
343   public boolean has(byte [] family, byte [] qualifier) {
344   return has(family, qualifier, this.ts, new byte[0], true, true);
345   }
346
347   /**
348    * A convenience method to determine if this object's familyMap contains
349    * a value assigned to the given family, qualifier and timestamp.
350    * All 3 given arguments must match the KeyValue object to return true.
351    *
352    * @param family column family
353    * @param qualifier column qualifier
354    * @param ts timestamp
355    * @return returns true if the given family, qualifier and timestamp already has an
356    * existing KeyValue object in the family map.
357    */
358   public boolean has(byte [] family, byte [] qualifier, long ts) {
359   return has(family, qualifier, ts, new byte[0], false, true);
360   }
361
362   /**
363    * A convenience method to determine if this object's familyMap contains
364    * a value assigned to the given family, qualifier and timestamp.
365    * All 3 given arguments must match the KeyValue object to return true.
366    *
367    * @param family column family
368    * @param qualifier column qualifier
369    * @param value value to check
370    * @return returns true if the given family, qualifier and value already has an
371    * existing KeyValue object in the family map.
372    */
373   public boolean has(byte [] family, byte [] qualifier, byte [] value) {
374     return has(family, qualifier, this.ts, value, true, false);
375   }
376
377   /**
378    * A convenience method to determine if this object's familyMap contains
379    * the given value assigned to the given family, qualifier and timestamp.
380    * All 4 given arguments must match the KeyValue object to return true.
381    *
382    * @param family column family
383    * @param qualifier column qualifier
384    * @param ts timestamp
385    * @param value value to check
386    * @return returns true if the given family, qualifier timestamp and value
387    * already has an existing KeyValue object in the family map.
388    */
389   public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
390       return has(family, qualifier, ts, value, false, false);
391   }
392
393   /*
394    * Private method to determine if this object's familyMap contains
395    * the given value assigned to the given family, qualifier and timestamp
396    * respecting the 2 boolean arguments
397    *
398    * @param family
399    * @param qualifier
400    * @param ts
401    * @param value
402    * @param ignoreTS
403    * @param ignoreValue
404    * @return returns true if the given family, qualifier timestamp and value
405    * already has an existing KeyValue object in the family map.
406    */
407   private boolean has(byte[] family, byte[] qualifier, long ts, byte[] value,
408                       boolean ignoreTS, boolean ignoreValue) {
409     List<Cell> list = getCellList(family);
410     if (list.size() == 0) {
411       return false;
412     }
413     // Boolean analysis of ignoreTS/ignoreValue.
414     // T T => 2
415     // T F => 3 (first is always true)
416     // F T => 2
417     // F F => 1
418     if (!ignoreTS && !ignoreValue) {
419       for (Cell cell : list) {
420         if (CellUtil.matchingFamily(cell, family) &&
421             CellUtil.matchingQualifier(cell, qualifier)  &&
422             CellUtil.matchingValue(cell, value) &&
423             cell.getTimestamp() == ts) {
424           return true;
425         }
426       }
427     } else if (ignoreValue && !ignoreTS) {
428       for (Cell cell : list) {
429         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
430             && cell.getTimestamp() == ts) {
431           return true;
432         }
433       }
434     } else if (!ignoreValue && ignoreTS) {
435       for (Cell cell : list) {
436         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
437             && CellUtil.matchingValue(cell, value)) {
438           return true;
439         }
440       }
441     } else {
442       for (Cell cell : list) {
443         if (CellUtil.matchingFamily(cell, family) &&
444             CellUtil.matchingQualifier(cell, qualifier)) {
445           return true;
446         }
447       }
448     }
449     return false;
450   }
451
452   /**
453    * Returns a list of all KeyValue objects with matching column family and qualifier.
454    *
455    * @param family column family
456    * @param qualifier column qualifier
457    * @return a list of KeyValue objects with the matching family and qualifier,
458    * returns an empty list if one doesn't exist for the given family.
459    */
460   public List<Cell> get(byte[] family, byte[] qualifier) {
461     List<Cell> filteredList = new ArrayList<Cell>();
462     for (Cell cell: getCellList(family)) {
463       if (CellUtil.matchingQualifier(cell, qualifier)) {
464         filteredList.add(cell);
465       }
466     }
467     return filteredList;
468   }
469
470   @Override
471   public Put setAttribute(String name, byte[] value) {
472     return (Put) super.setAttribute(name, value);
473   }
474
475   @Override
476   public Put setId(String id) {
477     return (Put) super.setId(id);
478   }
479
480   @Override
481   public Put setDurability(Durability d) {
482     return (Put) super.setDurability(d);
483   }
484
485   @Override
486   public Put setFamilyCellMap(NavigableMap<byte[], List<Cell>> map) {
487     return (Put) super.setFamilyCellMap(map);
488   }
489
490   @Override
491   public Put setClusterIds(List<UUID> clusterIds) {
492     return (Put) super.setClusterIds(clusterIds);
493   }
494
495   @Override
496   public Put setCellVisibility(CellVisibility expression) {
497     return (Put) super.setCellVisibility(expression);
498   }
499
500   @Override
501   public Put setACL(String user, Permission perms) {
502     return (Put) super.setACL(user, perms);
503   }
504
505   @Override
506   public Put setACL(Map<String, Permission> perms) {
507     return (Put) super.setACL(perms);
508   }
509
510   @Override
511   public Put setTTL(long ttl) {
512     return (Put) super.setTTL(ttl);
513   }
514 }