View Javadoc

1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.client;
22  
23  import org.apache.hadoop.hbase.HConstants;
24  import org.apache.hadoop.hbase.KeyValue;
25  import org.apache.hadoop.hbase.util.Bytes;
26  import org.apache.hadoop.io.Writable;
27  
28  import java.io.DataInput;
29  import java.io.DataOutput;
30  import java.io.IOException;
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.TreeMap;
35  
36  /**
37   * Used to perform Delete operations on a single row.
38   * <p>
39   * To delete an entire row, instantiate a Delete object with the row
40   * to delete.  To further define the scope of what to delete, perform
41   * additional methods as outlined below.
42   * <p>
43   * To delete specific families, execute {@link #deleteFamily(byte[]) deleteFamily}
44   * for each family to delete.
45   * <p>
46   * To delete multiple versions of specific columns, execute
47   * {@link #deleteColumns(byte[], byte[]) deleteColumns}
48   * for each column to delete.
49   * <p>
50   * To delete specific versions of specific columns, execute
51   * {@link #deleteColumn(byte[], byte[], long) deleteColumn}
52   * for each column version to delete.
53   * <p>
54   * Specifying timestamps, deleteFamily and deleteColumns will delete all
55   * versions with a timestamp less than or equal to that passed.  If no
56   * timestamp is specified, an entry is added with a timestamp of 'now'
57   * where 'now' is the servers's System.currentTimeMillis().
58   * Specifying a timestamp to the deleteColumn method will
59   * delete versions only with a timestamp equal to that specified.
60   * If no timestamp is passed to deleteColumn, internally, it figures the
61   * most recent cell's timestamp and adds a delete at that timestamp; i.e.
62   * it deletes the most recently added cell.
63   * <p>The timestamp passed to the constructor is used ONLY for delete of
64   * rows.  For anything less -- a deleteColumn, deleteColumns or
65   * deleteFamily -- then you need to use the method overrides that take a
66   * timestamp.  The constructor timestamp is not referenced.
67   */
68  public class Delete implements Writable, Row, Comparable<Row> {
69    private static final byte DELETE_VERSION = (byte)1;
70  
71    private byte [] row = null;
72    // This ts is only used when doing a deleteRow.  Anything less,
73    private long ts;
74    private long lockId = -1L;
75    private final Map<byte [], List<KeyValue>> familyMap =
76      new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
77  
78    /** Constructor for Writable.  DO NOT USE */
79    public Delete() {
80      this((byte [])null);
81    }
82  
83    /**
84     * Create a Delete operation for the specified row.
85     * <p>
86     * If no further operations are done, this will delete everything
87     * associated with the specified row (all versions of all columns in all
88     * families).
89     * @param row row key
90     */
91    public Delete(byte [] row) {
92      this(row, HConstants.LATEST_TIMESTAMP, null);
93    }
94  
95    /**
96     * Create a Delete operation for the specified row and timestamp, using
97     * an optional row lock.<p>
98     *
99     * If no further operations are done, this will delete all columns in all
100    * families of the specified row with a timestamp less than or equal to the
101    * specified timestamp.<p>
102    *
103    * This timestamp is ONLY used for a delete row operation.  If specifying
104    * families or columns, you must specify each timestamp individually.
105    * @param row row key
106    * @param timestamp maximum version timestamp (only for delete row)
107    * @param rowLock previously acquired row lock, or null
108    */
109   public Delete(byte [] row, long timestamp, RowLock rowLock) {
110     this.row = row;
111     this.ts = timestamp;
112     if (rowLock != null) {
113     	this.lockId = rowLock.getLockId();
114     }
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.lockId = d.getLockId();
124     this.familyMap.putAll(d.getFamilyMap());
125   }
126 
127   public int compareTo(final Row d) {
128     return Bytes.compareTo(this.getRow(), d.getRow());
129   }
130 
131   /**
132    * Method to check if the familyMap is empty
133    * @return true if empty, false otherwise
134    */
135   public boolean isEmpty() {
136     return familyMap.isEmpty();
137   }
138 
139   /**
140    * Delete all versions of all columns of the specified family.
141    * <p>
142    * Overrides previous calls to deleteColumn and deleteColumns for the
143    * specified family.
144    * @param family family name
145    * @return this for invocation chaining
146    */
147   public Delete deleteFamily(byte [] family) {
148     this.deleteFamily(family, HConstants.LATEST_TIMESTAMP);
149     return this;
150   }
151 
152   /**
153    * Delete all columns of the specified family with a timestamp less than
154    * or equal to the specified timestamp.
155    * <p>
156    * Overrides previous calls to deleteColumn and deleteColumns for the
157    * specified family.
158    * @param family family name
159    * @param timestamp maximum version timestamp
160    * @return this for invocation chaining
161    */
162   public Delete deleteFamily(byte [] family, long timestamp) {
163     List<KeyValue> list = familyMap.get(family);
164     if(list == null) {
165       list = new ArrayList<KeyValue>();
166     } else if(!list.isEmpty()) {
167       list.clear();
168     }
169     list.add(new KeyValue(row, family, null, timestamp, KeyValue.Type.DeleteFamily));
170     familyMap.put(family, list);
171     return this;
172   }
173 
174   /**
175    * Delete all versions of the specified column.
176    * @param family family name
177    * @param qualifier column qualifier
178    * @return this for invocation chaining
179    */
180   public Delete deleteColumns(byte [] family, byte [] qualifier) {
181     this.deleteColumns(family, qualifier, HConstants.LATEST_TIMESTAMP);
182     return this;
183   }
184 
185   /**
186    * Delete all versions of the specified column with a timestamp less than
187    * or equal to the specified timestamp.
188    * @param family family name
189    * @param qualifier column qualifier
190    * @param timestamp maximum version timestamp
191    * @return this for invocation chaining
192    */
193   public Delete deleteColumns(byte [] family, byte [] qualifier, long timestamp) {
194     List<KeyValue> list = familyMap.get(family);
195     if (list == null) {
196       list = new ArrayList<KeyValue>();
197     }
198     list.add(new KeyValue(this.row, family, qualifier, timestamp,
199       KeyValue.Type.DeleteColumn));
200     familyMap.put(family, list);
201     return this;
202   }
203 
204   /**
205    * Delete the latest version of the specified column.
206    * This is an expensive call in that on the server-side, it first does a
207    * get to find the latest versions timestamp.  Then it adds a delete using
208    * the fetched cells timestamp.
209    * @param family family name
210    * @param qualifier column qualifier
211    * @return this for invocation chaining
212    */
213   public Delete deleteColumn(byte [] family, byte [] qualifier) {
214     this.deleteColumn(family, qualifier, HConstants.LATEST_TIMESTAMP);
215     return this;
216   }
217 
218   /**
219    * Delete the specified version of the specified column.
220    * @param family family name
221    * @param qualifier column qualifier
222    * @param timestamp version timestamp
223    * @return this for invocation chaining
224    */
225   public Delete deleteColumn(byte [] family, byte [] qualifier, long timestamp) {
226     List<KeyValue> list = familyMap.get(family);
227     if(list == null) {
228       list = new ArrayList<KeyValue>();
229     }
230     list.add(new KeyValue(
231         this.row, family, qualifier, timestamp, KeyValue.Type.Delete));
232     familyMap.put(family, list);
233     return this;
234   }
235 
236   /**
237    * Method for retrieving the delete's familyMap
238    * @return familyMap
239    */
240   public Map<byte [], List<KeyValue>> getFamilyMap() {
241     return this.familyMap;
242   }
243 
244   /**
245    *  Method for retrieving the delete's row
246    * @return row
247    */
248   public byte [] getRow() {
249     return this.row;
250   }
251 
252   /**
253    * Method for retrieving the delete's RowLock
254    * @return RowLock
255    */
256   public RowLock getRowLock() {
257     return new RowLock(this.row, this.lockId);
258   }
259 
260   /**
261    * Method for retrieving the delete's lock ID.
262    *
263    * @return The lock ID.
264    */
265   public long getLockId() {
266 	return this.lockId;
267   }
268 
269   /**
270    * Method for retrieving the delete's timestamp
271    * @return timestamp
272    */
273   public long getTimeStamp() {
274     return this.ts;
275   }
276 
277   /**
278    * Set the timestamp of the delete.
279    * 
280    * @param timestamp
281    */
282   public void setTimestamp(long timestamp) {
283     this.ts = timestamp;
284   }
285 
286   /**
287    * @return string
288    */
289   @Override
290   public String toString() {
291     StringBuilder sb = new StringBuilder();
292     sb.append("row=");
293     sb.append(Bytes.toStringBinary(this.row));
294     sb.append(", ts=");
295     sb.append(this.ts);
296     sb.append(", families={");
297     boolean moreThanOne = false;
298     for(Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
299       if(moreThanOne) {
300         sb.append(", ");
301       } else {
302         moreThanOne = true;
303       }
304       sb.append("(family=");
305       sb.append(Bytes.toString(entry.getKey()));
306       sb.append(", keyvalues=(");
307       boolean moreThanOneB = false;
308       for(KeyValue kv : entry.getValue()) {
309         if(moreThanOneB) {
310           sb.append(", ");
311         } else {
312           moreThanOneB = true;
313         }
314         sb.append(kv.toString());
315       }
316       sb.append(")");
317     }
318     sb.append("}");
319     return sb.toString();
320   }
321 
322   //Writable
323   public void readFields(final DataInput in) throws IOException {
324     int version = in.readByte();
325     if (version > DELETE_VERSION) {
326       throw new IOException("version not supported");
327     }
328     this.row = Bytes.readByteArray(in);
329     this.ts = in.readLong();
330     this.lockId = in.readLong();
331     this.familyMap.clear();
332     int numFamilies = in.readInt();
333     for(int i=0;i<numFamilies;i++) {
334       byte [] family = Bytes.readByteArray(in);
335       int numColumns = in.readInt();
336       List<KeyValue> list = new ArrayList<KeyValue>(numColumns);
337       for(int j=0;j<numColumns;j++) {
338     	KeyValue kv = new KeyValue();
339     	kv.readFields(in);
340     	list.add(kv);
341       }
342       this.familyMap.put(family, list);
343     }
344   }
345 
346   public void write(final DataOutput out) throws IOException {
347     out.writeByte(DELETE_VERSION);
348     Bytes.writeByteArray(out, this.row);
349     out.writeLong(this.ts);
350     out.writeLong(this.lockId);
351     out.writeInt(familyMap.size());
352     for(Map.Entry<byte [], List<KeyValue>> entry : familyMap.entrySet()) {
353       Bytes.writeByteArray(out, entry.getKey());
354       List<KeyValue> list = entry.getValue();
355       out.writeInt(list.size());
356       for(KeyValue kv : list) {
357         kv.write(out);
358       }
359     }
360   }
361 
362   /**
363    * Delete all versions of the specified column, given in
364    * <code>family:qualifier</code> notation, and with a timestamp less than
365    * or equal to the specified timestamp.
366    * @param column colon-delimited family and qualifier
367    * @param timestamp maximum version timestamp
368    * @deprecated use {@link #deleteColumn(byte[], byte[], long)} instead
369    * @return this for invocation chaining
370    */
371   public Delete deleteColumns(byte [] column, long timestamp) {
372     byte [][] parts = KeyValue.parseColumn(column);
373     this.deleteColumns(parts[0], parts[1], timestamp);
374     return this;
375   }
376 
377   /**
378    * Delete the latest version of the specified column, given in
379    * <code>family:qualifier</code> notation.
380    * @param column colon-delimited family and qualifier
381    * @deprecated use {@link #deleteColumn(byte[], byte[])} instead
382    * @return this for invocation chaining
383    */
384   public Delete deleteColumn(byte [] column) {
385     byte [][] parts = KeyValue.parseColumn(column);
386     this.deleteColumn(parts[0], parts[1], HConstants.LATEST_TIMESTAMP);
387     return this;
388   }
389 
390 
391 }