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    * Copy constructor.  Creates a Put operation cloned from the specified Put.
121    * @param putToCopy put to copy
122    */
123   public Put(Put putToCopy) {
124     this(putToCopy.getRow(), putToCopy.ts);
125     this.familyMap = new TreeMap<byte [], List<Cell>>(Bytes.BYTES_COMPARATOR);
126     for(Map.Entry<byte [], List<Cell>> entry: putToCopy.getFamilyCellMap().entrySet()) {
127       this.familyMap.put(entry.getKey(), new ArrayList<Cell>(entry.getValue()));
128     }
129     this.durability = putToCopy.durability;
130     for (Map.Entry<String, byte[]> entry : putToCopy.getAttributesMap().entrySet()) {
131       this.setAttribute(entry.getKey(), entry.getValue());
132     }
133   }
134
135   /**
136    * Add the specified column and value to this Put operation.
137    * @param family family name
138    * @param qualifier column qualifier
139    * @param value column value
140    * @return this
141    */
142   public Put addColumn(byte [] family, byte [] qualifier, byte [] value) {
143     return addColumn(family, qualifier, this.ts, value);
144   }
145
146   /**
147    * See {@link #addColumn(byte[], byte[], byte[])}. This version expects
148    * that the underlying arrays won't change. It's intended
149    * for usage internal HBase to and for advanced client applications.
150    */
151   public Put addImmutable(byte [] family, byte [] qualifier, byte [] value) {
152     return addImmutable(family, qualifier, this.ts, value);
153   }
154
155   /**
156    * This expects that the underlying arrays won't change. It's intended
157    * for usage internal HBase to and for advanced client applications.
158    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
159    * that should not be exposed publicly.
160    */
161   @InterfaceAudience.Private
162   public Put addImmutable(byte[] family, byte [] qualifier, byte [] value, Tag[] tag) {
163     return addImmutable(family, qualifier, this.ts, value, tag);
164   }
165
166   /**
167    * Add the specified column and value, with the specified timestamp as
168    * its version to this Put operation.
169    * @param family family name
170    * @param qualifier column qualifier
171    * @param ts version timestamp
172    * @param value column value
173    * @return this
174    */
175   public Put addColumn(byte [] family, byte [] qualifier, long ts, byte [] value) {
176     if (ts < 0) {
177       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
178     }
179     List<Cell> list = getCellList(family);
180     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
181     list.add(kv);
182     familyMap.put(CellUtil.cloneFamily(kv), list);
183     return this;
184   }
185
186   /**
187    * See {@link #addColumn(byte[], byte[], long, byte[])}. This version expects
188    * that the underlying arrays won't change. It's intended
189    * for usage internal HBase to and for advanced client applications.
190    */
191   public Put addImmutable(byte [] family, byte [] qualifier, long ts, byte [] value) {
192     if (ts < 0) {
193       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
194     }
195     List<Cell> list = getCellList(family);
196     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
197     list.add(kv);
198     familyMap.put(family, list);
199     return this;
200   }
201
202   /**
203    * This expects that the underlying arrays won't change. It's intended
204    * for usage internal HBase to and for advanced client applications.
205    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
206    * that should not be exposed publicly.
207    */
208   @InterfaceAudience.Private
209   public Put addImmutable(byte[] family, byte[] qualifier, long ts, byte[] value, Tag[] tag) {
210     List<Cell> list = getCellList(family);
211     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
212     list.add(kv);
213     familyMap.put(family, list);
214     return this;
215   }
216
217   /**
218    * This expects that the underlying arrays won't change. It's intended
219    * for usage internal HBase to and for advanced client applications.
220    * <p>Marked as audience Private as of 1.2.0. {@link Tag} is an internal implementation detail
221    * that should not be exposed publicly.
222    */
223   @InterfaceAudience.Private
224   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value,
225                           Tag[] tag) {
226     if (ts < 0) {
227       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
228     }
229     List<Cell> list = getCellList(family);
230     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, tag);
231     list.add(kv);
232     familyMap.put(family, list);
233     return this;
234   }
235 
236
237   /**
238    * Add the specified column and value, with the specified timestamp as
239    * its version to this Put operation.
240    * @param family family name
241    * @param qualifier column qualifier
242    * @param ts version timestamp
243    * @param value column value
244    * @return this
245    */
246   public Put addColumn(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
247     if (ts < 0) {
248       throw new IllegalArgumentException("Timestamp cannot be negative. ts=" + ts);
249     }
250     List<Cell> list = getCellList(family);
251     KeyValue kv = createPutKeyValue(family, qualifier, ts, value, null);
252     list.add(kv);
253     familyMap.put(CellUtil.cloneFamily(kv), list);
254     return this;
255   }
256
257   /**
258    * See {@link #addColumn(byte[], ByteBuffer, long, ByteBuffer)}. This version expects
259    * that the underlying arrays won't change. It's intended
260    * for usage internal HBase to and for advanced client applications.
261    */
262   public Put addImmutable(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value) {
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, null);
268     list.add(kv);
269     familyMap.put(family, list);
270     return this;
271   }
272
273   /**
274    * Add the specified KeyValue to this Put operation.  Operation assumes that
275    * the passed KeyValue is immutable and its backing array will not be modified
276    * for the duration of this Put.
277    * @param kv individual KeyValue
278    * @return this
279    * @throws java.io.IOException e
280    */
281   public Put add(Cell kv) throws IOException{
282     byte [] family = CellUtil.cloneFamily(kv);
283     List<Cell> list = getCellList(family);
284     //Checking that the row of the kv is the same as the put
285     int res = Bytes.compareTo(this.row, 0, row.length,
286         kv.getRowArray(), kv.getRowOffset(), kv.getRowLength());
287     if (res != 0) {
288       throw new WrongRowIOException("The row in " + kv.toString() +
289         " doesn't match the original one " +  Bytes.toStringBinary(this.row));
290     }
291     list.add(kv);
292     familyMap.put(family, list);
293     return this;
294   }
295
296   /**
297    * A convenience method to determine if this object's familyMap contains
298    * a value assigned to the given family &amp; qualifier.
299    * Both given arguments must match the KeyValue object to return true.
300    *
301    * @param family column family
302    * @param qualifier column qualifier
303    * @return returns true if the given family and qualifier already has an
304    * existing KeyValue object in the family map.
305    */
306   public boolean has(byte [] family, byte [] qualifier) {
307   return has(family, qualifier, this.ts, new byte[0], true, true);
308   }
309
310   /**
311    * A convenience method to determine if this object's familyMap contains
312    * a value assigned to the given family, qualifier and timestamp.
313    * All 3 given arguments must match the KeyValue object to return true.
314    *
315    * @param family column family
316    * @param qualifier column qualifier
317    * @param ts timestamp
318    * @return returns true if the given family, qualifier and timestamp already has an
319    * existing KeyValue object in the family map.
320    */
321   public boolean has(byte [] family, byte [] qualifier, long ts) {
322   return has(family, qualifier, ts, new byte[0], false, true);
323   }
324
325   /**
326    * A convenience method to determine if this object's familyMap contains
327    * a value assigned to the given family, qualifier and timestamp.
328    * All 3 given arguments must match the KeyValue object to return true.
329    *
330    * @param family column family
331    * @param qualifier column qualifier
332    * @param value value to check
333    * @return returns true if the given family, qualifier and value already has an
334    * existing KeyValue object in the family map.
335    */
336   public boolean has(byte [] family, byte [] qualifier, byte [] value) {
337     return has(family, qualifier, this.ts, value, true, false);
338   }
339
340   /**
341    * A convenience method to determine if this object's familyMap contains
342    * the given value assigned to the given family, qualifier and timestamp.
343    * All 4 given arguments must match the KeyValue object to return true.
344    *
345    * @param family column family
346    * @param qualifier column qualifier
347    * @param ts timestamp
348    * @param value value to check
349    * @return returns true if the given family, qualifier timestamp and value
350    * already has an existing KeyValue object in the family map.
351    */
352   public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
353       return has(family, qualifier, ts, value, false, false);
354   }
355
356   /*
357    * Private method to determine if this object's familyMap contains
358    * the given value assigned to the given family, qualifier and timestamp
359    * respecting the 2 boolean arguments
360    *
361    * @param family
362    * @param qualifier
363    * @param ts
364    * @param value
365    * @param ignoreTS
366    * @param ignoreValue
367    * @return returns true if the given family, qualifier timestamp and value
368    * already has an existing KeyValue object in the family map.
369    */
370   private boolean has(byte[] family, byte[] qualifier, long ts, byte[] value,
371                       boolean ignoreTS, boolean ignoreValue) {
372     List<Cell> list = getCellList(family);
373     if (list.size() == 0) {
374       return false;
375     }
376     // Boolean analysis of ignoreTS/ignoreValue.
377     // T T => 2
378     // T F => 3 (first is always true)
379     // F T => 2
380     // F F => 1
381     if (!ignoreTS && !ignoreValue) {
382       for (Cell cell : list) {
383         if (CellUtil.matchingFamily(cell, family) &&
384             CellUtil.matchingQualifier(cell, qualifier)  &&
385             CellUtil.matchingValue(cell, value) &&
386             cell.getTimestamp() == ts) {
387           return true;
388         }
389       }
390     } else if (ignoreValue && !ignoreTS) {
391       for (Cell cell : list) {
392         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
393             && cell.getTimestamp() == ts) {
394           return true;
395         }
396       }
397     } else if (!ignoreValue && ignoreTS) {
398       for (Cell cell : list) {
399         if (CellUtil.matchingFamily(cell, family) && CellUtil.matchingQualifier(cell, qualifier)
400             && CellUtil.matchingValue(cell, value)) {
401           return true;
402         }
403       }
404     } else {
405       for (Cell cell : list) {
406         if (CellUtil.matchingFamily(cell, family) &&
407             CellUtil.matchingQualifier(cell, qualifier)) {
408           return true;
409         }
410       }
411     }
412     return false;
413   }
414
415   /**
416    * Returns a list of all KeyValue objects with matching column family and qualifier.
417    *
418    * @param family column family
419    * @param qualifier column qualifier
420    * @return a list of KeyValue objects with the matching family and qualifier,
421    * returns an empty list if one doesn't exist for the given family.
422    */
423   public List<Cell> get(byte[] family, byte[] qualifier) {
424     List<Cell> filteredList = new ArrayList<Cell>();
425     for (Cell cell: getCellList(family)) {
426       if (CellUtil.matchingQualifier(cell, qualifier)) {
427         filteredList.add(cell);
428       }
429     }
430     return filteredList;
431   }
432
433   @Override
434   public Put setAttribute(String name, byte[] value) {
435     return (Put) super.setAttribute(name, value);
436   }
437
438   @Override
439   public Put setId(String id) {
440     return (Put) super.setId(id);
441   }
442
443   @Override
444   public Put setDurability(Durability d) {
445     return (Put) super.setDurability(d);
446   }
447
448   @Override
449   public Put setFamilyCellMap(NavigableMap<byte[], List<Cell>> map) {
450     return (Put) super.setFamilyCellMap(map);
451   }
452
453   @Override
454   public Put setClusterIds(List<UUID> clusterIds) {
455     return (Put) super.setClusterIds(clusterIds);
456   }
457
458   @Override
459   public Put setCellVisibility(CellVisibility expression) {
460     return (Put) super.setCellVisibility(expression);
461   }
462
463   @Override
464   public Put setACL(String user, Permission perms) {
465     return (Put) super.setACL(user, perms);
466   }
467
468   @Override
469   public Put setACL(Map<String, Permission> perms) {
470     return (Put) super.setACL(perms);
471   }
472
473   @Override
474   public Put setTTL(long ttl) {
475     return (Put) super.setTTL(ttl);
476   }
477 }