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 }