Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.io.IOException;
import java.util.concurrent.TimeUnit;
import com.google.protobuf.AbstractMessageLite;
import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Parser;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.util.CharsetUtil;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.stumbleupon.async.Deferred;
/**
* Abstract base class for all RPC requests going out to HBase.
*
* Implementations of this class are not expected to be synchronized.
*
*
A note on passing {@code byte} arrays in argument
* None of the method that receive a {@code byte[]} in argument will copy it.
* If you change the contents of any byte array you give to an instance of
* this class, you may affect the behavior of the request in an
* unpredictable way. If you need to change the byte array,
* {@link Object#clone() clone} it before giving it to this class. For those
* familiar with the term "defensive copy", we don't do it in order to avoid
* unnecessary memory copies when you know you won't be changing (or event
* holding a reference to) the byte array, which is frequently the case.
*/
public abstract class HBaseRpc {
private static final Logger LOG = LoggerFactory.getLogger(HBaseRpc.class);
/**
* An RPC from which you can get a table name.
* @since 1.1
*/
public interface HasTable {
/**
* Returns the name of the table this RPC is for.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the name of the table this RPC is for.
*/
public byte[] table();
}
/**
* An RPC from which you can get a row key name.
* @since 1.1
*/
public interface HasKey {
/**
* Returns the row key this RPC is for.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the row key this RPC is for.
*/
public byte[] key();
}
/**
* An RPC from which you can get a family name.
* @since 1.1
*/
public interface HasFamily {
/**
* Returns the family this RPC is for.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the family this RPC is for.
*/
public byte[] family();
}
/**
* An RPC from which you can get a column qualifier name.
* @since 1.1
*/
public interface HasQualifier {
/**
* Returns the column qualifier this RPC is for.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the column qualifier this RPC is for.
*/
public byte[] qualifier();
}
/**
* An RPC from which you can get multiple column qualifier names.
* @since 1.1
*/
public interface HasQualifiers {
/**
* Returns the column qualifiers this RPC is for.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the column qualifiers this RPC is for.
*/
public byte[][] qualifiers();
}
/**
* An RPC from which you can get a value.
* @since 1.1
*/
public interface HasValue {
/**
* Returns the value contained in this RPC.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the value contained in this RPC.
*/
public byte[] value();
}
/**
* An RPC from which you can get multiple values.
* @since 1.3
*/
public interface HasValues {
/**
* Returns the values contained in this RPC.
*
* DO NOT MODIFY THE CONTENTS OF THE ARRAY RETURNED.
* @return the values contained in this RPC.
*/
public byte[][] values();
}
/**
* An RPC from which you can get a timestamp.
* @since 1.2
*/
public interface HasTimestamp {
/**
* Returns the strictly positive timestamp contained in this RPC.
* @return the strictly positive timestamp contained in this RPC.
*/
public long timestamp();
}
/**
* Package-private interface to mark RPCs that are changing data in HBase.
* @since 1.4
*/
interface IsEdit {
/** RPC method name to use with HBase 0.95+. */
static final byte[] MUTATE = { 'M', 'u', 't', 'a', 't', 'e' };
}
private boolean trace_rpc;
public boolean isTraceRPC() {
return trace_rpc;
}
public void setTraceRPC(boolean trace_rpc) {
this.trace_rpc = trace_rpc;
}
/*
* This class, although it's part of the public API, is mostly here to make
* it easier for this library to manipulate the HBase RPC protocol.
*
*
* Unofficial Hadoop / HBase RPC protocol documentation
* ****************************************************
*
* HBase uses a modified version of the Hadoop RPC protocol. They took
* Hadoop's RPC code, copy-pasted it into HBase, and tweaked it a little
* bit (mostly in a desperate attempt to try to make it less inefficient).
*
* RPCs are numbered with an arbitrary 32-bit ID. It is customary, but not
* mandatory, to start at 0 and increment by 1 every time you send out an
* RPC. The ID is allowed to wrap around and become negative. As long as
* no 2 RPCs share the same ID at the same time, we're fine.
*
* When requests are written out to the wire, they're framed. Meaning, a
* 4 byte integer value is first written in order to specify how many bytes
* are in the request (excluding the first 4 bytes themselves). The size -1
* is special. The client uses it to send a "ping" to the server at regular
* intervals, and the server specifically ignores any RPC with size -1. We
* don't do this in this client, because it's mostly useless, and we rely on
* TCP keepalive instead.
*
* Then the RPC ID is written (4 bytes). BTW, all integer values are
* encoded in big endian, as it's the default in Java world (Sun, SPARC...).
*
* Then the length of the method name is written on 2 bytes (I guess 1 byte
* wasn't enough in case you wanted to have 32768 byte long method names).
*
* Then the method name itself is written as-is (as a byte array).
*
* The last 4 fields are what constitute the "RPC header". The remaining
* bytes are the parameters of the request. First, there is a 4-byte int
* that specifies how many parameters follow (this way you can have up to
* 2 147 483 648 parameters, which may come in handy in a few centuries).
*
* In HBase 0.92 and above, 3 more fields have been added in the header as
* previously described. The first is a one byte version number that comes
* right before the method name, indicating how the parameters of the RPC
* have been serialized. Then there is a 8 byte (!) client version that's
* right after the method name, followed by a 4 byte "fingerprint", which
* is a sort of hash code of the method's signature (name, return type, and
* parameters types). Note that the client version seems to be always set
* to zero...
*
* In Hadoop RPC, the name of the class is first serialized (2 bytes
* specifying the length of the string, followed by that number of bytes
* of a UTF-8 encoded string in case you name your classes with Kanjis).
* In HBase RPC, a 1-byte ID representing the class name is written instead
* of writing the full class name. Those IDs are hard-coded in a central
* location (`HbaseObjectWritable', HBase's copy-pasted-hacked version of
* Hadoop's `ObjectWritable').
*
* The way each parameter is serialized depends on the object type being
* serialized. Since Hadoop doesn't use any automatic serialization
* framework, every class is free to serialize itself however it wants.
* The way it works is that for built-in types, they'll handle the
* serialization manually, and for other objects, they require that those
* objects implement their `Writable' interface which requires that a method
* named `readFields' and a method named `write' be implemented to
* de-serialize / serialize the object. So since the RPC layer knows the
* name of the class of the parameter, it will grab its `Class' using the
* Java Classloader and then `newInstance' it and then use `readFields' to
* populate the newly created instance. Thankfully most objects use a
* common library to serialize their own fields recursively, however things
* aren't always consistent, particularly when HBase chose to diverge from
* Hadoop in certain (but not all) code paths.
*
* The way RPC responses are encoded is as follows. First comes the 4-byte
* RPC ID. Then 1 byte containing flags indicating whether or not the
* request failed (0x01) on the remote side, and whether the response is
* framed (0x02). If flags are only 0x00, this is an old-style (pre 0.92)
* successful response that is not framed. Framed responses contain a
* 4-byte integer with the length of the entire response, including the
* leading RPC ID, flags, and the length itself. If there is a length, it
* is always followed by a 4-byte integer with the state of the RPC follows.
* As of 0.92, this state mostly useless. If the request failed (flag 0x01
* is set), the rest of the response is just 2 Hadoop-encoded
* strings (2-byte length, followed by a UTF-8 string). The first string is
* the name of the class of the exception and the second is the message of
* the exception (which typically includes some of the server-side stack
* trace). Note that if the response is NOT framed, it's not easy to tell
* ahead of time how many bytes to expect or where the next response starts.
*
* If the RPC was successful, the remaining of the payload is serialized
* using the same method as the RPC parameters are serialized (see above).
*
* Before the very first RPC, the server expects a "hello" message that
* starts with 4-byte magic number, followed by the RPC version (1 byte).
* Then comes 4 bytes to specify the rest of the length of the "hello"
* message. The remaining is a `Writable' instance serialized that
* specifies which authentication provider to use and give our credentials.
* In HBase 0.92 and above, the `Writable' should represent what protocol
* the client wants to speak, which should be the name of an interface.
* "org.apache.hadoop.hbase.ipc.HRegionInterface" should be used.
* The "hello" message is implemented in `RegionClient#helloRpc'. In order
* to support HBase 0.92, we always piggy back a `getProtocolVersion' RPC
* right after the header, so we can tell what version the server is using
* and how to serialize RPCs and read its responses.
*/
// ------ //
// Flags. //
// ------ //
// 5th byte into the response.
// See ipc/ResponseFlag.java in HBase's source code.
static final byte RPC_SUCCESS = 0x00;
static final byte RPC_ERROR = 0x01;
/**
* Indicates that the next byte is an integer with the length of the response.
* This can be found on both successful ({@link RPC_SUCCESS}) or failed
* ({@link RPC_ERROR}) responses.
* @since HBase 0.92
*/
static final byte RPC_FRAMED = 0x02;
// ----------- //
// RPC Status. //
// ----------- //
// 4 byte integer (on wire), located 9 byte into the response, only if
// {@link RPC_FRAMED} is set.
// See ipc/Status.java in HBase's source code.
/**
* Indicates that an error prevented the RPC from being executed.
* This is a somewhat misleading name. It indicates that the RPC couldn't
* be executed, typically because of a protocol version mismatch, an
* incorrectly encoded RPC (or possibly corrupted on-wire such that the
* server couldn't deserialize it), or an authentication error (unsure about
* that one).
*/
static final byte RPC_FATAL = -1;
/**
* To be implemented by the concrete sub-type.
* This method is expected to instantiate a {@link ChannelBuffer} using
* either {@link #newBuffer} and return it
* properly populated so it's ready to be written out to the wire (except
* for the "RPC header" that contains the RPC ID and method name and such,
* which is going to be populated automatically just before sending the RPC
* out, see {@link RegionClient#encode}.
*
* Notice that this method is package-private, so only classes within this
* package can use this as a base class.
*
* @param server_version What RPC protocol version the server is running.
*/
abstract ChannelBuffer serialize(byte server_version);
/**
* To be implemented by the concrete sub-type.
* This method is expected to de-serialize a response received for the
* current RPC, when communicating with HBase 0.95 and newer.
*
* Notice that this method is package-private, so only classes within this
* package can use this as a base class.
*
* @param buf The buffer from which to de-serialize the response.
* @param cell_size The size, in bytes, of the "cell block" that follows the
* protobuf of the RPC response. If 0, then there is just the protobuf.
* The value is guaranteed to be both positive and of a "reasonable" size.
*/
abstract Object deserialize(ChannelBuffer buf, int cell_size);
/**
* Throws an exception if the argument is non-zero.
*/
static void ensureNoCell(final int cell_size) {
if (cell_size != 0) {
throw new InvalidResponseException(
"Should not have gotten any cell blocks, yet there are "
+ cell_size + " bytes that follow the protobuf response."
+ " This should never happen."
+ " Are you using an incompatible version of HBase?", null);
}
}
/**
* The Deferred that will be invoked when this RPC completes or fails.
* In case of a successful completion, this Deferred's first callback
* will be invoked with an {@link Object} containing the de-serialized
* RPC response in argument.
* Once an RPC has been used, we create a new Deferred for it, in case
* the user wants to re-use it.
*/
private Deferred