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.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.TreeMap;
28  
29  import org.apache.hadoop.classification.InterfaceAudience;
30  import org.apache.hadoop.classification.InterfaceStability;
31  import org.apache.hadoop.hbase.Cell;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.KeyValue;
34  import org.apache.hadoop.hbase.KeyValueUtil;
35  import org.apache.hadoop.hbase.io.HeapSize;
36  import org.apache.hadoop.hbase.util.Bytes;
37  
38  /**
39   * Used to perform Put operations for a single row.
40   * <p>
41   * To perform a Put, instantiate a Put object with the row to insert to and
42   * for each column to be inserted, execute {@link #add(byte[], byte[], byte[]) add} or
43   * {@link #add(byte[], byte[], long, byte[]) add} if setting the timestamp.
44   */
45  @InterfaceAudience.Public
46  @InterfaceStability.Stable
47  public class Put extends Mutation implements HeapSize, Comparable<Row> {
48    /**
49     * Create a Put operation for the specified row.
50     * @param row row key
51     */
52    public Put(byte [] row) {
53      this(row, HConstants.LATEST_TIMESTAMP);
54    }
55  
56    /**
57     * Create a Put operation for the specified row, using a given timestamp.
58     *
59     * @param row row key; we make a copy of what we are passed to keep local.
60     * @param ts timestamp
61     */
62    public Put(byte[] row, long ts) {
63      this(row, 0, row.length, ts);
64    }
65  
66    /**
67     * We make a copy of the passed in row key to keep local.
68     * @param rowArray
69     * @param rowOffset
70     * @param rowLength
71     * @param ts
72     */
73    public Put(byte [] rowArray, int rowOffset, int rowLength, long ts) {
74      checkRow(rowArray, rowOffset, rowLength);
75      this.row = Bytes.copy(rowArray, rowOffset, rowLength);
76      this.ts = ts;
77    }
78  
79    /**
80     * Copy constructor.  Creates a Put operation cloned from the specified Put.
81     * @param putToCopy put to copy
82     */
83    public Put(Put putToCopy) {
84      this(putToCopy.getRow(), putToCopy.ts);
85      this.familyMap = new TreeMap<byte [], List<? extends Cell>>(Bytes.BYTES_COMPARATOR);
86      for(Map.Entry<byte [], List<? extends Cell>> entry: putToCopy.getFamilyMap().entrySet()) {
87        this.familyMap.put(entry.getKey(), entry.getValue());
88      }
89      this.writeToWAL = putToCopy.writeToWAL;
90    }
91  
92    /**
93     * Add the specified column and value to this Put operation.
94     * @param family family name
95     * @param qualifier column qualifier
96     * @param value column value
97     * @return this
98     */
99    public Put add(byte [] family, byte [] qualifier, byte [] value) {
100     return add(family, qualifier, this.ts, value);
101   }
102 
103   /**
104    * Add the specified column and value, with the specified timestamp as
105    * its version to this Put operation.
106    * @param family family name
107    * @param qualifier column qualifier
108    * @param ts version timestamp
109    * @param value column value
110    * @return this
111    */
112   @SuppressWarnings("unchecked")
113   public Put add(byte [] family, byte [] qualifier, long ts, byte [] value) {
114     List<? extends Cell> list = getCellList(family);
115     KeyValue kv = createPutKeyValue(family, qualifier, ts, value);
116     ((List<KeyValue>)list).add(kv);
117     familyMap.put(kv.getFamily(), list);
118     return this;
119   }
120 
121   /**
122    * Add the specified KeyValue to this Put operation.  Operation assumes that
123    * the passed KeyValue is immutable and its backing array will not be modified
124    * for the duration of this Put.
125    * @param kv individual KeyValue
126    * @return this
127    * @throws java.io.IOException e
128    */
129   @SuppressWarnings("unchecked")
130   public Put add(KeyValue kv) throws IOException{
131     byte [] family = kv.getFamily();
132     List<? extends Cell> list = getCellList(family);
133     //Checking that the row of the kv is the same as the put
134     int res = Bytes.compareTo(this.row, 0, row.length,
135         kv.getBuffer(), kv.getRowOffset(), kv.getRowLength());
136     if (res != 0) {
137       throw new WrongRowIOException("The row in " + kv.toString() +
138         " doesn't match the original one " +  Bytes.toStringBinary(this.row));
139     }
140     ((List<KeyValue>)list).add(kv);
141     familyMap.put(family, list);
142     return this;
143   }
144 
145   /**
146    * A convenience method to determine if this object's familyMap contains
147    * a value assigned to the given family & qualifier.
148    * Both given arguments must match the KeyValue object to return true.
149    *
150    * @param family column family
151    * @param qualifier column qualifier
152    * @return returns true if the given family and qualifier already has an
153    * existing KeyValue object in the family map.
154    */
155   public boolean has(byte [] family, byte [] qualifier) {
156   return has(family, qualifier, this.ts, new byte[0], true, true);
157   }
158 
159   /**
160    * A convenience method to determine if this object's familyMap contains
161    * a value assigned to the given family, qualifier and timestamp.
162    * All 3 given arguments must match the KeyValue object to return true.
163    *
164    * @param family column family
165    * @param qualifier column qualifier
166    * @param ts timestamp
167    * @return returns true if the given family, qualifier and timestamp already has an
168    * existing KeyValue object in the family map.
169    */
170   public boolean has(byte [] family, byte [] qualifier, long ts) {
171   return has(family, qualifier, ts, new byte[0], false, true);
172   }
173 
174   /**
175    * A convenience method to determine if this object's familyMap contains
176    * a value assigned to the given family, qualifier and timestamp.
177    * All 3 given arguments must match the KeyValue object to return true.
178    *
179    * @param family column family
180    * @param qualifier column qualifier
181    * @param value value to check
182    * @return returns true if the given family, qualifier and value already has an
183    * existing KeyValue object in the family map.
184    */
185   public boolean has(byte [] family, byte [] qualifier, byte [] value) {
186     return has(family, qualifier, this.ts, value, true, false);
187   }
188 
189   /**
190    * A convenience method to determine if this object's familyMap contains
191    * the given value assigned to the given family, qualifier and timestamp.
192    * All 4 given arguments must match the KeyValue object to return true.
193    *
194    * @param family column family
195    * @param qualifier column qualifier
196    * @param ts timestamp
197    * @param value value to check
198    * @return returns true if the given family, qualifier timestamp and value
199    * already has an existing KeyValue object in the family map.
200    */
201   public boolean has(byte [] family, byte [] qualifier, long ts, byte [] value) {
202       return has(family, qualifier, ts, value, false, false);
203   }
204 
205   /*
206    * Private method to determine if this object's familyMap contains
207    * the given value assigned to the given family, qualifier and timestamp
208    * respecting the 2 boolean arguments
209    *
210    * @param family
211    * @param qualifier
212    * @param ts
213    * @param value
214    * @param ignoreTS
215    * @param ignoreValue
216    * @return returns true if the given family, qualifier timestamp and value
217    * already has an existing KeyValue object in the family map.
218    */
219   private boolean has(byte[] family, byte[] qualifier, long ts, byte[] value,
220                       boolean ignoreTS, boolean ignoreValue) {
221     List<? extends Cell> list = getCellList(family);
222     if (list.size() == 0) {
223       return false;
224     }
225     // Boolean analysis of ignoreTS/ignoreValue.
226     // T T => 2
227     // T F => 3 (first is always true)
228     // F T => 2
229     // F F => 1
230     if (!ignoreTS && !ignoreValue) {
231       for (Cell cell : list) {
232         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
233         if (Arrays.equals(kv.getFamily(), family) &&
234             Arrays.equals(kv.getQualifier(), qualifier) &&
235             Arrays.equals(kv.getValue(), value) &&
236             kv.getTimestamp() == ts) {
237           return true;
238         }
239       }
240     } else if (ignoreValue && !ignoreTS) {
241       for (Cell cell : list) {
242         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
243         if (Arrays.equals(kv.getFamily(), family) && Arrays.equals(kv.getQualifier(), qualifier)
244             && kv.getTimestamp() == ts) {
245           return true;
246         }
247       }
248     } else if (!ignoreValue && ignoreTS) {
249       for (Cell cell : list) {
250         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
251         if (Arrays.equals(kv.getFamily(), family) && Arrays.equals(kv.getQualifier(), qualifier)
252             && Arrays.equals(kv.getValue(), value)) {
253           return true;
254         }
255       }
256     } else {
257       for (Cell cell : list) {
258         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
259         if (Arrays.equals(kv.getFamily(), family) &&
260             Arrays.equals(kv.getQualifier(), qualifier)) {
261           return true;
262         }
263       }
264     }
265     return false;
266   }
267 
268   /**
269    * Returns a list of all KeyValue objects with matching column family and qualifier.
270    *
271    * @param family column family
272    * @param qualifier column qualifier
273    * @return a list of KeyValue objects with the matching family and qualifier,
274    * returns an empty list if one doesnt exist for the given family.
275    */
276   public List<KeyValue> get(byte[] family, byte[] qualifier) {
277     List<KeyValue> filteredList = new ArrayList<KeyValue>();
278     for (Cell cell: getCellList(family)) {
279       KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
280       if (Arrays.equals(kv.getQualifier(), qualifier)) {
281         filteredList.add(kv);
282       }
283     }
284     return filteredList;
285   }
286 }