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  
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    * @param ts maximum version timestamp (only for delete row)
110    */
111   public Delete(final byte [] rowArray, final int rowOffset, final int rowLength, long ts) {
112     checkRow(rowArray, rowOffset, rowLength);
113     this.row = Bytes.copy(rowArray, rowOffset, rowLength);
114     this.ts = ts;
115   }
116 
117   /**
118    * @param d Delete to clone.
119    */
120   public Delete(final Delete d) {
121     this.row = d.getRow();
122     this.ts = d.getTimeStamp();
123     this.familyMap.putAll(d.getFamilyMap());
124     this.writeToWAL = d.writeToWAL;
125   }
126 
127   /**
128    * Advanced use only.
129    * Add an existing delete marker to this Delete object.
130    * @param kv An existing KeyValue of type "delete".
131    * @return this for invocation chaining
132    * @throws IOException
133    */
134   @SuppressWarnings("unchecked")
135   public Delete addDeleteMarker(KeyValue kv) throws IOException {
136     // TODO: Deprecate and rename 'add' so it matches how we add KVs to Puts.
137     if (!kv.isDelete()) {
138       throw new IOException("The recently added KeyValue is not of type "
139           + "delete. Rowkey: " + Bytes.toStringBinary(this.row));
140     }
141     if (Bytes.compareTo(this.row, 0, row.length, kv.getBuffer(),
142         kv.getRowOffset(), kv.getRowLength()) != 0) {
143       throw new WrongRowIOException("The row in " + kv.toString() +
144         " doesn't match the original one " +  Bytes.toStringBinary(this.row));
145     }
146     byte [] family = kv.getFamily();
147     List<? extends Cell> list = familyMap.get(family);
148     if (list == null) {
149       list = new ArrayList<Cell>();
150     }
151     // Cast so explicit list type rather than ? extends Cell.  Help the compiler out.  See
152     // http://stackoverflow.com/questions/6474784/java-using-generics-with-lists-and-interfaces
153     ((List<KeyValue>)list).add(kv);
154     familyMap.put(family, list);
155     return this;
156   }
157 
158   /**
159    * Delete all versions of all columns of the specified family.
160    * <p>
161    * Overrides previous calls to deleteColumn and deleteColumns for the
162    * specified family.
163    * @param family family name
164    * @return this for invocation chaining
165    */
166   public Delete deleteFamily(byte [] family) {
167     this.deleteFamily(family, HConstants.LATEST_TIMESTAMP);
168     return this;
169   }
170 
171   /**
172    * Delete all columns of the specified family with a timestamp less than
173    * or equal to the specified timestamp.
174    * <p>
175    * Overrides previous calls to deleteColumn and deleteColumns for the
176    * specified family.
177    * @param family family name
178    * @param timestamp maximum version timestamp
179    * @return this for invocation chaining
180    */
181   @SuppressWarnings("unchecked")
182   public Delete deleteFamily(byte [] family, long timestamp) {
183     List<? extends Cell> list = familyMap.get(family);
184     if(list == null) {
185       list = new ArrayList<Cell>();
186     } else if(!list.isEmpty()) {
187       list.clear();
188     }
189     KeyValue kv = new KeyValue(row, family, null, timestamp, KeyValue.Type.DeleteFamily);
190     // Cast so explicit list type rather than ? extends Cell.  Help the compiler out.  See
191     // http://stackoverflow.com/questions/6474784/java-using-generics-with-lists-and-interfaces
192     ((List<KeyValue>)list).add(kv);
193     familyMap.put(family, list);
194     return this;
195   }
196 
197   /**
198    * Delete all versions of the specified column.
199    * @param family family name
200    * @param qualifier column qualifier
201    * @return this for invocation chaining
202    */
203   public Delete deleteColumns(byte [] family, byte [] qualifier) {
204     this.deleteColumns(family, qualifier, HConstants.LATEST_TIMESTAMP);
205     return this;
206   }
207 
208   /**
209    * Delete all versions of the specified column with a timestamp less than
210    * or equal to the specified timestamp.
211    * @param family family name
212    * @param qualifier column qualifier
213    * @param timestamp maximum version timestamp
214    * @return this for invocation chaining
215    */
216   @SuppressWarnings("unchecked")
217   public Delete deleteColumns(byte [] family, byte [] qualifier, long timestamp) {
218     List<? extends Cell> list = familyMap.get(family);
219     if (list == null) {
220       list = new ArrayList<Cell>();
221     }
222     // Cast so explicit list type rather than ? extends Cell.  Help the compiler out.  See
223     // http://stackoverflow.com/questions/6474784/java-using-generics-with-lists-and-interfaces
224     ((List<KeyValue>)list).add(new KeyValue(this.row, family, qualifier, timestamp,
225         KeyValue.Type.DeleteColumn));
226     familyMap.put(family, list);
227     return this;
228   }
229 
230   /**
231    * Delete the latest version of the specified column.
232    * This is an expensive call in that on the server-side, it first does a
233    * get to find the latest versions timestamp.  Then it adds a delete using
234    * the fetched cells timestamp.
235    * @param family family name
236    * @param qualifier column qualifier
237    * @return this for invocation chaining
238    */
239   public Delete deleteColumn(byte [] family, byte [] qualifier) {
240     this.deleteColumn(family, qualifier, HConstants.LATEST_TIMESTAMP);
241     return this;
242   }
243 
244   /**
245    * Delete the specified version of the specified column.
246    * @param family family name
247    * @param qualifier column qualifier
248    * @param timestamp version timestamp
249    * @return this for invocation chaining
250    */
251   @SuppressWarnings("unchecked")
252   public Delete deleteColumn(byte [] family, byte [] qualifier, long timestamp) {
253     List<? extends Cell> list = familyMap.get(family);
254     if(list == null) {
255       list = new ArrayList<Cell>();
256     }
257     // Cast so explicit list type rather than ? extends Cell.  Help the compiler out.  See
258     // http://stackoverflow.com/questions/6474784/java-using-generics-with-lists-and-interfaces
259     KeyValue kv = new KeyValue(this.row, family, qualifier, timestamp, KeyValue.Type.Delete);
260     ((List<KeyValue>)list).add(kv);
261     familyMap.put(family, list);
262     return this;
263   }
264 
265   /**
266    * Set the timestamp of the delete.
267    * 
268    * @param timestamp
269    */
270   public void setTimestamp(long timestamp) {
271     this.ts = timestamp;
272   }
273 
274   @Override
275   public Map<String, Object> toMap(int maxCols) {
276     // we start with the fingerprint map and build on top of it.
277     Map<String, Object> map = super.toMap(maxCols);
278     // why is put not doing this?
279     map.put("ts", this.ts);
280     return map;
281   }
282 }