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