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