Package org.hbase.async

Source Code of org.hbase.async.AtomicIncrementRequest

/*
* 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 java.util.ArrayList;

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;

/**
* Atomically increments a value in HBase.
*
* <h1>A note on passing {@code byte} arrays in argument</h1>
* 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}.
* <h1>A note on passing {@code String}s in argument</h1>
* All strings are assumed to use the platform's default charset.
*/
public final class AtomicIncrementRequest extends HBaseRpc
  implements HBaseRpc.HasTable, HBaseRpc.HasKey,
             HBaseRpc.HasFamily, HBaseRpc.HasQualifier, HBaseRpc.IsEdit {

  private static final byte[] INCREMENT_COLUMN_VALUE = new byte[] {
    'i', 'n', 'c', 'r', 'e', 'm', 'e', 'n', 't',
    'C', 'o', 'l', 'u', 'm', 'n',
    'V', 'a', 'l', 'u', 'e'
  };

  private final byte[] family;
  private final byte[] qualifier;
  private long amount;
  private boolean durable = true;

  /**
   * Constructor.
   * <strong>These byte arrays will NOT be copied.</strong>
   * @param table The non-empty name of the table to use.
   * @param key The row key of the value to increment.
   * @param family The column family of the value to increment.
   * @param qualifier The column qualifier of the value to increment.
   * @param amount Amount by which to increment the value in HBase.
   * If negative, the value in HBase will be decremented.
   */
  public AtomicIncrementRequest(final byte[] table,
                                final byte[] key,
                                final byte[] family,
                                final byte[] qualifier,
                                final long amount) {
    super(table, key);
    KeyValue.checkFamily(family);
    KeyValue.checkQualifier(qualifier);
    this.family = family;
    this.qualifier = qualifier;
    this.amount = amount;
  }

  /**
   * Constructor.  This is equivalent to:
   * {@link #AtomicIncrementRequest(byte[], byte[], byte[], byte[], long)
   * AtomicIncrementRequest}{@code (table, key, family, qualifier, 1)}
   * <p>
   * <strong>These byte arrays will NOT be copied.</strong>
   * @param table The non-empty name of the table to use.
   * @param key The row key of the value to increment.
   * @param family The column family of the value to increment.
   * @param qualifier The column qualifier of the value to increment.
   */
  public AtomicIncrementRequest(final byte[] table,
                                final byte[] key,
                                final byte[] family,
                                final byte[] qualifier) {
    this(table, key, family, qualifier, 1);
  }

  /**
   * Constructor.
   * All strings are assumed to use the platform's default charset.
   * @param table The non-empty name of the table to use.
   * @param key The row key of the value to increment.
   * @param family The column family of the value to increment.
   * @param qualifier The column qualifier of the value to increment.
   * @param amount Amount by which to increment the value in HBase.
   * If negative, the value in HBase will be decremented.
   */
  public AtomicIncrementRequest(final String table,
                                final String key,
                                final String family,
                                final String qualifier,
                                final long amount) {
    this(table.getBytes(), key.getBytes(), family.getBytes(),
         qualifier.getBytes(), amount);
  }

  /**
   * Constructor.  This is equivalent to:
   * All strings are assumed to use the platform's default charset.
   * {@link #AtomicIncrementRequest(String, String, String, String, long)
   * AtomicIncrementRequest}{@code (table, key, family, qualifier, 1)}
   * @param table The non-empty name of the table to use.
   * @param key The row key of the value to increment.
   * @param family The column family of the value to increment.
   * @param qualifier The column qualifier of the value to increment.
   */
  public AtomicIncrementRequest(final String table,
                                final String key,
                                final String family,
                                final String qualifier) {
    this(table.getBytes(), key.getBytes(), family.getBytes(),
         qualifier.getBytes(), 1);
  }

  /**
   * Returns the amount by which the value is going to be incremented.
   */
  public long getAmount() {
    return amount;
  }

  /**
   * Changes the amount by which the value is going to be incremented.
   * @param amount The new amount.  If negative, the value will be decremented.
   */
  public void setAmount(final long amount) {
    this.amount = amount;
  }

  @Override
  byte[] method(final byte server_version) {
    return (server_version >= RegionClient.SERVER_VERSION_095_OR_ABOVE
            ? MUTATE
            : INCREMENT_COLUMN_VALUE);
  }

  @Override
  public byte[] table() {
    return table;
  }

  @Override
  public byte[] key() {
    return key;
  }

  @Override
  public byte[] family() {
    return family;
  }

  @Override
  public byte[] qualifier() {
    return qualifier;
  }

  public String toString() {
    return super.toStringWithQualifier("AtomicIncrementRequest",
                                       family, qualifier,
                                       ", amount=" + amount);
  }

  // ---------------------- //
  // Package private stuff. //
  // ---------------------- //

  /**
   * Changes whether or not this atomic increment should use the WAL.
   * @param durable {@code true} to use the WAL, {@code false} otherwise.
   */
  void setDurable(final boolean durable) {
    this.durable = durable;
  }

  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 += 3// vint: row key length (3 bytes => max length = 32768).
    size += key.length;  // The row key.
    size += 1// byte: Type of the 3rd parameter.
    size += 1// vint: Family length (guaranteed on 1 byte).
    size += family.length;  // The family.
    size += 1// byte: Type of the 4th parameter.
    size += 3// vint: Qualifier length.
    size += qualifier.length;  // The qualifier.
    size += 1// byte: Type of the 5th parameter.
    size += 8// long: Amount.
    size += 1// byte: Type of the 6th parameter.
    size += 1// bool: Whether or not to write to the WAL.
    return size;
  }

  /** Serializes this request.  */
  ChannelBuffer serialize(final byte server_version) {
    if (server_version < RegionClient.SERVER_VERSION_095_OR_ABOVE) {
      return serializeOld(server_version);
    }
    final MutationProto.ColumnValue.QualifierValue qualifier =
      MutationProto.ColumnValue.QualifierValue.newBuilder()
      .setQualifier(Bytes.wrap(this.qualifier))
      .setValue(Bytes.wrap(Bytes.fromLong(amount)))
      .build();
    final MutationProto.ColumnValue column =
      MutationProto.ColumnValue.newBuilder()
      .setFamily(Bytes.wrap(family))
      .addQualifierValue(qualifier)
      .build();
    final MutationProto.Builder incr = MutationProto.newBuilder()
      .setRow(Bytes.wrap(key))
      .setMutateType(MutationProto.MutationType.INCREMENT)
      .addColumnValue(column);
    if (!durable) {
      incr.setDurability(MutationProto.Durability.SKIP_WAL);
    }
    final MutateRequest req = MutateRequest.newBuilder()
      .setRegion(region.toProtobuf())
      .setMutation(incr.build())
      .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(6)// Number of parameters.

    writeHBaseByteArray(buf, region.name());
    writeHBaseByteArray(buf, key);
    writeHBaseByteArray(buf, family);
    writeHBaseByteArray(buf, qualifier);
    writeHBaseLong(buf, amount);
    writeHBaseBool(buf, durable);

    return buf;
  }

  @Override
  Object deserialize(final ChannelBuffer buf, int cell_size) {
    final MutateResponse resp = readProtobuf(buf, MutateResponse.PARSER);
    // An increment must always produce a result, so we shouldn't need to
    // check whether the `result' field is set here.
    final ArrayList<KeyValue> kvs = GetRequest.convertResult(resp.getResult(),
                                                             buf, cell_size);
    if (kvs.size() != 1) {
      throw new InvalidResponseException("Atomic increment returned "
        + kvs.size() + " KeyValue(s), but we expected exactly one. kvs="
        + kvs, resp);
    }
    return Bytes.getLong(kvs.get(0).value());
  }

}
TOP

Related Classes of org.hbase.async.AtomicIncrementRequest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.