org.hbase.async.DeleteRequest Maven / Gradle / Ivy
Show all versions of asynchbase Show documentation
/*
* Copyright (C) 2010-2012 The Async HBase Authors. All rights reserved.
* This file is part of Async HBase.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the StumbleUpon nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.hbase.async;
import org.jboss.netty.buffer.ChannelBuffer;
import org.hbase.async.generated.ClientPB.MutateRequest;
import org.hbase.async.generated.ClientPB.MutateResponse;
import org.hbase.async.generated.ClientPB.MutationProto;
/**
* Deletes some data into HBase.
*
* A note on passing {@code byte} arrays in argument
* None of the method that receive a {@code byte[]} in argument will copy it.
* For more info, please refer to the documentation of {@link HBaseRpc}.
* A note on passing {@code String}s in argument
* All strings are assumed to use the platform's default charset.
* A note on passing {@code timestamp}s in argument
* Irrespective of the order in which you send RPCs, a {@code DeleteRequest}
* that is created with a specific timestamp in argument will only delete
* values in HBase that were previously stored with a timestamp less than
* or equal to that of the {@code DeleteRequest} unless
* {@link #setDeleteAtTimestampOnly} is also called, in which case only the
* value at the specified timestamp is deleted.
*/
public final class DeleteRequest extends BatchableRpc
implements HBaseRpc.HasTable, HBaseRpc.HasKey,
HBaseRpc.HasFamily, HBaseRpc.HasQualifiers, HBaseRpc.IsEdit {
private static final byte[] DELETE = new byte[] {
'd', 'e', 'l', 'e', 't', 'e'
};
/** Code type used for serialized `Delete' objects. */
static final byte CODE = 31;
/** Special value for {@link #qualifiers} when deleting a whole family. */
private static final byte[][] DELETE_FAMILY_MARKER =
new byte[][] { HBaseClient.EMPTY_ARRAY };
/** Special value for {@link #family} when deleting a whole row. */
static final byte[] WHOLE_ROW = new byte[0];
private final byte[][] qualifiers;
/** Whether to delete the value only at the specified timestamp. */
private boolean at_timestamp_only = false;
/**
* Constructor to delete an entire row.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final byte[] table, final byte[] key) {
this(table, key, null, null, KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete an entire row before a specific timestamp.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param timestamp The timestamp to set on this edit.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table, final byte[] key,
final long timestamp) {
this(table, key, null, null, timestamp, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific family.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.1
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family) {
this(table, key, family, null, KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific family before a specific timestamp.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param timestamp The timestamp to set on this edit.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final long timestamp) {
this(table, key, family, null, timestamp, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* Can be {@code null} since version 1.1.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[] qualifier) {
this(table, key, family,
qualifier == null ? null : new byte[][] { qualifier },
KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell before a specific timestamp.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* Can be {@code null}, to delete the whole family.
* @param timestamp The timestamp to set on this edit.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[] qualifier,
final long timestamp) {
this(table, key, family,
qualifier == null ? null : new byte[][] { qualifier },
timestamp, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific number of cells in a row.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifiers The column qualifiers to delete in that family.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.1
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[][] qualifiers) {
this(table, key, family, qualifiers,
KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific number of cells in a row.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifiers The column qualifiers to delete in that family.
* @param timestamp The timestamp to set on this edit.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[][] qualifiers,
final long timestamp) {
this(table, key, family, qualifiers, timestamp, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell with an explicit row lock.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* @param lock An explicit row lock to use with this request.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[] qualifier,
final RowLock lock) {
this(table, key, family,
qualifier == null ? null : new byte[][] { qualifier },
KeyValue.TIMESTAMP_NOW, lock.id());
}
/**
* Constructor to delete a specific cell with an explicit row lock.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* @param timestamp The timestamp to set on this edit.
* @param lock An explicit row lock to use with this request.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[] qualifier,
final long timestamp,
final RowLock lock) {
this(table, key, family,
qualifier == null ? null : new byte[][] { qualifier },
timestamp, lock.id());
}
/**
* Constructor to delete a specific number of cells in a row.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifiers The column qualifiers to delete in that family.
* Can be {@code null}.
* @param lock An explicit row lock to use with this request.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.1
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[][] qualifiers,
final RowLock lock) {
this(table, key, family, qualifiers, KeyValue.TIMESTAMP_NOW, lock.id());
}
/**
* Constructor to delete a specific number of cells in a row with a row lock.
* These byte arrays will NOT be copied.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifiers The column qualifiers to delete in that family.
* Can be {@code null}.
* @param timestamp The timestamp to set on this edit.
* @param lock An explicit row lock to use with this request.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[][] qualifiers,
final long timestamp,
final RowLock lock) {
this(table, key, family, qualifiers, timestamp, lock.id());
}
/**
* Constructor to delete an entire row.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final String table, final String key) {
this(table.getBytes(), key.getBytes(), null, null,
KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific family.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @throws IllegalArgumentException if any argument is malformed.
* @since 1.1
*/
public DeleteRequest(final String table,
final String key,
final String family) {
this(table.getBytes(), key.getBytes(), family.getBytes(), null,
KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* Can be {@code null} since version 1.1.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final String table,
final String key,
final String family,
final String qualifier) {
this(table.getBytes(), key.getBytes(), family.getBytes(),
qualifier == null ? null : new byte[][] { qualifier.getBytes() },
KeyValue.TIMESTAMP_NOW, RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell with an explicit row lock.
* @param table The table to edit.
* @param key The key of the row to edit in that table.
* @param family The column family to edit in that table.
* @param qualifier The column qualifier to delete in that family.
* Can be {@code null} since version 1.1.
* @param lock An explicit row lock to use with this request.
* @throws IllegalArgumentException if any argument is malformed.
*/
public DeleteRequest(final String table,
final String key,
final String family,
final String qualifier,
final RowLock lock) {
this(table.getBytes(), key.getBytes(), family.getBytes(),
qualifier == null ? null : new byte[][] { qualifier.getBytes() },
KeyValue.TIMESTAMP_NOW, lock.id());
}
/**
* Constructor to delete a specific cell.
* @param table The table to edit.
* @param kv The specific {@link KeyValue} to delete. Note that if this
* {@link KeyValue} specifies a timestamp, then this specific timestamp only
* will be deleted.
* @since 1.2
*/
public DeleteRequest(final byte[] table, final KeyValue kv) {
this(table, kv.key(), kv.family(), new byte[][] { kv.qualifier() },
kv.timestamp(), RowLock.NO_LOCK);
}
/**
* Constructor to delete a specific cell with an explicit row lock.
* @param table The table to edit.
* @param kv The specific {@link KeyValue} to delete. Note that if this
* {@link KeyValue} specifies a timestamp, then this specific timestamp only
* will be deleted.
* @param lock An explicit row lock to use with this request.
* @since 1.2
*/
public DeleteRequest(final byte[] table,
final KeyValue kv,
final RowLock lock) {
this(table, kv.key(), kv.family(), new byte[][] { kv.qualifier() },
kv.timestamp(), lock.id());
}
/** Private constructor. */
private DeleteRequest(final byte[] table,
final byte[] key,
final byte[] family,
final byte[][] qualifiers,
final long timestamp,
final long lockid) {
super(table, key, family == null ? WHOLE_ROW : family, timestamp, lockid);
if (family != null) {
KeyValue.checkFamily(family);
}
if (qualifiers != null) {
if (family == null) {
throw new IllegalArgumentException("You can't delete specific qualifiers"
+ " without specifying which family they belong to."
+ " table=" + Bytes.pretty(table)
+ ", key=" + Bytes.pretty(key));
}
if (qualifiers.length == 0) {
throw new IllegalArgumentException("Don't pass an empty list of"
+ " qualifiers, this would delete the entire row of table="
+ Bytes.pretty(table) + " at key " + Bytes.pretty(key));
}
for (final byte[] qualifier : qualifiers) {
KeyValue.checkQualifier(qualifier);
}
this.qualifiers = qualifiers;
} else {
// No specific qualifier to delete: delete the entire family. Not that
// if `family == null', we'll delete the whole row anyway.
this.qualifiers = DELETE_FAMILY_MARKER;
}
}
/**
* Deletes only the cell value with the timestamp specified in the
* constructor.
*
* Only applicable when qualifier(s) is also specified.
* @since 1.5
*/
public void setDeleteAtTimestampOnly(final boolean at_timestamp_only) {
this.at_timestamp_only = at_timestamp_only;
}
/**
* Returns whether to only delete the cell value at the timestamp.
* @since 1.5
*/
public boolean deleteAtTimestampOnly() {
return at_timestamp_only;
}
@Override
byte[] method(final byte server_version) {
return (server_version >= RegionClient.SERVER_VERSION_095_OR_ABOVE
? MUTATE
: DELETE);
}
@Override
public byte[] table() {
return table;
}
@Override
public byte[] key() {
return key;
}
@Override
public byte[][] qualifiers() {
return qualifiers;
}
public String toString() {
return super.toStringWithQualifiers("DeleteRequest", family, qualifiers);
}
// ---------------------- //
// Package private stuff. //
// ---------------------- //
@Override
byte version(final byte unused_server_version) {
// Versions are:
// 1: Before 0.92.0. This method only gets called for 0.92 and above.
// 2: HBASE-3921 in 0.92.0 added "attributes" at the end.
// 3: HBASE-3961 in 0.92.0 allowed skipping the WAL.
return 3; // 3 because we allow skipping the WAL.
}
@Override
byte code() {
return CODE;
}
@Override
int numKeyValues() {
return qualifiers.length;
}
@Override
void serializePayload(final ChannelBuffer buf) {
if (family == null) {
return; // No payload when deleting whole rows.
}
// Are we deleting a whole family at once or just a bunch of columns?
final byte type = (qualifiers == DELETE_FAMILY_MARKER
? KeyValue.DELETE_FAMILY
: (at_timestamp_only
? KeyValue.DELETE
: KeyValue.DELETE_COLUMN));
// Write the KeyValues
for (final byte[] qualifier : qualifiers) {
KeyValue.serialize(buf, type, timestamp,
key, family, qualifier, null);
}
}
/**
* Predicts a lower bound on the serialized size of this RPC.
* This is to avoid using a dynamic buffer, to avoid re-sizing the buffer.
* Since we use a static buffer, if the prediction is wrong and turns out
* to be less than what we need, there will be an exception which will
* prevent the RPC from being serialized. That'd be a severe bug.
*/
private int predictSerializedSize() {
int size = 0;
size += 4; // int: Number of parameters.
size += 1; // byte: Type of the 1st parameter.
size += 3; // vint: region name length (3 bytes => max length = 32768).
size += region.name().length; // The region name.
size += 1; // byte: Type of the 2nd parameter.
size += 1; // byte: Type again (see HBASE-2877).
size += 1; // byte: Version of Delete.
size += 3; // vint: row key length (3 bytes => max length = 32768).
size += key.length; // The row key.
size += 8; // long: Timestamp.
size += 8; // long: Lock ID.
size += 4; // int: Number of families.
size += 1; // vint: Family length (guaranteed on 1 byte).
if (family == null) {
return size;
}
size += family.length; // The column family.
size += 4; // int: Number of KeyValues for this family.
return size + payloadSize();
}
/** Returns the serialized size of all the {@link KeyValue}s in this RPC. */
@Override
int payloadSize() {
if (family == WHOLE_ROW) {
return 0; // No payload when deleting whole rows.
}
int size = 0;
size += 4; // int: Total length of the whole KeyValue.
size += 4; // int: Total length of the key part of the KeyValue.
size += 4; // int: Length of the value part of the KeyValue.
size += 2; // short:Length of the key.
size += key.length; // The row key (again!).
size += 1; // byte: Family length (again!).
size += family.length; // The column family (again!).
size += 8; // long: The timestamp (again!).
size += 1; // byte: The type of KeyValue.
size *= qualifiers.length;
for (final byte[] qualifier : qualifiers) {
size += qualifier.length; // The column qualifier.
}
return size;
}
@Override
MutationProto toMutationProto() {
final MutationProto.Builder del = MutationProto.newBuilder()
.setRow(Bytes.wrap(key))
.setMutateType(MutationProto.MutationType.DELETE);
if (family != WHOLE_ROW) {
final MutationProto.ColumnValue.Builder columns = // All columns ...
MutationProto.ColumnValue.newBuilder()
.setFamily(Bytes.wrap(family)); // ... for this family.
final MutationProto.DeleteType type =
(qualifiers == DELETE_FAMILY_MARKER
? MutationProto.DeleteType.DELETE_FAMILY
: (at_timestamp_only
? MutationProto.DeleteType.DELETE_ONE_VERSION
: MutationProto.DeleteType.DELETE_MULTIPLE_VERSIONS));
// Now add all the qualifiers to delete.
for (int i = 0; i < qualifiers.length; i++) {
final MutationProto.ColumnValue.QualifierValue column =
MutationProto.ColumnValue.QualifierValue.newBuilder()
.setQualifier(Bytes.wrap(qualifiers[i]))
.setTimestamp(timestamp)
.setDeleteType(type)
.build();
columns.addQualifierValue(column);
}
del.addColumnValue(columns);
}
if (!durable) {
del.setDurability(MutationProto.Durability.SKIP_WAL);
}
return del.build();
}
/** Serializes this request. */
ChannelBuffer serialize(final byte server_version) {
if (server_version < RegionClient.SERVER_VERSION_095_OR_ABOVE) {
return serializeOld(server_version);
}
final MutateRequest req = MutateRequest.newBuilder()
.setRegion(region.toProtobuf())
.setMutation(toMutationProto())
.build();
return toChannelBuffer(MUTATE, req);
}
/** Serializes this request for HBase 0.94 and before. */
private ChannelBuffer serializeOld(final byte server_version) {
final ChannelBuffer buf = newBuffer(server_version,
predictSerializedSize());
buf.writeInt(2); // Number of parameters.
// 1st param: byte array containing region name
writeHBaseByteArray(buf, region.name());
// 2nd param: Delete object.
buf.writeByte(CODE); // Code for a `Delete' parameter.
buf.writeByte(CODE); // Code again (see HBASE-2877).
buf.writeByte(1); // Delete#DELETE_VERSION. Stick to v1 here for now.
writeByteArray(buf, key);
buf.writeLong(timestamp); // Maximum timestamp.
buf.writeLong(lockid); // Lock ID.
// Families.
if (family == WHOLE_ROW) {
buf.writeInt(0); // Number of families that follow.
return buf;
}
buf.writeInt(1); // Number of families that follow.
// Each family is then written like so:
writeByteArray(buf, family); // Column family name.
buf.writeInt(qualifiers.length); // How many KeyValues for this family?
serializePayload(buf);
return buf;
}
@Override
Object deserialize(final ChannelBuffer buf, int cell_size) {
HBaseRpc.ensureNoCell(cell_size);
final MutateResponse resp = readProtobuf(buf, MutateResponse.PARSER);
return null;
}
}