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