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 }