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 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(), 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    */
171   public Put addImmutable(byte[] family, byte [] qualifier, byte [] value, Tag[] tag) {
172     return addImmutable(family, qualifier, this.ts, value, tag);
173   }
174 
175   /**
176    * Add the specified column and value, with the specified timestamp as
177    * its version to this Put operation.
178    * @param family family name
179    * @param qualifier column qualifier
180    * @param ts version timestamp
181    * @param value column value
182    * @return this
183    * @deprecated Since 1.0.0. Use {@link #addColumn(byte[], byte[], long, byte[])}
184    */
185   @Deprecated
186   public Put add(byte [] family, byte [] qualifier, long ts, byte [] value) {
187     return addColumn(family, qualifier, ts, value);
188   }
189 
190   /**
191    * Add the specified column and value, with the specified timestamp as
192    * its version to this Put operation.
193    * @param family family name
194    * @param qualifier column qualifier
195    * @param ts version timestamp
196    * @param value column value
197    * @return this
198    */
199   public Put addColumn(byte [] family, byte [] qualifier, long ts, byte [] value) {
200     if (ts < 0) {
201       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
202     }
203     List<Cell> list = getCellList(family);
204     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
205     list.add(kv);
206     familyMap.put(CellUtil.cloneFamily(kv), list);
207     return this;
208   }
209 
210   /**
211    * See {@link #add(byte[], byte[], long, byte[])}. This version expects
212    * that the underlying arrays won't change. It's intended
213    * for usage internal HBase to and for advanced client applications.
214    */
215   public Put addImmutable(byte [] family, byte [] qualifier, long ts, byte [] value) {
216     if (ts < 0) {
217       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
218     }
219     List<Cell> list = getCellList(family);
220     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
221     list.add(kv);
222     familyMap.put(family, list);
223     return this;
224   }
225 
226   /**
227    * This expects that the underlying arrays won't change. It's intended
228    * for usage internal HBase to and for advanced client applications.
229    */
230   public Put addImmutable(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tag) {
231     List<Cell> list = getCellList(family);
232     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
233     list.add(kv);
234     familyMap.put(family, list);
235     return this;
236   }
237 
238   /**
239    * This expects that the underlying arrays won't change. It's intended
240    * for usage internal HBase to and for advanced client applications.
241    */
242   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value,
243                           Tag[] tag) {
244     if (ts < 0) {
245       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
246     }
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   /**
256    * Add the specified column and value, with the specified timestamp as
257    * its version to this Put operation.
258    * @param family family name
259    * @param qualifier column qualifier
260    * @param ts version timestamp
261    * @param value column value
262    * @return this
263    * @deprecated Since 1.0.0. Use {@link Put#addColumn(byte[], ByteBuffer, long, ByteBuffer)}
264    */
265   @Deprecated
266   public Put add(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
267     return addColumn(family, qualifier, ts, value);
268   }
269 
270   /**
271    * Add the specified column and value, with the specified timestamp as
272    * its version to this Put operation.
273    * @param family family name
274    * @param qualifier column qualifier
275    * @param ts version timestamp
276    * @param value column value
277    * @return this
278    */
279   public Put addColumn(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
280     if (ts < 0) {
281       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
282     }
283     List<Cell> list = getCellList(family);
284     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
285     list.add(kv);
286     familyMap.put(CellUtil.cloneFamily(kv), list);
287     return this;
288   }
289 
290   /**
291    * See {@link #add(byte[], ByteBuffer, long, ByteBuffer)}. This version expects
292    * that the underlying arrays won't change. It's intended
293    * for usage internal HBase to and for advanced client applications.
294    */
295   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
296     if (ts < 0) {
297       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
298     }
299     List<Cell> list = getCellList(family);
300     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
301     list.add(kv);
302     familyMap.put(family, list);
303     return this;
304   }
305 
306   /**
307    * Add the specified KeyValue to this Put operation.  Operation assumes that
308    * the passed KeyValue is immutable and its backing array will not be modified
309    * for the duration of this Put.
310    * @param kv individual KeyValue
311    * @return this
312    * @throws java.io.IOException e
313    */
314   public Put add(Cell kv) throws IOException{
315     byte [] family = CellUtil.cloneFamily(kv);
316     List<Cell> list = getCellList(family);
317     //Checking that the row of the kv is the same as the put
318     int res = Bytes.compareTo(this.row, 0, row.length,
319         kv.getRowArray(), kv.getRowOffset(), kv.getRowLength());
320     if (res != 0) {
321       throw new WrongRowIOException("The row in " + kv.toString() +
322         " doesn't match the original one " +  Bytes.toStringBinary(this.row));
323     }
324     list.add(kv);
325     familyMap.put(family, list);
326     return this;
327   }
328 
329   /**
330    * A convenience method to determine if this object's familyMap contains
331    * a value assigned to the given family & qualifier.
332    * Both given arguments must match the KeyValue object to return true.
333    *
334    * @param family column family
335    * @param qualifier column qualifier
336    * @return returns true if the given family and qualifier already has an
337    * existing KeyValue object in the family map.
338    */
339   public boolean has(byte [] family, byte [] qualifier) {
340   return has(family, qualifier, this.ts, new byte[0], true, true);
341   }
342 
343   /**
344    * A convenience method to determine if this object's familyMap contains
345    * a value assigned to the given family, qualifier and timestamp.
346    * All 3 given arguments must match the KeyValue object to return true.
347    *
348    * @param family column family
349    * @param qualifier column qualifier
350    * @param ts timestamp
351    * @return returns true if the given family, qualifier and timestamp already has an
352    * existing KeyValue object in the family map.
353    */
354   public boolean has(byte [] family, byte [] qualifier, long ts) {
355   return has(family, qualifier, ts, new byte[0], false, true);
356   }
357 
358   /**
359    * A convenience method to determine if this object's familyMap contains
360    * a value assigned to the given family, qualifier and timestamp.
361    * All 3 given arguments must match the KeyValue object to return true.
362    *
363    * @param family column family
364    * @param qualifier column qualifier
365    * @param value value to check
366    * @return returns true if the given family, qualifier and value already has an
367    * existing KeyValue object in the family map.
368    */
369   public boolean has(byte [] family, byte [] qualifier, byte [] value) {
370     return has(family, qualifier, this.ts, value, true, false);
371   }
372 
373   /**
374    * A convenience method to determine if this object's familyMap contains
375    * the given value assigned to the given family, qualifier and timestamp.
376    * All 4 given arguments must match the KeyValue object to return true.
377    *
378    * @param family column family
379    * @param qualifier column qualifier
380    * @param ts timestamp
381    * @param value value to check
382    * @return returns true if the given family, qualifier timestamp and value
383    * already has an existing KeyValue object in the family map.
384    */
385   public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
386       return has(family, qualifier, ts, value, false, false);
387   }
388 
389   /*
390    * Private method to determine if this object's familyMap contains
391    * the given value assigned to the given family, qualifier and timestamp
392    * respecting the 2 boolean arguments
393    *
394    * @param family
395    * @param qualifier
396    * @param ts
397    * @param value
398    * @param ignoreTS
399    * @param ignoreValue
400    * @return returns true if the given family, qualifier timestamp and value
401    * already has an existing KeyValue object in the family map.
402    */
403   private boolean has(byte[] family, byte[] qualifier, long ts, byte[] value,
404                       boolean ignoreTS, boolean ignoreValue) {
405     List<Cell> list = getCellList(family);
406     if (list.size() == 0) {
407       return false;
408     }
409     // Boolean analysis of ignoreTS/ignoreValue.
410     // T T => 2
411     // T F => 3 (first is always true)
412     // F T => 2
413     // F F => 1
414     if (!ignoreTS && !ignoreValue) {
415       for (Cell cell : list) {
416         if (CellUtil.matchingFamily(cell, family) &&
417             CellUtil.matchingQualifier(cell, qualifier)  &&
418             CellUtil.matchingValue(cell, value) &&
419             cell.getTimestamp() == ts) {
420           return true;
421         }
422       }
423     } else if (ignoreValue && !ignoreTS) {
424       for (Cell cell : list) {
425         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
426             && cell.getTimestamp() == ts) {
427           return true;
428         }
429       }
430     } else if (!ignoreValue && ignoreTS) {
431       for (Cell cell : list) {
432         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
433             && CellUtil.matchingValue(cell, value)) {
434           return true;
435         }
436       }
437     } else {
438       for (Cell cell : list) {
439         if (CellUtil.matchingFamily(cell, family) &&
440             CellUtil.matchingQualifier(cell, qualifier)) {
441           return true;
442         }
443       }
444     }
445     return false;
446   }
447 
448   /**
449    * Returns a list of all KeyValue objects with matching column family and qualifier.
450    *
451    * @param family column family
452    * @param qualifier column qualifier
453    * @return a list of KeyValue objects with the matching family and qualifier,
454    * returns an empty list if one doesn't exist for the given family.
455    */
456   public List<Cell> get(byte[] family, byte[] qualifier) {
457     List<Cell> filteredList = new ArrayList<Cell>();
458     for (Cell cell: getCellList(family)) {
459       if (CellUtil.matchingQualifier(cell, qualifier)) {
460         filteredList.add(cell);
461       }
462     }
463     return filteredList;
464   }
465 
466   @Override
467   public Put setAttribute(String name, byte[] value) {
468     return (Put) super.setAttribute(name, value);
469   }
470 
471   @Override
472   public Put setId(String id) {
473     return (Put) super.setId(id);
474   }
475 
476   @Override
477   public Put setDurability(Durability d) {
478     return (Put) super.setDurability(d);
479   }
480 
481   @Override
482   public Put setFamilyCellMap(NavigableMap<byte[], List<Cell>> map) {
483     return (Put) super.setFamilyCellMap(map);
484   }
485 
486   @Override
487   public Put setClusterIds(List<UUID> clusterIds) {
488     return (Put) super.setClusterIds(clusterIds);
489   }
490 
491   @Override
492   public Put setCellVisibility(CellVisibility expression) {
493     return (Put) super.setCellVisibility(expression);
494   }
495 
496   @Override
497   public Put setACL(String user, Permission perms) {
498     return (Put) super.setACL(user, perms);
499   }
500 
501   @Override
502   public Put setACL(Map<String, Permission> perms) {
503     return (Put) super.setACL(perms);
504   }
505 
506   @Override
507   public Put setTTL(long ttl) {
508     return (Put) super.setTTL(ttl);
509   }
510 }