| /* |
| * Copyright 2010 The Apache Software Foundation |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.hadoop.hbase.client; |
| |
| import org.apache.hadoop.hbase.HConstants; |
| import org.apache.hadoop.hbase.KeyValue; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.apache.hadoop.io.Writable; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| /** |
| * Used to perform Delete operations on a single row. |
| * <p> |
| * To delete an entire row, instantiate a Delete object with the row |
| * to delete. To further define the scope of what to delete, perform |
| * additional methods as outlined below. |
| * <p> |
| * To delete specific families, execute {@link #deleteFamily(byte[]) deleteFamily} |
| * for each family to delete. |
| * <p> |
| * To delete multiple versions of specific columns, execute |
| * {@link #deleteColumns(byte[], byte[]) deleteColumns} |
| * for each column to delete. |
| * <p> |
| * To delete specific versions of specific columns, execute |
| * {@link #deleteColumn(byte[], byte[], long) deleteColumn} |
| * for each column version to delete. |
| * <p> |
| * Specifying timestamps, deleteFamily and deleteColumns will delete all |
| * versions with a timestamp less than or equal to that passed. If no |
| * timestamp is specified, an entry is added with a timestamp of 'now' |
| * where 'now' is the servers's System.currentTimeMillis(). |
| * Specifying a timestamp to the deleteColumn method will |
| * delete versions only with a timestamp equal to that specified. |
| * If no timestamp is passed to deleteColumn, internally, it figures the |
| * most recent cell's timestamp and adds a delete at that timestamp; i.e. |
| * it deletes the most recently added cell. |
| * <p>The timestamp passed to the constructor is used ONLY for delete of |
| * rows. For anything less -- a deleteColumn, deleteColumns or |
| * deleteFamily -- then you need to use the method overrides that take a |
| * timestamp. The constructor timestamp is not referenced. |
| */ |
| public class Delete implements Writable, Row, Comparable<Row> { |
| private static final byte DELETE_VERSION = (byte)1; |
| |
| private byte [] row = null; |
| // This ts is only used when doing a deleteRow. Anything less, |
| private long ts; |
| private long lockId = -1L; |
| private final Map<byte [], List<KeyValue>> familyMap = |
| new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR); |
| |
| /** Constructor for Writable. DO NOT USE */ |
| public Delete() { |
| this((byte [])null); |
| } |
| |
| /** |
| * Create a Delete operation for the specified row. |
| * <p> |
| * If no further operations are done, this will delete everything |
| * associated with the specified row (all versions of all columns in all |
| * families). |
| * @param row row key |
| */ |
| public Delete(byte [] row) { |
| this(row, HConstants.LATEST_TIMESTAMP, null); |
| } |
| |
| /** |
| * Create a Delete operation for the specified row and timestamp, using |
| * an optional row lock.<p> |
| * |
| * If no further operations are done, this will delete all columns in all |
| * families of the specified row with a timestamp less than or equal to the |
| * specified timestamp.<p> |
| * |
| * This timestamp is ONLY used for a delete row operation. If specifying |
| * families or columns, you must specify each timestamp individually. |
| * @param row row key |
| * @param timestamp maximum version timestamp (only for delete row) |
| * @param rowLock previously acquired row lock, or null |
| */ |
| public Delete(byte [] row, long timestamp, RowLock rowLock) { |
| this.row = row; |
| this.ts = timestamp; |
| if (rowLock != null) { |
| this.lockId = rowLock.getLockId(); |
| } |
| } |
| |
| /** |
| * @param d Delete to clone. |
| */ |
| public Delete(final Delete d) { |
| this.row = d.getRow(); |
| this.ts = d.getTimeStamp(); |
| this.lockId = d.getLockId(); |
| this.familyMap.putAll(d.getFamilyMap()); |
| } |
| |
| public int compareTo(final Row d) { |
| return Bytes.compareTo(this.getRow(), d.getRow()); |
| } |
| |
| /** |
| * Method to check if the familyMap is empty |
| * @return true if empty, false otherwise |
| */ |
| public boolean isEmpty() { |
| return familyMap.isEmpty(); |
| } |
| |
| /** |
| * Delete all versions of all columns of the specified family. |
| * <p> |
| * Overrides previous calls to deleteColumn and deleteColumns for the |
| * specified family. |
| * @param family family name |
| * @return this for invocation chaining |
| */ |
| public Delete deleteFamily(byte [] family) { |
| this.deleteFamily(family, HConstants.LATEST_TIMESTAMP); |
| return this; |
| } |
| |
| /** |
| * Delete all columns of the specified family with a timestamp less than |
| * or equal to the specified timestamp. |
| * <p> |
| * Overrides previous calls to deleteColumn and deleteColumns for the |
| * specified family. |
| * @param family family name |
| * @param timestamp maximum version timestamp |
| * @return this for invocation chaining |
| */ |
| public Delete deleteFamily(byte [] family, long timestamp) { |
| List<KeyValue> list = familyMap.get(family); |
| if(list == null) { |
| list = new ArrayList<KeyValue>(); |
| } else if(!list.isEmpty()) { |
| list.clear(); |
| } |
| list.add(new KeyValue(row, family, null, timestamp, KeyValue.Type.DeleteFamily)); |
| familyMap.put(family, list); |
| return this; |
| } |
| |
| /** |
| * Delete all versions of the specified column. |
| * @param family family name |
| * @param qualifier column qualifier |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumns(byte [] family, byte [] qualifier) { |
| this.deleteColumns(family, qualifier, HConstants.LATEST_TIMESTAMP); |
| return this; |
| } |
| |
| /** |
| * Delete all versions of the specified column with a timestamp less than |
| * or equal to the specified timestamp. |
| * @param family family name |
| * @param qualifier column qualifier |
| * @param timestamp maximum version timestamp |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumns(byte [] family, byte [] qualifier, long timestamp) { |
| List<KeyValue> list = familyMap.get(family); |
| if (list == null) { |
| list = new ArrayList<KeyValue>(); |
| } |
| list.add(new KeyValue(this.row, family, qualifier, timestamp, |
| KeyValue.Type.DeleteColumn)); |
| familyMap.put(family, list); |
| return this; |
| } |
| |
| /** |
| * Delete the latest version of the specified column. |
| * This is an expensive call in that on the server-side, it first does a |
| * get to find the latest versions timestamp. Then it adds a delete using |
| * the fetched cells timestamp. |
| * @param family family name |
| * @param qualifier column qualifier |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumn(byte [] family, byte [] qualifier) { |
| this.deleteColumn(family, qualifier, HConstants.LATEST_TIMESTAMP); |
| return this; |
| } |
| |
| /** |
| * Delete the specified version of the specified column. |
| * @param family family name |
| * @param qualifier column qualifier |
| * @param timestamp version timestamp |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumn(byte [] family, byte [] qualifier, long timestamp) { |
| List<KeyValue> list = familyMap.get(family); |
| if(list == null) { |
| list = new ArrayList<KeyValue>(); |
| } |
| list.add(new KeyValue( |
| this.row, family, qualifier, timestamp, KeyValue.Type.Delete)); |
| familyMap.put(family, list); |
| return this; |
| } |
| |
| /** |
| * Method for retrieving the delete's familyMap |
| * @return familyMap |
| */ |
| public Map<byte [], List<KeyValue>> getFamilyMap() { |
| return this.familyMap; |
| } |
| |
| /** |
| * Method for retrieving the delete's row |
| * @return row |
| */ |
| public byte [] getRow() { |
| return this.row; |
| } |
| |
| /** |
| * Method for retrieving the delete's RowLock |
| * @return RowLock |
| */ |
| public RowLock getRowLock() { |
| return new RowLock(this.row, this.lockId); |
| } |
| |
| /** |
| * Method for retrieving the delete's lock ID. |
| * |
| * @return The lock ID. |
| */ |
| public long getLockId() { |
| return this.lockId; |
| } |
| |
| /** |
| * Method for retrieving the delete's timestamp |
| * @return timestamp |
| */ |
| public long getTimeStamp() { |
| return this.ts; |
| } |
| |
| /** |
| * Set the timestamp of the delete. |
| * |
| * @param timestamp |
| */ |
| public void setTimestamp(long timestamp) { |
| this.ts = timestamp; |
| } |
| |
| /** |
| * @return string |
| */ |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("row="); |
| sb.append(Bytes.toString(this.row)); |
| sb.append(", ts="); |
| sb.append(this.ts); |
| sb.append(", families={"); |
| boolean moreThanOne = false; |
| for(Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) { |
| if(moreThanOne) { |
| sb.append(", "); |
| } else { |
| moreThanOne = true; |
| } |
| sb.append("(family="); |
| sb.append(Bytes.toString(entry.getKey())); |
| sb.append(", keyvalues=("); |
| boolean moreThanOneB = false; |
| for(KeyValue kv : entry.getValue()) { |
| if(moreThanOneB) { |
| sb.append(", "); |
| } else { |
| moreThanOneB = true; |
| } |
| sb.append(kv.toString()); |
| } |
| sb.append(")"); |
| } |
| sb.append("}"); |
| return sb.toString(); |
| } |
| |
| //Writable |
| public void readFields(final DataInput in) throws IOException { |
| int version = in.readByte(); |
| if (version > DELETE_VERSION) { |
| throw new IOException("version not supported"); |
| } |
| this.row = Bytes.readByteArray(in); |
| this.ts = in.readLong(); |
| this.lockId = in.readLong(); |
| this.familyMap.clear(); |
| int numFamilies = in.readInt(); |
| for(int i=0;i<numFamilies;i++) { |
| byte [] family = Bytes.readByteArray(in); |
| int numColumns = in.readInt(); |
| List<KeyValue> list = new ArrayList<KeyValue>(numColumns); |
| for(int j=0;j<numColumns;j++) { |
| KeyValue kv = new KeyValue(); |
| kv.readFields(in); |
| list.add(kv); |
| } |
| this.familyMap.put(family, list); |
| } |
| } |
| |
| public void write(final DataOutput out) throws IOException { |
| out.writeByte(DELETE_VERSION); |
| Bytes.writeByteArray(out, this.row); |
| out.writeLong(this.ts); |
| out.writeLong(this.lockId); |
| out.writeInt(familyMap.size()); |
| for(Map.Entry<byte [], List<KeyValue>> entry : familyMap.entrySet()) { |
| Bytes.writeByteArray(out, entry.getKey()); |
| List<KeyValue> list = entry.getValue(); |
| out.writeInt(list.size()); |
| for(KeyValue kv : list) { |
| kv.write(out); |
| } |
| } |
| } |
| |
| /** |
| * Delete all versions of the specified column, given in |
| * <code>family:qualifier</code> notation, and with a timestamp less than |
| * or equal to the specified timestamp. |
| * @param column colon-delimited family and qualifier |
| * @param timestamp maximum version timestamp |
| * @deprecated use {@link #deleteColumn(byte[], byte[], long)} instead |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumns(byte [] column, long timestamp) { |
| byte [][] parts = KeyValue.parseColumn(column); |
| this.deleteColumns(parts[0], parts[1], timestamp); |
| return this; |
| } |
| |
| /** |
| * Delete the latest version of the specified column, given in |
| * <code>family:qualifier</code> notation. |
| * @param column colon-delimited family and qualifier |
| * @deprecated use {@link #deleteColumn(byte[], byte[])} instead |
| * @return this for invocation chaining |
| */ |
| public Delete deleteColumn(byte [] column) { |
| byte [][] parts = KeyValue.parseColumn(column); |
| this.deleteColumn(parts[0], parts[1], HConstants.LATEST_TIMESTAMP); |
| return this; |
| } |
| |
| |
| } |