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.durability = putToCopy.durability;
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 }