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.List;
25 import java.util.Map;
26
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.classification.InterfaceStability;
29 import org.apache.hadoop.hbase.Cell;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.KeyValue;
32 import org.apache.hadoop.hbase.util.Bytes;
33
34 /**
35 * Used to perform Delete operations on a single row.
36 * <p>
37 * To delete an entire row, instantiate a Delete object with the row
38 * to delete. To further define the scope of what to delete, perform
39 * additional methods as outlined below.
40 * <p>
41 * To delete specific families, execute {@link #deleteFamily(byte[]) deleteFamily}
42 * for each family to delete.
43 * <p>
44 * To delete multiple versions of specific columns, execute
45 * {@link #deleteColumns(byte[], byte[]) deleteColumns}
46 * for each column to delete.
47 * <p>
48 * To delete specific versions of specific columns, execute
49 * {@link #deleteColumn(byte[], byte[], long) deleteColumn}
50 * for each column version to delete.
51 * <p>
52 * Specifying timestamps, deleteFamily and deleteColumns will delete all
53 * versions with a timestamp less than or equal to that passed. If no
54 * timestamp is specified, an entry is added with a timestamp of 'now'
55 * where 'now' is the servers's System.currentTimeMillis().
56 * Specifying a timestamp to the deleteColumn method will
57 * delete versions only with a timestamp equal to that specified.
58 * If no timestamp is passed to deleteColumn, internally, it figures the
59 * most recent cell's timestamp and adds a delete at that timestamp; i.e.
60 * it deletes the most recently added cell.
61 * <p>The timestamp passed to the constructor is used ONLY for delete of
62 * rows. For anything less -- a deleteColumn, deleteColumns or
63 * deleteFamily -- then you need to use the method overrides that take a
64 * timestamp. The constructor timestamp is not referenced.
65 */
66 @InterfaceAudience.Public
67 @InterfaceStability.Stable
68 public class Delete extends Mutation implements Comparable<Row> {
69 /**
70 * Create a Delete operation for the specified row.
71 * <p>
72 * If no further operations are done, this will delete everything
73 * associated with the specified row (all versions of all columns in all
74 * families).
75 * @param row row key
76 */
77 public Delete(byte [] row) {
78 this(row, HConstants.LATEST_TIMESTAMP);
79 }
80
81 /**
82 * Create a Delete operation for the specified row and timestamp.<p>
83 *
84 * If no further operations are done, this will delete all columns in all
85 * families of the specified row with a timestamp less than or equal to the
86 * specified timestamp.<p>
87 *
88 * This timestamp is ONLY used for a delete row operation. If specifying
89 * families or columns, you must specify each timestamp individually.
90 * @param row row key
91 * @param timestamp maximum version timestamp (only for delete row)
92 */
93 public Delete(byte [] row, long timestamp) {
94 this(row, 0, row.length, timestamp);
95 }
96
97 /**
98 * Create a Delete operation for the specified row and timestamp.<p>
99 *
100 * If no further operations are done, this will delete all columns in all
101 * families of the specified row with a timestamp less than or equal to the
102 * specified timestamp.<p>
103 *
104 * This timestamp is ONLY used for a delete row operation. If specifying
105 * families or columns, you must specify each timestamp individually.
106 * @param rowArray We make a local copy of this passed in row.
107 * @param rowOffset
108 * @param rowLength
109 */
110 public Delete(final byte [] rowArray, final int rowOffset, final int rowLength) {
111 this(rowArray, rowOffset, rowLength, HConstants.LATEST_TIMESTAMP);
112 }
113
114 /**
115 * Create a Delete operation for the specified row and timestamp.<p>
116 *
117 * If no further operations are done, this will delete all columns in all
118 * families of the specified row with a timestamp less than or equal to the
119 * specified timestamp.<p>
120 *
121 * This timestamp is ONLY used for a delete row operation. If specifying
122 * families or columns, you must specify each timestamp individually.
123 * @param rowArray We make a local copy of this passed in row.
124 * @param rowOffset
125 * @param rowLength
126 * @param ts maximum version timestamp (only for delete row)
127 */
128 public Delete(final byte [] rowArray, final int rowOffset, final int rowLength, long ts) {
129 checkRow(rowArray, rowOffset, rowLength);
130 this.row = Bytes.copy(rowArray, rowOffset, rowLength);
131 this.ts = ts;
132 }
133
134 /**
135 * @param d Delete to clone.
136 */
137 public Delete(final Delete d) {
138 this.row = d.getRow();
139 this.ts = d.getTimeStamp();
140 this.familyMap.putAll(d.getFamilyCellMap());
141 this.durability = d.durability;
142 }
143
144 /**
145 * Advanced use only.
146 * Add an existing delete marker to this Delete object.
147 * @param kv An existing KeyValue of type "delete".
148 * @return this for invocation chaining
149 * @throws IOException
150 */
151 @SuppressWarnings("unchecked")
152 public Delete addDeleteMarker(KeyValue kv) throws IOException {
153 // TODO: Deprecate and rename 'add' so it matches how we add KVs to Puts.
154 if (!kv.isDelete()) {
155 throw new IOException("The recently added KeyValue is not of type "
156 + "delete. Rowkey: " + Bytes.toStringBinary(this.row));
157 }
158 if (Bytes.compareTo(this.row, 0, row.length, kv.getBuffer(),
159 kv.getRowOffset(), kv.getRowLength()) != 0) {
160 throw new WrongRowIOException("The row in " + kv.toString() +
161 " doesn't match the original one " + Bytes.toStringBinary(this.row));
162 }
163 byte [] family = kv.getFamily();
164 List<Cell> list = familyMap.get(family);
165 if (list == null) {
166 list = new ArrayList<Cell>();
167 }
168 list.add(kv);
169 familyMap.put(family, list);
170 return this;
171 }
172
173 /**
174 * Delete all versions of all columns of the specified family.
175 * <p>
176 * Overrides previous calls to deleteColumn and deleteColumns for the
177 * specified family.
178 * @param family family name
179 * @return this for invocation chaining
180 */
181 public Delete deleteFamily(byte [] family) {
182 this.deleteFamily(family, HConstants.LATEST_TIMESTAMP);
183 return this;
184 }
185
186 /**
187 * Delete all columns of the specified family with a timestamp less than
188 * or equal to the specified timestamp.
189 * <p>
190 * Overrides previous calls to deleteColumn and deleteColumns for the
191 * specified family.
192 * @param family family name
193 * @param timestamp maximum version timestamp
194 * @return this for invocation chaining
195 */
196 @SuppressWarnings("unchecked")
197 public Delete deleteFamily(byte [] family, long timestamp) {
198 List<Cell> list = familyMap.get(family);
199 if(list == null) {
200 list = new ArrayList<Cell>();
201 } else if(!list.isEmpty()) {
202 list.clear();
203 }
204 KeyValue kv = new KeyValue(row, family, null, timestamp, KeyValue.Type.DeleteFamily);
205 list.add(kv);
206 familyMap.put(family, list);
207 return this;
208 }
209
210 /**
211 * Delete all columns of the specified family with a timestamp equal to
212 * the specified timestamp.
213 * @param family family name
214 * @param timestamp version timestamp
215 * @return this for invocation chaining
216 */
217 public Delete deleteFamilyVersion(byte [] family, long timestamp) {
218 List<Cell> list = familyMap.get(family);
219 if(list == null) {
220 list = new ArrayList<Cell>();
221 }
222 list.add(new KeyValue(row, family, null, timestamp,
223 KeyValue.Type.DeleteFamilyVersion));
224 familyMap.put(family, list);
225 return this;
226 }
227
228
229 /**
230 * Delete all versions of the specified column.
231 * @param family family name
232 * @param qualifier column qualifier
233 * @return this for invocation chaining
234 */
235 public Delete deleteColumns(byte [] family, byte [] qualifier) {
236 this.deleteColumns(family, qualifier, HConstants.LATEST_TIMESTAMP);
237 return this;
238 }
239
240 /**
241 * Delete all versions of the specified column with a timestamp less than
242 * or equal to the specified timestamp.
243 * @param family family name
244 * @param qualifier column qualifier
245 * @param timestamp maximum version timestamp
246 * @return this for invocation chaining
247 */
248 @SuppressWarnings("unchecked")
249 public Delete deleteColumns(byte [] family, byte [] qualifier, long timestamp) {
250 List<Cell> list = familyMap.get(family);
251 if (list == null) {
252 list = new ArrayList<Cell>();
253 }
254 list.add(new KeyValue(this.row, family, qualifier, timestamp,
255 KeyValue.Type.DeleteColumn));
256 familyMap.put(family, list);
257 return this;
258 }
259
260 /**
261 * Delete the latest version of the specified column.
262 * This is an expensive call in that on the server-side, it first does a
263 * get to find the latest versions timestamp. Then it adds a delete using
264 * the fetched cells timestamp.
265 * @param family family name
266 * @param qualifier column qualifier
267 * @return this for invocation chaining
268 */
269 public Delete deleteColumn(byte [] family, byte [] qualifier) {
270 this.deleteColumn(family, qualifier, HConstants.LATEST_TIMESTAMP);
271 return this;
272 }
273
274 /**
275 * Delete the specified version of the specified column.
276 * @param family family name
277 * @param qualifier column qualifier
278 * @param timestamp version timestamp
279 * @return this for invocation chaining
280 */
281 @SuppressWarnings("unchecked")
282 public Delete deleteColumn(byte [] family, byte [] qualifier, long timestamp) {
283 List<Cell> list = familyMap.get(family);
284 if(list == null) {
285 list = new ArrayList<Cell>();
286 }
287 KeyValue kv = new KeyValue(this.row, family, qualifier, timestamp, KeyValue.Type.Delete);
288 list.add(kv);
289 familyMap.put(family, list);
290 return this;
291 }
292
293 /**
294 * Set the timestamp of the delete.
295 *
296 * @param timestamp
297 */
298 public void setTimestamp(long timestamp) {
299 this.ts = timestamp;
300 }
301
302 @Override
303 public Map<String, Object> toMap(int maxCols) {
304 // we start with the fingerprint map and build on top of it.
305 Map<String, Object> map = super.toMap(maxCols);
306 // why is put not doing this?
307 map.put("ts", this.ts);
308 return map;
309 }
310 }