<?xml version="1.0" encoding="UTF-8"?>
<appendix xml:id="hbase.rpc"
      version="5.0" xmlns="http://docbook.org/ns/docbook"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      xmlns:svg="http://www.w3.org/2000/svg"
      xmlns:m="http://www.w3.org/1998/Math/MathML"
      xmlns:html="http://www.w3.org/1999/xhtml"
      xmlns:db="http://docbook.org/ns/docbook">
  <!--/**
 * 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.
 */
-->

  <title>0.95 RPC Specification</title>
  <para>In 0.95, all client/server communication is done with
      <link xlink:href="https://code.google.com/p/protobuf/">protobuf’ed</link> Messages rather than with
      <link xlink:href="http://hadoop.apache.org/docs/current/api/org/apache/hadoop/io/Writable.html">Hadoop Writables</link>.
      Our RPC wire format therefore changes.
      This document describes the client/server request/response protocol and our new RPC wire-format.</para>
  <para/>
  <para>For what RPC is like in 0.94 and previous,
      see Benoît/Tsuna’s <link xlink:href="https://github.com/OpenTSDB/asynchbase/blob/master/src/HBaseRpc.java#L164">Unofficial Hadoop / HBase RPC protocol documentation</link>.
      For more background on how we arrived at this spec., see
      <link xlink:href="https://docs.google.com/document/d/1WCKwgaLDqBw2vpux0jPsAu2WPTRISob7HGCO8YhfDTA/edit#">HBase RPC: WIP</link></para>
  <para/>
  <section><title>Goals</title>
      <para>
      <orderedlist>
          <listitem>
              <para>A wire-format we can evolve</para>
          </listitem>
          <listitem>
              <para>A format that does not require our rewriting server core or
                  radically changing its current architecture (for later).</para>
          </listitem>
      </orderedlist>
  </para>
  </section>
  <section><title>TODO</title>
      <para>
      <orderedlist>
          <listitem>
              <para>List of problems with currently specified format and where
                  we would like to go in a version2, etc. For example, what would we
                  have to change if anything to move server async or to support
                  streaming/chunking?</para>
          </listitem>
          <listitem>
              <para>Diagram on how it works</para>
          </listitem>
          <listitem>
              <para>A grammar that succinctly describes the wire-format. Currently
                  we have these words and the content of the rpc protobuf idl but
                  a grammar for the back and forth would help with groking rpc.  Also,
                  a little state machine on client/server interactions would help
              with understanding (and ensuring correct implementation).</para>
          </listitem>
      </orderedlist>
  </para>
  </section>
  <section><title>RPC</title>
  <para>The client will send setup information on connection establish.
      Thereafter, the client invokes methods against the remote server sending a protobuf Message and receiving a protobuf Message in response.
      Communication is synchronous.  All back and forth is preceded by an int that has the total length of the request/response.
      Optionally, Cells(KeyValues) can be passed outside of protobufs in follow-behind Cell blocks (because
      <link xlink:href="https://docs.google.com/document/d/1WEtrq-JTIUhlnlnvA0oYRLp0F8MKpEBeBSCFcQiacdw/edit#">we can’t protobuf megabytes of KeyValues</link> or Cells).
      These CellBlocks are encoded and optionally compressed.</para>
  <para/>
  <para>For more detail on the protobufs involved, see the
      <link xlink:href="http://svn.apache.org/viewvc/hbase/trunk/hbase-protocol/src/main/protobuf/RPC.proto?view=markup">RPC.proto</link> file in trunk.</para>

  <section>
      <title>Connection Setup</title>
      <para>Client initiates connection.</para>
  <section><title>Client</title>
      <para>On connection setup, client sends a preamble followed by a connection header.
      </para>

  <section>
  <title>&lt;preamble&gt;</title>
  <para><programlisting>&lt;MAGIC 4 byte integer&gt; &lt;1 byte RPC Format Version&gt; &lt;1 byte auth type&gt;<footnote><para> We need the auth method spec. here so the connection header is encoded if auth enabled.</para></footnote></programlisting></para>
  <para>E.g.: HBas0x000x50 -- 4 bytes of MAGIC -- ‘HBas’ -- plus one-byte of version, 0 in this case, and one byte, 0x50 (SIMPLE). of an auth type.</para>
  </section>

  <section>
      <title>&lt;Protobuf ConnectionHeader Message&gt;</title>
      <para>Has user info, and “protocol”, as well as the encoders and compression the client will use sending CellBlocks.
          CellBlock encoders and compressors are for the life of the connection.
          CellBlock encoders implement org.apache.hadoop.hbase.codec.Codec.
          CellBlocks may then also be compressed.
          Compressors implement org.apache.hadoop.io.compress.CompressionCodec.
          This protobuf is written using writeDelimited so is prefaced by a pb varint
          with its serialized length</para>
  </section>
  </section><!--Client-->

  <section><title>Server</title>
      <para>After client sends preamble and connection header,
          server does NOT respond if successful connection setup.
          No response means server is READY to accept requests and to give out response.
      If the version or authentication in the preamble is not agreeable or the server has trouble parsing the preamble,
      it will throw a org.apache.hadoop.hbase.ipc.FatalConnectionException explaining the error and will then disconnect.
      If the client in the connection header -- i.e. the protobuf’d Message that comes after the connection preamble -- asks for for a
      Service the server does not support or a codec the server does not have, again we throw a FatalConnectionException with explanation.</para>
  </section>
  </section>

  <section><title>Request</title>
      <para>After a Connection has been set up, client makes requests.  Server responds.</para>
      <para>A request is made up of a protobuf RequestHeader followed by a protobuf Message parameter.
          The header includes the method name and optionally, metadata on the optional CellBlock that may be following.
          The parameter type suits the method being invoked: i.e. if we are doing a getRegionInfo request,
          the protobuf Message param will be an instance of GetRegionInfoRequest.
          The response will be a GetRegionInfoResponse.
          The CellBlock is optionally used ferrying the bulk of the RPC data: i.e Cells/KeyValues.</para>
  <para/>
  <section><title>Request Parts</title>
      <section><title>&lt;Total Length&gt;</title>
          <para>The request is prefaced by an int that holds the total length of what follows.</para>
      </section>
      <section><title>&lt;Protobuf RequestHeader Message&gt;</title>
          <para>Will have call.id, trace.id, and method name, etc. including optional Metadata on the Cell block IFF one is following.
              Data is protobuf’d inline in this pb Message or optionally comes in the following CellBlock</para>
      </section>
      <section><title>&lt;Protobuf Param Message&gt;</title>
          <para>If the method being invoked is getRegionInfo, if you study the Service descriptor for the client to regionserver protocol,
              you will find that the request sends a GetRegionInfoRequest protobuf Message param in this position.</para>
      </section>
      <section><title>&lt;CellBlock&gt;</title>
  <para>An encoded and optionally compressed Cell block.</para>
      </section>
  </section><!--Request parts-->
  </section><!--Request-->

  <section><title>Response</title>
      <para>Same as Request, it is a protobuf ResponseHeader followed by a protobuf Message response where the Message response type suits the method invoked.
          Bulk of the data may come in a following CellBlock.</para>
  <section><title>Response Parts</title>
      <section><title>&lt;Total Length&gt;</title>
          <para>The response is prefaced by an int that holds the total length of what follows.</para>
      </section>
          <section><title>&lt;Protobuf ResponseHeader Message&gt;</title>
  <para>Will have call.id, etc. Will include exception if failed processing.  Optionally includes metadata on optional, IFF there is a CellBlock following.</para>
  </section>

  <section><title>&lt;Protobuf Response Message&gt;</title>
      <para>Return or may be nothing if exception. If the method being invoked is getRegionInfo, if you study the Service descriptor for the client to regionserver protocol,
          you will find that the response sends a GetRegionInfoResponse protobuf Message param in this position.</para>
  </section>
  <section><title>&lt;CellBlock&gt;</title>
  <para>An encoded and optionally compressed Cell block.</para>
  </section>
  </section><!--Parts-->
  </section><!--Response-->

  <section><title>Exceptions</title>
      <para>There are two distinct types.
          There is the request failed which is encapsulated inside the response header for the response.
          The connection stays open to receive new requests.
          The second type, the FatalConnectionException, kills the connection.</para>
      <para>Exceptions can carry extra information.
          See the ExceptionResponse protobuf type.
          It has a flag to indicate do-no-retry as well as other miscellaneous payload to help improve client responsiveness.</para>
  </section>
  <section><title>CellBlocks</title>
      <para>These are not versioned.
          Server can do the codec or it cannot.
          If new version of a codec with say, tighter encoding, then give it a new class name.
          Codecs will live on the server for all time so old clients can connect.</para>
  </section>
  </section>


  <section><title>Notes</title>
  <section><title>Constraints</title>
  <para>In some part, current wire-format -- i.e. all requests and responses preceeded by a length -- has been dictated by current server non-async architecture.</para>
  </section>
  <section><title>One fat pb request or header+param</title>
      <para>We went with pb header followed by pb param making a request and a pb header followed by pb response for now.
          Doing header+param rather than a single protobuf Message with both header and param content:</para>
      <para>
  <orderedlist>
    <listitem>
      <para>Is closer to what we currently have</para>
    </listitem>
    <listitem>
      <para>Having a single fat pb requires extra copying putting the already pb’d param into the body of the fat request pb (and same making result)</para>
    </listitem>
    <listitem>
      <para>We can decide whether to accept the request or not before we read the param; for example, the request might be low priority.  As is, we read header+param in one go as server is currently implemented so this is a TODO.</para>
    </listitem>
  </orderedlist>
  </para>
  <para>The advantages are minor.  If later, fat request has clear advantage, can roll out a v2 later.</para>
  </section>
  <section xml:id="rpc.configs"><title>RPC Configurations</title>
  <section><title>CellBlock Codecs</title>
      <para>To enable a codec other than the default <classname>KeyValueCodec</classname>,
          set <varname>hbase.client.rpc.codec</varname>
          to the name of the Codec class to use.  Codec must implement hbase's <classname>Codec</classname> Interface.  After connection setup,
          all passed cellblocks will be sent with this codec.  The server will return cellblocks using this same codec as long
          as the codec is on the servers' CLASSPATH (else you will get <classname>UnsupportedCellCodecException</classname>).</para>
      <para>To change the default codec, set <varname>hbase.client.default.rpc.codec</varname>.
      </para>
      <para>To disable cellblocks completely and to go pure protobuf, set the default to the
          empty String and do not specify a codec in your Configuration.  So, set <varname>hbase.client.default.rpc.codec</varname>
          to the empty string and do not set <varname>hbase.client.rpc.codec</varname>.
          This will cause the client to connect to the server with no codec specified.
          If a server sees no codec, it will return all responses in pure protobuf.
          Running pure protobuf all the time will be slower than running with cellblocks.
      </para>
  </section>
  <section><title>Compression</title>
      <para>Uses hadoops compression codecs.  To enable compressing of passed CellBlocks, set <varname>hbase.client.rpc.compressor</varname>
          to the name of the Compressor to use.  Compressor must implement Hadoops' CompressionCodec Interface.  After connection setup,
          all passed cellblocks will be sent compressed.  The server will return cellblocks compressed using this same compressor as long
          as the compressor is on its CLASSPATH (else you will get <classname>UnsupportedCompressionCodecException</classname>).</para>
  </section>
  </section>
  </section>
</appendix>
