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