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