You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2022/07/04 15:39:22 UTC

[hbase-connectors] 01/01: tmp

This is an automated email from the ASF dual-hosted git repository.

zhangduo pushed a commit to branch HBASE-20998
in repository https://gitbox.apache.org/repos/asf/hbase-connectors.git

commit 82650c853aab6c2c9e4edf0f1391bfd394ece2ca
Author: Duo Zhang <zh...@apache.org>
AuthorDate: Mon Jul 4 23:39:04 2022 +0800

    tmp
---
 hbase-thrift/pom.xml                               |   232 +
 .../org/apache/hadoop/hbase/thrift/CallQueue.java  |   256 +
 .../org/apache/hadoop/hbase/thrift/Constants.java  |   157 +
 .../hadoop/hbase/thrift/HBaseServiceHandler.java   |    81 +
 .../hbase/thrift/HThreadedSelectorServerArgs.java  |    83 +
 .../hbase/thrift/HbaseHandlerMetricsProxy.java     |    80 +
 .../hbase/thrift/HttpAuthenticationException.java  |    47 +
 .../org/apache/hadoop/hbase/thrift/ImplType.java   |   140 +
 .../hadoop/hbase/thrift/IncrementCoalescer.java    |   376 +
 .../hbase/thrift/IncrementCoalescerMBean.java      |    51 +
 .../hbase/thrift/TBoundedThreadPoolServer.java     |   299 +
 .../hbase/thrift/THBaseThreadPoolExecutor.java     |    62 +
 .../hbase/thrift/ThriftHBaseServiceHandler.java    |  1346 +
 .../hadoop/hbase/thrift/ThriftHttpServlet.java     |   246 +
 .../apache/hadoop/hbase/thrift/ThriftMetrics.java  |   179 +
 .../apache/hadoop/hbase/thrift/ThriftServer.java   |   867 +
 .../hadoop/hbase/thrift/ThriftUtilities.java       |   249 +
 .../hbase/thrift/generated/AlreadyExists.java      |   379 +
 .../hbase/thrift/generated/BatchMutation.java      |   551 +
 .../hbase/thrift/generated/ColumnDescriptor.java   |  1201 +
 .../hadoop/hbase/thrift/generated/Hbase.java       | 64110 +++++++++++++++++++
 .../hadoop/hbase/thrift/generated/IOError.java     |   480 +
 .../hbase/thrift/generated/IllegalArgument.java    |   379 +
 .../hadoop/hbase/thrift/generated/Mutation.java    |   709 +
 .../thrift/generated/TAccessControlEntity.java     |   820 +
 .../hadoop/hbase/thrift/generated/TAppend.java     |   825 +
 .../hadoop/hbase/thrift/generated/TCell.java       |   494 +
 .../hadoop/hbase/thrift/generated/TColumn.java     |   501 +
 .../hadoop/hbase/thrift/generated/TIncrement.java  |   728 +
 .../hbase/thrift/generated/TPermissionScope.java   |    43 +
 .../hadoop/hbase/thrift/generated/TRegionInfo.java |  1037 +
 .../hadoop/hbase/thrift/generated/TRowResult.java  |   726 +
 .../hadoop/hbase/thrift/generated/TScan.java       |  1387 +
 .../hbase/thrift/generated/TThriftServerType.java  |    46 +
 .../hadoop/hbase/thrift/util/ConnectionCache.java  |   259 +
 .../hbase/thrift2/ThriftHBaseServiceHandler.java   |   918 +
 .../apache/hadoop/hbase/thrift2/ThriftServer.java  |   114 +
 .../hadoop/hbase/thrift2/ThriftUtilities.java      |  1703 +
 .../hadoop/hbase/thrift2/client/ThriftAdmin.java   |  1317 +
 .../hbase/thrift2/client/ThriftClientBuilder.java  |    35 +
 .../hbase/thrift2/client/ThriftConnection.java     |   382 +
 .../hadoop/hbase/thrift2/client/ThriftTable.java   |   505 +
 .../thrift2/generated/NamespaceDescriptor.java     |   554 +
 .../thrift2/generated/TAccessControlEntity.java    |   807 +
 .../hadoop/hbase/thrift2/generated/TAppend.java    |  1038 +
 .../hbase/thrift2/generated/TAuthorization.java    |   423 +
 .../hbase/thrift2/generated/TBloomFilterType.java  |    65 +
 .../hbase/thrift2/generated/TCellVisibility.java   |   373 +
 .../hadoop/hbase/thrift2/generated/TColumn.java    |   613 +
 .../thrift2/generated/TColumnFamilyDescriptor.java |  2490 +
 .../hbase/thrift2/generated/TColumnIncrement.java  |   607 +
 .../hbase/thrift2/generated/TColumnValue.java      |   938 +
 .../hbase/thrift2/generated/TCompareOperator.java  |    62 +
 .../thrift2/generated/TCompressionAlgorithm.java   |    62 +
 .../hbase/thrift2/generated/TConsistency.java      |    48 +
 .../thrift2/generated/TDataBlockEncoding.java      |    59 +
 .../hadoop/hbase/thrift2/generated/TDelete.java    |  1084 +
 .../hbase/thrift2/generated/TDeleteType.java       |    54 +
 .../hbase/thrift2/generated/TDurability.java       |    59 +
 .../hbase/thrift2/generated/TFilterByOperator.java |    43 +
 .../hadoop/hbase/thrift2/generated/TGet.java       |  2003 +
 .../hbase/thrift2/generated/THBaseService.java     | 57060 +++++++++++++++++
 .../hbase/thrift2/generated/THRegionInfo.java      |  1019 +
 .../hbase/thrift2/generated/THRegionLocation.java  |   479 +
 .../hadoop/hbase/thrift2/generated/TIOError.java   |   481 +
 .../hbase/thrift2/generated/TIllegalArgument.java  |   377 +
 .../hadoop/hbase/thrift2/generated/TIncrement.java |  1045 +
 .../hbase/thrift2/generated/TKeepDeletedCells.java |    65 +
 .../hbase/thrift2/generated/TLogQueryFilter.java   |  1055 +
 .../hadoop/hbase/thrift2/generated/TLogType.java   |    43 +
 .../hadoop/hbase/thrift2/generated/TMutation.java  |   348 +
 .../thrift2/generated/TNamespaceDescriptor.java    |   535 +
 .../hbase/thrift2/generated/TOnlineLogRecord.java  |  1643 +
 .../hbase/thrift2/generated/TPermissionScope.java  |    43 +
 .../hadoop/hbase/thrift2/generated/TPut.java       |  1050 +
 .../hadoop/hbase/thrift2/generated/TReadType.java  |    46 +
 .../hadoop/hbase/thrift2/generated/TResult.java    |   756 +
 .../hbase/thrift2/generated/TRowMutations.java     |   540 +
 .../hadoop/hbase/thrift2/generated/TScan.java      |  2412 +
 .../hbase/thrift2/generated/TServerName.java       |   574 +
 .../hbase/thrift2/generated/TTableDescriptor.java  |   825 +
 .../hadoop/hbase/thrift2/generated/TTableName.java |   533 +
 .../hbase/thrift2/generated/TThriftServerType.java |    46 +
 .../hadoop/hbase/thrift2/generated/TTimeRange.java |   457 +
 .../org/apache/hadoop/hbase/thrift2/package.html   |   103 +
 .../static/css/bootstrap-theme.min.css             |     6 +
 .../hbase-webapps/static/css/bootstrap.min.css     |     6 +
 .../resources/hbase-webapps/static/css/hbase.css   |    42 +
 .../static/fonts/glyphicons-halflings-regular.eot  |   Bin 0 -> 20127 bytes
 .../static/fonts/glyphicons-halflings-regular.svg  |   288 +
 .../static/fonts/glyphicons-halflings-regular.ttf  |   Bin 0 -> 45404 bytes
 .../static/fonts/glyphicons-halflings-regular.woff |   Bin 0 -> 23424 bytes
 .../fonts/glyphicons-halflings-regular.woff2       |   Bin 0 -> 18028 bytes
 .../resources/hbase-webapps/static/hbase_logo.png  |   Bin 0 -> 2997 bytes
 .../hbase-webapps/static/hbase_logo_med.gif        |   Bin 0 -> 3592 bytes
 .../hbase-webapps/static/hbase_logo_small.png      |   Bin 0 -> 1926 bytes
 .../hbase-webapps/static/js/bootstrap.min.js       |     6 +
 .../hbase-webapps/static/js/jquery.min.js          |     2 +
 .../main/resources/hbase-webapps/static/js/tab.js  |    38 +
 .../main/resources/hbase-webapps/thrift/index.html |    20 +
 .../main/resources/hbase-webapps/thrift/thrift.jsp |   162 +
 .../org/apache/hadoop/hbase/thrift/Hbase.thrift    |  1019 +
 .../org/apache/hadoop/hbase/thrift2/hbase.thrift   |  1164 +
 pom.xml                                            |     1 +
 104 files changed, 170071 insertions(+)

diff --git a/hbase-thrift/pom.xml b/hbase-thrift/pom.xml
new file mode 100644
index 0000000..7b71097
--- /dev/null
+++ b/hbase-thrift/pom.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <!--
+  /**
+   * 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.
+   */
+  -->
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.hbase.connectors</groupId>
+    <artifactId>hbase-connectors</artifactId>
+    <version>${revision}</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <artifactId>hbase-thrift</artifactId>
+  <packaging>jar</packaging>
+  <name>Apache HBase - Thrift</name>
+  <description>HBase Thrift Server</description>
+  <properties>
+    <thrift.version>0.14.1</thrift.version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.thrift</groupId>
+      <artifactId>libthrift</artifactId>
+      <version>${thrift.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-client</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <resources>
+      <!-- Add the build webabpps to the classpth -->
+      <resource>
+        <directory>${project.build.directory}</directory>
+        <includes>
+          <include>hbase-webapps/**</include>
+        </includes>
+      </resource>
+      <resource>
+        <directory>src/main/resources/</directory>
+        <includes>
+          <include>**/*.thrift</include>
+        </includes>
+      </resource>
+    </resources>
+    <plugins>
+    <!-- General ant tasks, bound to different build phases -->
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <executions>
+          <!-- Generate web app sources -->
+          <execution>
+            <id>generate</id>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <target>
+                <property location="${project.build.directory}/hbase-webapps" name="build.webapps"/>
+                <property location="${basedir}/src/main/resources/hbase-webapps" name="src.webapps"/>
+                <property location="${project.build.directory}/generated-sources" name="generated.sources"/>
+                <mkdir dir="${build.webapps}"/>
+                <copy todir="${build.webapps}">
+                  <fileset dir="${src.webapps}">
+                    <exclude name="**/*.jsp"/>
+                    <exclude name="**/.*"/>
+                    <exclude name="**/*~"/>
+                  </fileset>
+                </copy>
+                <!--The compile.classpath is passed in by maven -->
+                <taskdef classname="org.apache.jasper.JspC" classpathref="maven.compile.classpath" name="jspcompiler"/>
+                <mkdir dir="${build.webapps}/thrift/WEB-INF"/>
+                <jspcompiler outputdir="${generated.sources}/java" package="org.apache.hadoop.hbase.generated.thrift" uriroot="${src.webapps}/thrift" webxml="${build.webapps}/thrift/WEB-INF/web.xml"/>
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <!-- Add the generated sources -->
+          <execution>
+            <id>jspcSource-packageInfo-source</id>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/java</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- Make a jar and put the sources in the jar -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <!--
+      Profile for regenerating the thrift java classes.
+      The generated files are to be committed to version control.
+      Activate using:
+       mvn compile -Pcompile-thrift
+    -->
+    <profile>
+      <id>compile-thrift</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-enforcer-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>enforce-thrift-version</id>
+                <goals>
+                  <goal>enforce</goal>
+                </goals>
+                <configuration>
+                  <rules>
+                    <requireProperty>
+                      <property>thrift.version</property>
+                      <message>"The Thrift version must be specified."</message>
+                      <regex>0\.14\.1</regex>
+                      <regexMessage>-
+-
+[FATAL] ==========================================================================================
+[FATAL] HBase Thrift requires the thrift generator version 0.14.1.
+[FATAL] Setting it to something else needs to be reviewed for wire and behavior compatibility.
+[FATAL] ==========================================================================================
+-
+-</regexMessage>
+                    </requireProperty>
+                  </rules>
+                  <fail>true</fail>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>${exec.maven.version}</version>
+            <executions>
+              <execution>
+                <id>check-thrift-version</id>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <phase>generate-sources</phase>
+                <configuration>
+                  <executable>sh</executable>
+                  <workingDirectory>${basedir}</workingDirectory>
+                  <arguments>
+                    <argument>-c</argument>
+                    <argument>${thrift.path} -version | \
+                      fgrep 'Thrift version ${thrift.version}' &amp;&amp; exit 0;
+                      echo "========== [FATAL] Need Thrift version ${thrift.version} ==========";
+                      exit 1</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+              <execution>
+                <id>thrift</id>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <phase>generate-sources</phase>
+                <configuration>
+                  <executable>${thrift.path}</executable>
+                  <workingDirectory>${basedir}</workingDirectory>
+                  <arguments>
+                    <argument>-strict</argument>
+                    <argument>--gen</argument>
+                    <argument>java</argument>
+                    <argument>-out</argument>
+                    <argument>${basedir}/src/main/java</argument>
+                    <argument>${basedir}/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+              <execution>
+                <id>thrift2</id>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <phase>generate-sources</phase>
+                <configuration>
+                  <executable>${thrift.path}</executable>
+                  <workingDirectory>${basedir}</workingDirectory>
+                  <arguments>
+                    <argument>-strict</argument>
+                    <argument>--gen</argument>
+                    <argument>java</argument>
+                    <argument>-out</argument>
+                    <argument>${basedir}/src/main/java</argument>
+                    <argument>${basedir}/src/main/resources/org/apache/hadoop/hbase/thrift2/hbase.thrift</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/CallQueue.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/CallQueue.java
new file mode 100644
index 0000000..145e25f
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/CallQueue.java
@@ -0,0 +1,256 @@
+/*
+ * 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.thrift;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A BlockingQueue reports waiting time in queue and queue length to ThriftMetrics.
+ */
+@InterfaceAudience.Private
+public class CallQueue implements BlockingQueue<Runnable> {
+  private static final Logger LOG = LoggerFactory.getLogger(CallQueue.class);
+
+  private final BlockingQueue<Call> underlyingQueue;
+  private final ThriftMetrics metrics;
+
+  public CallQueue(BlockingQueue<Call> underlyingQueue, ThriftMetrics metrics) {
+    this.underlyingQueue = underlyingQueue;
+    this.metrics = metrics;
+  }
+
+  private static long now() {
+    return System.nanoTime();
+  }
+
+  public static class Call implements Runnable {
+    final long startTime;
+    final Runnable underlyingRunnable;
+
+    Call(Runnable underlyingRunnable) {
+      this.underlyingRunnable = underlyingRunnable;
+      this.startTime = now();
+    }
+
+    @Override
+    public void run() {
+      underlyingRunnable.run();
+    }
+
+    public long timeInQueue() {
+      return now() - startTime;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+      if (other instanceof Call) {
+        Call otherCall = (Call) (other);
+        return this.underlyingRunnable.equals(otherCall.underlyingRunnable);
+      } else if (other instanceof Runnable) {
+        return this.underlyingRunnable.equals(other);
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      return this.underlyingRunnable.hashCode();
+    }
+  }
+
+  @Override
+  public Runnable poll() {
+    Call result = underlyingQueue.poll();
+    updateMetrics(result);
+    return result;
+  }
+
+  private void updateMetrics(Call result) {
+    if (result == null) {
+      return;
+    }
+    metrics.incTimeInQueue(result.timeInQueue());
+    metrics.setCallQueueLen(this.size());
+  }
+
+  @Override
+  public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
+    Call result = underlyingQueue.poll(timeout, unit);
+    updateMetrics(result);
+    return result;
+  }
+
+  @Override
+  public Runnable remove() {
+    Call result = underlyingQueue.remove();
+    updateMetrics(result);
+    return result;
+  }
+
+  @Override
+  public Runnable take() throws InterruptedException {
+    Call result = underlyingQueue.take();
+    updateMetrics(result);
+    return result;
+  }
+
+  @Override
+  public int drainTo(Collection<? super Runnable> destination) {
+    return drainTo(destination, Integer.MAX_VALUE);
+  }
+
+  @Override
+  public int drainTo(Collection<? super Runnable> destination, int maxElements) {
+    if (destination == this) {
+      throw new IllegalArgumentException("A BlockingQueue cannot drain to itself.");
+    }
+    List<Call> drained = new ArrayList<>();
+    underlyingQueue.drainTo(drained, maxElements);
+    for (Call r : drained) {
+      updateMetrics(r);
+    }
+    destination.addAll(drained);
+    int sz = drained.size();
+    LOG.info("Elements drained: " + sz);
+    return sz;
+  }
+
+  @Override
+  public boolean offer(Runnable element) {
+    return underlyingQueue.offer(new Call(element));
+  }
+
+  @Override
+  public boolean offer(Runnable element, long timeout, TimeUnit unit) throws InterruptedException {
+    return underlyingQueue.offer(new Call(element), timeout, unit);
+  }
+
+  @Override
+  public void put(Runnable element) throws InterruptedException {
+    underlyingQueue.put(new Call(element));
+  }
+
+  @Override
+  public boolean add(Runnable element) {
+    return underlyingQueue.add(new Call(element));
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Runnable> elements) {
+    int added = 0;
+    for (Runnable r : elements) {
+      added += underlyingQueue.add(new Call(r)) ? 1 : 0;
+    }
+    return added != 0;
+  }
+
+  @Override
+  public Runnable element() {
+    return underlyingQueue.element();
+  }
+
+  @Override
+  public Runnable peek() {
+    return underlyingQueue.peek();
+  }
+
+  @Override
+  public void clear() {
+    underlyingQueue.clear();
+  }
+
+  @Override
+  public boolean containsAll(Collection<?> elements) {
+    return underlyingQueue.containsAll(elements);
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return underlyingQueue.isEmpty();
+  }
+
+  @Override
+  public Iterator<Runnable> iterator() {
+    return new Iterator<Runnable>() {
+      final Iterator<Call> underlyingIterator = underlyingQueue.iterator();
+
+      @Override
+      public Runnable next() {
+        return underlyingIterator.next();
+      }
+
+      @Override
+      public boolean hasNext() {
+        return underlyingIterator.hasNext();
+      }
+
+      @Override
+      public void remove() {
+        underlyingIterator.remove();
+      }
+    };
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> elements) {
+    return underlyingQueue.removeAll(elements);
+  }
+
+  @Override
+  public boolean retainAll(Collection<?> elements) {
+    return underlyingQueue.retainAll(elements);
+  }
+
+  @Override
+  public int size() {
+    return underlyingQueue.size();
+  }
+
+  @Override
+  public Object[] toArray() {
+    return underlyingQueue.toArray();
+  }
+
+  @Override
+  public <T> T[] toArray(T[] array) {
+    return underlyingQueue.toArray(array);
+  }
+
+  @Override
+  public boolean contains(Object element) {
+    return underlyingQueue.contains(element);
+  }
+
+  @Override
+  public int remainingCapacity() {
+    return underlyingQueue.remainingCapacity();
+  }
+
+  @Override
+  public boolean remove(Object element) {
+    return underlyingQueue.remove(element);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/Constants.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/Constants.java
new file mode 100644
index 0000000..83bb90e
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/Constants.java
@@ -0,0 +1,157 @@
+/*
+ * 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.thrift;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Thrift related constants
+ */
+@InterfaceAudience.Private
+public final class Constants {
+  private Constants() {
+  }
+
+  // Jetty's max header size is Character.MAX_VALUE - 1, See ArrayTernaryTrie for more details
+  // And in newer jetty version, they add a check when creating a server so we must follow this
+  // limitation otherwise the UTs will fail
+  public static final int DEFAULT_HTTP_MAX_HEADER_SIZE = Character.MAX_VALUE - 1;
+
+  public static final String SERVER_TYPE_CONF_KEY = "hbase.regionserver.thrift.server.type";
+
+  public static final String COMPACT_CONF_KEY = "hbase.regionserver.thrift.compact";
+  public static final boolean COMPACT_CONF_DEFAULT = false;
+
+  public static final String FRAMED_CONF_KEY = "hbase.regionserver.thrift.framed";
+  public static final boolean FRAMED_CONF_DEFAULT = false;
+
+  public static final String MAX_FRAME_SIZE_CONF_KEY =
+    "hbase.regionserver.thrift.framed.max_frame_size_in_mb";
+  public static final int MAX_FRAME_SIZE_CONF_DEFAULT = 2;
+
+  public static final String COALESCE_INC_KEY = "hbase.regionserver.thrift.coalesceIncrement";
+  public static final String USE_HTTP_CONF_KEY = "hbase.regionserver.thrift.http";
+
+  public static final String HTTP_MIN_THREADS_KEY = "hbase.thrift.http_threads.min";
+  public static final int HTTP_MIN_THREADS_KEY_DEFAULT = 2;
+
+  public static final String HTTP_MAX_THREADS_KEY = "hbase.thrift.http_threads.max";
+  public static final int HTTP_MAX_THREADS_KEY_DEFAULT = 100;
+
+  // ssl related configs
+  public static final String THRIFT_SSL_ENABLED_KEY = "hbase.thrift.ssl.enabled";
+  public static final String THRIFT_SSL_KEYSTORE_STORE_KEY = "hbase.thrift.ssl.keystore.store";
+  public static final String THRIFT_SSL_KEYSTORE_PASSWORD_KEY =
+    "hbase.thrift.ssl.keystore.password";
+  public static final String THRIFT_SSL_KEYSTORE_KEYPASSWORD_KEY =
+    "hbase.thrift.ssl.keystore.keypassword";
+  public static final String THRIFT_SSL_EXCLUDE_CIPHER_SUITES_KEY =
+    "hbase.thrift.ssl.exclude.cipher.suites";
+  public static final String THRIFT_SSL_INCLUDE_CIPHER_SUITES_KEY =
+    "hbase.thrift.ssl.include.cipher.suites";
+  public static final String THRIFT_SSL_EXCLUDE_PROTOCOLS_KEY =
+    "hbase.thrift.ssl.exclude.protocols";
+  public static final String THRIFT_SSL_INCLUDE_PROTOCOLS_KEY =
+    "hbase.thrift.ssl.include.protocols";
+  public static final String THRIFT_SSL_KEYSTORE_TYPE_KEY = "hbase.thrift.ssl.keystore.type";
+  public static final String THRIFT_SSL_KEYSTORE_TYPE_DEFAULT = "jks";
+
+  public static final String THRIFT_SUPPORT_PROXYUSER_KEY = "hbase.thrift.support.proxyuser";
+
+  // kerberos related configs
+  public static final String THRIFT_DNS_INTERFACE_KEY = "hbase.thrift.dns.interface";
+  public static final String THRIFT_DNS_NAMESERVER_KEY = "hbase.thrift.dns.nameserver";
+  public static final String THRIFT_KERBEROS_PRINCIPAL_KEY = "hbase.thrift.kerberos.principal";
+  public static final String THRIFT_KEYTAB_FILE_KEY = "hbase.thrift.keytab.file";
+  public static final String THRIFT_SPNEGO_PRINCIPAL_KEY = "hbase.thrift.spnego.principal";
+  public static final String THRIFT_SPNEGO_KEYTAB_FILE_KEY = "hbase.thrift.spnego.keytab.file";
+
+  /**
+   * Amount of time in milliseconds before a server thread will timeout waiting for client to send
+   * data on a connected socket. Currently, applies only to TBoundedThreadPoolServer
+   */
+  public static final String THRIFT_SERVER_SOCKET_READ_TIMEOUT_KEY =
+    "hbase.thrift.server.socket.read.timeout";
+  public static final int THRIFT_SERVER_SOCKET_READ_TIMEOUT_DEFAULT = 60000;
+
+  /**
+   * Thrift quality of protection configuration key. Valid values can be: auth-conf: authentication,
+   * integrity and confidentiality checking auth-int: authentication and integrity checking auth:
+   * authentication only This is used to authenticate the callers and support impersonation. The
+   * thrift server and the HBase cluster must run in secure mode.
+   */
+  public static final String THRIFT_QOP_KEY = "hbase.thrift.security.qop";
+
+  public static final String BACKLOG_CONF_KEY = "hbase.regionserver.thrift.backlog";
+  public static final int BACKLOG_CONF_DEAFULT = 0;
+
+  public static final String BIND_CONF_KEY = "hbase.regionserver.thrift.ipaddress";
+  public static final String DEFAULT_BIND_ADDR = "0.0.0.0";
+
+  public static final String PORT_CONF_KEY = "hbase.regionserver.thrift.port";
+  public static final int DEFAULT_LISTEN_PORT = 9090;
+
+  public static final String THRIFT_HTTP_ALLOW_OPTIONS_METHOD =
+    "hbase.thrift.http.allow.options.method";
+  public static final boolean THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT = false;
+
+  public static final String THRIFT_INFO_SERVER_PORT = "hbase.thrift.info.port";
+  public static final int THRIFT_INFO_SERVER_PORT_DEFAULT = 9095;
+
+  public static final String THRIFT_INFO_SERVER_BINDING_ADDRESS = "hbase.thrift.info.bindAddress";
+  public static final String THRIFT_INFO_SERVER_BINDING_ADDRESS_DEFAULT = "0.0.0.0";
+
+  public static final String THRIFT_QUEUE_SIZE = "hbase.thrift.queue.size";
+  public static final int THRIFT_QUEUE_SIZE_DEFAULT = Integer.MAX_VALUE;
+
+  public static final String THRIFT_SELECTOR_NUM = "hbase.thrift.selector.num";
+
+  public static final String THRIFT_FILTERS = "hbase.thrift.filters";
+
+  // Command line options
+
+  public static final String READ_TIMEOUT_OPTION = "readTimeout";
+  public static final String MIN_WORKERS_OPTION = "minWorkers";
+  public static final String MAX_WORKERS_OPTION = "workers";
+  public static final String MAX_QUEUE_SIZE_OPTION = "queue";
+  public static final String SELECTOR_NUM_OPTION = "selectors";
+  public static final String KEEP_ALIVE_SEC_OPTION = "keepAliveSec";
+  public static final String BIND_OPTION = "bind";
+  public static final String COMPACT_OPTION = "compact";
+  public static final String FRAMED_OPTION = "framed";
+  public static final String PORT_OPTION = "port";
+  public static final String INFOPORT_OPTION = "infoport";
+
+  // for thrift2 server
+  public static final String READONLY_OPTION = "readonly";
+
+  public static final String THRIFT_READONLY_ENABLED = "hbase.thrift.readonly";
+  public static final boolean THRIFT_READONLY_ENABLED_DEFAULT = false;
+
+  public static final String HBASE_THRIFT_CLIENT_SCANNER_CACHING =
+    "hbase.thrift.client.scanner.caching";
+
+  public static final int HBASE_THRIFT_CLIENT_SCANNER_CACHING_DEFAULT = 20;
+
+  public static final String HBASE_THRIFT_SERVER_NAME = "hbase.thrift.server.name";
+  public static final String HBASE_THRIFT_SERVER_PORT = "hbase.thrift.server.port";
+
+  public static final String HBASE_THRIFT_CLIENT_BUIDLER_CLASS =
+    "hbase.thrift.client.builder.class";
+
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HBaseServiceHandler.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HBaseServiceHandler.java
new file mode 100644
index 0000000..5071c6d
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HBaseServiceHandler.java
@@ -0,0 +1,81 @@
+/*
+ * 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.thrift;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseInterfaceAudience;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.security.UserProvider;
+import org.apache.hadoop.hbase.thrift.util.ConnectionCache;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * abstract class for HBase handler providing a Connection cache and get table/admin method
+ */
+@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
+public abstract class HBaseServiceHandler {
+  public static final String CLEANUP_INTERVAL = "hbase.thrift.connection.cleanup-interval";
+  public static final String MAX_IDLETIME = "hbase.thrift.connection.max-idletime";
+
+  protected Configuration conf;
+
+  protected final ConnectionCache connectionCache;
+
+  public HBaseServiceHandler(final Configuration c, final UserProvider userProvider)
+    throws IOException {
+    this.conf = c;
+    int cleanInterval = conf.getInt(CLEANUP_INTERVAL, 10 * 1000);
+    int maxIdleTime = conf.getInt(MAX_IDLETIME, 10 * 60 * 1000);
+    connectionCache = new ConnectionCache(conf, userProvider, cleanInterval, maxIdleTime);
+  }
+
+  protected ThriftMetrics metrics = null;
+
+  public void initMetrics(ThriftMetrics metrics) {
+    this.metrics = metrics;
+  }
+
+  public void setEffectiveUser(String effectiveUser) {
+    connectionCache.setEffectiveUser(effectiveUser);
+  }
+
+  /**
+   * Obtain HBaseAdmin. Creates the instance if it is not already created.
+   */
+  protected Admin getAdmin() throws IOException {
+    return connectionCache.getAdmin();
+  }
+
+  /**
+   * Creates and returns a Table instance from a given table name. n * name of table
+   * @return Table object
+   * @throws IOException if getting the table fails
+   */
+  protected Table getTable(final byte[] tableName) throws IOException {
+    String table = Bytes.toString(tableName);
+    return connectionCache.getTable(table);
+  }
+
+  protected Table getTable(final ByteBuffer tableName) throws IOException {
+    return getTable(Bytes.getBytes(tableName));
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HThreadedSelectorServerArgs.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HThreadedSelectorServerArgs.java
new file mode 100644
index 0000000..b8a7dda
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HThreadedSelectorServerArgs.java
@@ -0,0 +1,83 @@
+/*
+ * 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.thrift;
+
+import java.util.Locale;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.thrift.server.TThreadedSelectorServer;
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A TThreadedSelectorServer.Args that reads hadoop configuration
+ */
+@InterfaceAudience.Private
+public class HThreadedSelectorServerArgs extends TThreadedSelectorServer.Args {
+  private static final Logger LOG = LoggerFactory.getLogger(TThreadedSelectorServer.class);
+
+  /**
+   * Number of selector threads for reading and writing socket
+   */
+  public static final String SELECTOR_THREADS_CONF_KEY = "hbase.thrift.selector.threads";
+
+  /**
+   * Number fo threads for processing the thrift calls
+   */
+  public static final String WORKER_THREADS_CONF_KEY = "hbase.thrift.worker.threads";
+
+  /**
+   * Time to wait for server to stop gracefully
+   */
+  public static final String STOP_TIMEOUT_CONF_KEY = "hbase.thrift.stop.timeout.seconds";
+
+  /**
+   * Maximum number of accepted elements per selector
+   */
+  public static final String ACCEPT_QUEUE_SIZE_PER_THREAD_CONF_KEY =
+    "hbase.thrift.accept.queue.size.per.selector";
+
+  /**
+   * The strategy for handling new accepted connections.
+   */
+  public static final String ACCEPT_POLICY_CONF_KEY = "hbase.thrift.accept.policy";
+
+  public HThreadedSelectorServerArgs(TNonblockingServerTransport transport, Configuration conf) {
+    super(transport);
+    readConf(conf);
+  }
+
+  private void readConf(Configuration conf) {
+    int selectorThreads = conf.getInt(SELECTOR_THREADS_CONF_KEY, getSelectorThreads());
+    int workerThreads = conf.getInt(WORKER_THREADS_CONF_KEY, getWorkerThreads());
+    int stopTimeoutVal = conf.getInt(STOP_TIMEOUT_CONF_KEY, getStopTimeoutVal());
+    int acceptQueueSizePerThread =
+      conf.getInt(ACCEPT_QUEUE_SIZE_PER_THREAD_CONF_KEY, getAcceptQueueSizePerThread());
+    AcceptPolicy acceptPolicy = AcceptPolicy.valueOf(
+      conf.get(ACCEPT_POLICY_CONF_KEY, getAcceptPolicy().toString()).toUpperCase(Locale.ROOT));
+
+    super.selectorThreads(selectorThreads).workerThreads(workerThreads)
+      .stopTimeoutVal(stopTimeoutVal).acceptQueueSizePerThread(acceptQueueSizePerThread)
+      .acceptPolicy(acceptPolicy);
+
+    LOG.info("Read configuration selectorThreads:" + selectorThreads + " workerThreads:"
+      + workerThreads + " stopTimeoutVal:" + stopTimeoutVal + "sec" + " acceptQueueSizePerThread:"
+      + acceptQueueSizePerThread + " acceptPolicy:" + acceptPolicy);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java
new file mode 100644
index 0000000..c1c312f
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HbaseHandlerMetricsProxy.java
@@ -0,0 +1,80 @@
+/*
+ * 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.thrift;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.thrift.generated.Hbase;
+import org.apache.hadoop.hbase.thrift2.generated.THBaseService;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * Converts a Hbase.Iface using InvocationHandler so that it reports process time of each call to
+ * ThriftMetrics.
+ */
+@InterfaceAudience.Private
+public final class HbaseHandlerMetricsProxy implements InvocationHandler {
+
+  private final Object handler;
+  private final ThriftMetrics metrics;
+
+  public static Hbase.Iface newInstance(Hbase.Iface handler, ThriftMetrics metrics,
+    Configuration conf) {
+    return (Hbase.Iface) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
+      new Class[] { Hbase.Iface.class }, new HbaseHandlerMetricsProxy(handler, metrics, conf));
+  }
+
+  // for thrift 2
+  public static THBaseService.Iface newInstance(THBaseService.Iface handler, ThriftMetrics metrics,
+    Configuration conf) {
+    return (THBaseService.Iface) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
+      new Class[] { THBaseService.Iface.class },
+      new HbaseHandlerMetricsProxy(handler, metrics, conf));
+  }
+
+  private HbaseHandlerMetricsProxy(Object handler, ThriftMetrics metrics, Configuration conf) {
+    this.handler = handler;
+    this.metrics = metrics;
+  }
+
+  @Override
+  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+    Object result;
+    long start = now();
+    try {
+      result = m.invoke(handler, args);
+    } catch (InvocationTargetException e) {
+      metrics.exception(e.getCause());
+      throw e.getTargetException();
+    } catch (Exception e) {
+      metrics.exception(e);
+      throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
+    } finally {
+      long processTime = now() - start;
+      metrics.incMethodTime(m.getName(), processTime);
+    }
+    return result;
+  }
+
+  private static long now() {
+    return System.nanoTime();
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HttpAuthenticationException.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HttpAuthenticationException.java
new file mode 100644
index 0000000..a1cc718
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/HttpAuthenticationException.java
@@ -0,0 +1,47 @@
+/*
+ * 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.thrift;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+@InterfaceAudience.Private
+public class HttpAuthenticationException extends Exception {
+  private static final long serialVersionUID = 0;
+
+  /**
+   * @param cause original exception
+   */
+  public HttpAuthenticationException(Throwable cause) {
+    super(cause);
+  }
+
+  /**
+   * @param msg exception message
+   */
+  public HttpAuthenticationException(String msg) {
+    super(msg);
+  }
+
+  /**
+   * @param msg   exception message
+   * @param cause original exception
+   */
+  public HttpAuthenticationException(String msg, Throwable cause) {
+    super(msg, cause);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ImplType.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ImplType.java
new file mode 100644
index 0000000..85d8e70
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ImplType.java
@@ -0,0 +1,140 @@
+/*
+ * 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.thrift;
+
+import static org.apache.hadoop.hbase.thrift.Constants.SERVER_TYPE_CONF_KEY;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.thrift.server.THsHaServer;
+import org.apache.thrift.server.TNonblockingServer;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TThreadedSelectorServer;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.Option;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.OptionGroup;
+
+/** An enum of server implementation selections */
+@InterfaceAudience.Private
+public enum ImplType {
+  HS_HA("hsha", true, THsHaServer.class, true),
+  NONBLOCKING("nonblocking", true, TNonblockingServer.class, true),
+  THREAD_POOL("threadpool", false, TBoundedThreadPoolServer.class, true),
+  THREADED_SELECTOR("threadedselector", true, TThreadedSelectorServer.class, true);
+
+  private static final Logger LOG = LoggerFactory.getLogger(ImplType.class);
+  public static final ImplType DEFAULT = THREAD_POOL;
+
+  final String option;
+  final boolean isAlwaysFramed;
+  final Class<? extends TServer> serverClass;
+  final boolean canSpecifyBindIP;
+
+  private ImplType(String option, boolean isAlwaysFramed, Class<? extends TServer> serverClass,
+    boolean canSpecifyBindIP) {
+    this.option = option;
+    this.isAlwaysFramed = isAlwaysFramed;
+    this.serverClass = serverClass;
+    this.canSpecifyBindIP = canSpecifyBindIP;
+  }
+
+  /**
+   * @return <code>-option</code>
+   */
+  @Override
+  public String toString() {
+    return "-" + option;
+  }
+
+  public String getOption() {
+    return option;
+  }
+
+  public boolean isAlwaysFramed() {
+    return isAlwaysFramed;
+  }
+
+  public String getDescription() {
+    StringBuilder sb = new StringBuilder("Use the " + serverClass.getSimpleName());
+    if (isAlwaysFramed) {
+      sb.append(" This implies the framed transport.");
+    }
+    if (this == DEFAULT) {
+      sb.append("This is the default.");
+    }
+    return sb.toString();
+  }
+
+  static OptionGroup createOptionGroup() {
+    OptionGroup group = new OptionGroup();
+    for (ImplType t : values()) {
+      group.addOption(new Option(t.option, t.getDescription()));
+    }
+    return group;
+  }
+
+  public static ImplType getServerImpl(Configuration conf) {
+    String confType = conf.get(SERVER_TYPE_CONF_KEY, THREAD_POOL.option);
+    for (ImplType t : values()) {
+      if (confType.equals(t.option)) {
+        return t;
+      }
+    }
+    throw new AssertionError("Unknown server ImplType.option:" + confType);
+  }
+
+  static void setServerImpl(CommandLine cmd, Configuration conf) {
+    ImplType chosenType = null;
+    int numChosen = 0;
+    for (ImplType t : values()) {
+      if (cmd.hasOption(t.option)) {
+        chosenType = t;
+        ++numChosen;
+      }
+    }
+    if (numChosen < 1) {
+      LOG.info("Using default thrift server type");
+      chosenType = DEFAULT;
+    } else if (numChosen > 1) {
+      throw new AssertionError(
+        "Exactly one option out of " + Arrays.toString(values()) + " has to be specified");
+    }
+    LOG.info("Using thrift server type " + chosenType.option);
+    conf.set(SERVER_TYPE_CONF_KEY, chosenType.option);
+  }
+
+  public String simpleClassName() {
+    return serverClass.getSimpleName();
+  }
+
+  public static List<String> serversThatCannotSpecifyBindIP() {
+    List<String> l = new ArrayList<>();
+    for (ImplType t : values()) {
+      if (!t.canSpecifyBindIP) {
+        l.add(t.simpleClassName());
+      }
+    }
+    return l;
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescer.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescer.java
new file mode 100644
index 0000000..6f48e76
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescer.java
@@ -0,0 +1,376 @@
+/*
+ * 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.thrift;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
+import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.thrift.generated.TIncrement;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.Threads;
+import org.apache.hadoop.metrics2.util.MBeans;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+ * This class will coalesce increments from a thift server if
+ * hbase.regionserver.thrift.coalesceIncrement is set to true. Turning this config to true will
+ * cause the thrift server to queue increments into an instance of this class. The thread pool
+ * associated with this class will drain the coalesced increments as the thread is able. This can
+ * cause data loss if the thrift server dies or is shut down before everything in the queue is
+ * drained.
+ */
+@InterfaceAudience.Private
+public class IncrementCoalescer implements IncrementCoalescerMBean {
+  /**
+   * Used to identify a cell that will be incremented.
+   */
+  static class FullyQualifiedRow {
+    private byte[] table;
+    private byte[] rowKey;
+    private byte[] family;
+    private byte[] qualifier;
+
+    public FullyQualifiedRow(byte[] table, byte[] rowKey, byte[] fam, byte[] qual) {
+      super();
+      this.table = table;
+      this.rowKey = rowKey;
+      this.family = fam;
+      this.qualifier = qual;
+    }
+
+    public byte[] getTable() {
+      return table;
+    }
+
+    public void setTable(byte[] table) {
+      this.table = table;
+    }
+
+    public byte[] getRowKey() {
+      return rowKey;
+    }
+
+    public byte[] getFamily() {
+      return family;
+    }
+
+    public void setFamily(byte[] fam) {
+      this.family = fam;
+    }
+
+    public byte[] getQualifier() {
+      return qualifier;
+    }
+
+    public void setQualifier(byte[] qual) {
+      this.qualifier = qual;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + Arrays.hashCode(family);
+      result = prime * result + Arrays.hashCode(qualifier);
+      result = prime * result + Arrays.hashCode(rowKey);
+      result = prime * result + Arrays.hashCode(table);
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj) {
+        return true;
+      }
+      if (obj == null) {
+        return false;
+      }
+      if (getClass() != obj.getClass()) {
+        return false;
+      }
+
+      FullyQualifiedRow other = (FullyQualifiedRow) obj;
+
+      if (!Arrays.equals(family, other.family)) {
+        return false;
+      }
+      if (!Arrays.equals(qualifier, other.qualifier)) {
+        return false;
+      }
+      if (!Arrays.equals(rowKey, other.rowKey)) {
+        return false;
+      }
+
+      return Arrays.equals(table, other.table);
+    }
+  }
+
+  private final LongAdder failedIncrements = new LongAdder();
+  private final LongAdder successfulCoalescings = new LongAdder();
+  private final LongAdder totalIncrements = new LongAdder();
+  private final ConcurrentMap<FullyQualifiedRow, Long> countersMap =
+    new ConcurrentHashMap<>(100000, 0.75f, 1500);
+  private final ThreadPoolExecutor pool;
+  private final ThriftHBaseServiceHandler handler;
+
+  private int maxQueueSize = 500000;
+  private static final int CORE_POOL_SIZE = 1;
+
+  private static final Logger LOG = LoggerFactory.getLogger(IncrementCoalescer.class);
+
+  public IncrementCoalescer(ThriftHBaseServiceHandler hand) {
+    this.handler = hand;
+    LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
+    pool = new ThreadPoolExecutor(CORE_POOL_SIZE, CORE_POOL_SIZE, 50, TimeUnit.MILLISECONDS, queue,
+      new ThreadFactoryBuilder().setNameFormat("IncrementCoalescer-pool-%d").setDaemon(true)
+        .setUncaughtExceptionHandler(Threads.LOGGING_EXCEPTION_HANDLER).build());
+    MBeans.register("thrift", "Thrift", this);
+  }
+
+  public boolean queueIncrement(TIncrement inc) {
+    if (!canQueue()) {
+      failedIncrements.increment();
+      return false;
+    }
+    return internalQueueTincrement(inc);
+  }
+
+  public boolean queueIncrements(List<TIncrement> incs) {
+    if (!canQueue()) {
+      failedIncrements.increment();
+      return false;
+    }
+
+    for (TIncrement tinc : incs) {
+      internalQueueTincrement(tinc);
+    }
+
+    return true;
+  }
+
+  private boolean internalQueueTincrement(TIncrement inc) {
+    byte[][] famAndQf = CellUtil.parseColumn(inc.getColumn());
+
+    if (famAndQf.length != 2) {
+      return false;
+    }
+
+    return internalQueueIncrement(inc.getTable(), inc.getRow(), famAndQf[0], famAndQf[1],
+      inc.getAmmount());
+  }
+
+  @SuppressWarnings("FutureReturnValueIgnored")
+  private boolean internalQueueIncrement(byte[] tableName, byte[] rowKey, byte[] fam, byte[] qual,
+    long ammount) {
+    int countersMapSize = countersMap.size();
+
+    // Make sure that the number of threads is scaled.
+    dynamicallySetCoreSize(countersMapSize);
+
+    totalIncrements.increment();
+
+    FullyQualifiedRow key = new FullyQualifiedRow(tableName, rowKey, fam, qual);
+
+    long currentAmount = ammount;
+    // Spin until able to insert the value back without collisions
+    while (true) {
+      Long value = countersMap.remove(key);
+      if (value == null) {
+        // There was nothing there, create a new value
+        value = currentAmount;
+      } else {
+        value += currentAmount;
+        successfulCoalescings.increment();
+      }
+      // Try to put the value, only if there was none
+      Long oldValue = countersMap.putIfAbsent(key, value);
+      if (oldValue == null) {
+        // We were able to put it in, we're done
+        break;
+      }
+      // Someone else was able to put a value in, so let's remember our
+      // current value (plus what we picked up) and retry to add it in
+      currentAmount = value;
+    }
+
+    // We limit the size of the queue simply because all we need is a
+    // notification that something needs to be incremented. No need
+    // for millions of callables that mean the same thing.
+    if (pool.getQueue().size() <= 1000) {
+      // queue it up
+      Callable<Integer> callable = createIncCallable();
+      pool.submit(callable);
+    }
+
+    return true;
+  }
+
+  public boolean canQueue() {
+    return countersMap.size() < maxQueueSize;
+  }
+
+  private Callable<Integer> createIncCallable() {
+    return () -> {
+      int failures = 0;
+      Set<FullyQualifiedRow> keys = countersMap.keySet();
+      for (FullyQualifiedRow row : keys) {
+        Long counter = countersMap.remove(row);
+        if (counter == null) {
+          continue;
+        }
+        Table table = null;
+        try {
+          table = handler.getTable(row.getTable());
+          if (failures > 2) {
+            throw new IOException("Auto-Fail rest of ICVs");
+          }
+          table.incrementColumnValue(row.getRowKey(), row.getFamily(), row.getQualifier(), counter);
+        } catch (IOException e) {
+          // log failure of increment
+          failures++;
+          LOG.error("FAILED_ICV: " + Bytes.toString(row.getTable()) + ", "
+            + Bytes.toStringBinary(row.getRowKey()) + ", " + Bytes.toStringBinary(row.getFamily())
+            + ", " + Bytes.toStringBinary(row.getQualifier()) + ", " + counter, e);
+        } finally {
+          if (table != null) {
+            table.close();
+          }
+        }
+      }
+      return failures;
+    };
+  }
+
+  /**
+   * This method samples the incoming requests and, if selected, will check if the corePoolSize
+   * should be changed.
+   * @param countersMapSize the size of the counters map
+   */
+  private void dynamicallySetCoreSize(int countersMapSize) {
+    // Here we are using countersMapSize as a random number, meaning this
+    // could be a Random object
+    if (countersMapSize % 10 != 0) {
+      return;
+    }
+    double currentRatio = (double) countersMapSize / (double) maxQueueSize;
+    int newValue;
+
+    if (currentRatio < 0.1) {
+      newValue = 1;
+    } else if (currentRatio < 0.3) {
+      newValue = 2;
+    } else if (currentRatio < 0.5) {
+      newValue = 4;
+    } else if (currentRatio < 0.7) {
+      newValue = 8;
+    } else if (currentRatio < 0.9) {
+      newValue = 14;
+    } else {
+      newValue = 22;
+    }
+
+    if (pool.getCorePoolSize() != newValue) {
+      pool.setCorePoolSize(newValue);
+    }
+  }
+
+  // MBean get/set methods
+  @Override
+  public int getQueueSize() {
+    return pool.getQueue().size();
+  }
+
+  @Override
+  public int getMaxQueueSize() {
+    return this.maxQueueSize;
+  }
+
+  @Override
+  public void setMaxQueueSize(int newSize) {
+    this.maxQueueSize = newSize;
+  }
+
+  @Override
+  public long getPoolCompletedTaskCount() {
+    return pool.getCompletedTaskCount();
+  }
+
+  @Override
+  public long getPoolTaskCount() {
+    return pool.getTaskCount();
+  }
+
+  @Override
+  public int getPoolLargestPoolSize() {
+    return pool.getLargestPoolSize();
+  }
+
+  @Override
+  public int getCorePoolSize() {
+    return pool.getCorePoolSize();
+  }
+
+  @Override
+  public void setCorePoolSize(int newCoreSize) {
+    pool.setCorePoolSize(newCoreSize);
+  }
+
+  @Override
+  public int getMaxPoolSize() {
+    return pool.getMaximumPoolSize();
+  }
+
+  @Override
+  public void setMaxPoolSize(int newMaxSize) {
+    pool.setMaximumPoolSize(newMaxSize);
+  }
+
+  @Override
+  public long getFailedIncrements() {
+    return failedIncrements.sum();
+  }
+
+  @Override
+  public long getSuccessfulCoalescings() {
+    return successfulCoalescings.sum();
+  }
+
+  @Override
+  public long getTotalIncrements() {
+    return totalIncrements.sum();
+  }
+
+  @Override
+  public long getCountersMapSize() {
+    return countersMap.size();
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescerMBean.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescerMBean.java
new file mode 100644
index 0000000..e7e528c
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/IncrementCoalescerMBean.java
@@ -0,0 +1,51 @@
+/*
+ * 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.thrift;
+
+import org.apache.yetus.audience.InterfaceAudience;
+
+@InterfaceAudience.Private
+public interface IncrementCoalescerMBean {
+  int getQueueSize();
+
+  int getMaxQueueSize();
+
+  void setMaxQueueSize(int newSize);
+
+  long getPoolCompletedTaskCount();
+
+  long getPoolTaskCount();
+
+  int getPoolLargestPoolSize();
+
+  int getCorePoolSize();
+
+  void setCorePoolSize(int newCoreSize);
+
+  int getMaxPoolSize();
+
+  void setMaxPoolSize(int newMaxSize);
+
+  long getFailedIncrements();
+
+  long getSuccessfulCoalescings();
+
+  long getTotalIncrements();
+
+  long getCountersMapSize();
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/TBoundedThreadPoolServer.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/TBoundedThreadPoolServer.java
new file mode 100644
index 0000000..8da9173
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/TBoundedThreadPoolServer.java
@@ -0,0 +1,299 @@
+/*
+ * 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.thrift;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+import org.apache.hadoop.hbase.util.Threads;
+import org.apache.thrift.TException;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TThreadPoolServer;
+import org.apache.thrift.transport.TServerTransport;
+import org.apache.thrift.transport.TSocket;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+ * A bounded thread pool server customized for HBase.
+ */
+@InterfaceAudience.Private
+public class TBoundedThreadPoolServer extends TServer {
+
+  private static final String QUEUE_FULL_MSG = "Queue is full, closing connection";
+
+  /**
+   * The "core size" of the thread pool. New threads are created on every connection until this many
+   * threads are created.
+   */
+  public static final String MIN_WORKER_THREADS_CONF_KEY = "hbase.thrift.minWorkerThreads";
+
+  /**
+   * This default core pool size should be enough for many test scenarios. We want to override this
+   * with a much larger number (e.g. at least 200) for a large-scale production setup.
+   */
+  public static final int DEFAULT_MIN_WORKER_THREADS = 16;
+
+  /**
+   * The maximum size of the thread pool. When the pending request queue overflows, new threads are
+   * created until their number reaches this number. After that, the server starts dropping
+   * connections.
+   */
+  public static final String MAX_WORKER_THREADS_CONF_KEY = "hbase.thrift.maxWorkerThreads";
+
+  public static final int DEFAULT_MAX_WORKER_THREADS = 1000;
+
+  /**
+   * The maximum number of pending connections waiting in the queue. If there are no idle threads in
+   * the pool, the server queues requests. Only when the queue overflows, new threads are added, up
+   * to hbase.thrift.maxQueuedRequests threads.
+   */
+  public static final String MAX_QUEUED_REQUESTS_CONF_KEY = "hbase.thrift.maxQueuedRequests";
+
+  public static final int DEFAULT_MAX_QUEUED_REQUESTS = 1000;
+
+  /**
+   * Default amount of time in seconds to keep a thread alive. Worker threads are stopped after
+   * being idle for this long.
+   */
+  public static final String THREAD_KEEP_ALIVE_TIME_SEC_CONF_KEY =
+    "hbase.thrift.threadKeepAliveTimeSec";
+
+  private static final int DEFAULT_THREAD_KEEP_ALIVE_TIME_SEC = 60;
+
+  /**
+   * Time to wait after interrupting all worker threads. This is after a clean shutdown has been
+   * attempted.
+   */
+  public static final int TIME_TO_WAIT_AFTER_SHUTDOWN_MS = 5000;
+
+  private static final Logger LOG =
+    LoggerFactory.getLogger(TBoundedThreadPoolServer.class.getName());
+
+  private final CallQueue callQueue;
+
+  public static class Args extends TThreadPoolServer.Args {
+    int maxQueuedRequests;
+    int threadKeepAliveTimeSec;
+
+    public Args(TServerTransport transport, Configuration conf) {
+      super(transport);
+      minWorkerThreads = conf.getInt(MIN_WORKER_THREADS_CONF_KEY, DEFAULT_MIN_WORKER_THREADS);
+      maxWorkerThreads = conf.getInt(MAX_WORKER_THREADS_CONF_KEY, DEFAULT_MAX_WORKER_THREADS);
+      maxQueuedRequests = conf.getInt(MAX_QUEUED_REQUESTS_CONF_KEY, DEFAULT_MAX_QUEUED_REQUESTS);
+      threadKeepAliveTimeSec =
+        conf.getInt(THREAD_KEEP_ALIVE_TIME_SEC_CONF_KEY, DEFAULT_THREAD_KEEP_ALIVE_TIME_SEC);
+    }
+
+    @Override
+    public String toString() {
+      return "min worker threads=" + minWorkerThreads + ", max worker threads=" + maxWorkerThreads
+        + ", max queued requests=" + maxQueuedRequests;
+    }
+  }
+
+  /** Executor service for handling client connections */
+  private ThreadPoolExecutor executorService;
+
+  /** Flag for stopping the server */
+  private volatile boolean stopped;
+
+  private Args serverOptions;
+
+  public TBoundedThreadPoolServer(Args options, ThriftMetrics metrics) {
+    super(options);
+
+    int minWorkerThreads = options.minWorkerThreads;
+    int maxWorkerThreads = options.maxWorkerThreads;
+    if (options.maxQueuedRequests > 0) {
+      this.callQueue = new CallQueue(new LinkedBlockingQueue<>(options.maxQueuedRequests), metrics);
+      minWorkerThreads = maxWorkerThreads;
+    } else {
+      this.callQueue = new CallQueue(new SynchronousQueue<>(), metrics);
+    }
+
+    ThreadFactoryBuilder tfb = new ThreadFactoryBuilder();
+    tfb.setDaemon(true);
+    tfb.setNameFormat("thrift-worker-%d");
+    executorService = new THBaseThreadPoolExecutor(minWorkerThreads, maxWorkerThreads,
+      options.threadKeepAliveTimeSec, TimeUnit.SECONDS, this.callQueue, tfb.build(), metrics);
+    executorService.allowCoreThreadTimeOut(true);
+    serverOptions = options;
+  }
+
+  @Override
+  public void serve() {
+    try {
+      serverTransport_.listen();
+    } catch (TTransportException ttx) {
+      LOG.error("Error occurred during listening.", ttx);
+      return;
+    }
+
+    Runtime.getRuntime().addShutdownHook(new Thread(getClass().getSimpleName() + "-shutdown-hook") {
+      @Override
+      public void run() {
+        TBoundedThreadPoolServer.this.stop();
+      }
+    });
+
+    stopped = false;
+    while (!stopped && !Thread.interrupted()) {
+      TTransport client = null;
+      try {
+        client = serverTransport_.accept();
+      } catch (TTransportException ttx) {
+        if (!stopped) {
+          LOG.warn("Transport error when accepting message", ttx);
+          continue;
+        } else {
+          // The server has been stopped
+          break;
+        }
+      }
+
+      ClientConnnection command = new ClientConnnection(client);
+      try {
+        executorService.execute(command);
+      } catch (RejectedExecutionException rex) {
+        if (client.getClass() == TSocket.class) {
+          // We expect the client to be TSocket.
+          LOG.warn(
+            QUEUE_FULL_MSG + " from " + ((TSocket) client).getSocket().getRemoteSocketAddress());
+        } else {
+          LOG.warn(QUEUE_FULL_MSG, rex);
+        }
+        client.close();
+      }
+    }
+
+    shutdownServer();
+  }
+
+  /**
+   * Loop until {@link ExecutorService#awaitTermination} finally does return without an interrupted
+   * exception. If we don't do this, then we'll shut down prematurely. We want to let the executor
+   * service clear its task queue, closing client sockets appropriately.
+   */
+  private void shutdownServer() {
+    executorService.shutdown();
+
+    long msLeftToWait = serverOptions.stopTimeoutUnit.toMillis(serverOptions.stopTimeoutVal);
+    long timeMillis = EnvironmentEdgeManager.currentTime();
+
+    LOG
+      .info("Waiting for up to " + msLeftToWait + " ms to finish processing" + " pending requests");
+    boolean interrupted = false;
+    while (msLeftToWait >= 0) {
+      try {
+        executorService.awaitTermination(msLeftToWait, TimeUnit.MILLISECONDS);
+        break;
+      } catch (InterruptedException ix) {
+        long timePassed = EnvironmentEdgeManager.currentTime() - timeMillis;
+        msLeftToWait -= timePassed;
+        timeMillis += timePassed;
+        interrupted = true;
+      }
+    }
+
+    LOG.info("Interrupting all worker threads and waiting for " + TIME_TO_WAIT_AFTER_SHUTDOWN_MS
+      + " ms longer");
+
+    // This will interrupt all the threads, even those running a task.
+    executorService.shutdownNow();
+    Threads.sleepWithoutInterrupt(TIME_TO_WAIT_AFTER_SHUTDOWN_MS);
+
+    // Preserve the interrupted status.
+    if (interrupted) {
+      Thread.currentThread().interrupt();
+    }
+    LOG.info("Thrift server shutdown complete");
+  }
+
+  @Override
+  public void stop() {
+    stopped = true;
+    serverTransport_.interrupt();
+  }
+
+  private final class ClientConnnection implements Runnable {
+
+    private TTransport client;
+
+    /**
+     * Default constructor.
+     * @param client Transport to process
+     */
+    private ClientConnnection(TTransport client) {
+      this.client = client;
+    }
+
+    /**
+     * Loops on processing a client forever
+     */
+    @Override
+    public void run() {
+      TProcessor processor = null;
+      TTransport inputTransport = null;
+      TTransport outputTransport = null;
+      TProtocol inputProtocol = null;
+      TProtocol outputProtocol = null;
+      try {
+        processor = processorFactory_.getProcessor(client);
+        inputTransport = inputTransportFactory_.getTransport(client);
+        outputTransport = outputTransportFactory_.getTransport(client);
+        inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);
+        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);
+        // we check stopped_ first to make sure we're not supposed to be shutting
+        // down. this is necessary for graceful shutdown.
+        while (true) {
+          if (stopped) {
+            break;
+          }
+          processor.process(inputProtocol, outputProtocol);
+        }
+      } catch (TTransportException ttx) {
+        // Assume the client died and continue silently
+      } catch (TException tx) {
+        LOG.error("Thrift error occurred during processing of message.", tx);
+      } catch (Exception x) {
+        LOG.error("Error occurred during processing of message.", x);
+      }
+
+      if (inputTransport != null) {
+        inputTransport.close();
+      }
+
+      if (outputTransport != null) {
+        outputTransport.close();
+      }
+    }
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/THBaseThreadPoolExecutor.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/THBaseThreadPoolExecutor.java
new file mode 100644
index 0000000..a3562c7
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/THBaseThreadPoolExecutor.java
@@ -0,0 +1,62 @@
+/*
+ * 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.thrift;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.apache.yetus.audience.InterfaceAudience;
+
+/**
+ * A ThreadPoolExecutor customized for working with HBase thrift to update metrics before and after
+ * the execution of a task.
+ */
+
+@InterfaceAudience.Private
+public class THBaseThreadPoolExecutor extends ThreadPoolExecutor {
+
+  private ThriftMetrics metrics;
+
+  public THBaseThreadPoolExecutor(int corePoolSize, int maxPoolSize, long keepAliveTime,
+    TimeUnit unit, BlockingQueue<Runnable> workQueue, ThriftMetrics metrics) {
+    this(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, null, metrics);
+  }
+
+  public THBaseThreadPoolExecutor(int corePoolSize, int maxPoolSize, long keepAliveTime,
+    TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
+    ThriftMetrics metrics) {
+    super(corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue);
+    if (threadFactory != null) {
+      setThreadFactory(threadFactory);
+    }
+    this.metrics = metrics;
+  }
+
+  @Override
+  protected void beforeExecute(Thread t, Runnable r) {
+    super.beforeExecute(t, r);
+    metrics.incActiveWorkerCount();
+  }
+
+  @Override
+  protected void afterExecute(Runnable r, Throwable t) {
+    metrics.decActiveWorkerCount();
+    super.afterExecute(r, t);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHBaseServiceHandler.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHBaseServiceHandler.java
new file mode 100644
index 0000000..d7085c6
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHBaseServiceHandler.java
@@ -0,0 +1,1346 @@
+/*
+ * 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.thrift;
+
+import static org.apache.hadoop.hbase.HConstants.DEFAULT_HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD;
+import static org.apache.hadoop.hbase.HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD;
+import static org.apache.hadoop.hbase.thrift.Constants.COALESCE_INC_KEY;
+import static org.apache.hadoop.hbase.util.Bytes.getBytes;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.CatalogFamilyFormat;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellBuilder;
+import org.apache.hadoop.hbase.CellBuilderFactory;
+import org.apache.hadoop.hbase.CellBuilderType;
+import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.DoNotRetryIOException;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.TableNotFoundException;
+import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.Durability;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.Increment;
+import org.apache.hadoop.hbase.client.OperationWithAttributes;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.RegionInfo;
+import org.apache.hadoop.hbase.client.RegionLocator;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.filter.Filter;
+import org.apache.hadoop.hbase.filter.ParseFilter;
+import org.apache.hadoop.hbase.filter.PrefixFilter;
+import org.apache.hadoop.hbase.filter.WhileMatchFilter;
+import org.apache.hadoop.hbase.security.UserProvider;
+import org.apache.hadoop.hbase.security.access.AccessControlClient;
+import org.apache.hadoop.hbase.security.access.Permission;
+import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
+import org.apache.hadoop.hbase.thrift.generated.BatchMutation;
+import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
+import org.apache.hadoop.hbase.thrift.generated.Hbase;
+import org.apache.hadoop.hbase.thrift.generated.IOError;
+import org.apache.hadoop.hbase.thrift.generated.IllegalArgument;
+import org.apache.hadoop.hbase.thrift.generated.Mutation;
+import org.apache.hadoop.hbase.thrift.generated.TAccessControlEntity;
+import org.apache.hadoop.hbase.thrift.generated.TAppend;
+import org.apache.hadoop.hbase.thrift.generated.TCell;
+import org.apache.hadoop.hbase.thrift.generated.TIncrement;
+import org.apache.hadoop.hbase.thrift.generated.TPermissionScope;
+import org.apache.hadoop.hbase.thrift.generated.TRegionInfo;
+import org.apache.hadoop.hbase.thrift.generated.TRowResult;
+import org.apache.hadoop.hbase.thrift.generated.TScan;
+import org.apache.hadoop.hbase.thrift.generated.TThriftServerType;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.thrift.TException;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
+import org.apache.hbase.thirdparty.com.google.common.cache.Cache;
+import org.apache.hbase.thirdparty.com.google.common.cache.CacheBuilder;
+
+/**
+ * The HBaseServiceHandler is a glue object that connects Thrift RPC calls to the HBase client API
+ * primarily defined in the Admin and Table objects.
+ */
+@InterfaceAudience.Private
+@SuppressWarnings("deprecation")
+public class ThriftHBaseServiceHandler extends HBaseServiceHandler implements Hbase.Iface {
+  private static final Logger LOG = LoggerFactory.getLogger(ThriftHBaseServiceHandler.class);
+
+  public static final int HREGION_VERSION = 1;
+
+  // nextScannerId and scannerMap are used to manage scanner state
+  private int nextScannerId = 0;
+  private Cache<Integer, ResultScannerWrapper> scannerMap;
+  IncrementCoalescer coalescer;
+
+  /**
+   * Returns a list of all the column families for a given Table.
+   */
+  byte[][] getAllColumns(Table table) throws IOException {
+    ColumnFamilyDescriptor[] cds = table.getDescriptor().getColumnFamilies();
+    byte[][] columns = new byte[cds.length][];
+    for (int i = 0; i < cds.length; i++) {
+      columns[i] = Bytes.add(cds[i].getName(), KeyValue.COLUMN_FAMILY_DELIM_ARRAY);
+    }
+    return columns;
+  }
+
+  /**
+   * Assigns a unique ID to the scanner and adds the mapping to an internal hash-map.
+   * @param scanner the {@link ResultScanner} to add
+   * @return integer scanner id
+   */
+  protected synchronized int addScanner(ResultScanner scanner, boolean sortColumns) {
+    int id = nextScannerId++;
+    ResultScannerWrapper resultScannerWrapper = new ResultScannerWrapper(scanner, sortColumns);
+    scannerMap.put(id, resultScannerWrapper);
+    return id;
+  }
+
+  /**
+   * Returns the scanner associated with the specified ID.
+   * @param id the ID of the scanner to get
+   * @return a Scanner, or null if ID was invalid.
+   */
+  private synchronized ResultScannerWrapper getScanner(int id) {
+    return scannerMap.getIfPresent(id);
+  }
+
+  /**
+   * Removes the scanner associated with the specified ID from the internal id-&gt;scanner hash-map.
+   * @param id the ID of the scanner to remove
+   */
+  private synchronized void removeScanner(int id) {
+    scannerMap.invalidate(id);
+  }
+
+  protected ThriftHBaseServiceHandler(final Configuration c, final UserProvider userProvider)
+    throws IOException {
+    super(c, userProvider);
+    long cacheTimeout =
+      c.getLong(HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, DEFAULT_HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD)
+        * 2;
+
+    scannerMap =
+      CacheBuilder.newBuilder().expireAfterAccess(cacheTimeout, TimeUnit.MILLISECONDS).build();
+
+    this.coalescer = new IncrementCoalescer(this);
+  }
+
+  @Override
+  public void enableTable(ByteBuffer tableName) throws IOError {
+    try {
+      getAdmin().enableTable(getTableName(tableName));
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public void disableTable(ByteBuffer tableName) throws IOError {
+    try {
+      getAdmin().disableTable(getTableName(tableName));
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public boolean isTableEnabled(ByteBuffer tableName) throws IOError {
+    try {
+      return this.connectionCache.getAdmin().isTableEnabled(getTableName(tableName));
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public Map<ByteBuffer, Boolean> getTableNamesWithIsTableEnabled() throws IOError {
+    try {
+      HashMap<ByteBuffer, Boolean> tables = new HashMap<>();
+      for (ByteBuffer tableName : this.getTableNames()) {
+        tables.put(tableName, this.isTableEnabled(tableName));
+      }
+      return tables;
+    } catch (IOError e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  // ThriftServerRunner.compact should be deprecated and replaced with methods specific to
+  // table and region.
+  @Override
+  public void compact(ByteBuffer tableNameOrRegionName) throws IOError {
+    try {
+      try {
+        getAdmin().compactRegion(getBytes(tableNameOrRegionName));
+      } catch (IllegalArgumentException e) {
+        // Invalid region, try table
+        getAdmin().compact(TableName.valueOf(getBytes(tableNameOrRegionName)));
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  // ThriftServerRunner.majorCompact should be deprecated and replaced with methods specific
+  // to table and region.
+  @Override
+  public void majorCompact(ByteBuffer tableNameOrRegionName) throws IOError {
+    try {
+      try {
+        getAdmin().compactRegion(getBytes(tableNameOrRegionName));
+      } catch (IllegalArgumentException e) {
+        // Invalid region, try table
+        getAdmin().compact(TableName.valueOf(getBytes(tableNameOrRegionName)));
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public List<ByteBuffer> getTableNames() throws IOError {
+    try {
+      TableName[] tableNames = this.getAdmin().listTableNames();
+      ArrayList<ByteBuffer> list = new ArrayList<>(tableNames.length);
+      for (TableName tableName : tableNames) {
+        list.add(ByteBuffer.wrap(tableName.getName()));
+      }
+      return list;
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  /**
+   * @return the list of regions in the given table, or an empty list if the table does not exist
+   */
+  @Override
+  public List<TRegionInfo> getTableRegions(ByteBuffer tableName) throws IOError {
+    try (RegionLocator locator = connectionCache.getRegionLocator(getBytes(tableName))) {
+      List<HRegionLocation> regionLocations = locator.getAllRegionLocations();
+      List<TRegionInfo> results = new ArrayList<>(regionLocations.size());
+      for (HRegionLocation regionLocation : regionLocations) {
+        RegionInfo info = regionLocation.getRegion();
+        ServerName serverName = regionLocation.getServerName();
+        TRegionInfo region = new TRegionInfo();
+        region.serverName = ByteBuffer.wrap(Bytes.toBytes(serverName.getHostname()));
+        region.port = serverName.getPort();
+        region.startKey = ByteBuffer.wrap(info.getStartKey());
+        region.endKey = ByteBuffer.wrap(info.getEndKey());
+        region.id = info.getRegionId();
+        region.name = ByteBuffer.wrap(info.getRegionName());
+        region.version = HREGION_VERSION; // HRegion now not versioned, PB encoding used
+        results.add(region);
+      }
+      return results;
+    } catch (TableNotFoundException e) {
+      // Return empty list for non-existing table
+      return Collections.emptyList();
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public List<TCell> get(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+    if (famAndQf.length == 1) {
+      return get(tableName, row, famAndQf[0], null, attributes);
+    }
+    if (famAndQf.length == 2) {
+      return get(tableName, row, famAndQf[0], famAndQf[1], attributes);
+    }
+    throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
+  }
+
+  /**
+   * Note: this internal interface is slightly different from public APIs in regard to handling of
+   * the qualifier. Here we differ from the public Java API in that null != byte[0]. Rather, we
+   * respect qual == null as a request for the entire column family. The caller (
+   * {@link #get(ByteBuffer, ByteBuffer, ByteBuffer, Map)}) interface IS consistent in that the
+   * column is parse like normal.
+   */
+  protected List<TCell> get(ByteBuffer tableName, ByteBuffer row, byte[] family, byte[] qualifier,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Get get = new Get(getBytes(row));
+      addAttributes(get, attributes);
+      if (qualifier == null) {
+        get.addFamily(family);
+      } else {
+        get.addColumn(family, qualifier);
+      }
+      Result result = table.get(get);
+      return ThriftUtilities.cellFromHBase(result.rawCells());
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
+    int numVersions, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+    if (famAndQf.length == 1) {
+      return getVer(tableName, row, famAndQf[0], null, numVersions, attributes);
+    }
+    if (famAndQf.length == 2) {
+      return getVer(tableName, row, famAndQf[0], famAndQf[1], numVersions, attributes);
+    }
+    throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
+
+  }
+
+  /**
+   * Note: this public interface is slightly different from public Java APIs in regard to handling
+   * of the qualifier. Here we differ from the public Java API in that null != byte[0]. Rather, we
+   * respect qual == null as a request for the entire column family. If you want to access the
+   * entire column family, use {@link #getVer(ByteBuffer, ByteBuffer, ByteBuffer, int, Map)} with a
+   * {@code column} value that lacks a {@code ':'}.
+   */
+  public List<TCell> getVer(ByteBuffer tableName, ByteBuffer row, byte[] family, byte[] qualifier,
+    int numVersions, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Get get = new Get(getBytes(row));
+      addAttributes(get, attributes);
+      if (null == qualifier) {
+        get.addFamily(family);
+      } else {
+        get.addColumn(family, qualifier);
+      }
+      get.readVersions(numVersions);
+      Result result = table.get(get);
+      return ThriftUtilities.cellFromHBase(result.rawCells());
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public List<TCell> getVerTs(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
+    long timestamp, int numVersions, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+    if (famAndQf.length == 1) {
+      return getVerTs(tableName, row, famAndQf[0], null, timestamp, numVersions, attributes);
+    }
+    if (famAndQf.length == 2) {
+      return getVerTs(tableName, row, famAndQf[0], famAndQf[1], timestamp, numVersions, attributes);
+    }
+    throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
+  }
+
+  /**
+   * Note: this internal interface is slightly different from public APIs in regard to handling of
+   * the qualifier. Here we differ from the public Java API in that null != byte[0]. Rather, we
+   * respect qual == null as a request for the entire column family. The caller (
+   * {@link #getVerTs(ByteBuffer, ByteBuffer, ByteBuffer, long, int, Map)}) interface IS consistent
+   * in that the column is parse like normal.
+   */
+  protected List<TCell> getVerTs(ByteBuffer tableName, ByteBuffer row, byte[] family,
+    byte[] qualifier, long timestamp, int numVersions, Map<ByteBuffer, ByteBuffer> attributes)
+    throws IOError {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Get get = new Get(getBytes(row));
+      addAttributes(get, attributes);
+      if (null == qualifier) {
+        get.addFamily(family);
+      } else {
+        get.addColumn(family, qualifier);
+      }
+      get.setTimeRange(0, timestamp);
+      get.readVersions(numVersions);
+      Result result = table.get(get);
+      return ThriftUtilities.cellFromHBase(result.rawCells());
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public List<TRowResult> getRow(ByteBuffer tableName, ByteBuffer row,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowWithColumnsTs(tableName, row, null, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowWithColumns(ByteBuffer tableName, ByteBuffer row,
+    List<ByteBuffer> columns, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowWithColumnsTs(tableName, row, columns, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowTs(ByteBuffer tableName, ByteBuffer row, long timestamp,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowWithColumnsTs(tableName, row, null, timestamp, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowWithColumnsTs(ByteBuffer tableName, ByteBuffer row,
+    List<ByteBuffer> columns, long timestamp, Map<ByteBuffer, ByteBuffer> attributes)
+    throws IOError {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      if (columns == null) {
+        Get get = new Get(getBytes(row));
+        addAttributes(get, attributes);
+        get.setTimeRange(0, timestamp);
+        Result result = table.get(get);
+        return ThriftUtilities.rowResultFromHBase(result);
+      }
+      Get get = new Get(getBytes(row));
+      addAttributes(get, attributes);
+      for (ByteBuffer column : columns) {
+        byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+        if (famAndQf.length == 1) {
+          get.addFamily(famAndQf[0]);
+        } else {
+          get.addColumn(famAndQf[0], famAndQf[1]);
+        }
+      }
+      get.setTimeRange(0, timestamp);
+      Result result = table.get(get);
+      return ThriftUtilities.rowResultFromHBase(result);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public List<TRowResult> getRows(ByteBuffer tableName, List<ByteBuffer> rows,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowsWithColumnsTs(tableName, rows, null, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowsWithColumns(ByteBuffer tableName, List<ByteBuffer> rows,
+    List<ByteBuffer> columns, Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowsWithColumnsTs(tableName, rows, columns, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowsTs(ByteBuffer tableName, List<ByteBuffer> rows, long timestamp,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    return getRowsWithColumnsTs(tableName, rows, null, timestamp, attributes);
+  }
+
+  @Override
+  public List<TRowResult> getRowsWithColumnsTs(ByteBuffer tableName, List<ByteBuffer> rows,
+    List<ByteBuffer> columns, long timestamp, Map<ByteBuffer, ByteBuffer> attributes)
+    throws IOError {
+
+    Table table = null;
+    try {
+      List<Get> gets = new ArrayList<>(rows.size());
+      table = getTable(tableName);
+      if (metrics != null) {
+        metrics.incNumRowKeysInBatchGet(rows.size());
+      }
+      for (ByteBuffer row : rows) {
+        Get get = new Get(getBytes(row));
+        addAttributes(get, attributes);
+        if (columns != null) {
+
+          for (ByteBuffer column : columns) {
+            byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+            if (famAndQf.length == 1) {
+              get.addFamily(famAndQf[0]);
+            } else {
+              get.addColumn(famAndQf[0], famAndQf[1]);
+            }
+          }
+        }
+        get.setTimeRange(0, timestamp);
+        gets.add(get);
+      }
+      Result[] result = table.get(gets);
+      return ThriftUtilities.rowResultFromHBase(result);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void deleteAll(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    deleteAllTs(tableName, row, column, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public void deleteAllTs(ByteBuffer tableName, ByteBuffer row, ByteBuffer column, long timestamp,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Delete delete = new Delete(getBytes(row));
+      addAttributes(delete, attributes);
+      byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+      if (famAndQf.length == 1) {
+        delete.addFamily(famAndQf[0], timestamp);
+      } else {
+        delete.addColumns(famAndQf[0], famAndQf[1], timestamp);
+      }
+      table.delete(delete);
+
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void deleteAllRow(ByteBuffer tableName, ByteBuffer row,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    deleteAllRowTs(tableName, row, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public void deleteAllRowTs(ByteBuffer tableName, ByteBuffer row, long timestamp,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Delete delete = new Delete(getBytes(row), timestamp);
+      addAttributes(delete, attributes);
+      table.delete(delete);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void createTable(ByteBuffer in_tableName, List<ColumnDescriptor> columnFamilies)
+    throws IOError, IllegalArgument, AlreadyExists {
+    TableName tableName = getTableName(in_tableName);
+    try {
+      if (getAdmin().tableExists(tableName)) {
+        throw new AlreadyExists("table name already in use");
+      }
+      TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(tableName);
+      for (ColumnDescriptor col : columnFamilies) {
+        builder.setColumnFamily(ThriftUtilities.colDescFromThrift(col));
+      }
+      getAdmin().createTable(builder.build());
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } catch (IllegalArgumentException e) {
+      LOG.warn(e.getMessage(), e);
+      throw new IllegalArgument(Throwables.getStackTraceAsString(e));
+    }
+  }
+
+  private static TableName getTableName(ByteBuffer buffer) {
+    return TableName.valueOf(getBytes(buffer));
+  }
+
+  @Override
+  public void deleteTable(ByteBuffer in_tableName) throws IOError {
+    TableName tableName = getTableName(in_tableName);
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("deleteTable: table={}", tableName);
+    }
+    try {
+      if (!getAdmin().tableExists(tableName)) {
+        throw new IOException("table does not exist");
+      }
+      getAdmin().deleteTable(tableName);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public void mutateRow(ByteBuffer tableName, ByteBuffer row, List<Mutation> mutations,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError, IllegalArgument {
+    mutateRowTs(tableName, row, mutations, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public void mutateRowTs(ByteBuffer tableName, ByteBuffer row, List<Mutation> mutations,
+    long timestamp, Map<ByteBuffer, ByteBuffer> attributes) throws IOError, IllegalArgument {
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Put put = new Put(getBytes(row), timestamp);
+      addAttributes(put, attributes);
+
+      Delete delete = new Delete(getBytes(row));
+      addAttributes(delete, attributes);
+      if (metrics != null) {
+        metrics.incNumRowKeysInBatchMutate(mutations.size());
+      }
+
+      // I apologize for all this mess :)
+      CellBuilder builder = CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY);
+      for (Mutation m : mutations) {
+        byte[][] famAndQf = CellUtil.parseColumn(getBytes(m.column));
+        if (m.isDelete) {
+          if (famAndQf.length == 1) {
+            delete.addFamily(famAndQf[0], timestamp);
+          } else {
+            delete.addColumns(famAndQf[0], famAndQf[1], timestamp);
+          }
+          delete.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
+        } else {
+          if (famAndQf.length == 1) {
+            LOG.warn("No column qualifier specified. Delete is the only mutation supported "
+              + "over the whole column family.");
+          } else {
+            put.add(builder.clear().setRow(put.getRow()).setFamily(famAndQf[0])
+              .setQualifier(famAndQf[1]).setTimestamp(put.getTimestamp()).setType(Cell.Type.Put)
+              .setValue(m.value != null ? getBytes(m.value) : HConstants.EMPTY_BYTE_ARRAY).build());
+          }
+          put.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
+        }
+      }
+      if (!delete.isEmpty()) {
+        table.delete(delete);
+      }
+      if (!put.isEmpty()) {
+        table.put(put);
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } catch (IllegalArgumentException e) {
+      LOG.warn(e.getMessage(), e);
+      throw new IllegalArgument(Throwables.getStackTraceAsString(e));
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void mutateRows(ByteBuffer tableName, List<BatchMutation> rowBatches,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError, IllegalArgument, TException {
+    mutateRowsTs(tableName, rowBatches, HConstants.LATEST_TIMESTAMP, attributes);
+  }
+
+  @Override
+  public void mutateRowsTs(ByteBuffer tableName, List<BatchMutation> rowBatches, long timestamp,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError, IllegalArgument, TException {
+    List<Put> puts = new ArrayList<>();
+    List<Delete> deletes = new ArrayList<>();
+    CellBuilder builder = CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY);
+    for (BatchMutation batch : rowBatches) {
+      byte[] row = getBytes(batch.row);
+      List<Mutation> mutations = batch.mutations;
+      Delete delete = new Delete(row);
+      addAttributes(delete, attributes);
+      Put put = new Put(row, timestamp);
+      addAttributes(put, attributes);
+      for (Mutation m : mutations) {
+        byte[][] famAndQf = CellUtil.parseColumn(getBytes(m.column));
+        if (m.isDelete) {
+          // no qualifier, family only.
+          if (famAndQf.length == 1) {
+            delete.addFamily(famAndQf[0], timestamp);
+          } else {
+            delete.addColumns(famAndQf[0], famAndQf[1], timestamp);
+          }
+          delete.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
+        } else {
+          if (famAndQf.length == 1) {
+            LOG.warn("No column qualifier specified. Delete is the only mutation supported "
+              + "over the whole column family.");
+          }
+          if (famAndQf.length == 2) {
+            try {
+              put.add(builder.clear().setRow(put.getRow()).setFamily(famAndQf[0])
+                .setQualifier(famAndQf[1]).setTimestamp(put.getTimestamp()).setType(Cell.Type.Put)
+                .setValue(m.value != null ? getBytes(m.value) : HConstants.EMPTY_BYTE_ARRAY)
+                .build());
+            } catch (IOException e) {
+              throw new IllegalArgumentException(e);
+            }
+          } else {
+            throw new IllegalArgumentException("Invalid famAndQf provided.");
+          }
+          put.setDurability(m.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
+        }
+      }
+      if (!delete.isEmpty()) {
+        deletes.add(delete);
+      }
+      if (!put.isEmpty()) {
+        puts.add(put);
+      }
+    }
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      if (!puts.isEmpty()) {
+        table.put(puts);
+      }
+      if (!deletes.isEmpty()) {
+        table.delete(deletes);
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } catch (IllegalArgumentException e) {
+      LOG.warn(e.getMessage(), e);
+      throw new IllegalArgument(Throwables.getStackTraceAsString(e));
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public long atomicIncrement(ByteBuffer tableName, ByteBuffer row, ByteBuffer column, long amount)
+    throws IOError, IllegalArgument, TException {
+    byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+    if (famAndQf.length == 1) {
+      return atomicIncrement(tableName, row, famAndQf[0], HConstants.EMPTY_BYTE_ARRAY, amount);
+    }
+    return atomicIncrement(tableName, row, famAndQf[0], famAndQf[1], amount);
+  }
+
+  protected long atomicIncrement(ByteBuffer tableName, ByteBuffer row, byte[] family,
+    byte[] qualifier, long amount) throws IOError, IllegalArgument, TException {
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      return table.incrementColumnValue(getBytes(row), family, qualifier, amount);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void scannerClose(int id) throws IOError, IllegalArgument {
+    LOG.debug("scannerClose: id={}", id);
+    ResultScannerWrapper resultScannerWrapper = getScanner(id);
+    if (resultScannerWrapper == null) {
+      LOG.warn("scanner ID is invalid");
+      throw new IllegalArgument("scanner ID is invalid");
+    }
+    resultScannerWrapper.getScanner().close();
+    removeScanner(id);
+  }
+
+  @Override
+  public List<TRowResult> scannerGetList(int id, int nbRows) throws IllegalArgument, IOError {
+    LOG.debug("scannerGetList: id={}", id);
+    ResultScannerWrapper resultScannerWrapper = getScanner(id);
+    if (null == resultScannerWrapper) {
+      String message = "scanner ID is invalid";
+      LOG.warn(message);
+      throw new IllegalArgument("scanner ID is invalid");
+    }
+
+    Result[] results;
+    try {
+      results = resultScannerWrapper.getScanner().next(nbRows);
+      if (null == results) {
+        return new ArrayList<>();
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      // Add scanner back to scannerMap; protects against case
+      // where scanner expired during processing of request.
+      scannerMap.put(id, resultScannerWrapper);
+    }
+    return ThriftUtilities.rowResultFromHBase(results, resultScannerWrapper.isColumnSorted());
+  }
+
+  @Override
+  public List<TRowResult> scannerGet(int id) throws IllegalArgument, IOError {
+    return scannerGetList(id, 1);
+  }
+
+  @Override
+  public int scannerOpenWithScan(ByteBuffer tableName, TScan tScan,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan();
+      addAttributes(scan, attributes);
+      if (tScan.isSetStartRow()) {
+        scan.withStartRow(tScan.getStartRow());
+      }
+      if (tScan.isSetStopRow()) {
+        scan.withStopRow(tScan.getStopRow());
+      }
+      if (tScan.isSetTimestamp()) {
+        scan.setTimeRange(0, tScan.getTimestamp());
+      }
+      if (tScan.isSetCaching()) {
+        scan.setCaching(tScan.getCaching());
+      }
+      if (tScan.isSetBatchSize()) {
+        scan.setBatch(tScan.getBatchSize());
+      }
+      if (tScan.isSetColumns() && !tScan.getColumns().isEmpty()) {
+        for (ByteBuffer column : tScan.getColumns()) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      if (tScan.isSetFilterString()) {
+        ParseFilter parseFilter = new ParseFilter();
+        scan.setFilter(parseFilter.parseFilterString(tScan.getFilterString()));
+      }
+      if (tScan.isSetReversed()) {
+        scan.setReversed(tScan.isReversed());
+      }
+      if (tScan.isSetCacheBlocks()) {
+        scan.setCacheBlocks(tScan.isCacheBlocks());
+      }
+      return addScanner(table.getScanner(scan), tScan.sortColumns);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public int scannerOpen(ByteBuffer tableName, ByteBuffer startRow, List<ByteBuffer> columns,
+    Map<ByteBuffer, ByteBuffer> attributes) throws IOError {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan().withStartRow(getBytes(startRow));
+      addAttributes(scan, attributes);
+      if (columns != null && !columns.isEmpty()) {
+        for (ByteBuffer column : columns) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      return addScanner(table.getScanner(scan), false);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public int scannerOpenWithStop(ByteBuffer tableName, ByteBuffer startRow, ByteBuffer stopRow,
+    List<ByteBuffer> columns, Map<ByteBuffer, ByteBuffer> attributes) throws IOError, TException {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan().withStartRow(getBytes(startRow)).withStopRow(getBytes(stopRow));
+      addAttributes(scan, attributes);
+      if (columns != null && !columns.isEmpty()) {
+        for (ByteBuffer column : columns) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      return addScanner(table.getScanner(scan), false);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public int scannerOpenWithPrefix(ByteBuffer tableName, ByteBuffer startAndPrefix,
+    List<ByteBuffer> columns, Map<ByteBuffer, ByteBuffer> attributes) throws IOError, TException {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan().withStartRow(getBytes(startAndPrefix));
+      addAttributes(scan, attributes);
+      Filter f = new WhileMatchFilter(new PrefixFilter(getBytes(startAndPrefix)));
+      scan.setFilter(f);
+      if (columns != null && !columns.isEmpty()) {
+        for (ByteBuffer column : columns) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      return addScanner(table.getScanner(scan), false);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public int scannerOpenTs(ByteBuffer tableName, ByteBuffer startRow, List<ByteBuffer> columns,
+    long timestamp, Map<ByteBuffer, ByteBuffer> attributes) throws IOError, TException {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan().withStartRow(getBytes(startRow));
+      addAttributes(scan, attributes);
+      scan.setTimeRange(0, timestamp);
+      if (columns != null && !columns.isEmpty()) {
+        for (ByteBuffer column : columns) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      return addScanner(table.getScanner(scan), false);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public int scannerOpenWithStopTs(ByteBuffer tableName, ByteBuffer startRow, ByteBuffer stopRow,
+    List<ByteBuffer> columns, long timestamp, Map<ByteBuffer, ByteBuffer> attributes)
+    throws IOError, TException {
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      Scan scan = new Scan().withStartRow(getBytes(startRow)).withStopRow(getBytes(stopRow));
+      addAttributes(scan, attributes);
+      scan.setTimeRange(0, timestamp);
+      if (columns != null && !columns.isEmpty()) {
+        for (ByteBuffer column : columns) {
+          byte[][] famQf = CellUtil.parseColumn(getBytes(column));
+          if (famQf.length == 1) {
+            scan.addFamily(famQf[0]);
+          } else {
+            scan.addColumn(famQf[0], famQf[1]);
+          }
+        }
+      }
+      scan.setTimeRange(0, timestamp);
+      return addScanner(table.getScanner(scan), false);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public Map<ByteBuffer, ColumnDescriptor> getColumnDescriptors(ByteBuffer tableName)
+    throws IOError, TException {
+
+    Table table = null;
+    try {
+      TreeMap<ByteBuffer, ColumnDescriptor> columns = new TreeMap<>();
+
+      table = getTable(tableName);
+      TableDescriptor desc = table.getDescriptor();
+
+      for (ColumnFamilyDescriptor e : desc.getColumnFamilies()) {
+        ColumnDescriptor col = ThriftUtilities.colDescFromHbase(e);
+        columns.put(col.name, col);
+      }
+      return columns;
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  private void closeTable(Table table) throws IOError {
+    try {
+      if (table != null) {
+        table.close();
+      }
+    } catch (IOException e) {
+      LOG.error(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  @Override
+  public TRegionInfo getRegionInfo(ByteBuffer searchRow) throws IOError {
+    try {
+      byte[] row = getBytes(searchRow);
+      Result startRowResult =
+        getReverseScanResult(TableName.META_TABLE_NAME.getName(), row, HConstants.CATALOG_FAMILY);
+
+      if (startRowResult == null) {
+        throw new IOException(
+          "Cannot find row in " + TableName.META_TABLE_NAME + ", row=" + Bytes.toStringBinary(row));
+      }
+
+      // find region start and end keys
+      RegionInfo regionInfo = CatalogFamilyFormat.getRegionInfo(startRowResult);
+      if (regionInfo == null) {
+        throw new IOException("RegionInfo REGIONINFO was null or " + " empty in Meta for row="
+          + Bytes.toStringBinary(row));
+      }
+      TRegionInfo region = new TRegionInfo();
+      region.setStartKey(regionInfo.getStartKey());
+      region.setEndKey(regionInfo.getEndKey());
+      region.id = regionInfo.getRegionId();
+      region.setName(regionInfo.getRegionName());
+      region.version = HREGION_VERSION; // version not used anymore, PB encoding used.
+
+      // find region assignment to server
+      ServerName serverName = CatalogFamilyFormat.getServerName(startRowResult, 0);
+      if (serverName != null) {
+        region.setServerName(Bytes.toBytes(serverName.getHostname()));
+        region.port = serverName.getPort();
+      }
+      return region;
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    }
+  }
+
+  private Result getReverseScanResult(byte[] tableName, byte[] row, byte[] family)
+    throws IOException {
+    Scan scan = new Scan().withStartRow(row);
+    scan.setReversed(true);
+    scan.addFamily(family);
+    scan.withStartRow(row);
+    try (Table table = getTable(tableName); ResultScanner scanner = table.getScanner(scan)) {
+      return scanner.next();
+    }
+  }
+
+  @Override
+  public void increment(TIncrement tincrement) throws IOError, TException {
+
+    if (tincrement.getRow().length == 0 || tincrement.getTable().length == 0) {
+      throw new TException("Must supply a table and a row key; can't increment");
+    }
+
+    if (conf.getBoolean(COALESCE_INC_KEY, false)) {
+      this.coalescer.queueIncrement(tincrement);
+      return;
+    }
+
+    Table table = null;
+    try {
+      table = getTable(tincrement.getTable());
+      Increment inc = ThriftUtilities.incrementFromThrift(tincrement);
+      table.increment(inc);
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public void incrementRows(List<TIncrement> tincrements) throws IOError, TException {
+    if (conf.getBoolean(COALESCE_INC_KEY, false)) {
+      this.coalescer.queueIncrements(tincrements);
+      return;
+    }
+    for (TIncrement tinc : tincrements) {
+      increment(tinc);
+    }
+  }
+
+  @Override
+  public List<TCell> append(TAppend tappend) throws IOError, TException {
+    if (tappend.getRow().length == 0 || tappend.getTable().length == 0) {
+      throw new TException("Must supply a table and a row key; can't append");
+    }
+
+    Table table = null;
+    try {
+      table = getTable(tappend.getTable());
+      Append append = ThriftUtilities.appendFromThrift(tappend);
+      Result result = table.append(append);
+      return ThriftUtilities.cellFromHBase(result.rawCells());
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public boolean checkAndPut(ByteBuffer tableName, ByteBuffer row, ByteBuffer column,
+    ByteBuffer value, Mutation mput, Map<ByteBuffer, ByteBuffer> attributes)
+    throws IOError, IllegalArgument, TException {
+    Put put;
+    try {
+      put = new Put(getBytes(row), HConstants.LATEST_TIMESTAMP);
+      addAttributes(put, attributes);
+
+      byte[][] famAndQf = CellUtil.parseColumn(getBytes(mput.column));
+      put.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY).setRow(put.getRow())
+        .setFamily(famAndQf[0]).setQualifier(famAndQf[1]).setTimestamp(put.getTimestamp())
+        .setType(Cell.Type.Put)
+        .setValue(mput.value != null ? getBytes(mput.value) : HConstants.EMPTY_BYTE_ARRAY).build());
+      put.setDurability(mput.writeToWAL ? Durability.SYNC_WAL : Durability.SKIP_WAL);
+    } catch (IOException | IllegalArgumentException e) {
+      LOG.warn(e.getMessage(), e);
+      throw new IllegalArgument(Throwables.getStackTraceAsString(e));
+    }
+
+    Table table = null;
+    try {
+      table = getTable(tableName);
+      byte[][] famAndQf = CellUtil.parseColumn(getBytes(column));
+      Table.CheckAndMutateBuilder mutateBuilder =
+        table.checkAndMutate(getBytes(row), famAndQf[0]).qualifier(famAndQf[1]);
+      if (value != null) {
+        return mutateBuilder.ifEquals(getBytes(value)).thenPut(put);
+      } else {
+        return mutateBuilder.ifNotExists().thenPut(put);
+      }
+    } catch (IOException e) {
+      LOG.warn(e.getMessage(), e);
+      throw getIOError(e);
+    } catch (IllegalArgumentException e) {
+      LOG.warn(e.getMessage(), e);
+      throw new IllegalArgument(Throwables.getStackTraceAsString(e));
+    } finally {
+      closeTable(table);
+    }
+  }
+
+  @Override
+  public TThriftServerType getThriftServerType() {
+    return TThriftServerType.ONE;
+  }
+
+  @Override
+  public String getClusterId() throws TException {
+    return connectionCache.getClusterId();
+  }
+
+  @Override
+  public boolean grant(TAccessControlEntity info) throws IOError, TException {
+    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
+    try {
+      if (info.scope == TPermissionScope.NAMESPACE) {
+        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), info.getNsName(),
+          info.getUsername(), actions);
+      } else if (info.scope == TPermissionScope.TABLE) {
+        TableName tableName = TableName.valueOf(info.getTableName());
+        AccessControlClient.grant(connectionCache.getAdmin().getConnection(), tableName,
+          info.getUsername(), null, null, actions);
+      }
+    } catch (Throwable t) {
+      if (t instanceof IOException) {
+        throw getIOError(t);
+      } else {
+        throw getIOError(new DoNotRetryIOException(t.getMessage()));
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public boolean revoke(TAccessControlEntity info) throws IOError, TException {
+    Permission.Action[] actions = ThriftUtilities.permissionActionsFromString(info.actions);
+    try {
+      if (info.scope == TPermissionScope.NAMESPACE) {
+        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), info.getNsName(),
+          info.getUsername(), actions);
+      } else if (info.scope == TPermissionScope.TABLE) {
+        TableName tableName = TableName.valueOf(info.getTableName());
+        AccessControlClient.revoke(connectionCache.getAdmin().getConnection(), tableName,
+          info.getUsername(), null, null, actions);
+      }
+    } catch (Throwable t) {
+      if (t instanceof IOException) {
+        throw getIOError(t);
+      } else {
+        throw getIOError(new DoNotRetryIOException(t.getMessage()));
+      }
+    }
+    return true;
+  }
+
+  private static IOError getIOError(Throwable throwable) {
+    IOError error = new IOErrorWithCause(throwable);
+    error.setCanRetry(!(throwable instanceof DoNotRetryIOException));
+    error.setMessage(Throwables.getStackTraceAsString(throwable));
+    return error;
+  }
+
+  /**
+   * Adds all the attributes into the Operation object
+   */
+  private static void addAttributes(OperationWithAttributes op,
+    Map<ByteBuffer, ByteBuffer> attributes) {
+    if (attributes == null || attributes.isEmpty()) {
+      return;
+    }
+    for (Map.Entry<ByteBuffer, ByteBuffer> entry : attributes.entrySet()) {
+      String name = Bytes.toStringBinary(getBytes(entry.getKey()));
+      byte[] value = getBytes(entry.getValue());
+      op.setAttribute(name, value);
+    }
+  }
+
+  protected static class ResultScannerWrapper {
+
+    private final ResultScanner scanner;
+    private final boolean sortColumns;
+
+    public ResultScannerWrapper(ResultScanner resultScanner, boolean sortResultColumns) {
+      scanner = resultScanner;
+      sortColumns = sortResultColumns;
+    }
+
+    public ResultScanner getScanner() {
+      return scanner;
+    }
+
+    public boolean isColumnSorted() {
+      return sortColumns;
+    }
+  }
+
+  public static class IOErrorWithCause extends IOError {
+    private final Throwable cause;
+
+    public IOErrorWithCause(Throwable cause) {
+      this.cause = cause;
+    }
+
+    @Override
+    public synchronized Throwable getCause() {
+      return cause;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+      if (super.equals(other) && other instanceof IOErrorWithCause) {
+        Throwable otherCause = ((IOErrorWithCause) other).getCause();
+        if (this.getCause() != null) {
+          return otherCause != null && this.getCause().equals(otherCause);
+        } else {
+          return otherCause == null;
+        }
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      int result = super.hashCode();
+      result = 31 * result + (cause != null ? cause.hashCode() : 0);
+      return result;
+    }
+  }
+
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
new file mode 100644
index 0000000..d7b4445
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHttpServlet.java
@@ -0,0 +1,246 @@
+/*
+ * 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.thrift;
+
+import static org.apache.hadoop.hbase.http.ProxyUserAuthenticationFilter.getDoasFromHeader;
+
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Base64;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.hadoop.hbase.security.SecurityUtil;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+import org.apache.http.HttpHeaders;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.TServlet;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Thrift Http Servlet is used for performing Kerberos authentication if security is enabled and
+ * also used for setting the user specified in "doAs" parameter.
+ */
+@InterfaceAudience.Private
+public class ThriftHttpServlet extends TServlet {
+  private static final long serialVersionUID = 1L;
+  private static final Logger LOG = LoggerFactory.getLogger(ThriftHttpServlet.class.getName());
+  private final transient UserGroupInformation serviceUGI;
+  private final transient UserGroupInformation httpUGI;
+  private final transient HBaseServiceHandler handler;
+  private final boolean doAsEnabled;
+  private final boolean securityEnabled;
+
+  // HTTP Header related constants.
+  public static final String NEGOTIATE = "Negotiate";
+
+  public ThriftHttpServlet(TProcessor processor, TProtocolFactory protocolFactory,
+    UserGroupInformation serviceUGI, UserGroupInformation httpUGI, HBaseServiceHandler handler,
+    boolean securityEnabled, boolean doAsEnabled) {
+    super(processor, protocolFactory);
+    this.serviceUGI = serviceUGI;
+    this.httpUGI = httpUGI;
+    this.handler = handler;
+    this.securityEnabled = securityEnabled;
+    this.doAsEnabled = doAsEnabled;
+  }
+
+  @Override
+  protected void doPost(HttpServletRequest request, HttpServletResponse response)
+    throws ServletException, IOException {
+    String effectiveUser = request.getRemoteUser();
+    if (securityEnabled) {
+      /*
+       * Check that the AUTHORIZATION header has any content. If it does not then return a 401
+       * requesting AUTHORIZATION header to be sent. This is typical where the first request doesn't
+       * send the AUTHORIZATION header initially.
+       */
+      String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+      if (authHeader == null || authHeader.isEmpty()) {
+        // Send a 401 to the client
+        response.addHeader(HttpHeaders.WWW_AUTHENTICATE, NEGOTIATE);
+        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        return;
+      }
+
+      try {
+        // As Thrift HTTP transport doesn't support SPNEGO yet (THRIFT-889),
+        // Kerberos authentication is being done at servlet level.
+        final RemoteUserIdentity identity = doKerberosAuth(request);
+        effectiveUser = identity.principal;
+        // It is standard for client applications expect this header.
+        // Please see http://tools.ietf.org/html/rfc4559 for more details.
+        response.addHeader(HttpHeaders.WWW_AUTHENTICATE, NEGOTIATE + " " + identity.outToken);
+      } catch (HttpAuthenticationException e) {
+        LOG.error("Kerberos Authentication failed", e);
+        // Send a 401 to the client
+        response.addHeader(HttpHeaders.WWW_AUTHENTICATE, NEGOTIATE);
+        response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+          "Authentication Error: " + e.getMessage());
+        return;
+      }
+    }
+
+    if (effectiveUser == null) {
+      effectiveUser = serviceUGI.getShortUserName();
+    }
+
+    String doAsUserFromQuery = getDoasFromHeader(request);
+    if (doAsUserFromQuery != null) {
+      if (!doAsEnabled) {
+        throw new ServletException("Support for proxyuser is not configured");
+      }
+      // The authenticated remote user is attempting to perform 'doAs' proxy user.
+      UserGroupInformation remoteUser = UserGroupInformation.createRemoteUser(effectiveUser);
+      // create and attempt to authorize a proxy user (the client is attempting
+      // to do proxy user)
+      UserGroupInformation ugi =
+        UserGroupInformation.createProxyUser(doAsUserFromQuery, remoteUser);
+      // validate the proxy user authorization
+      try {
+        ProxyUsers.authorize(ugi, request.getRemoteAddr());
+      } catch (AuthorizationException e) {
+        throw new ServletException(e);
+      }
+      effectiveUser = doAsUserFromQuery;
+    }
+    handler.setEffectiveUser(effectiveUser);
+    super.doPost(request, response);
+  }
+
+  /**
+   * Do the GSS-API kerberos authentication. We already have a logged in subject in the form of
+   * httpUGI, which GSS-API will extract information from.
+   */
+  private RemoteUserIdentity doKerberosAuth(HttpServletRequest request)
+    throws HttpAuthenticationException {
+    HttpKerberosServerAction action = new HttpKerberosServerAction(request, httpUGI);
+    try {
+      String principal = httpUGI.doAs(action);
+      return new RemoteUserIdentity(principal, action.outToken);
+    } catch (Exception e) {
+      LOG.info("Failed to authenticate with {} kerberos principal", httpUGI.getUserName());
+      throw new HttpAuthenticationException(e);
+    }
+  }
+
+  /**
+   * Basic "struct" class to hold the final base64-encoded, authenticated GSSAPI token for the user
+   * with the given principal talking to the Thrift server.
+   */
+  private static class RemoteUserIdentity {
+    final String outToken;
+    final String principal;
+
+    RemoteUserIdentity(String principal, String outToken) {
+      this.principal = principal;
+      this.outToken = outToken;
+    }
+  }
+
+  private static class HttpKerberosServerAction implements PrivilegedExceptionAction<String> {
+    final HttpServletRequest request;
+    final UserGroupInformation httpUGI;
+    String outToken = null;
+
+    HttpKerberosServerAction(HttpServletRequest request, UserGroupInformation httpUGI) {
+      this.request = request;
+      this.httpUGI = httpUGI;
+    }
+
+    @Override
+    public String run() throws HttpAuthenticationException {
+      // Get own Kerberos credentials for accepting connection
+      GSSManager manager = GSSManager.getInstance();
+      GSSContext gssContext = null;
+      String serverPrincipal = SecurityUtil.getPrincipalWithoutRealm(httpUGI.getUserName());
+      try {
+        // This Oid for Kerberos GSS-API mechanism.
+        Oid kerberosMechOid = new Oid("1.2.840.113554.1.2.2");
+        // Oid for SPNego GSS-API mechanism.
+        Oid spnegoMechOid = new Oid("1.3.6.1.5.5.2");
+        // Oid for kerberos principal name
+        Oid krb5PrincipalOid = new Oid("1.2.840.113554.1.2.2.1");
+        // GSS name for server
+        GSSName serverName = manager.createName(serverPrincipal, krb5PrincipalOid);
+        // GSS credentials for server
+        GSSCredential serverCreds =
+          manager.createCredential(serverName, GSSCredential.DEFAULT_LIFETIME,
+            new Oid[] { kerberosMechOid, spnegoMechOid }, GSSCredential.ACCEPT_ONLY);
+        // Create a GSS context
+        gssContext = manager.createContext(serverCreds);
+        // Get service ticket from the authorization header
+        String serviceTicketBase64 = getAuthHeader(request);
+        byte[] inToken = Base64.getDecoder().decode(serviceTicketBase64);
+        byte[] res = gssContext.acceptSecContext(inToken, 0, inToken.length);
+        if (res != null) {
+          outToken = Base64.getEncoder().encodeToString(res).replace("\n", "");
+        }
+        // Authenticate or deny based on its context completion
+        if (!gssContext.isEstablished()) {
+          throw new HttpAuthenticationException("Kerberos authentication failed: "
+            + "unable to establish context with the service ticket " + "provided by the client.");
+        }
+        return SecurityUtil.getUserFromPrincipal(gssContext.getSrcName().toString());
+      } catch (GSSException e) {
+        throw new HttpAuthenticationException("Kerberos authentication failed: ", e);
+      } finally {
+        if (gssContext != null) {
+          try {
+            gssContext.dispose();
+          } catch (GSSException e) {
+            LOG.warn("Error while disposing GSS Context", e);
+          }
+        }
+      }
+    }
+
+    /**
+     * Returns the base64 encoded auth header payload
+     * @throws HttpAuthenticationException if a remote or network exception occurs
+     */
+    private String getAuthHeader(HttpServletRequest request) throws HttpAuthenticationException {
+      String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+      // Each http request must have an Authorization header
+      if (authHeader == null || authHeader.isEmpty()) {
+        throw new HttpAuthenticationException(
+          "Authorization header received " + "from the client is empty.");
+      }
+      String authHeaderBase64String;
+      int beginIndex = (NEGOTIATE + " ").length();
+      authHeaderBase64String = authHeader.substring(beginIndex);
+      // Authorization header must have a payload
+      if (authHeaderBase64String.isEmpty()) {
+        throw new HttpAuthenticationException(
+          "Authorization header received " + "from the client does not contain any data.");
+      }
+      return authHeaderBase64String;
+    }
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java
new file mode 100644
index 0000000..ef609b2
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftMetrics.java
@@ -0,0 +1,179 @@
+/*
+ * 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.thrift;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.CallDroppedException;
+import org.apache.hadoop.hbase.CallQueueTooBigException;
+import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
+import org.apache.hadoop.hbase.MultiActionResultTooLarge;
+import org.apache.hadoop.hbase.NotServingRegionException;
+import org.apache.hadoop.hbase.RegionTooBusyException;
+import org.apache.hadoop.hbase.UnknownScannerException;
+import org.apache.hadoop.hbase.exceptions.ClientExceptionsUtil;
+import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException;
+import org.apache.hadoop.hbase.exceptions.OutOfOrderScannerNextException;
+import org.apache.hadoop.hbase.exceptions.RegionMovedException;
+import org.apache.hadoop.hbase.exceptions.RequestTooBigException;
+import org.apache.hadoop.hbase.exceptions.ScannerResetException;
+import org.apache.hadoop.hbase.quotas.QuotaExceededException;
+import org.apache.hadoop.hbase.quotas.RpcThrottlingException;
+import org.apache.hadoop.hbase.thrift.generated.IOError;
+import org.apache.hadoop.hbase.thrift2.generated.TIOError;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is for maintaining the various statistics of thrift server and publishing them through
+ * the metrics interfaces.
+ */
+@InterfaceAudience.Private
+public class ThriftMetrics {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ThriftMetrics.class);
+
+  public enum ThriftServerType {
+    ONE,
+    TWO
+  }
+
+  public MetricsThriftServerSource getSource() {
+    return source;
+  }
+
+  public void setSource(MetricsThriftServerSource source) {
+    this.source = source;
+  }
+
+  protected MetricsThriftServerSource source;
+  protected final long slowResponseTime;
+  public static final String SLOW_RESPONSE_NANO_SEC = "hbase.thrift.slow.response.nano.second";
+  public static final long DEFAULT_SLOW_RESPONSE_NANO_SEC = 10 * 1000 * 1000;
+  private final ThriftServerType thriftServerType;
+
+  public ThriftMetrics(Configuration conf, ThriftServerType t) {
+    slowResponseTime = conf.getLong(SLOW_RESPONSE_NANO_SEC, DEFAULT_SLOW_RESPONSE_NANO_SEC);
+    thriftServerType = t;
+    if (t == ThriftServerType.ONE) {
+      source = CompatibilitySingletonFactory.getInstance(MetricsThriftServerSourceFactory.class)
+        .createThriftOneSource();
+    } else if (t == ThriftServerType.TWO) {
+      source = CompatibilitySingletonFactory.getInstance(MetricsThriftServerSourceFactory.class)
+        .createThriftTwoSource();
+    }
+
+  }
+
+  public void incTimeInQueue(long time) {
+    source.incTimeInQueue(time);
+  }
+
+  public void setCallQueueLen(int len) {
+    source.setCallQueueLen(len);
+  }
+
+  public void incNumRowKeysInBatchGet(int diff) {
+    source.incNumRowKeysInBatchGet(diff);
+  }
+
+  public void incNumRowKeysInBatchMutate(int diff) {
+    source.incNumRowKeysInBatchMutate(diff);
+  }
+
+  public void incMethodTime(String name, long time) {
+    source.incMethodTime(name, time);
+    // inc general processTime
+    source.incCall(time);
+    if (time > slowResponseTime) {
+      source.incSlowCall(time);
+    }
+  }
+
+  public void incActiveWorkerCount() {
+    source.incActiveWorkerCount();
+  }
+
+  public void decActiveWorkerCount() {
+    source.decActiveWorkerCount();
+  }
+
+  /**
+   * Increment the count for a specific exception type. This is called for each exception type that
+   * is returned to the thrift handler.
+   * @param rawThrowable type of exception
+   */
+  public void exception(Throwable rawThrowable) {
+    source.exception();
+
+    Throwable throwable = unwrap(rawThrowable);
+    /**
+     * Keep some metrics for commonly seen exceptions Try and put the most common types first. Place
+     * child types before the parent type that they extend. If this gets much larger we might have
+     * to go to a hashmap
+     */
+    if (throwable != null) {
+      if (throwable instanceof OutOfOrderScannerNextException) {
+        source.outOfOrderException();
+      } else if (throwable instanceof RegionTooBusyException) {
+        source.tooBusyException();
+      } else if (throwable instanceof UnknownScannerException) {
+        source.unknownScannerException();
+      } else if (throwable instanceof ScannerResetException) {
+        source.scannerResetException();
+      } else if (throwable instanceof RegionMovedException) {
+        source.movedRegionException();
+      } else if (throwable instanceof NotServingRegionException) {
+        source.notServingRegionException();
+      } else if (throwable instanceof FailedSanityCheckException) {
+        source.failedSanityException();
+      } else if (throwable instanceof MultiActionResultTooLarge) {
+        source.multiActionTooLargeException();
+      } else if (throwable instanceof CallQueueTooBigException) {
+        source.callQueueTooBigException();
+      } else if (throwable instanceof QuotaExceededException) {
+        source.quotaExceededException();
+      } else if (throwable instanceof RpcThrottlingException) {
+        source.rpcThrottlingException();
+      } else if (throwable instanceof CallDroppedException) {
+        source.callDroppedException();
+      } else if (throwable instanceof RequestTooBigException) {
+        source.requestTooBigException();
+      } else {
+        source.otherExceptions();
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Unknown exception type", throwable);
+        }
+      }
+    }
+  }
+
+  protected static Throwable unwrap(Throwable t) {
+    if (t == null) {
+      return t;
+    }
+    if (t instanceof TIOError || t instanceof IOError) {
+      t = t.getCause();
+    }
+    return ClientExceptionsUtil.findException(t);
+  }
+
+  public ThriftServerType getThriftServerType() {
+    return thriftServerType;
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java
new file mode 100644
index 0000000..33bd2ae
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftServer.java
@@ -0,0 +1,867 @@
+/*
+ * 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.thrift;
+
+import static org.apache.hadoop.hbase.thrift.Constants.BACKLOG_CONF_DEAFULT;
+import static org.apache.hadoop.hbase.thrift.Constants.BACKLOG_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.BIND_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.BIND_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.COMPACT_CONF_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.COMPACT_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.COMPACT_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.DEFAULT_BIND_ADDR;
+import static org.apache.hadoop.hbase.thrift.Constants.DEFAULT_HTTP_MAX_HEADER_SIZE;
+import static org.apache.hadoop.hbase.thrift.Constants.DEFAULT_LISTEN_PORT;
+import static org.apache.hadoop.hbase.thrift.Constants.FRAMED_CONF_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.FRAMED_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.FRAMED_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.HTTP_MAX_THREADS_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.HTTP_MAX_THREADS_KEY_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.HTTP_MIN_THREADS_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.HTTP_MIN_THREADS_KEY_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.INFOPORT_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.KEEP_ALIVE_SEC_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.MAX_FRAME_SIZE_CONF_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.MAX_FRAME_SIZE_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.MAX_QUEUE_SIZE_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.MAX_WORKERS_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.MIN_WORKERS_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.PORT_CONF_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.PORT_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.READ_TIMEOUT_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.SELECTOR_NUM_OPTION;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_DNS_INTERFACE_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_DNS_NAMESERVER_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_FILTERS;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_HTTP_ALLOW_OPTIONS_METHOD;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_INFO_SERVER_BINDING_ADDRESS;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_INFO_SERVER_BINDING_ADDRESS_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_INFO_SERVER_PORT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_INFO_SERVER_PORT_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_KERBEROS_PRINCIPAL_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_KEYTAB_FILE_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_QOP_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SELECTOR_NUM;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SERVER_SOCKET_READ_TIMEOUT_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SERVER_SOCKET_READ_TIMEOUT_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SPNEGO_KEYTAB_FILE_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SPNEGO_PRINCIPAL_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_ENABLED_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_EXCLUDE_CIPHER_SUITES_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_EXCLUDE_PROTOCOLS_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_INCLUDE_CIPHER_SUITES_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_INCLUDE_PROTOCOLS_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_KEYSTORE_KEYPASSWORD_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_KEYSTORE_PASSWORD_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_KEYSTORE_STORE_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_KEYSTORE_TYPE_DEFAULT;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SSL_KEYSTORE_TYPE_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.THRIFT_SUPPORT_PROXYUSER_KEY;
+import static org.apache.hadoop.hbase.thrift.Constants.USE_HTTP_CONF_KEY;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.SaslServer;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.conf.Configured;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.HBaseInterfaceAudience;
+import org.apache.hadoop.hbase.filter.ParseFilter;
+import org.apache.hadoop.hbase.http.HttpServerUtil;
+import org.apache.hadoop.hbase.http.InfoServer;
+import org.apache.hadoop.hbase.log.HBaseMarkers;
+import org.apache.hadoop.hbase.security.SaslUtil;
+import org.apache.hadoop.hbase.security.SecurityUtil;
+import org.apache.hadoop.hbase.security.UserProvider;
+import org.apache.hadoop.hbase.thrift.generated.Hbase;
+import org.apache.hadoop.hbase.util.DNS;
+import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+import org.apache.hadoop.hbase.util.JvmPauseMonitor;
+import org.apache.hadoop.hbase.util.Strings;
+import org.apache.hadoop.hbase.util.VersionInfo;
+import org.apache.hadoop.security.SaslRpcServer;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+import org.apache.hadoop.util.Shell.ExitCodeException;
+import org.apache.hadoop.util.Tool;
+import org.apache.hadoop.util.ToolRunner;
+import org.apache.thrift.TProcessor;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.THsHaServer;
+import org.apache.thrift.server.TNonblockingServer;
+import org.apache.thrift.server.TServer;
+import org.apache.thrift.server.TServlet;
+import org.apache.thrift.server.TThreadedSelectorServer;
+import org.apache.thrift.transport.TNonblockingServerSocket;
+import org.apache.thrift.transport.TNonblockingServerTransport;
+import org.apache.thrift.transport.TSaslServerTransport;
+import org.apache.thrift.transport.TServerSocket;
+import org.apache.thrift.transport.TServerTransport;
+import org.apache.thrift.transport.TTransportFactory;
+import org.apache.thrift.transport.layered.TFramedTransport;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.com.google.common.base.Joiner;
+import org.apache.hbase.thirdparty.com.google.common.base.Splitter;
+import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLine;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.CommandLineParser;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.DefaultParser;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.HelpFormatter;
+import org.apache.hbase.thirdparty.org.apache.commons.cli.Options;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.http.HttpVersion;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.HttpConfiguration;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.HttpConnectionFactory;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.Server;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.ServerConnector;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.server.SslConnectionFactory;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.servlet.ServletContextHandler;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.servlet.ServletHolder;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.apache.hbase.thirdparty.org.eclipse.jetty.util.thread.QueuedThreadPool;
+
+/**
+ * ThriftServer- this class starts up a Thrift server which implements the Hbase API specified in
+ * the Hbase.thrift IDL file. The server runs in an independent process.
+ */
+@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
+public class ThriftServer extends Configured implements Tool {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ThriftServer.class);
+
+  protected Configuration conf;
+
+  protected InfoServer infoServer;
+
+  protected TProcessor processor;
+
+  protected ThriftMetrics metrics;
+  protected HBaseServiceHandler hbaseServiceHandler;
+  protected UserGroupInformation serviceUGI;
+  protected UserGroupInformation httpUGI;
+  protected boolean httpEnabled;
+
+  protected SaslUtil.QualityOfProtection qop;
+  protected String host;
+  protected int listenPort;
+
+  protected boolean securityEnabled;
+  protected boolean doAsEnabled;
+
+  protected JvmPauseMonitor pauseMonitor;
+
+  protected volatile TServer tserver;
+  protected volatile Server httpServer;
+
+  //
+  // Main program and support routines
+  //
+
+  public ThriftServer(Configuration conf) {
+    this.conf = HBaseConfiguration.create(conf);
+  }
+
+  protected ThriftMetrics createThriftMetrics(Configuration conf) {
+    return new ThriftMetrics(conf, ThriftMetrics.ThriftServerType.ONE);
+  }
+
+  protected void setupParamters() throws IOException {
+    // login the server principal (if using secure Hadoop)
+    UserProvider userProvider = UserProvider.instantiate(conf);
+    securityEnabled =
+      userProvider.isHadoopSecurityEnabled() && userProvider.isHBaseSecurityEnabled();
+    if (securityEnabled) {
+      host = Strings.domainNamePointerToHostName(
+        DNS.getDefaultHost(conf.get(THRIFT_DNS_INTERFACE_KEY, "default"),
+          conf.get(THRIFT_DNS_NAMESERVER_KEY, "default")));
+      userProvider.login(THRIFT_KEYTAB_FILE_KEY, THRIFT_KERBEROS_PRINCIPAL_KEY, host);
+
+      // Setup the SPNEGO user for HTTP if configured
+      String spnegoPrincipal = getSpengoPrincipal(conf, host);
+      String spnegoKeytab = getSpnegoKeytab(conf);
+      UserGroupInformation.setConfiguration(conf);
+      // login the SPNEGO principal using UGI to avoid polluting the login user
+      this.httpUGI =
+        UserGroupInformation.loginUserFromKeytabAndReturnUGI(spnegoPrincipal, spnegoKeytab);
+    }
+    this.serviceUGI = userProvider.getCurrent().getUGI();
+    if (httpUGI == null) {
+      this.httpUGI = serviceUGI;
+    }
+
+    this.listenPort = conf.getInt(PORT_CONF_KEY, DEFAULT_LISTEN_PORT);
+    this.metrics = createThriftMetrics(conf);
+    this.pauseMonitor = new JvmPauseMonitor(conf, this.metrics.getSource());
+    this.hbaseServiceHandler = createHandler(conf, userProvider);
+    this.hbaseServiceHandler.initMetrics(metrics);
+    this.processor = createProcessor();
+
+    httpEnabled = conf.getBoolean(USE_HTTP_CONF_KEY, false);
+    doAsEnabled = conf.getBoolean(THRIFT_SUPPORT_PROXYUSER_KEY, false);
+    if (doAsEnabled && !httpEnabled) {
+      LOG.warn("Fail to enable the doAs feature. " + USE_HTTP_CONF_KEY + " is not configured");
+    }
+
+    String strQop = conf.get(THRIFT_QOP_KEY);
+    if (strQop != null) {
+      this.qop = SaslUtil.getQop(strQop);
+    }
+    if (qop != null) {
+      if (
+        qop != SaslUtil.QualityOfProtection.AUTHENTICATION
+          && qop != SaslUtil.QualityOfProtection.INTEGRITY
+          && qop != SaslUtil.QualityOfProtection.PRIVACY
+      ) {
+        throw new IOException(String.format("Invalid %s: It must be one of %s, %s, or %s.",
+          THRIFT_QOP_KEY, SaslUtil.QualityOfProtection.AUTHENTICATION.name(),
+          SaslUtil.QualityOfProtection.INTEGRITY.name(),
+          SaslUtil.QualityOfProtection.PRIVACY.name()));
+      }
+      checkHttpSecurity(qop, conf);
+      if (!securityEnabled) {
+        throw new IOException("Thrift server must run in secure mode to support authentication");
+      }
+    }
+    registerFilters(conf);
+    pauseMonitor.start();
+  }
+
+  private String getSpengoPrincipal(Configuration conf, String host) throws IOException {
+    String principal = conf.get(THRIFT_SPNEGO_PRINCIPAL_KEY);
+    if (principal == null) {
+      // We cannot use the Hadoop configuration deprecation handling here since
+      // the THRIFT_KERBEROS_PRINCIPAL_KEY config is still valid for regular Kerberos
+      // communication. The preference should be to use the THRIFT_SPNEGO_PRINCIPAL_KEY
+      // config so that THRIFT_KERBEROS_PRINCIPAL_KEY doesn't control both backend
+      // Kerberos principal and SPNEGO principal.
+      LOG.info("Using deprecated {} config for SPNEGO principal. Use {} instead.",
+        THRIFT_KERBEROS_PRINCIPAL_KEY, THRIFT_SPNEGO_PRINCIPAL_KEY);
+      principal = conf.get(THRIFT_KERBEROS_PRINCIPAL_KEY);
+    }
+    // Handle _HOST in principal value
+    return org.apache.hadoop.security.SecurityUtil.getServerPrincipal(principal, host);
+  }
+
+  private String getSpnegoKeytab(Configuration conf) {
+    String keytab = conf.get(THRIFT_SPNEGO_KEYTAB_FILE_KEY);
+    if (keytab == null) {
+      // We cannot use the Hadoop configuration deprecation handling here since
+      // the THRIFT_KEYTAB_FILE_KEY config is still valid for regular Kerberos
+      // communication. The preference should be to use the THRIFT_SPNEGO_KEYTAB_FILE_KEY
+      // config so that THRIFT_KEYTAB_FILE_KEY doesn't control both backend
+      // Kerberos keytab and SPNEGO keytab.
+      LOG.info("Using deprecated {} config for SPNEGO keytab. Use {} instead.",
+        THRIFT_KEYTAB_FILE_KEY, THRIFT_SPNEGO_KEYTAB_FILE_KEY);
+      keytab = conf.get(THRIFT_KEYTAB_FILE_KEY);
+    }
+    return keytab;
+  }
+
+  protected void startInfoServer() throws IOException {
+    // Put up info server.
+    int port = conf.getInt(THRIFT_INFO_SERVER_PORT, THRIFT_INFO_SERVER_PORT_DEFAULT);
+
+    if (port >= 0) {
+      conf.setLong("startcode", EnvironmentEdgeManager.currentTime());
+      String a =
+        conf.get(THRIFT_INFO_SERVER_BINDING_ADDRESS, THRIFT_INFO_SERVER_BINDING_ADDRESS_DEFAULT);
+      infoServer = new InfoServer("thrift", a, port, false, conf);
+      infoServer.setAttribute("hbase.conf", conf);
+      infoServer.setAttribute("hbase.thrift.server.type", metrics.getThriftServerType().name());
+      infoServer.start();
+    }
+  }
+
+  protected void checkHttpSecurity(SaslUtil.QualityOfProtection qop, Configuration conf) {
+    if (
+      qop == SaslUtil.QualityOfProtection.PRIVACY && conf.getBoolean(USE_HTTP_CONF_KEY, false)
+        && !conf.getBoolean(THRIFT_SSL_ENABLED_KEY, false)
+    ) {
+      throw new IllegalArgumentException(
+        "Thrift HTTP Server's QoP is privacy, but " + THRIFT_SSL_ENABLED_KEY + " is false");
+    }
+  }
+
+  protected HBaseServiceHandler createHandler(Configuration conf, UserProvider userProvider)
+    throws IOException {
+    return new ThriftHBaseServiceHandler(conf, userProvider);
+  }
+
+  protected TProcessor createProcessor() {
+    return new Hbase.Processor<>(
+      HbaseHandlerMetricsProxy.newInstance((Hbase.Iface) hbaseServiceHandler, metrics, conf));
+  }
+
+  /**
+   * the thrift server, not null means the server is started, for test only
+   * @return the tServer
+   */
+  @InterfaceAudience.Private
+  public TServer getTserver() {
+    return tserver;
+  }
+
+  /**
+   * the Jetty server, not null means the HTTP server is started, for test only
+   * @return the http server
+   */
+  @InterfaceAudience.Private
+  public Server getHttpServer() {
+    return httpServer;
+  }
+
+  protected void printUsageAndExit(Options options, int exitCode) throws ExitCodeException {
+    HelpFormatter formatter = new HelpFormatter();
+    formatter.printHelp("Thrift", null, options,
+      "To start the Thrift server run 'hbase-daemon.sh start thrift' or " + "'hbase thrift'\n"
+        + "To shutdown the thrift server run 'hbase-daemon.sh stop "
+        + "thrift' or send a kill signal to the thrift server pid",
+      true);
+    throw new ExitCodeException(exitCode, "");
+  }
+
+  /**
+   * Create a Servlet for the http server
+   * @param protocolFactory protocolFactory
+   * @return the servlet
+   */
+  protected TServlet createTServlet(TProtocolFactory protocolFactory) {
+    return new ThriftHttpServlet(processor, protocolFactory, serviceUGI, httpUGI,
+      hbaseServiceHandler, securityEnabled, doAsEnabled);
+  }
+
+  /**
+   * Setup an HTTP Server using Jetty to serve calls from THttpClient
+   * @throws IOException IOException
+   */
+  protected void setupHTTPServer() throws IOException {
+    TProtocolFactory protocolFactory = new TBinaryProtocol.Factory();
+    TServlet thriftHttpServlet = createTServlet(protocolFactory);
+
+    // Set the default max thread number to 100 to limit
+    // the number of concurrent requests so that Thrfit HTTP server doesn't OOM easily.
+    // Jetty set the default max thread number to 250, if we don't set it.
+    //
+    // Our default min thread number 2 is the same as that used by Jetty.
+    int minThreads = conf.getInt(HTTP_MIN_THREADS_KEY, conf
+      .getInt(TBoundedThreadPoolServer.MIN_WORKER_THREADS_CONF_KEY, HTTP_MIN_THREADS_KEY_DEFAULT));
+    int maxThreads = conf.getInt(HTTP_MAX_THREADS_KEY, conf
+      .getInt(TBoundedThreadPoolServer.MAX_WORKER_THREADS_CONF_KEY, HTTP_MAX_THREADS_KEY_DEFAULT));
+    QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads);
+    threadPool.setMinThreads(minThreads);
+    httpServer = new Server(threadPool);
+
+    // Context handler
+    ServletContextHandler ctxHandler =
+      new ServletContextHandler(httpServer, "/", ServletContextHandler.SESSIONS);
+    ctxHandler.addServlet(new ServletHolder(thriftHttpServlet), "/*");
+    HttpServerUtil.constrainHttpMethods(ctxHandler,
+      conf.getBoolean(THRIFT_HTTP_ALLOW_OPTIONS_METHOD, THRIFT_HTTP_ALLOW_OPTIONS_METHOD_DEFAULT));
+
+    // set up Jetty and run the embedded server
+    HttpConfiguration httpConfig = new HttpConfiguration();
+    httpConfig.setSecureScheme("https");
+    httpConfig.setSecurePort(listenPort);
+    httpConfig.setHeaderCacheSize(DEFAULT_HTTP_MAX_HEADER_SIZE);
+    httpConfig.setRequestHeaderSize(DEFAULT_HTTP_MAX_HEADER_SIZE);
+    httpConfig.setResponseHeaderSize(DEFAULT_HTTP_MAX_HEADER_SIZE);
+    httpConfig.setSendServerVersion(false);
+    httpConfig.setSendDateHeader(false);
+
+    ServerConnector serverConnector;
+    if (conf.getBoolean(THRIFT_SSL_ENABLED_KEY, false)) {
+      HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
+      httpsConfig.addCustomizer(new SecureRequestCustomizer());
+
+      SslContextFactory.Server sslCtxFactory = new SslContextFactory.Server();
+      String keystore = conf.get(THRIFT_SSL_KEYSTORE_STORE_KEY);
+      String password =
+        HBaseConfiguration.getPassword(conf, THRIFT_SSL_KEYSTORE_PASSWORD_KEY, null);
+      String keyPassword =
+        HBaseConfiguration.getPassword(conf, THRIFT_SSL_KEYSTORE_KEYPASSWORD_KEY, password);
+      sslCtxFactory.setKeyStorePath(keystore);
+      sslCtxFactory.setKeyStorePassword(password);
+      sslCtxFactory.setKeyManagerPassword(keyPassword);
+      sslCtxFactory
+        .setKeyStoreType(conf.get(THRIFT_SSL_KEYSTORE_TYPE_KEY, THRIFT_SSL_KEYSTORE_TYPE_DEFAULT));
+
+      String[] excludeCiphers =
+        conf.getStrings(THRIFT_SSL_EXCLUDE_CIPHER_SUITES_KEY, ArrayUtils.EMPTY_STRING_ARRAY);
+      if (excludeCiphers.length != 0) {
+        sslCtxFactory.setExcludeCipherSuites(excludeCiphers);
+      }
+      String[] includeCiphers =
+        conf.getStrings(THRIFT_SSL_INCLUDE_CIPHER_SUITES_KEY, ArrayUtils.EMPTY_STRING_ARRAY);
+      if (includeCiphers.length != 0) {
+        sslCtxFactory.setIncludeCipherSuites(includeCiphers);
+      }
+
+      // Disable SSLv3 by default due to "Poodle" Vulnerability - CVE-2014-3566
+      String[] excludeProtocols = conf.getStrings(THRIFT_SSL_EXCLUDE_PROTOCOLS_KEY, "SSLv3");
+      if (excludeProtocols.length != 0) {
+        sslCtxFactory.setExcludeProtocols(excludeProtocols);
+      }
+      String[] includeProtocols =
+        conf.getStrings(THRIFT_SSL_INCLUDE_PROTOCOLS_KEY, ArrayUtils.EMPTY_STRING_ARRAY);
+      if (includeProtocols.length != 0) {
+        sslCtxFactory.setIncludeProtocols(includeProtocols);
+      }
+
+      serverConnector = new ServerConnector(httpServer,
+        new SslConnectionFactory(sslCtxFactory, HttpVersion.HTTP_1_1.toString()),
+        new HttpConnectionFactory(httpsConfig));
+    } else {
+      serverConnector = new ServerConnector(httpServer, new HttpConnectionFactory(httpConfig));
+    }
+    serverConnector.setPort(listenPort);
+    serverConnector.setHost(getBindAddress(conf).getHostAddress());
+    httpServer.addConnector(serverConnector);
+    httpServer.setStopAtShutdown(true);
+
+    if (doAsEnabled) {
+      ProxyUsers.refreshSuperUserGroupsConfiguration(conf);
+    }
+    LOG.info("Starting Thrift HTTP Server on {}", Integer.toString(listenPort));
+  }
+
+  /**
+   * Setting up the thrift TServer
+   */
+  protected void setupServer() throws Exception {
+    // Construct correct ProtocolFactory
+    TProtocolFactory protocolFactory = getProtocolFactory();
+
+    ImplType implType = ImplType.getServerImpl(conf);
+    TProcessor processorToUse = processor;
+
+    // Construct correct TransportFactory
+    TTransportFactory transportFactory;
+    if (conf.getBoolean(FRAMED_CONF_KEY, FRAMED_CONF_DEFAULT) || implType.isAlwaysFramed) {
+      if (qop != null) {
+        throw new RuntimeException(
+          "Thrift server authentication" + " doesn't work with framed transport yet");
+      }
+      transportFactory = new TFramedTransport.Factory(
+        conf.getInt(MAX_FRAME_SIZE_CONF_KEY, MAX_FRAME_SIZE_CONF_DEFAULT) * 1024 * 1024);
+      LOG.debug("Using framed transport");
+    } else if (qop == null) {
+      transportFactory = new TTransportFactory();
+    } else {
+      // Extract the name from the principal
+      String thriftKerberosPrincipal = conf.get(THRIFT_KERBEROS_PRINCIPAL_KEY);
+      if (thriftKerberosPrincipal == null) {
+        throw new IllegalArgumentException(THRIFT_KERBEROS_PRINCIPAL_KEY + " cannot be null");
+      }
+      String name = SecurityUtil.getUserFromPrincipal(thriftKerberosPrincipal);
+      Map<String, String> saslProperties = SaslUtil.initSaslProperties(qop.name());
+      TSaslServerTransport.Factory saslFactory = new TSaslServerTransport.Factory();
+      saslFactory.addServerDefinition("GSSAPI", name, host, saslProperties,
+        new SaslRpcServer.SaslGssCallbackHandler() {
+          @Override
+          public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
+            AuthorizeCallback ac = null;
+            for (Callback callback : callbacks) {
+              if (callback instanceof AuthorizeCallback) {
+                ac = (AuthorizeCallback) callback;
+              } else {
+                throw new UnsupportedCallbackException(callback,
+                  "Unrecognized SASL GSSAPI Callback");
+              }
+            }
+            if (ac != null) {
+              String authid = ac.getAuthenticationID();
+              String authzid = ac.getAuthorizationID();
+              if (!authid.equals(authzid)) {
+                ac.setAuthorized(false);
+              } else {
+                ac.setAuthorized(true);
+                String userName = SecurityUtil.getUserFromPrincipal(authzid);
+                LOG.info("Effective user: {}", userName);
+                ac.setAuthorizedID(userName);
+              }
+            }
+          }
+        });
+      transportFactory = saslFactory;
+
+      // Create a processor wrapper, to get the caller
+      processorToUse = (inProt, outProt) -> {
+        TSaslServerTransport saslServerTransport = (TSaslServerTransport) inProt.getTransport();
+        SaslServer saslServer = saslServerTransport.getSaslServer();
+        String principal = saslServer.getAuthorizationID();
+        hbaseServiceHandler.setEffectiveUser(principal);
+        processor.process(inProt, outProt);
+      };
+    }
+
+    if (conf.get(BIND_CONF_KEY) != null && !implType.canSpecifyBindIP) {
+      LOG.error(
+        "Server types {} don't support IP address binding at the moment. See "
+          + "https://issues.apache.org/jira/browse/HBASE-2155 for details.",
+        Joiner.on(", ").join(ImplType.serversThatCannotSpecifyBindIP()));
+      throw new RuntimeException("-" + BIND_CONF_KEY + " not supported with " + implType);
+    }
+
+    InetSocketAddress inetSocketAddress = new InetSocketAddress(getBindAddress(conf), listenPort);
+    if (
+      implType == ImplType.HS_HA || implType == ImplType.NONBLOCKING
+        || implType == ImplType.THREADED_SELECTOR
+    ) {
+      TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(inetSocketAddress);
+      if (implType == ImplType.NONBLOCKING) {
+        tserver = getTNonBlockingServer(serverTransport, protocolFactory, processorToUse,
+          transportFactory, inetSocketAddress);
+      } else if (implType == ImplType.HS_HA) {
+        tserver = getTHsHaServer(serverTransport, protocolFactory, processorToUse, transportFactory,
+          inetSocketAddress);
+      } else { // THREADED_SELECTOR
+        tserver = getTThreadedSelectorServer(serverTransport, protocolFactory, processorToUse,
+          transportFactory, inetSocketAddress);
+      }
+      LOG.info("starting HBase {} server on {}", implType.simpleClassName(),
+        Integer.toString(listenPort));
+    } else if (implType == ImplType.THREAD_POOL) {
+      this.tserver =
+        getTThreadPoolServer(protocolFactory, processorToUse, transportFactory, inetSocketAddress);
+    } else {
+      throw new AssertionError(
+        "Unsupported Thrift server implementation: " + implType.simpleClassName());
+    }
+
+    // A sanity check that we instantiated the right type of server.
+    if (tserver.getClass() != implType.serverClass) {
+      throw new AssertionError("Expected to create Thrift server class "
+        + implType.serverClass.getName() + " but got " + tserver.getClass().getName());
+    }
+  }
+
+  protected TServer getTNonBlockingServer(TNonblockingServerTransport serverTransport,
+    TProtocolFactory protocolFactory, TProcessor processor, TTransportFactory transportFactory,
+    InetSocketAddress inetSocketAddress) {
+    LOG.info("starting HBase Nonblocking Thrift server on " + inetSocketAddress.toString());
+    TNonblockingServer.Args serverArgs = new TNonblockingServer.Args(serverTransport);
+    serverArgs.processor(processor);
+    serverArgs.transportFactory(transportFactory);
+    serverArgs.protocolFactory(protocolFactory);
+    return new TNonblockingServer(serverArgs);
+  }
+
+  protected TServer getTHsHaServer(TNonblockingServerTransport serverTransport,
+    TProtocolFactory protocolFactory, TProcessor processor, TTransportFactory transportFactory,
+    InetSocketAddress inetSocketAddress) {
+    LOG.info("starting HBase HsHA Thrift server on " + inetSocketAddress.toString());
+    THsHaServer.Args serverArgs = new THsHaServer.Args(serverTransport);
+    int queueSize = conf.getInt(TBoundedThreadPoolServer.MAX_QUEUED_REQUESTS_CONF_KEY,
+      TBoundedThreadPoolServer.DEFAULT_MAX_QUEUED_REQUESTS);
+    CallQueue callQueue = new CallQueue(new LinkedBlockingQueue<>(queueSize), metrics);
+    int workerThread = conf.getInt(TBoundedThreadPoolServer.MAX_WORKER_THREADS_CONF_KEY,
+      serverArgs.getMaxWorkerThreads());
+    ExecutorService executorService = createExecutor(callQueue, workerThread, workerThread);
+    serverArgs.executorService(executorService).processor(processor)
+      .transportFactory(transportFactory).protocolFactory(protocolFactory);
+    return new THsHaServer(serverArgs);
+  }
+
+  protected TServer getTThreadedSelectorServer(TNonblockingServerTransport serverTransport,
+    TProtocolFactory protocolFactory, TProcessor processor, TTransportFactory transportFactory,
+    InetSocketAddress inetSocketAddress) {
+    LOG.info("starting HBase ThreadedSelector Thrift server on " + inetSocketAddress.toString());
+    TThreadedSelectorServer.Args serverArgs =
+      new HThreadedSelectorServerArgs(serverTransport, conf);
+    int queueSize = conf.getInt(TBoundedThreadPoolServer.MAX_QUEUED_REQUESTS_CONF_KEY,
+      TBoundedThreadPoolServer.DEFAULT_MAX_QUEUED_REQUESTS);
+    CallQueue callQueue = new CallQueue(new LinkedBlockingQueue<>(queueSize), metrics);
+    int workerThreads = conf.getInt(TBoundedThreadPoolServer.MAX_WORKER_THREADS_CONF_KEY,
+      serverArgs.getWorkerThreads());
+    int selectorThreads = conf.getInt(THRIFT_SELECTOR_NUM, serverArgs.getSelectorThreads());
+    serverArgs.selectorThreads(selectorThreads);
+    ExecutorService executorService = createExecutor(callQueue, workerThreads, workerThreads);
+    serverArgs.executorService(executorService).processor(processor)
+      .transportFactory(transportFactory).protocolFactory(protocolFactory);
+    return new TThreadedSelectorServer(serverArgs);
+  }
+
+  protected TServer getTThreadPoolServer(TProtocolFactory protocolFactory, TProcessor processor,
+    TTransportFactory transportFactory, InetSocketAddress inetSocketAddress) throws Exception {
+    LOG.info("starting HBase ThreadPool Thrift server on " + inetSocketAddress.toString());
+    // Thrift's implementation uses '0' as a placeholder for 'use the default.'
+    int backlog = conf.getInt(BACKLOG_CONF_KEY, BACKLOG_CONF_DEAFULT);
+    int readTimeout =
+      conf.getInt(THRIFT_SERVER_SOCKET_READ_TIMEOUT_KEY, THRIFT_SERVER_SOCKET_READ_TIMEOUT_DEFAULT);
+    TServerTransport serverTransport =
+      new TServerSocket(new TServerSocket.ServerSocketTransportArgs().bindAddr(inetSocketAddress)
+        .backlog(backlog).clientTimeout(readTimeout));
+
+    TBoundedThreadPoolServer.Args serverArgs =
+      new TBoundedThreadPoolServer.Args(serverTransport, conf);
+    serverArgs.processor(processor).transportFactory(transportFactory)
+      .protocolFactory(protocolFactory);
+    return new TBoundedThreadPoolServer(serverArgs, metrics);
+  }
+
+  protected TProtocolFactory getProtocolFactory() {
+    TProtocolFactory protocolFactory;
+
+    if (conf.getBoolean(COMPACT_CONF_KEY, COMPACT_CONF_DEFAULT)) {
+      LOG.debug("Using compact protocol");
+      protocolFactory = new TCompactProtocol.Factory();
+    } else {
+      LOG.debug("Using binary protocol");
+      protocolFactory = new TBinaryProtocol.Factory();
+    }
+
+    return protocolFactory;
+  }
+
+  protected ExecutorService createExecutor(BlockingQueue<Runnable> callQueue, int minWorkers,
+    int maxWorkers) {
+    ThreadFactoryBuilder tfb = new ThreadFactoryBuilder();
+    tfb.setDaemon(true);
+    tfb.setNameFormat("thrift-worker-%d");
+    ThreadPoolExecutor threadPool = new THBaseThreadPoolExecutor(minWorkers, maxWorkers,
+      Long.MAX_VALUE, TimeUnit.SECONDS, callQueue, tfb.build(), metrics);
+    threadPool.allowCoreThreadTimeOut(true);
+    return threadPool;
+  }
+
+  protected InetAddress getBindAddress(Configuration conf) throws UnknownHostException {
+    String bindAddressStr = conf.get(BIND_CONF_KEY, DEFAULT_BIND_ADDR);
+    return InetAddress.getByName(bindAddressStr);
+  }
+
+  public static void registerFilters(Configuration conf) {
+    String[] filters = conf.getStrings(THRIFT_FILTERS);
+    Splitter splitter = Splitter.on(':');
+    if (filters != null) {
+      for (String filterClass : filters) {
+        List<String> filterPart = splitter.splitToList(filterClass);
+        if (filterPart.size() != 2) {
+          LOG.warn("Invalid filter specification " + filterClass + " - skipping");
+        } else {
+          ParseFilter.registerFilter(filterPart.get(0), filterPart.get(1));
+        }
+      }
+    }
+  }
+
+  /**
+   * Add options to command lines
+   * @param options options
+   */
+  protected void addOptions(Options options) {
+    options.addOption("b", BIND_OPTION, true,
+      "Address to bind " + "the Thrift server to. [default: " + DEFAULT_BIND_ADDR + "]");
+    options.addOption("p", PORT_OPTION, true,
+      "Port to bind to [default: " + DEFAULT_LISTEN_PORT + "]");
+    options.addOption("f", FRAMED_OPTION, false, "Use framed transport");
+    options.addOption("c", COMPACT_OPTION, false, "Use the compact protocol");
+    options.addOption("h", "help", false, "Print help information");
+    options.addOption("s", SELECTOR_NUM_OPTION, true, "How many selector threads to use.");
+    options.addOption(null, INFOPORT_OPTION, true, "Port for web UI");
+
+    options.addOption("m", MIN_WORKERS_OPTION, true,
+      "The minimum number of worker threads for " + ImplType.THREAD_POOL.simpleClassName());
+
+    options.addOption("w", MAX_WORKERS_OPTION, true,
+      "The maximum number of worker threads for " + ImplType.THREAD_POOL.simpleClassName());
+
+    options.addOption("q", MAX_QUEUE_SIZE_OPTION, true,
+      "The maximum number of queued requests in " + ImplType.THREAD_POOL.simpleClassName());
+
+    options.addOption("k", KEEP_ALIVE_SEC_OPTION, true,
+      "The amount of time in secods to keep a thread alive when idle in "
+        + ImplType.THREAD_POOL.simpleClassName());
+
+    options.addOption("t", READ_TIMEOUT_OPTION, true,
+      "Amount of time in milliseconds before a server thread will timeout "
+        + "waiting for client to send data on a connected socket. Currently, "
+        + "only applies to TBoundedThreadPoolServer");
+
+    options.addOptionGroup(ImplType.createOptionGroup());
+  }
+
+  protected void parseCommandLine(CommandLine cmd, Options options) throws ExitCodeException {
+    // Get port to bind to
+    try {
+      if (cmd.hasOption(PORT_OPTION)) {
+        int listenPort = Integer.parseInt(cmd.getOptionValue(PORT_OPTION));
+        conf.setInt(PORT_CONF_KEY, listenPort);
+      }
+    } catch (NumberFormatException e) {
+      LOG.error("Could not parse the value provided for the port option", e);
+      printUsageAndExit(options, -1);
+    }
+    // check for user-defined info server port setting, if so override the conf
+    try {
+      if (cmd.hasOption(INFOPORT_OPTION)) {
+        String val = cmd.getOptionValue(INFOPORT_OPTION);
+        conf.setInt(THRIFT_INFO_SERVER_PORT, Integer.parseInt(val));
+        LOG.debug("Web UI port set to " + val);
+      }
+    } catch (NumberFormatException e) {
+      LOG.error("Could not parse the value provided for the " + INFOPORT_OPTION + " option", e);
+      printUsageAndExit(options, -1);
+    }
+    // Make optional changes to the configuration based on command-line options
+    optionToConf(cmd, MIN_WORKERS_OPTION, conf,
+      TBoundedThreadPoolServer.MIN_WORKER_THREADS_CONF_KEY);
+    optionToConf(cmd, MAX_WORKERS_OPTION, conf,
+      TBoundedThreadPoolServer.MAX_WORKER_THREADS_CONF_KEY);
+    optionToConf(cmd, MAX_QUEUE_SIZE_OPTION, conf,
+      TBoundedThreadPoolServer.MAX_QUEUED_REQUESTS_CONF_KEY);
+    optionToConf(cmd, KEEP_ALIVE_SEC_OPTION, conf,
+      TBoundedThreadPoolServer.THREAD_KEEP_ALIVE_TIME_SEC_CONF_KEY);
+    optionToConf(cmd, READ_TIMEOUT_OPTION, conf, THRIFT_SERVER_SOCKET_READ_TIMEOUT_KEY);
+    optionToConf(cmd, SELECTOR_NUM_OPTION, conf, THRIFT_SELECTOR_NUM);
+
+    // Set general thrift server options
+    boolean compact = cmd.hasOption(COMPACT_OPTION) || conf.getBoolean(COMPACT_CONF_KEY, false);
+    conf.setBoolean(COMPACT_CONF_KEY, compact);
+    boolean framed = cmd.hasOption(FRAMED_OPTION) || conf.getBoolean(FRAMED_CONF_KEY, false);
+    conf.setBoolean(FRAMED_CONF_KEY, framed);
+
+    optionToConf(cmd, BIND_OPTION, conf, BIND_CONF_KEY);
+
+    ImplType.setServerImpl(cmd, conf);
+  }
+
+  /**
+   * Parse the command line options to set parameters the conf.
+   */
+  protected void processOptions(final String[] args) throws Exception {
+    if (args == null || args.length == 0) {
+      return;
+    }
+    Options options = new Options();
+    addOptions(options);
+
+    CommandLineParser parser = new DefaultParser();
+    CommandLine cmd = parser.parse(options, args);
+
+    if (cmd.hasOption("help")) {
+      printUsageAndExit(options, 1);
+    }
+    parseCommandLine(cmd, options);
+  }
+
+  public void stop() {
+    if (this.infoServer != null) {
+      LOG.info("Stopping infoServer");
+      try {
+        this.infoServer.stop();
+      } catch (Exception ex) {
+        LOG.error("Failed to stop infoServer", ex);
+      }
+    }
+    if (pauseMonitor != null) {
+      pauseMonitor.stop();
+    }
+    if (tserver != null) {
+      tserver.stop();
+      tserver = null;
+    }
+    if (httpServer != null) {
+      try {
+        httpServer.stop();
+        httpServer = null;
+      } catch (Exception e) {
+        LOG.error("Problem encountered in shutting down HTTP server", e);
+      }
+      httpServer = null;
+    }
+  }
+
+  protected static void optionToConf(CommandLine cmd, String option, Configuration conf,
+    String destConfKey) {
+    if (cmd.hasOption(option)) {
+      String value = cmd.getOptionValue(option);
+      LOG.info("Set configuration key:" + destConfKey + " value:" + value);
+      conf.set(destConfKey, value);
+    }
+  }
+
+  /**
+   * Run without any command line arguments
+   * @return exit code
+   * @throws Exception exception
+   */
+  public int run() throws Exception {
+    return run(null);
+  }
+
+  @Override
+  public int run(String[] strings) throws Exception {
+    processOptions(strings);
+    setupParamters();
+    if (httpEnabled) {
+      setupHTTPServer();
+    } else {
+      setupServer();
+    }
+    serviceUGI.doAs(new PrivilegedAction<Object>() {
+      @Override
+      public Object run() {
+        try {
+          startInfoServer();
+          if (httpEnabled) {
+            httpServer.start();
+            httpServer.join();
+          } else {
+            tserver.serve();
+          }
+        } catch (Exception e) {
+          LOG.error(HBaseMarkers.FATAL, "Cannot run ThriftServer", e);
+
+          System.exit(-1);
+        }
+        return null;
+      }
+    });
+    return 0;
+  }
+
+  public static void main(String[] args) throws Exception {
+    LOG.info("***** STARTING service '" + ThriftServer.class.getSimpleName() + "' *****");
+    VersionInfo.logVersion();
+    final Configuration conf = HBaseConfiguration.create();
+    // for now, only time we return is on an argument error.
+    final int status = ToolRunner.run(conf, new ThriftServer(conf), args);
+    LOG.info("***** STOPPING service '" + ThriftServer.class.getSimpleName() + "' *****");
+    System.exit(status);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java
new file mode 100644
index 0000000..38edd98
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftUtilities.java
@@ -0,0 +1,249 @@
+/*
+ * 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.thrift;
+
+import static org.apache.hadoop.hbase.util.Bytes.getBytes;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeMap;
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.client.Append;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.Increment;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.io.compress.Compression;
+import org.apache.hadoop.hbase.regionserver.BloomType;
+import org.apache.hadoop.hbase.security.access.Permission;
+import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
+import org.apache.hadoop.hbase.thrift.generated.IllegalArgument;
+import org.apache.hadoop.hbase.thrift.generated.TAppend;
+import org.apache.hadoop.hbase.thrift.generated.TCell;
+import org.apache.hadoop.hbase.thrift.generated.TColumn;
+import org.apache.hadoop.hbase.thrift.generated.TIncrement;
+import org.apache.hadoop.hbase.thrift.generated.TRowResult;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.yetus.audience.InterfaceAudience;
+
+@InterfaceAudience.Private
+public final class ThriftUtilities {
+  private ThriftUtilities() {
+  }
+
+  /**
+   * This utility method creates a new Hbase HColumnDescriptor object based on a Thrift
+   * ColumnDescriptor "struct".
+   * @param in Thrift ColumnDescriptor object n * @throws IllegalArgument if the column name is
+   *           empty
+   */
+  public static ColumnFamilyDescriptor colDescFromThrift(ColumnDescriptor in)
+    throws IllegalArgument {
+    Compression.Algorithm comp =
+      Compression.getCompressionAlgorithmByName(in.compression.toLowerCase(Locale.ROOT));
+    BloomType bt = BloomType.valueOf(in.bloomFilterType);
+
+    if (in.name == null || !in.name.hasRemaining()) {
+      throw new IllegalArgument("column name is empty");
+    }
+    byte[] parsedName = CellUtil.parseColumn(Bytes.getBytes(in.name))[0];
+    return ColumnFamilyDescriptorBuilder.newBuilder(parsedName).setMaxVersions(in.maxVersions)
+      .setCompressionType(comp).setInMemory(in.inMemory).setBlockCacheEnabled(in.blockCacheEnabled)
+      .setTimeToLive(in.timeToLive > 0 ? in.timeToLive : Integer.MAX_VALUE).setBloomFilterType(bt)
+      .build();
+  }
+
+  /**
+   * This utility method creates a new Thrift ColumnDescriptor "struct" based on an Hbase
+   * HColumnDescriptor object. n * Hbase HColumnDescriptor object
+   * @return Thrift ColumnDescriptor
+   */
+  public static ColumnDescriptor colDescFromHbase(ColumnFamilyDescriptor in) {
+    ColumnDescriptor col = new ColumnDescriptor();
+    col.name = ByteBuffer.wrap(Bytes.add(in.getName(), KeyValue.COLUMN_FAMILY_DELIM_ARRAY));
+    col.maxVersions = in.getMaxVersions();
+    col.compression = in.getCompressionType().toString();
+    col.inMemory = in.isInMemory();
+    col.blockCacheEnabled = in.isBlockCacheEnabled();
+    col.bloomFilterType = in.getBloomFilterType().toString();
+    col.timeToLive = in.getTimeToLive();
+    return col;
+  }
+
+  /**
+   * This utility method creates a list of Thrift TCell "struct" based on an Hbase Cell object. The
+   * empty list is returned if the input is null. n * Hbase Cell object
+   * @return Thrift TCell array
+   */
+  public static List<TCell> cellFromHBase(Cell in) {
+    List<TCell> list = new ArrayList<>(1);
+    if (in != null) {
+      list.add(new TCell(ByteBuffer.wrap(CellUtil.cloneValue(in)), in.getTimestamp()));
+    }
+    return list;
+  }
+
+  /**
+   * This utility method creates a list of Thrift TCell "struct" based on an Hbase Cell array. The
+   * empty list is returned if the input is null.
+   * @param in Hbase Cell array
+   * @return Thrift TCell array
+   */
+  public static List<TCell> cellFromHBase(Cell[] in) {
+    List<TCell> list = null;
+    if (in != null) {
+      list = new ArrayList<>(in.length);
+      for (int i = 0; i < in.length; i++) {
+        list.add(new TCell(ByteBuffer.wrap(CellUtil.cloneValue(in[i])), in[i].getTimestamp()));
+      }
+    } else {
+      list = new ArrayList<>(0);
+    }
+    return list;
+  }
+
+  /**
+   * This utility method creates a list of Thrift TRowResult "struct" based on an Hbase RowResult
+   * object. The empty list is returned if the input is null. n * Hbase RowResult object n * This
+   * boolean dictates if row data is returned in a sorted order sortColumns = True will set
+   * TRowResult's sortedColumns member which is an ArrayList of TColumn struct sortColumns = False
+   * will set TRowResult's columns member which is a map of columnName and TCell struct
+   * @return Thrift TRowResult array
+   */
+  public static List<TRowResult> rowResultFromHBase(Result[] in, boolean sortColumns) {
+    List<TRowResult> results = new ArrayList<>(in.length);
+    for (Result result_ : in) {
+      if (result_ == null || result_.isEmpty()) {
+        continue;
+      }
+
+      TRowResult result = new TRowResult();
+      result.row = ByteBuffer.wrap(result_.getRow());
+
+      if (sortColumns) {
+        result.sortedColumns = new ArrayList<>();
+        for (Cell kv : result_.rawCells()) {
+          result.sortedColumns.add(new TColumn(
+            ByteBuffer
+              .wrap(CellUtil.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))),
+            new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp())));
+        }
+      } else {
+        result.columns = new TreeMap<>();
+        for (Cell kv : result_.rawCells()) {
+          result.columns.put(
+            ByteBuffer
+              .wrap(CellUtil.makeColumn(CellUtil.cloneFamily(kv), CellUtil.cloneQualifier(kv))),
+            new TCell(ByteBuffer.wrap(CellUtil.cloneValue(kv)), kv.getTimestamp()));
+        }
+      }
+
+      results.add(result);
+    }
+
+    return results;
+  }
+
+  /**
+   * This utility method creates a list of Thrift TRowResult "struct" based on an array of Hbase
+   * RowResult objects. The empty list is returned if the input is null. n * Array of Hbase
+   * RowResult objects
+   * @return Thrift TRowResult array
+   */
+  public static List<TRowResult> rowResultFromHBase(Result[] in) {
+    return rowResultFromHBase(in, false);
+  }
+
+  public static List<TRowResult> rowResultFromHBase(Result in) {
+    Result[] result = { in };
+    return rowResultFromHBase(result);
+  }
+
+  /**
+   * From a {@link TIncrement} create an {@link Increment}.
+   * @param tincrement the Thrift version of an increment
+   * @return an increment that the {@link TIncrement} represented.
+   */
+  public static Increment incrementFromThrift(TIncrement tincrement) {
+    Increment inc = new Increment(tincrement.getRow());
+    byte[][] famAndQf = CellUtil.parseColumn(tincrement.getColumn());
+
+    if (famAndQf.length != 2) {
+      return null;
+    }
+
+    inc.addColumn(famAndQf[0], famAndQf[1], tincrement.getAmmount());
+    return inc;
+  }
+
+  /**
+   * From a {@link TAppend} create an {@link Append}.
+   * @param tappend the Thrift version of an append.
+   * @return an increment that the {@link TAppend} represented.
+   */
+  public static Append appendFromThrift(TAppend tappend) {
+    Append append = new Append(tappend.getRow());
+    List<ByteBuffer> columns = tappend.getColumns();
+    List<ByteBuffer> values = tappend.getValues();
+
+    if (columns.size() != values.size()) {
+      throw new IllegalArgumentException(
+        "Sizes of columns and values in tappend object are not matching");
+    }
+
+    int length = columns.size();
+
+    for (int i = 0; i < length; i++) {
+      byte[][] famAndQf = CellUtil.parseColumn(getBytes(columns.get(i)));
+      append.addColumn(famAndQf[0], famAndQf[1], getBytes(values.get(i)));
+    }
+    return append;
+  }
+
+  public static Permission.Action[] permissionActionsFromString(String permission_actions) {
+    Set<Permission.Action> actions = new HashSet<>();
+    for (char c : permission_actions.toCharArray()) {
+      switch (c) {
+        case 'R':
+          actions.add(Permission.Action.READ);
+          break;
+        case 'W':
+          actions.add(Permission.Action.WRITE);
+          break;
+        case 'C':
+          actions.add(Permission.Action.CREATE);
+          break;
+        case 'X':
+          actions.add(Permission.Action.EXEC);
+          break;
+        case 'A':
+          actions.add(Permission.Action.ADMIN);
+          break;
+        default:
+          break;
+      }
+    }
+    return actions.toArray(new Permission.Action[0]);
+  }
+}
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java
new file mode 100644
index 0000000..612a3ce
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/AlreadyExists.java
@@ -0,0 +1,379 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.hadoop.hbase.thrift.generated;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * An AlreadyExists exceptions signals that a table with the specified
+ * name already exists
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-19")
+public class AlreadyExists extends org.apache.thrift.TException implements org.apache.thrift.TBase<AlreadyExists, AlreadyExists._Fields>, java.io.Serializable, Cloneable, Comparable<AlreadyExists> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AlreadyExists");
+
+  private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message", org.apache.thrift.protocol.TType.STRING, (short)1);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new AlreadyExistsStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new AlreadyExistsTupleSchemeFactory();
+
+  public @org.apache.thrift.annotation.Nullable java.lang.String message; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    MESSAGE((short)1, "message");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // MESSAGE
+          return MESSAGE;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(AlreadyExists.class, metaDataMap);
+  }
+
+  public AlreadyExists() {
+  }
+
+  public AlreadyExists(
+    java.lang.String message)
+  {
+    this();
+    this.message = message;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public AlreadyExists(AlreadyExists other) {
+    if (other.isSetMessage()) {
+      this.message = other.message;
+    }
+  }
+
+  public AlreadyExists deepCopy() {
+    return new AlreadyExists(this);
+  }
+
+  @Override
+  public void clear() {
+    this.message = null;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getMessage() {
+    return this.message;
+  }
+
+  public AlreadyExists setMessage(@org.apache.thrift.annotation.Nullable java.lang.String message) {
+    this.message = message;
+    return this;
+  }
+
+  public void unsetMessage() {
+    this.message = null;
+  }
+
+  /** Returns true if field message is set (has been assigned a value) and false otherwise */
+  public boolean isSetMessage() {
+    return this.message != null;
+  }
+
+  public void setMessageIsSet(boolean value) {
+    if (!value) {
+      this.message = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case MESSAGE:
+      if (value == null) {
+        unsetMessage();
+      } else {
+        setMessage((java.lang.String)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case MESSAGE:
+      return getMessage();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case MESSAGE:
+      return isSetMessage();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof AlreadyExists)
+      return this.equals((AlreadyExists)that);
+    return false;
+  }
+
+  public boolean equals(AlreadyExists that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_message = true && this.isSetMessage();
+    boolean that_present_message = true && that.isSetMessage();
+    if (this_present_message || that_present_message) {
+      if (!(this_present_message && that_present_message))
+        return false;
+      if (!this.message.equals(that.message))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetMessage()) ? 131071 : 524287);
+    if (isSetMessage())
+      hashCode = hashCode * 8191 + message.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(AlreadyExists other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetMessage(), other.isSetMessage());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMessage()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, other.message);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("AlreadyExists(");
+    boolean first = true;
+
+    sb.append("message:");
+    if (this.message == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.message);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class AlreadyExistsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AlreadyExistsStandardScheme getScheme() {
+      return new AlreadyExistsStandardScheme();
+    }
+  }
+
+  private static class AlreadyExistsStandardScheme extends org.apache.thrift.scheme.StandardScheme<AlreadyExists> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, AlreadyExists struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // MESSAGE
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.message = iprot.readString();
+              struct.setMessageIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, AlreadyExists struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.message != null) {
+        oprot.writeFieldBegin(MESSAGE_FIELD_DESC);
+        oprot.writeString(struct.message);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class AlreadyExistsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public AlreadyExistsTupleScheme getScheme() {
+      return new AlreadyExistsTupleScheme();
+    }
+  }
+
+  private static class AlreadyExistsTupleScheme extends org.apache.thrift.scheme.TupleScheme<AlreadyExists> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, AlreadyExists struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetMessage()) {
+        optionals.set(0);
+      }
+      oprot.writeBitSet(optionals, 1);
+      if (struct.isSetMessage()) {
+        oprot.writeString(struct.message);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, AlreadyExists struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet incoming = iprot.readBitSet(1);
+      if (incoming.get(0)) {
+        struct.message = iprot.readString();
+        struct.setMessageIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java
new file mode 100644
index 0000000..e1ec71d
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/BatchMutation.java
@@ -0,0 +1,551 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.hadoop.hbase.thrift.generated;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * A BatchMutation object is used to apply a number of Mutations to a single row.
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-19")
+public class BatchMutation implements org.apache.thrift.TBase<BatchMutation, BatchMutation._Fields>, java.io.Serializable, Cloneable, Comparable<BatchMutation> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("BatchMutation");
+
+  private static final org.apache.thrift.protocol.TField ROW_FIELD_DESC = new org.apache.thrift.protocol.TField("row", org.apache.thrift.protocol.TType.STRING, (short)1);
+  private static final org.apache.thrift.protocol.TField MUTATIONS_FIELD_DESC = new org.apache.thrift.protocol.TField("mutations", org.apache.thrift.protocol.TType.LIST, (short)2);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new BatchMutationStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new BatchMutationTupleSchemeFactory();
+
+  public @org.apache.thrift.annotation.Nullable java.nio.ByteBuffer row; // required
+  public @org.apache.thrift.annotation.Nullable java.util.List<Mutation> mutations; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    ROW((short)1, "row"),
+    MUTATIONS((short)2, "mutations");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // ROW
+          return ROW;
+        case 2: // MUTATIONS
+          return MUTATIONS;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.ROW, new org.apache.thrift.meta_data.FieldMetaData("row", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , "Text")));
+    tmpMap.put(_Fields.MUTATIONS, new org.apache.thrift.meta_data.FieldMetaData("mutations", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.ListMetaData(org.apache.thrift.protocol.TType.LIST, 
+            new org.apache.thrift.meta_data.StructMetaData(org.apache.thrift.protocol.TType.STRUCT, Mutation.class))));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(BatchMutation.class, metaDataMap);
+  }
+
+  public BatchMutation() {
+  }
+
+  public BatchMutation(
+    java.nio.ByteBuffer row,
+    java.util.List<Mutation> mutations)
+  {
+    this();
+    this.row = org.apache.thrift.TBaseHelper.copyBinary(row);
+    this.mutations = mutations;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public BatchMutation(BatchMutation other) {
+    if (other.isSetRow()) {
+      this.row = org.apache.thrift.TBaseHelper.copyBinary(other.row);
+    }
+    if (other.isSetMutations()) {
+      java.util.List<Mutation> __this__mutations = new java.util.ArrayList<Mutation>(other.mutations.size());
+      for (Mutation other_element : other.mutations) {
+        __this__mutations.add(new Mutation(other_element));
+      }
+      this.mutations = __this__mutations;
+    }
+  }
+
+  public BatchMutation deepCopy() {
+    return new BatchMutation(this);
+  }
+
+  @Override
+  public void clear() {
+    this.row = null;
+    this.mutations = null;
+  }
+
+  public byte[] getRow() {
+    setRow(org.apache.thrift.TBaseHelper.rightSize(row));
+    return row == null ? null : row.array();
+  }
+
+  public java.nio.ByteBuffer bufferForRow() {
+    return org.apache.thrift.TBaseHelper.copyBinary(row);
+  }
+
+  public BatchMutation setRow(byte[] row) {
+    this.row = row == null ? (java.nio.ByteBuffer)null   : java.nio.ByteBuffer.wrap(row.clone());
+    return this;
+  }
+
+  public BatchMutation setRow(@org.apache.thrift.annotation.Nullable java.nio.ByteBuffer row) {
+    this.row = org.apache.thrift.TBaseHelper.copyBinary(row);
+    return this;
+  }
+
+  public void unsetRow() {
+    this.row = null;
+  }
+
+  /** Returns true if field row is set (has been assigned a value) and false otherwise */
+  public boolean isSetRow() {
+    return this.row != null;
+  }
+
+  public void setRowIsSet(boolean value) {
+    if (!value) {
+      this.row = null;
+    }
+  }
+
+  public int getMutationsSize() {
+    return (this.mutations == null) ? 0 : this.mutations.size();
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.Iterator<Mutation> getMutationsIterator() {
+    return (this.mutations == null) ? null : this.mutations.iterator();
+  }
+
+  public void addToMutations(Mutation elem) {
+    if (this.mutations == null) {
+      this.mutations = new java.util.ArrayList<Mutation>();
+    }
+    this.mutations.add(elem);
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.util.List<Mutation> getMutations() {
+    return this.mutations;
+  }
+
+  public BatchMutation setMutations(@org.apache.thrift.annotation.Nullable java.util.List<Mutation> mutations) {
+    this.mutations = mutations;
+    return this;
+  }
+
+  public void unsetMutations() {
+    this.mutations = null;
+  }
+
+  /** Returns true if field mutations is set (has been assigned a value) and false otherwise */
+  public boolean isSetMutations() {
+    return this.mutations != null;
+  }
+
+  public void setMutationsIsSet(boolean value) {
+    if (!value) {
+      this.mutations = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case ROW:
+      if (value == null) {
+        unsetRow();
+      } else {
+        if (value instanceof byte[]) {
+          setRow((byte[])value);
+        } else {
+          setRow((java.nio.ByteBuffer)value);
+        }
+      }
+      break;
+
+    case MUTATIONS:
+      if (value == null) {
+        unsetMutations();
+      } else {
+        setMutations((java.util.List<Mutation>)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case ROW:
+      return getRow();
+
+    case MUTATIONS:
+      return getMutations();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case ROW:
+      return isSetRow();
+    case MUTATIONS:
+      return isSetMutations();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof BatchMutation)
+      return this.equals((BatchMutation)that);
+    return false;
+  }
+
+  public boolean equals(BatchMutation that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_row = true && this.isSetRow();
+    boolean that_present_row = true && that.isSetRow();
+    if (this_present_row || that_present_row) {
+      if (!(this_present_row && that_present_row))
+        return false;
+      if (!this.row.equals(that.row))
+        return false;
+    }
+
+    boolean this_present_mutations = true && this.isSetMutations();
+    boolean that_present_mutations = true && that.isSetMutations();
+    if (this_present_mutations || that_present_mutations) {
+      if (!(this_present_mutations && that_present_mutations))
+        return false;
+      if (!this.mutations.equals(that.mutations))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetRow()) ? 131071 : 524287);
+    if (isSetRow())
+      hashCode = hashCode * 8191 + row.hashCode();
+
+    hashCode = hashCode * 8191 + ((isSetMutations()) ? 131071 : 524287);
+    if (isSetMutations())
+      hashCode = hashCode * 8191 + mutations.hashCode();
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(BatchMutation other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetRow(), other.isSetRow());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetRow()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.row, other.row);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetMutations(), other.isSetMutations());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMutations()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.mutations, other.mutations);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("BatchMutation(");
+    boolean first = true;
+
+    sb.append("row:");
+    if (this.row == null) {
+      sb.append("null");
+    } else {
+      org.apache.thrift.TBaseHelper.toString(this.row, sb);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("mutations:");
+    if (this.mutations == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.mutations);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class BatchMutationStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public BatchMutationStandardScheme getScheme() {
+      return new BatchMutationStandardScheme();
+    }
+  }
+
+  private static class BatchMutationStandardScheme extends org.apache.thrift.scheme.StandardScheme<BatchMutation> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, BatchMutation struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // ROW
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.row = iprot.readBinary();
+              struct.setRowIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // MUTATIONS
+            if (schemeField.type == org.apache.thrift.protocol.TType.LIST) {
+              {
+                org.apache.thrift.protocol.TList _list0 = iprot.readListBegin();
+                struct.mutations = new java.util.ArrayList<Mutation>(_list0.size);
+                @org.apache.thrift.annotation.Nullable Mutation _elem1;
+                for (int _i2 = 0; _i2 < _list0.size; ++_i2)
+                {
+                  _elem1 = new Mutation();
+                  _elem1.read(iprot);
+                  struct.mutations.add(_elem1);
+                }
+                iprot.readListEnd();
+              }
+              struct.setMutationsIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, BatchMutation struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.row != null) {
+        oprot.writeFieldBegin(ROW_FIELD_DESC);
+        oprot.writeBinary(struct.row);
+        oprot.writeFieldEnd();
+      }
+      if (struct.mutations != null) {
+        oprot.writeFieldBegin(MUTATIONS_FIELD_DESC);
+        {
+          oprot.writeListBegin(new org.apache.thrift.protocol.TList(org.apache.thrift.protocol.TType.STRUCT, struct.mutations.size()));
+          for (Mutation _iter3 : struct.mutations)
+          {
+            _iter3.write(oprot);
+          }
+          oprot.writeListEnd();
+        }
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class BatchMutationTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public BatchMutationTupleScheme getScheme() {
+      return new BatchMutationTupleScheme();
+    }
+  }
+
+  private static class BatchMutationTupleScheme extends org.apache.thrift.scheme.TupleScheme<BatchMutation> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, BatchMutation struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetRow()) {
+        optionals.set(0);
+      }
+      if (struct.isSetMutations()) {
+        optionals.set(1);
+      }
+      oprot.writeBitSet(optionals, 2);
+      if (struct.isSetRow()) {
+        oprot.writeBinary(struct.row);
+      }
+      if (struct.isSetMutations()) {
+        {
+          oprot.writeI32(struct.mutations.size());
+          for (Mutation _iter4 : struct.mutations)
+          {
+            _iter4.write(oprot);
+          }
+        }
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, BatchMutation struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet incoming = iprot.readBitSet(2);
+      if (incoming.get(0)) {
+        struct.row = iprot.readBinary();
+        struct.setRowIsSet(true);
+      }
+      if (incoming.get(1)) {
+        {
+          org.apache.thrift.protocol.TList _list5 = iprot.readListBegin(org.apache.thrift.protocol.TType.STRUCT);
+          struct.mutations = new java.util.ArrayList<Mutation>(_list5.size);
+          @org.apache.thrift.annotation.Nullable Mutation _elem6;
+          for (int _i7 = 0; _i7 < _list5.size; ++_i7)
+          {
+            _elem6 = new Mutation();
+            _elem6.read(iprot);
+            struct.mutations.add(_elem6);
+          }
+        }
+        struct.setMutationsIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java
new file mode 100644
index 0000000..58cdc9d
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/ColumnDescriptor.java
@@ -0,0 +1,1201 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.hadoop.hbase.thrift.generated;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+/**
+ * An HColumnDescriptor contains information about a column family
+ * such as the number of versions, compression settings, etc. It is
+ * used as input when creating a table or adding a column.
+ */
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-07-19")
+public class ColumnDescriptor implements org.apache.thrift.TBase<ColumnDescriptor, ColumnDescriptor._Fields>, java.io.Serializable, Cloneable, Comparable<ColumnDescriptor> {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ColumnDescriptor");
+
+  private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1);
+  private static final org.apache.thrift.protocol.TField MAX_VERSIONS_FIELD_DESC = new org.apache.thrift.protocol.TField("maxVersions", org.apache.thrift.protocol.TType.I32, (short)2);
+  private static final org.apache.thrift.protocol.TField COMPRESSION_FIELD_DESC = new org.apache.thrift.protocol.TField("compression", org.apache.thrift.protocol.TType.STRING, (short)3);
+  private static final org.apache.thrift.protocol.TField IN_MEMORY_FIELD_DESC = new org.apache.thrift.protocol.TField("inMemory", org.apache.thrift.protocol.TType.BOOL, (short)4);
+  private static final org.apache.thrift.protocol.TField BLOOM_FILTER_TYPE_FIELD_DESC = new org.apache.thrift.protocol.TField("bloomFilterType", org.apache.thrift.protocol.TType.STRING, (short)5);
+  private static final org.apache.thrift.protocol.TField BLOOM_FILTER_VECTOR_SIZE_FIELD_DESC = new org.apache.thrift.protocol.TField("bloomFilterVectorSize", org.apache.thrift.protocol.TType.I32, (short)6);
+  private static final org.apache.thrift.protocol.TField BLOOM_FILTER_NB_HASHES_FIELD_DESC = new org.apache.thrift.protocol.TField("bloomFilterNbHashes", org.apache.thrift.protocol.TType.I32, (short)7);
+  private static final org.apache.thrift.protocol.TField BLOCK_CACHE_ENABLED_FIELD_DESC = new org.apache.thrift.protocol.TField("blockCacheEnabled", org.apache.thrift.protocol.TType.BOOL, (short)8);
+  private static final org.apache.thrift.protocol.TField TIME_TO_LIVE_FIELD_DESC = new org.apache.thrift.protocol.TField("timeToLive", org.apache.thrift.protocol.TType.I32, (short)9);
+
+  private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new ColumnDescriptorStandardSchemeFactory();
+  private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new ColumnDescriptorTupleSchemeFactory();
+
+  public @org.apache.thrift.annotation.Nullable java.nio.ByteBuffer name; // required
+  public int maxVersions; // required
+  public @org.apache.thrift.annotation.Nullable java.lang.String compression; // required
+  public boolean inMemory; // required
+  public @org.apache.thrift.annotation.Nullable java.lang.String bloomFilterType; // required
+  public int bloomFilterVectorSize; // required
+  public int bloomFilterNbHashes; // required
+  public boolean blockCacheEnabled; // required
+  public int timeToLive; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    NAME((short)1, "name"),
+    MAX_VERSIONS((short)2, "maxVersions"),
+    COMPRESSION((short)3, "compression"),
+    IN_MEMORY((short)4, "inMemory"),
+    BLOOM_FILTER_TYPE((short)5, "bloomFilterType"),
+    BLOOM_FILTER_VECTOR_SIZE((short)6, "bloomFilterVectorSize"),
+    BLOOM_FILTER_NB_HASHES((short)7, "bloomFilterNbHashes"),
+    BLOCK_CACHE_ENABLED((short)8, "blockCacheEnabled"),
+    TIME_TO_LIVE((short)9, "timeToLive");
+
+    private static final java.util.Map<java.lang.String, _Fields> byName = new java.util.HashMap<java.lang.String, _Fields>();
+
+    static {
+      for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // NAME
+          return NAME;
+        case 2: // MAX_VERSIONS
+          return MAX_VERSIONS;
+        case 3: // COMPRESSION
+          return COMPRESSION;
+        case 4: // IN_MEMORY
+          return IN_MEMORY;
+        case 5: // BLOOM_FILTER_TYPE
+          return BLOOM_FILTER_TYPE;
+        case 6: // BLOOM_FILTER_VECTOR_SIZE
+          return BLOOM_FILTER_VECTOR_SIZE;
+        case 7: // BLOOM_FILTER_NB_HASHES
+          return BLOOM_FILTER_NB_HASHES;
+        case 8: // BLOCK_CACHE_ENABLED
+          return BLOCK_CACHE_ENABLED;
+        case 9: // TIME_TO_LIVE
+          return TIME_TO_LIVE;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    @org.apache.thrift.annotation.Nullable
+    public static _Fields findByName(java.lang.String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final java.lang.String _fieldName;
+
+    _Fields(short thriftId, java.lang.String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public java.lang.String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+  private static final int __MAXVERSIONS_ISSET_ID = 0;
+  private static final int __INMEMORY_ISSET_ID = 1;
+  private static final int __BLOOMFILTERVECTORSIZE_ISSET_ID = 2;
+  private static final int __BLOOMFILTERNBHASHES_ISSET_ID = 3;
+  private static final int __BLOCKCACHEENABLED_ISSET_ID = 4;
+  private static final int __TIMETOLIVE_ISSET_ID = 5;
+  private byte __isset_bitfield = 0;
+  public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.NAME, new org.apache.thrift.meta_data.FieldMetaData("name", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING        , "Text")));
+    tmpMap.put(_Fields.MAX_VERSIONS, new org.apache.thrift.meta_data.FieldMetaData("maxVersions", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.COMPRESSION, new org.apache.thrift.meta_data.FieldMetaData("compression", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.IN_MEMORY, new org.apache.thrift.meta_data.FieldMetaData("inMemory", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL)));
+    tmpMap.put(_Fields.BLOOM_FILTER_TYPE, new org.apache.thrift.meta_data.FieldMetaData("bloomFilterType", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    tmpMap.put(_Fields.BLOOM_FILTER_VECTOR_SIZE, new org.apache.thrift.meta_data.FieldMetaData("bloomFilterVectorSize", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.BLOOM_FILTER_NB_HASHES, new org.apache.thrift.meta_data.FieldMetaData("bloomFilterNbHashes", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    tmpMap.put(_Fields.BLOCK_CACHE_ENABLED, new org.apache.thrift.meta_data.FieldMetaData("blockCacheEnabled", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.BOOL)));
+    tmpMap.put(_Fields.TIME_TO_LIVE, new org.apache.thrift.meta_data.FieldMetaData("timeToLive", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));
+    metaDataMap = java.util.Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(ColumnDescriptor.class, metaDataMap);
+  }
+
+  public ColumnDescriptor() {
+    this.maxVersions = 3;
+
+    this.compression = "NONE";
+
+    this.inMemory = false;
+
+    this.bloomFilterType = "NONE";
+
+    this.bloomFilterVectorSize = 0;
+
+    this.bloomFilterNbHashes = 0;
+
+    this.blockCacheEnabled = false;
+
+    this.timeToLive = 2147483647;
+
+  }
+
+  public ColumnDescriptor(
+    java.nio.ByteBuffer name,
+    int maxVersions,
+    java.lang.String compression,
+    boolean inMemory,
+    java.lang.String bloomFilterType,
+    int bloomFilterVectorSize,
+    int bloomFilterNbHashes,
+    boolean blockCacheEnabled,
+    int timeToLive)
+  {
+    this();
+    this.name = org.apache.thrift.TBaseHelper.copyBinary(name);
+    this.maxVersions = maxVersions;
+    setMaxVersionsIsSet(true);
+    this.compression = compression;
+    this.inMemory = inMemory;
+    setInMemoryIsSet(true);
+    this.bloomFilterType = bloomFilterType;
+    this.bloomFilterVectorSize = bloomFilterVectorSize;
+    setBloomFilterVectorSizeIsSet(true);
+    this.bloomFilterNbHashes = bloomFilterNbHashes;
+    setBloomFilterNbHashesIsSet(true);
+    this.blockCacheEnabled = blockCacheEnabled;
+    setBlockCacheEnabledIsSet(true);
+    this.timeToLive = timeToLive;
+    setTimeToLiveIsSet(true);
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public ColumnDescriptor(ColumnDescriptor other) {
+    __isset_bitfield = other.__isset_bitfield;
+    if (other.isSetName()) {
+      this.name = org.apache.thrift.TBaseHelper.copyBinary(other.name);
+    }
+    this.maxVersions = other.maxVersions;
+    if (other.isSetCompression()) {
+      this.compression = other.compression;
+    }
+    this.inMemory = other.inMemory;
+    if (other.isSetBloomFilterType()) {
+      this.bloomFilterType = other.bloomFilterType;
+    }
+    this.bloomFilterVectorSize = other.bloomFilterVectorSize;
+    this.bloomFilterNbHashes = other.bloomFilterNbHashes;
+    this.blockCacheEnabled = other.blockCacheEnabled;
+    this.timeToLive = other.timeToLive;
+  }
+
+  public ColumnDescriptor deepCopy() {
+    return new ColumnDescriptor(this);
+  }
+
+  @Override
+  public void clear() {
+    this.name = null;
+    this.maxVersions = 3;
+
+    this.compression = "NONE";
+
+    this.inMemory = false;
+
+    this.bloomFilterType = "NONE";
+
+    this.bloomFilterVectorSize = 0;
+
+    this.bloomFilterNbHashes = 0;
+
+    this.blockCacheEnabled = false;
+
+    this.timeToLive = 2147483647;
+
+  }
+
+  public byte[] getName() {
+    setName(org.apache.thrift.TBaseHelper.rightSize(name));
+    return name == null ? null : name.array();
+  }
+
+  public java.nio.ByteBuffer bufferForName() {
+    return org.apache.thrift.TBaseHelper.copyBinary(name);
+  }
+
+  public ColumnDescriptor setName(byte[] name) {
+    this.name = name == null ? (java.nio.ByteBuffer)null   : java.nio.ByteBuffer.wrap(name.clone());
+    return this;
+  }
+
+  public ColumnDescriptor setName(@org.apache.thrift.annotation.Nullable java.nio.ByteBuffer name) {
+    this.name = org.apache.thrift.TBaseHelper.copyBinary(name);
+    return this;
+  }
+
+  public void unsetName() {
+    this.name = null;
+  }
+
+  /** Returns true if field name is set (has been assigned a value) and false otherwise */
+  public boolean isSetName() {
+    return this.name != null;
+  }
+
+  public void setNameIsSet(boolean value) {
+    if (!value) {
+      this.name = null;
+    }
+  }
+
+  public int getMaxVersions() {
+    return this.maxVersions;
+  }
+
+  public ColumnDescriptor setMaxVersions(int maxVersions) {
+    this.maxVersions = maxVersions;
+    setMaxVersionsIsSet(true);
+    return this;
+  }
+
+  public void unsetMaxVersions() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __MAXVERSIONS_ISSET_ID);
+  }
+
+  /** Returns true if field maxVersions is set (has been assigned a value) and false otherwise */
+  public boolean isSetMaxVersions() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __MAXVERSIONS_ISSET_ID);
+  }
+
+  public void setMaxVersionsIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __MAXVERSIONS_ISSET_ID, value);
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getCompression() {
+    return this.compression;
+  }
+
+  public ColumnDescriptor setCompression(@org.apache.thrift.annotation.Nullable java.lang.String compression) {
+    this.compression = compression;
+    return this;
+  }
+
+  public void unsetCompression() {
+    this.compression = null;
+  }
+
+  /** Returns true if field compression is set (has been assigned a value) and false otherwise */
+  public boolean isSetCompression() {
+    return this.compression != null;
+  }
+
+  public void setCompressionIsSet(boolean value) {
+    if (!value) {
+      this.compression = null;
+    }
+  }
+
+  public boolean isInMemory() {
+    return this.inMemory;
+  }
+
+  public ColumnDescriptor setInMemory(boolean inMemory) {
+    this.inMemory = inMemory;
+    setInMemoryIsSet(true);
+    return this;
+  }
+
+  public void unsetInMemory() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __INMEMORY_ISSET_ID);
+  }
+
+  /** Returns true if field inMemory is set (has been assigned a value) and false otherwise */
+  public boolean isSetInMemory() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __INMEMORY_ISSET_ID);
+  }
+
+  public void setInMemoryIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __INMEMORY_ISSET_ID, value);
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.String getBloomFilterType() {
+    return this.bloomFilterType;
+  }
+
+  public ColumnDescriptor setBloomFilterType(@org.apache.thrift.annotation.Nullable java.lang.String bloomFilterType) {
+    this.bloomFilterType = bloomFilterType;
+    return this;
+  }
+
+  public void unsetBloomFilterType() {
+    this.bloomFilterType = null;
+  }
+
+  /** Returns true if field bloomFilterType is set (has been assigned a value) and false otherwise */
+  public boolean isSetBloomFilterType() {
+    return this.bloomFilterType != null;
+  }
+
+  public void setBloomFilterTypeIsSet(boolean value) {
+    if (!value) {
+      this.bloomFilterType = null;
+    }
+  }
+
+  public int getBloomFilterVectorSize() {
+    return this.bloomFilterVectorSize;
+  }
+
+  public ColumnDescriptor setBloomFilterVectorSize(int bloomFilterVectorSize) {
+    this.bloomFilterVectorSize = bloomFilterVectorSize;
+    setBloomFilterVectorSizeIsSet(true);
+    return this;
+  }
+
+  public void unsetBloomFilterVectorSize() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __BLOOMFILTERVECTORSIZE_ISSET_ID);
+  }
+
+  /** Returns true if field bloomFilterVectorSize is set (has been assigned a value) and false otherwise */
+  public boolean isSetBloomFilterVectorSize() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __BLOOMFILTERVECTORSIZE_ISSET_ID);
+  }
+
+  public void setBloomFilterVectorSizeIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __BLOOMFILTERVECTORSIZE_ISSET_ID, value);
+  }
+
+  public int getBloomFilterNbHashes() {
+    return this.bloomFilterNbHashes;
+  }
+
+  public ColumnDescriptor setBloomFilterNbHashes(int bloomFilterNbHashes) {
+    this.bloomFilterNbHashes = bloomFilterNbHashes;
+    setBloomFilterNbHashesIsSet(true);
+    return this;
+  }
+
+  public void unsetBloomFilterNbHashes() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __BLOOMFILTERNBHASHES_ISSET_ID);
+  }
+
+  /** Returns true if field bloomFilterNbHashes is set (has been assigned a value) and false otherwise */
+  public boolean isSetBloomFilterNbHashes() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __BLOOMFILTERNBHASHES_ISSET_ID);
+  }
+
+  public void setBloomFilterNbHashesIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __BLOOMFILTERNBHASHES_ISSET_ID, value);
+  }
+
+  public boolean isBlockCacheEnabled() {
+    return this.blockCacheEnabled;
+  }
+
+  public ColumnDescriptor setBlockCacheEnabled(boolean blockCacheEnabled) {
+    this.blockCacheEnabled = blockCacheEnabled;
+    setBlockCacheEnabledIsSet(true);
+    return this;
+  }
+
+  public void unsetBlockCacheEnabled() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __BLOCKCACHEENABLED_ISSET_ID);
+  }
+
+  /** Returns true if field blockCacheEnabled is set (has been assigned a value) and false otherwise */
+  public boolean isSetBlockCacheEnabled() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __BLOCKCACHEENABLED_ISSET_ID);
+  }
+
+  public void setBlockCacheEnabledIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __BLOCKCACHEENABLED_ISSET_ID, value);
+  }
+
+  public int getTimeToLive() {
+    return this.timeToLive;
+  }
+
+  public ColumnDescriptor setTimeToLive(int timeToLive) {
+    this.timeToLive = timeToLive;
+    setTimeToLiveIsSet(true);
+    return this;
+  }
+
+  public void unsetTimeToLive() {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.clearBit(__isset_bitfield, __TIMETOLIVE_ISSET_ID);
+  }
+
+  /** Returns true if field timeToLive is set (has been assigned a value) and false otherwise */
+  public boolean isSetTimeToLive() {
+    return org.apache.thrift.EncodingUtils.testBit(__isset_bitfield, __TIMETOLIVE_ISSET_ID);
+  }
+
+  public void setTimeToLiveIsSet(boolean value) {
+    __isset_bitfield = org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __TIMETOLIVE_ISSET_ID, value);
+  }
+
+  public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) {
+    switch (field) {
+    case NAME:
+      if (value == null) {
+        unsetName();
+      } else {
+        if (value instanceof byte[]) {
+          setName((byte[])value);
+        } else {
+          setName((java.nio.ByteBuffer)value);
+        }
+      }
+      break;
+
+    case MAX_VERSIONS:
+      if (value == null) {
+        unsetMaxVersions();
+      } else {
+        setMaxVersions((java.lang.Integer)value);
+      }
+      break;
+
+    case COMPRESSION:
+      if (value == null) {
+        unsetCompression();
+      } else {
+        setCompression((java.lang.String)value);
+      }
+      break;
+
+    case IN_MEMORY:
+      if (value == null) {
+        unsetInMemory();
+      } else {
+        setInMemory((java.lang.Boolean)value);
+      }
+      break;
+
+    case BLOOM_FILTER_TYPE:
+      if (value == null) {
+        unsetBloomFilterType();
+      } else {
+        setBloomFilterType((java.lang.String)value);
+      }
+      break;
+
+    case BLOOM_FILTER_VECTOR_SIZE:
+      if (value == null) {
+        unsetBloomFilterVectorSize();
+      } else {
+        setBloomFilterVectorSize((java.lang.Integer)value);
+      }
+      break;
+
+    case BLOOM_FILTER_NB_HASHES:
+      if (value == null) {
+        unsetBloomFilterNbHashes();
+      } else {
+        setBloomFilterNbHashes((java.lang.Integer)value);
+      }
+      break;
+
+    case BLOCK_CACHE_ENABLED:
+      if (value == null) {
+        unsetBlockCacheEnabled();
+      } else {
+        setBlockCacheEnabled((java.lang.Boolean)value);
+      }
+      break;
+
+    case TIME_TO_LIVE:
+      if (value == null) {
+        unsetTimeToLive();
+      } else {
+        setTimeToLive((java.lang.Integer)value);
+      }
+      break;
+
+    }
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public java.lang.Object getFieldValue(_Fields field) {
+    switch (field) {
+    case NAME:
+      return getName();
+
+    case MAX_VERSIONS:
+      return getMaxVersions();
+
+    case COMPRESSION:
+      return getCompression();
+
+    case IN_MEMORY:
+      return isInMemory();
+
+    case BLOOM_FILTER_TYPE:
+      return getBloomFilterType();
+
+    case BLOOM_FILTER_VECTOR_SIZE:
+      return getBloomFilterVectorSize();
+
+    case BLOOM_FILTER_NB_HASHES:
+      return getBloomFilterNbHashes();
+
+    case BLOCK_CACHE_ENABLED:
+      return isBlockCacheEnabled();
+
+    case TIME_TO_LIVE:
+      return getTimeToLive();
+
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new java.lang.IllegalArgumentException();
+    }
+
+    switch (field) {
+    case NAME:
+      return isSetName();
+    case MAX_VERSIONS:
+      return isSetMaxVersions();
+    case COMPRESSION:
+      return isSetCompression();
+    case IN_MEMORY:
+      return isSetInMemory();
+    case BLOOM_FILTER_TYPE:
+      return isSetBloomFilterType();
+    case BLOOM_FILTER_VECTOR_SIZE:
+      return isSetBloomFilterVectorSize();
+    case BLOOM_FILTER_NB_HASHES:
+      return isSetBloomFilterNbHashes();
+    case BLOCK_CACHE_ENABLED:
+      return isSetBlockCacheEnabled();
+    case TIME_TO_LIVE:
+      return isSetTimeToLive();
+    }
+    throw new java.lang.IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(java.lang.Object that) {
+    if (that instanceof ColumnDescriptor)
+      return this.equals((ColumnDescriptor)that);
+    return false;
+  }
+
+  public boolean equals(ColumnDescriptor that) {
+    if (that == null)
+      return false;
+    if (this == that)
+      return true;
+
+    boolean this_present_name = true && this.isSetName();
+    boolean that_present_name = true && that.isSetName();
+    if (this_present_name || that_present_name) {
+      if (!(this_present_name && that_present_name))
+        return false;
+      if (!this.name.equals(that.name))
+        return false;
+    }
+
+    boolean this_present_maxVersions = true;
+    boolean that_present_maxVersions = true;
+    if (this_present_maxVersions || that_present_maxVersions) {
+      if (!(this_present_maxVersions && that_present_maxVersions))
+        return false;
+      if (this.maxVersions != that.maxVersions)
+        return false;
+    }
+
+    boolean this_present_compression = true && this.isSetCompression();
+    boolean that_present_compression = true && that.isSetCompression();
+    if (this_present_compression || that_present_compression) {
+      if (!(this_present_compression && that_present_compression))
+        return false;
+      if (!this.compression.equals(that.compression))
+        return false;
+    }
+
+    boolean this_present_inMemory = true;
+    boolean that_present_inMemory = true;
+    if (this_present_inMemory || that_present_inMemory) {
+      if (!(this_present_inMemory && that_present_inMemory))
+        return false;
+      if (this.inMemory != that.inMemory)
+        return false;
+    }
+
+    boolean this_present_bloomFilterType = true && this.isSetBloomFilterType();
+    boolean that_present_bloomFilterType = true && that.isSetBloomFilterType();
+    if (this_present_bloomFilterType || that_present_bloomFilterType) {
+      if (!(this_present_bloomFilterType && that_present_bloomFilterType))
+        return false;
+      if (!this.bloomFilterType.equals(that.bloomFilterType))
+        return false;
+    }
+
+    boolean this_present_bloomFilterVectorSize = true;
+    boolean that_present_bloomFilterVectorSize = true;
+    if (this_present_bloomFilterVectorSize || that_present_bloomFilterVectorSize) {
+      if (!(this_present_bloomFilterVectorSize && that_present_bloomFilterVectorSize))
+        return false;
+      if (this.bloomFilterVectorSize != that.bloomFilterVectorSize)
+        return false;
+    }
+
+    boolean this_present_bloomFilterNbHashes = true;
+    boolean that_present_bloomFilterNbHashes = true;
+    if (this_present_bloomFilterNbHashes || that_present_bloomFilterNbHashes) {
+      if (!(this_present_bloomFilterNbHashes && that_present_bloomFilterNbHashes))
+        return false;
+      if (this.bloomFilterNbHashes != that.bloomFilterNbHashes)
+        return false;
+    }
+
+    boolean this_present_blockCacheEnabled = true;
+    boolean that_present_blockCacheEnabled = true;
+    if (this_present_blockCacheEnabled || that_present_blockCacheEnabled) {
+      if (!(this_present_blockCacheEnabled && that_present_blockCacheEnabled))
+        return false;
+      if (this.blockCacheEnabled != that.blockCacheEnabled)
+        return false;
+    }
+
+    boolean this_present_timeToLive = true;
+    boolean that_present_timeToLive = true;
+    if (this_present_timeToLive || that_present_timeToLive) {
+      if (!(this_present_timeToLive && that_present_timeToLive))
+        return false;
+      if (this.timeToLive != that.timeToLive)
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int hashCode = 1;
+
+    hashCode = hashCode * 8191 + ((isSetName()) ? 131071 : 524287);
+    if (isSetName())
+      hashCode = hashCode * 8191 + name.hashCode();
+
+    hashCode = hashCode * 8191 + maxVersions;
+
+    hashCode = hashCode * 8191 + ((isSetCompression()) ? 131071 : 524287);
+    if (isSetCompression())
+      hashCode = hashCode * 8191 + compression.hashCode();
+
+    hashCode = hashCode * 8191 + ((inMemory) ? 131071 : 524287);
+
+    hashCode = hashCode * 8191 + ((isSetBloomFilterType()) ? 131071 : 524287);
+    if (isSetBloomFilterType())
+      hashCode = hashCode * 8191 + bloomFilterType.hashCode();
+
+    hashCode = hashCode * 8191 + bloomFilterVectorSize;
+
+    hashCode = hashCode * 8191 + bloomFilterNbHashes;
+
+    hashCode = hashCode * 8191 + ((blockCacheEnabled) ? 131071 : 524287);
+
+    hashCode = hashCode * 8191 + timeToLive;
+
+    return hashCode;
+  }
+
+  @Override
+  public int compareTo(ColumnDescriptor other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+
+    lastComparison = java.lang.Boolean.compare(isSetName(), other.isSetName());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetName()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.name, other.name);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetMaxVersions(), other.isSetMaxVersions());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMaxVersions()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.maxVersions, other.maxVersions);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetCompression(), other.isSetCompression());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetCompression()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.compression, other.compression);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetInMemory(), other.isSetInMemory());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetInMemory()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.inMemory, other.inMemory);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetBloomFilterType(), other.isSetBloomFilterType());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetBloomFilterType()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.bloomFilterType, other.bloomFilterType);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetBloomFilterVectorSize(), other.isSetBloomFilterVectorSize());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetBloomFilterVectorSize()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.bloomFilterVectorSize, other.bloomFilterVectorSize);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetBloomFilterNbHashes(), other.isSetBloomFilterNbHashes());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetBloomFilterNbHashes()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.bloomFilterNbHashes, other.bloomFilterNbHashes);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetBlockCacheEnabled(), other.isSetBlockCacheEnabled());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetBlockCacheEnabled()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.blockCacheEnabled, other.blockCacheEnabled);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    lastComparison = java.lang.Boolean.compare(isSetTimeToLive(), other.isSetTimeToLive());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetTimeToLive()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.timeToLive, other.timeToLive);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  @org.apache.thrift.annotation.Nullable
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
+    scheme(iprot).read(iprot, this);
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
+    scheme(oprot).write(oprot, this);
+  }
+
+  @Override
+  public java.lang.String toString() {
+    java.lang.StringBuilder sb = new java.lang.StringBuilder("ColumnDescriptor(");
+    boolean first = true;
+
+    sb.append("name:");
+    if (this.name == null) {
+      sb.append("null");
+    } else {
+      org.apache.thrift.TBaseHelper.toString(this.name, sb);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("maxVersions:");
+    sb.append(this.maxVersions);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("compression:");
+    if (this.compression == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.compression);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("inMemory:");
+    sb.append(this.inMemory);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("bloomFilterType:");
+    if (this.bloomFilterType == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.bloomFilterType);
+    }
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("bloomFilterVectorSize:");
+    sb.append(this.bloomFilterVectorSize);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("bloomFilterNbHashes:");
+    sb.append(this.bloomFilterNbHashes);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("blockCacheEnabled:");
+    sb.append(this.blockCacheEnabled);
+    first = false;
+    if (!first) sb.append(", ");
+    sb.append("timeToLive:");
+    sb.append(this.timeToLive);
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+    // check for sub-struct validity
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException {
+    try {
+      // it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.
+      __isset_bitfield = 0;
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private static class ColumnDescriptorStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public ColumnDescriptorStandardScheme getScheme() {
+      return new ColumnDescriptorStandardScheme();
+    }
+  }
+
+  private static class ColumnDescriptorStandardScheme extends org.apache.thrift.scheme.StandardScheme<ColumnDescriptor> {
+
+    public void read(org.apache.thrift.protocol.TProtocol iprot, ColumnDescriptor struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TField schemeField;
+      iprot.readStructBegin();
+      while (true)
+      {
+        schemeField = iprot.readFieldBegin();
+        if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { 
+          break;
+        }
+        switch (schemeField.id) {
+          case 1: // NAME
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.name = iprot.readBinary();
+              struct.setNameIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 2: // MAX_VERSIONS
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.maxVersions = iprot.readI32();
+              struct.setMaxVersionsIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 3: // COMPRESSION
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.compression = iprot.readString();
+              struct.setCompressionIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 4: // IN_MEMORY
+            if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) {
+              struct.inMemory = iprot.readBool();
+              struct.setInMemoryIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 5: // BLOOM_FILTER_TYPE
+            if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+              struct.bloomFilterType = iprot.readString();
+              struct.setBloomFilterTypeIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 6: // BLOOM_FILTER_VECTOR_SIZE
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.bloomFilterVectorSize = iprot.readI32();
+              struct.setBloomFilterVectorSizeIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 7: // BLOOM_FILTER_NB_HASHES
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.bloomFilterNbHashes = iprot.readI32();
+              struct.setBloomFilterNbHashesIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 8: // BLOCK_CACHE_ENABLED
+            if (schemeField.type == org.apache.thrift.protocol.TType.BOOL) {
+              struct.blockCacheEnabled = iprot.readBool();
+              struct.setBlockCacheEnabledIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          case 9: // TIME_TO_LIVE
+            if (schemeField.type == org.apache.thrift.protocol.TType.I32) {
+              struct.timeToLive = iprot.readI32();
+              struct.setTimeToLiveIsSet(true);
+            } else { 
+              org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+            }
+            break;
+          default:
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+        }
+        iprot.readFieldEnd();
+      }
+      iprot.readStructEnd();
+
+      // check for required fields of primitive type, which can't be checked in the validate method
+      struct.validate();
+    }
+
+    public void write(org.apache.thrift.protocol.TProtocol oprot, ColumnDescriptor struct) throws org.apache.thrift.TException {
+      struct.validate();
+
+      oprot.writeStructBegin(STRUCT_DESC);
+      if (struct.name != null) {
+        oprot.writeFieldBegin(NAME_FIELD_DESC);
+        oprot.writeBinary(struct.name);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldBegin(MAX_VERSIONS_FIELD_DESC);
+      oprot.writeI32(struct.maxVersions);
+      oprot.writeFieldEnd();
+      if (struct.compression != null) {
+        oprot.writeFieldBegin(COMPRESSION_FIELD_DESC);
+        oprot.writeString(struct.compression);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldBegin(IN_MEMORY_FIELD_DESC);
+      oprot.writeBool(struct.inMemory);
+      oprot.writeFieldEnd();
+      if (struct.bloomFilterType != null) {
+        oprot.writeFieldBegin(BLOOM_FILTER_TYPE_FIELD_DESC);
+        oprot.writeString(struct.bloomFilterType);
+        oprot.writeFieldEnd();
+      }
+      oprot.writeFieldBegin(BLOOM_FILTER_VECTOR_SIZE_FIELD_DESC);
+      oprot.writeI32(struct.bloomFilterVectorSize);
+      oprot.writeFieldEnd();
+      oprot.writeFieldBegin(BLOOM_FILTER_NB_HASHES_FIELD_DESC);
+      oprot.writeI32(struct.bloomFilterNbHashes);
+      oprot.writeFieldEnd();
+      oprot.writeFieldBegin(BLOCK_CACHE_ENABLED_FIELD_DESC);
+      oprot.writeBool(struct.blockCacheEnabled);
+      oprot.writeFieldEnd();
+      oprot.writeFieldBegin(TIME_TO_LIVE_FIELD_DESC);
+      oprot.writeI32(struct.timeToLive);
+      oprot.writeFieldEnd();
+      oprot.writeFieldStop();
+      oprot.writeStructEnd();
+    }
+
+  }
+
+  private static class ColumnDescriptorTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory {
+    public ColumnDescriptorTupleScheme getScheme() {
+      return new ColumnDescriptorTupleScheme();
+    }
+  }
+
+  private static class ColumnDescriptorTupleScheme extends org.apache.thrift.scheme.TupleScheme<ColumnDescriptor> {
+
+    @Override
+    public void write(org.apache.thrift.protocol.TProtocol prot, ColumnDescriptor struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet optionals = new java.util.BitSet();
+      if (struct.isSetName()) {
+        optionals.set(0);
+      }
+      if (struct.isSetMaxVersions()) {
+        optionals.set(1);
+      }
+      if (struct.isSetCompression()) {
+        optionals.set(2);
+      }
+      if (struct.isSetInMemory()) {
+        optionals.set(3);
+      }
+      if (struct.isSetBloomFilterType()) {
+        optionals.set(4);
+      }
+      if (struct.isSetBloomFilterVectorSize()) {
+        optionals.set(5);
+      }
+      if (struct.isSetBloomFilterNbHashes()) {
+        optionals.set(6);
+      }
+      if (struct.isSetBlockCacheEnabled()) {
+        optionals.set(7);
+      }
+      if (struct.isSetTimeToLive()) {
+        optionals.set(8);
+      }
+      oprot.writeBitSet(optionals, 9);
+      if (struct.isSetName()) {
+        oprot.writeBinary(struct.name);
+      }
+      if (struct.isSetMaxVersions()) {
+        oprot.writeI32(struct.maxVersions);
+      }
+      if (struct.isSetCompression()) {
+        oprot.writeString(struct.compression);
+      }
+      if (struct.isSetInMemory()) {
+        oprot.writeBool(struct.inMemory);
+      }
+      if (struct.isSetBloomFilterType()) {
+        oprot.writeString(struct.bloomFilterType);
+      }
+      if (struct.isSetBloomFilterVectorSize()) {
+        oprot.writeI32(struct.bloomFilterVectorSize);
+      }
+      if (struct.isSetBloomFilterNbHashes()) {
+        oprot.writeI32(struct.bloomFilterNbHashes);
+      }
+      if (struct.isSetBlockCacheEnabled()) {
+        oprot.writeBool(struct.blockCacheEnabled);
+      }
+      if (struct.isSetTimeToLive()) {
+        oprot.writeI32(struct.timeToLive);
+      }
+    }
+
+    @Override
+    public void read(org.apache.thrift.protocol.TProtocol prot, ColumnDescriptor struct) throws org.apache.thrift.TException {
+      org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot;
+      java.util.BitSet incoming = iprot.readBitSet(9);
+      if (incoming.get(0)) {
+        struct.name = iprot.readBinary();
+        struct.setNameIsSet(true);
+      }
+      if (incoming.get(1)) {
+        struct.maxVersions = iprot.readI32();
+        struct.setMaxVersionsIsSet(true);
+      }
+      if (incoming.get(2)) {
+        struct.compression = iprot.readString();
+        struct.setCompressionIsSet(true);
+      }
+      if (incoming.get(3)) {
+        struct.inMemory = iprot.readBool();
+        struct.setInMemoryIsSet(true);
+      }
+      if (incoming.get(4)) {
+        struct.bloomFilterType = iprot.readString();
+        struct.setBloomFilterTypeIsSet(true);
+      }
+      if (incoming.get(5)) {
+        struct.bloomFilterVectorSize = iprot.readI32();
+        struct.setBloomFilterVectorSizeIsSet(true);
+      }
+      if (incoming.get(6)) {
+        struct.bloomFilterNbHashes = iprot.readI32();
+        struct.setBloomFilterNbHashesIsSet(true);
+      }
+      if (incoming.get(7)) {
+        struct.blockCacheEnabled = iprot.readBool();
+        struct.setBlockCacheEnabledIsSet(true);
+      }
+      if (incoming.get(8)) {
+        struct.timeToLive = iprot.readI32();
+        struct.setTimeToLiveIsSet(true);
+      }
+    }
+  }
+
+  private static <S extends org.apache.thrift.scheme.IScheme> S scheme(org.apache.thrift.protocol.TProtocol proto) {
+    return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme();
+  }
+}
+
diff --git a/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/Hbase.java b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/Hbase.java
new file mode 100644
index 0000000..43bc7fb
--- /dev/null
+++ b/hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/generated/Hbase.java
@@ -0,0 +1,64110 @@
+/**
+ * Autogenerated by Thrift Compiler (0.14.1)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ *  @generated
+ */
+package org.apache.hadoop.hbase.thrift.generated;
+
+@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
+@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.14.1)", date = "2021-10-05")
+public class Hbase {
+
+  public interface Iface {
+
+    /**
+     * Brings a table on-line (enables it)
+     * 
+     * @param tableName name of the table
+     */
+    public void enableTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Disables a table (takes it off-line) If it is being served, the master
+     * will tell the servers to stop serving it.
+     * 
+     * @param tableName name of the table
+     */
+    public void disableTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * @return true if table is on-line
+     * 
+     * @param tableName name of the table to check
+     */
+    public boolean isTableEnabled(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    public void compact(java.nio.ByteBuffer tableNameOrRegionName) throws IOError, org.apache.thrift.TException;
+
+    public void majorCompact(java.nio.ByteBuffer tableNameOrRegionName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * List all the userspace tables.
+     * 
+     * @return returns a list of names
+     */
+    public java.util.List<java.nio.ByteBuffer> getTableNames() throws IOError, org.apache.thrift.TException;
+
+    /**
+     * List all the userspace tables and their enabled or disabled flags.
+     * 
+     * @return list of tables with is enabled flags
+     */
+    public java.util.Map<java.nio.ByteBuffer,java.lang.Boolean> getTableNamesWithIsTableEnabled() throws IOError, org.apache.thrift.TException;
+
+    /**
+     * List all the column families assoicated with a table.
+     * 
+     * @return list of column family descriptors
+     * 
+     * @param tableName table name
+     */
+    public java.util.Map<java.nio.ByteBuffer,ColumnDescriptor> getColumnDescriptors(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * List the regions associated with a table.
+     * 
+     * @return list of region descriptors
+     * 
+     * @param tableName table name
+     */
+    public java.util.List<TRegionInfo> getTableRegions(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Create a table with the specified column families.  The name
+     * field for each ColumnDescriptor must be set and must end in a
+     * colon (:). All other fields are optional and will get default
+     * values if not explicitly specified.
+     * 
+     * @throws IllegalArgument if an input parameter is invalid
+     * 
+     * @throws AlreadyExists if the table name already exists
+     * 
+     * @param tableName name of table to create
+     * 
+     * @param columnFamilies list of column family descriptors
+     */
+    public void createTable(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies) throws IOError, IllegalArgument, AlreadyExists, org.apache.thrift.TException;
+
+    /**
+     * Deletes a table
+     * 
+     * @throws IOError if table doesn't exist on server or there was some other
+     * problem
+     * 
+     * @param tableName name of table to delete
+     */
+    public void deleteTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a single TCell for the specified table, row, and column at the
+     * latest timestamp. Returns an empty list if no such value exists.
+     * 
+     * @return value for specified row/column
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param column column name
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TCell> get(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified number of versions for the specified table,
+     * row, and column.
+     * 
+     * @return list of cells for specified row/column
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param column column name
+     * 
+     * @param numVersions number of versions to retrieve
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TCell> getVer(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified number of versions for the specified table,
+     * row, and column.  Only versions less than or equal to the specified
+     * timestamp will be returned.
+     * 
+     * @return list of cells for specified row/column
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param column column name
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param numVersions number of versions to retrieve
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TCell> getVerTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get all the data for the specified table and row at the latest
+     * timestamp. Returns an empty list if the row does not exist.
+     * 
+     * @return TRowResult containing the row and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified columns for the specified table and row at the latest
+     * timestamp. Returns an empty list if the row does not exist.
+     * 
+     * @return TRowResult containing the row and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param columns List of columns to return, null for all columns
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowWithColumns(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get all the data for the specified table and row at the specified
+     * timestamp. Returns an empty list if the row does not exist.
+     * 
+     * @return TRowResult containing the row and map of columns to TCells
+     * 
+     * @param tableName name of the table
+     * 
+     * @param row row key
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified columns for the specified table and row at the specified
+     * timestamp. Returns an empty list if the row does not exist.
+     * 
+     * @return TRowResult containing the row and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param columns List of columns to return, null for all columns
+     * 
+     * @param timestamp
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowWithColumnsTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get all the data for the specified table and rows at the latest
+     * timestamp. Returns an empty list if no rows exist.
+     * 
+     * @return TRowResult containing the rows and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param rows row keys
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRows(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified columns for the specified table and rows at the latest
+     * timestamp. Returns an empty list if no rows exist.
+     * 
+     * @return TRowResult containing the rows and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param rows row keys
+     * 
+     * @param columns List of columns to return, null for all columns
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowsWithColumns(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get all the data for the specified table and rows at the specified
+     * timestamp. Returns an empty list if no rows exist.
+     * 
+     * @return TRowResult containing the rows and map of columns to TCells
+     * 
+     * @param tableName name of the table
+     * 
+     * @param rows row keys
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get the specified columns for the specified table and rows at the specified
+     * timestamp. Returns an empty list if no rows exist.
+     * 
+     * @return TRowResult containing the rows and map of columns to TCells
+     * 
+     * @param tableName name of table
+     * 
+     * @param rows row keys
+     * 
+     * @param columns List of columns to return, null for all columns
+     * 
+     * @param timestamp
+     * @param attributes Get attributes
+     */
+    public java.util.List<TRowResult> getRowsWithColumnsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Apply a series of mutations (updates/deletes) to a row in a
+     * single transaction.  If an exception is thrown, then the
+     * transaction is aborted.  Default current timestamp is used, and
+     * all entries will have an identical timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param mutations list of mutation commands
+     * 
+     * @param attributes Mutation attributes
+     */
+    public void mutateRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Apply a series of mutations (updates/deletes) to a row in a
+     * single transaction.  If an exception is thrown, then the
+     * transaction is aborted.  The specified timestamp is used, and
+     * all entries will have an identical timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param mutations list of mutation commands
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Mutation attributes
+     */
+    public void mutateRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Apply a series of batches (each a series of mutations on a single row)
+     * in a single transaction.  If an exception is thrown, then the
+     * transaction is aborted.  Default current timestamp is used, and
+     * all entries will have an identical timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param rowBatches list of row batches
+     * 
+     * @param attributes Mutation attributes
+     */
+    public void mutateRows(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Apply a series of batches (each a series of mutations on a single row)
+     * in a single transaction.  If an exception is thrown, then the
+     * transaction is aborted.  The specified timestamp is used, and
+     * all entries will have an identical timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param rowBatches list of row batches
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Mutation attributes
+     */
+    public void mutateRowsTs(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Atomically increment the column value specified.  Returns the next value post increment.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row to increment
+     * 
+     * @param column name of column
+     * 
+     * @param value amount to increment by
+     */
+    public long atomicIncrement(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long value) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Delete all cells that match the passed row and column.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row Row to update
+     * 
+     * @param column name of column whose value is to be deleted
+     * 
+     * @param attributes Delete attributes
+     */
+    public void deleteAll(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Delete all cells that match the passed row and column and whose
+     * timestamp is equal-to or older than the passed timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row Row to update
+     * 
+     * @param column name of column whose value is to be deleted
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Delete attributes
+     */
+    public void deleteAllTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Completely delete the row's cells.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row key of the row to be completely deleted.
+     * 
+     * @param attributes Delete attributes
+     */
+    public void deleteAllRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Increment a cell by the ammount.
+     * Increments can be applied async if hbase.regionserver.thrift.coalesceIncrement is set to true.
+     * False is the default.  Turn to true if you need the extra performance and can accept some
+     * data loss if a thrift server dies with increments still in the queue.
+     * 
+     * @param increment The single increment to apply
+     */
+    public void increment(TIncrement increment) throws IOError, org.apache.thrift.TException;
+
+    public void incrementRows(java.util.List<TIncrement> increments) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Completely delete the row's cells marked with a timestamp
+     * equal-to or older than the passed timestamp.
+     * 
+     * @param tableName name of table
+     * 
+     * @param row key of the row to be completely deleted.
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Delete attributes
+     */
+    public void deleteAllRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a scanner on the current table, using the Scan instance
+     * for the scan parameters.
+     * 
+     * @param tableName name of table
+     * 
+     * @param scan Scan instance
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpenWithScan(java.nio.ByteBuffer tableName, TScan scan, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a scanner on the current table starting at the specified row and
+     * ending at the last row in the table.  Return the specified columns.
+     * 
+     * @return scanner id to be used with other scanner procedures
+     * 
+     * @param tableName name of table
+     * 
+     * @param startRow Starting row in table to scan.
+     * Send "" (empty string) to start at the first row.
+     * 
+     * @param columns columns to scan. If column name is a column family, all
+     * columns of the specified column family are returned. It's also possible
+     * to pass a regex in the column qualifier.
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpen(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a scanner on the current table starting and stopping at the
+     * specified rows.  ending at the last row in the table.  Return the
+     * specified columns.
+     * 
+     * @return scanner id to be used with other scanner procedures
+     * 
+     * @param tableName name of table
+     * 
+     * @param startRow Starting row in table to scan.
+     * Send "" (empty string) to start at the first row.
+     * 
+     * @param stopRow row to stop scanning on. This row is *not* included in the
+     * scanner's results
+     * 
+     * @param columns columns to scan. If column name is a column family, all
+     * columns of the specified column family are returned. It's also possible
+     * to pass a regex in the column qualifier.
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpenWithStop(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Open a scanner for a given prefix.  That is all rows will have the specified
+     * prefix. No other rows will be returned.
+     * 
+     * @return scanner id to use with other scanner calls
+     * 
+     * @param tableName name of table
+     * 
+     * @param startAndPrefix the prefix (and thus start row) of the keys you want
+     * 
+     * @param columns the columns you want returned
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpenWithPrefix(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startAndPrefix, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a scanner on the current table starting at the specified row and
+     * ending at the last row in the table.  Return the specified columns.
+     * Only values with the specified timestamp are returned.
+     * 
+     * @return scanner id to be used with other scanner procedures
+     * 
+     * @param tableName name of table
+     * 
+     * @param startRow Starting row in table to scan.
+     * Send "" (empty string) to start at the first row.
+     * 
+     * @param columns columns to scan. If column name is a column family, all
+     * columns of the specified column family are returned. It's also possible
+     * to pass a regex in the column qualifier.
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpenTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Get a scanner on the current table starting and stopping at the
+     * specified rows.  ending at the last row in the table.  Return the
+     * specified columns.  Only values with the specified timestamp are
+     * returned.
+     * 
+     * @return scanner id to be used with other scanner procedures
+     * 
+     * @param tableName name of table
+     * 
+     * @param startRow Starting row in table to scan.
+     * Send "" (empty string) to start at the first row.
+     * 
+     * @param stopRow row to stop scanning on. This row is *not* included in the
+     * scanner's results
+     * 
+     * @param columns columns to scan. If column name is a column family, all
+     * columns of the specified column family are returned. It's also possible
+     * to pass a regex in the column qualifier.
+     * 
+     * @param timestamp timestamp
+     * 
+     * @param attributes Scan attributes
+     */
+    public int scannerOpenWithStopTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Returns the scanner's current row value and advances to the next
+     * row in the table.  When there are no more rows in the table, or a key
+     * greater-than-or-equal-to the scanner's specified stopRow is reached,
+     * an empty list is returned.
+     * 
+     * @return a TRowResult containing the current row and a map of the columns to TCells.
+     * 
+     * @throws IllegalArgument if ScannerID is invalid
+     * 
+     * @throws NotFound when the scanner reaches the end
+     * 
+     * @param id id of a scanner returned by scannerOpen
+     */
+    public java.util.List<TRowResult> scannerGet(int id) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Returns, starting at the scanner's current row value nbRows worth of
+     * rows and advances to the next row in the table.  When there are no more
+     * rows in the table, or a key greater-than-or-equal-to the scanner's
+     * specified stopRow is reached,  an empty list is returned.
+     * 
+     * @return a TRowResult containing the current row and a map of the columns to TCells.
+     * 
+     * @throws IllegalArgument if ScannerID is invalid
+     * 
+     * @throws NotFound when the scanner reaches the end
+     * 
+     * @param id id of a scanner returned by scannerOpen
+     * 
+     * @param nbRows number of results to return
+     */
+    public java.util.List<TRowResult> scannerGetList(int id, int nbRows) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Closes the server-state associated with an open scanner.
+     * 
+     * @throws IllegalArgument if ScannerID is invalid
+     * 
+     * @param id id of a scanner returned by scannerOpen
+     */
+    public void scannerClose(int id) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Get the regininfo for the specified row. It scans
+     * the metatable to find region's start and end keys.
+     * 
+     * @return value for specified row/column
+     * 
+     * @param row row key
+     */
+    public TRegionInfo getRegionInfo(java.nio.ByteBuffer row) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Appends values to one or more columns within a single row.
+     * 
+     * @return values of columns after the append operation.
+     * 
+     * @param append The single append operation to apply
+     */
+    public java.util.List<TCell> append(TAppend append) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Atomically checks if a row/family/qualifier value matches the expected
+     * value. If it does, it adds the corresponding mutation operation for put.
+     * 
+     * @return true if the new put was executed, false otherwise
+     * 
+     * @param tableName name of table
+     * 
+     * @param row row key
+     * 
+     * @param column column name
+     * 
+     * @param value the expected value for the column parameter, if not
+     * provided the check is for the non-existence of the
+     * column in question
+     * 
+     * @param mput mutation for the put
+     * 
+     * @param attributes Mutation attributes
+     */
+    public boolean checkAndPut(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.nio.ByteBuffer value, Mutation mput, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException;
+
+    /**
+     * Get the type of this thrift server.
+     * 
+     * @return the type of this thrift server
+     */
+    public TThriftServerType getThriftServerType() throws org.apache.thrift.TException;
+
+    /**
+     * Returns the cluster ID for this cluster.
+     */
+    public java.lang.String getClusterId() throws org.apache.thrift.TException;
+
+    /**
+     * Grant permissions in namespace or table level.
+     * 
+     * @param info
+     */
+    public boolean grant(TAccessControlEntity info) throws IOError, org.apache.thrift.TException;
+
+    /**
+     * Revoke permissions in namespace or table level.
+     * 
+     * @param info
+     */
+    public boolean revoke(TAccessControlEntity info) throws IOError, org.apache.thrift.TException;
+
+  }
+
+  public interface AsyncIface {
+
+    public void enableTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void disableTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void isTableEnabled(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException;
+
+    public void compact(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void majorCompact(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void getTableNames(org.apache.thrift.async.AsyncMethodCallback<java.util.List<java.nio.ByteBuffer>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getTableNamesWithIsTableEnabled(org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,java.lang.Boolean>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getColumnDescriptors(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,ColumnDescriptor>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getTableRegions(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRegionInfo>> resultHandler) throws org.apache.thrift.TException;
+
+    public void createTable(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void deleteTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void get(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getVer(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getVerTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowWithColumns(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowWithColumnsTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRows(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowsWithColumns(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRowsWithColumnsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void mutateRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void mutateRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void mutateRows(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void mutateRowsTs(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void atomicIncrement(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long value, org.apache.thrift.async.AsyncMethodCallback<java.lang.Long> resultHandler) throws org.apache.thrift.TException;
+
+    public void deleteAll(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void deleteAllTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void deleteAllRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void increment(TIncrement increment, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void incrementRows(java.util.List<TIncrement> increments, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void deleteAllRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpenWithScan(java.nio.ByteBuffer tableName, TScan scan, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpen(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpenWithStop(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpenWithPrefix(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startAndPrefix, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpenTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerOpenWithStopTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Integer> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerGet(int id, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerGetList(int id, int nbRows, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException;
+
+    public void scannerClose(int id, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
+
+    public void getRegionInfo(java.nio.ByteBuffer row, org.apache.thrift.async.AsyncMethodCallback<TRegionInfo> resultHandler) throws org.apache.thrift.TException;
+
+    public void append(TAppend append, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException;
+
+    public void checkAndPut(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.nio.ByteBuffer value, Mutation mput, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException;
+
+    public void getThriftServerType(org.apache.thrift.async.AsyncMethodCallback<TThriftServerType> resultHandler) throws org.apache.thrift.TException;
+
+    public void getClusterId(org.apache.thrift.async.AsyncMethodCallback<java.lang.String> resultHandler) throws org.apache.thrift.TException;
+
+    public void grant(TAccessControlEntity info, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException;
+
+    public void revoke(TAccessControlEntity info, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException;
+
+  }
+
+  public static class Client extends org.apache.thrift.TServiceClient implements Iface {
+    public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
+      public Factory() {}
+      public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
+        return new Client(prot);
+      }
+      public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
+        return new Client(iprot, oprot);
+      }
+    }
+
+    public Client(org.apache.thrift.protocol.TProtocol prot)
+    {
+      super(prot, prot);
+    }
+
+    public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
+      super(iprot, oprot);
+    }
+
+    public void enableTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_enableTable(tableName);
+      recv_enableTable();
+    }
+
+    public void send_enableTable(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      enableTable_args args = new enableTable_args();
+      args.setTableName(tableName);
+      sendBase("enableTable", args);
+    }
+
+    public void recv_enableTable() throws IOError, org.apache.thrift.TException
+    {
+      enableTable_result result = new enableTable_result();
+      receiveBase(result, "enableTable");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void disableTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_disableTable(tableName);
+      recv_disableTable();
+    }
+
+    public void send_disableTable(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      disableTable_args args = new disableTable_args();
+      args.setTableName(tableName);
+      sendBase("disableTable", args);
+    }
+
+    public void recv_disableTable() throws IOError, org.apache.thrift.TException
+    {
+      disableTable_result result = new disableTable_result();
+      receiveBase(result, "disableTable");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public boolean isTableEnabled(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_isTableEnabled(tableName);
+      return recv_isTableEnabled();
+    }
+
+    public void send_isTableEnabled(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      isTableEnabled_args args = new isTableEnabled_args();
+      args.setTableName(tableName);
+      sendBase("isTableEnabled", args);
+    }
+
+    public boolean recv_isTableEnabled() throws IOError, org.apache.thrift.TException
+    {
+      isTableEnabled_result result = new isTableEnabled_result();
+      receiveBase(result, "isTableEnabled");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "isTableEnabled failed: unknown result");
+    }
+
+    public void compact(java.nio.ByteBuffer tableNameOrRegionName) throws IOError, org.apache.thrift.TException
+    {
+      send_compact(tableNameOrRegionName);
+      recv_compact();
+    }
+
+    public void send_compact(java.nio.ByteBuffer tableNameOrRegionName) throws org.apache.thrift.TException
+    {
+      compact_args args = new compact_args();
+      args.setTableNameOrRegionName(tableNameOrRegionName);
+      sendBase("compact", args);
+    }
+
+    public void recv_compact() throws IOError, org.apache.thrift.TException
+    {
+      compact_result result = new compact_result();
+      receiveBase(result, "compact");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void majorCompact(java.nio.ByteBuffer tableNameOrRegionName) throws IOError, org.apache.thrift.TException
+    {
+      send_majorCompact(tableNameOrRegionName);
+      recv_majorCompact();
+    }
+
+    public void send_majorCompact(java.nio.ByteBuffer tableNameOrRegionName) throws org.apache.thrift.TException
+    {
+      majorCompact_args args = new majorCompact_args();
+      args.setTableNameOrRegionName(tableNameOrRegionName);
+      sendBase("majorCompact", args);
+    }
+
+    public void recv_majorCompact() throws IOError, org.apache.thrift.TException
+    {
+      majorCompact_result result = new majorCompact_result();
+      receiveBase(result, "majorCompact");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public java.util.List<java.nio.ByteBuffer> getTableNames() throws IOError, org.apache.thrift.TException
+    {
+      send_getTableNames();
+      return recv_getTableNames();
+    }
+
+    public void send_getTableNames() throws org.apache.thrift.TException
+    {
+      getTableNames_args args = new getTableNames_args();
+      sendBase("getTableNames", args);
+    }
+
+    public java.util.List<java.nio.ByteBuffer> recv_getTableNames() throws IOError, org.apache.thrift.TException
+    {
+      getTableNames_result result = new getTableNames_result();
+      receiveBase(result, "getTableNames");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getTableNames failed: unknown result");
+    }
+
+    public java.util.Map<java.nio.ByteBuffer,java.lang.Boolean> getTableNamesWithIsTableEnabled() throws IOError, org.apache.thrift.TException
+    {
+      send_getTableNamesWithIsTableEnabled();
+      return recv_getTableNamesWithIsTableEnabled();
+    }
+
+    public void send_getTableNamesWithIsTableEnabled() throws org.apache.thrift.TException
+    {
+      getTableNamesWithIsTableEnabled_args args = new getTableNamesWithIsTableEnabled_args();
+      sendBase("getTableNamesWithIsTableEnabled", args);
+    }
+
+    public java.util.Map<java.nio.ByteBuffer,java.lang.Boolean> recv_getTableNamesWithIsTableEnabled() throws IOError, org.apache.thrift.TException
+    {
+      getTableNamesWithIsTableEnabled_result result = new getTableNamesWithIsTableEnabled_result();
+      receiveBase(result, "getTableNamesWithIsTableEnabled");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getTableNamesWithIsTableEnabled failed: unknown result");
+    }
+
+    public java.util.Map<java.nio.ByteBuffer,ColumnDescriptor> getColumnDescriptors(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_getColumnDescriptors(tableName);
+      return recv_getColumnDescriptors();
+    }
+
+    public void send_getColumnDescriptors(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      getColumnDescriptors_args args = new getColumnDescriptors_args();
+      args.setTableName(tableName);
+      sendBase("getColumnDescriptors", args);
+    }
+
+    public java.util.Map<java.nio.ByteBuffer,ColumnDescriptor> recv_getColumnDescriptors() throws IOError, org.apache.thrift.TException
+    {
+      getColumnDescriptors_result result = new getColumnDescriptors_result();
+      receiveBase(result, "getColumnDescriptors");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getColumnDescriptors failed: unknown result");
+    }
+
+    public java.util.List<TRegionInfo> getTableRegions(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_getTableRegions(tableName);
+      return recv_getTableRegions();
+    }
+
+    public void send_getTableRegions(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      getTableRegions_args args = new getTableRegions_args();
+      args.setTableName(tableName);
+      sendBase("getTableRegions", args);
+    }
+
+    public java.util.List<TRegionInfo> recv_getTableRegions() throws IOError, org.apache.thrift.TException
+    {
+      getTableRegions_result result = new getTableRegions_result();
+      receiveBase(result, "getTableRegions");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getTableRegions failed: unknown result");
+    }
+
+    public void createTable(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies) throws IOError, IllegalArgument, AlreadyExists, org.apache.thrift.TException
+    {
+      send_createTable(tableName, columnFamilies);
+      recv_createTable();
+    }
+
+    public void send_createTable(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies) throws org.apache.thrift.TException
+    {
+      createTable_args args = new createTable_args();
+      args.setTableName(tableName);
+      args.setColumnFamilies(columnFamilies);
+      sendBase("createTable", args);
+    }
+
+    public void recv_createTable() throws IOError, IllegalArgument, AlreadyExists, org.apache.thrift.TException
+    {
+      createTable_result result = new createTable_result();
+      receiveBase(result, "createTable");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      if (result.exist != null) {
+        throw result.exist;
+      }
+      return;
+    }
+
+    public void deleteTable(java.nio.ByteBuffer tableName) throws IOError, org.apache.thrift.TException
+    {
+      send_deleteTable(tableName);
+      recv_deleteTable();
+    }
+
+    public void send_deleteTable(java.nio.ByteBuffer tableName) throws org.apache.thrift.TException
+    {
+      deleteTable_args args = new deleteTable_args();
+      args.setTableName(tableName);
+      sendBase("deleteTable", args);
+    }
+
+    public void recv_deleteTable() throws IOError, org.apache.thrift.TException
+    {
+      deleteTable_result result = new deleteTable_result();
+      receiveBase(result, "deleteTable");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public java.util.List<TCell> get(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_get(tableName, row, column, attributes);
+      return recv_get();
+    }
+
+    public void send_get(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      get_args args = new get_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setAttributes(attributes);
+      sendBase("get", args);
+    }
+
+    public java.util.List<TCell> recv_get() throws IOError, org.apache.thrift.TException
+    {
+      get_result result = new get_result();
+      receiveBase(result, "get");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "get failed: unknown result");
+    }
+
+    public java.util.List<TCell> getVer(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getVer(tableName, row, column, numVersions, attributes);
+      return recv_getVer();
+    }
+
+    public void send_getVer(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getVer_args args = new getVer_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setNumVersions(numVersions);
+      args.setAttributes(attributes);
+      sendBase("getVer", args);
+    }
+
+    public java.util.List<TCell> recv_getVer() throws IOError, org.apache.thrift.TException
+    {
+      getVer_result result = new getVer_result();
+      receiveBase(result, "getVer");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getVer failed: unknown result");
+    }
+
+    public java.util.List<TCell> getVerTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getVerTs(tableName, row, column, timestamp, numVersions, attributes);
+      return recv_getVerTs();
+    }
+
+    public void send_getVerTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getVerTs_args args = new getVerTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setTimestamp(timestamp);
+      args.setNumVersions(numVersions);
+      args.setAttributes(attributes);
+      sendBase("getVerTs", args);
+    }
+
+    public java.util.List<TCell> recv_getVerTs() throws IOError, org.apache.thrift.TException
+    {
+      getVerTs_result result = new getVerTs_result();
+      receiveBase(result, "getVerTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getVerTs failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRow(tableName, row, attributes);
+      return recv_getRow();
+    }
+
+    public void send_getRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRow_args args = new getRow_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setAttributes(attributes);
+      sendBase("getRow", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRow() throws IOError, org.apache.thrift.TException
+    {
+      getRow_result result = new getRow_result();
+      receiveBase(result, "getRow");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRow failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowWithColumns(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowWithColumns(tableName, row, columns, attributes);
+      return recv_getRowWithColumns();
+    }
+
+    public void send_getRowWithColumns(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowWithColumns_args args = new getRowWithColumns_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumns(columns);
+      args.setAttributes(attributes);
+      sendBase("getRowWithColumns", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowWithColumns() throws IOError, org.apache.thrift.TException
+    {
+      getRowWithColumns_result result = new getRowWithColumns_result();
+      receiveBase(result, "getRowWithColumns");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowWithColumns failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowTs(tableName, row, timestamp, attributes);
+      return recv_getRowTs();
+    }
+
+    public void send_getRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowTs_args args = new getRowTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("getRowTs", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowTs() throws IOError, org.apache.thrift.TException
+    {
+      getRowTs_result result = new getRowTs_result();
+      receiveBase(result, "getRowTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowTs failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowWithColumnsTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowWithColumnsTs(tableName, row, columns, timestamp, attributes);
+      return recv_getRowWithColumnsTs();
+    }
+
+    public void send_getRowWithColumnsTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowWithColumnsTs_args args = new getRowWithColumnsTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumns(columns);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("getRowWithColumnsTs", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowWithColumnsTs() throws IOError, org.apache.thrift.TException
+    {
+      getRowWithColumnsTs_result result = new getRowWithColumnsTs_result();
+      receiveBase(result, "getRowWithColumnsTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowWithColumnsTs failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRows(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRows(tableName, rows, attributes);
+      return recv_getRows();
+    }
+
+    public void send_getRows(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRows_args args = new getRows_args();
+      args.setTableName(tableName);
+      args.setRows(rows);
+      args.setAttributes(attributes);
+      sendBase("getRows", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRows() throws IOError, org.apache.thrift.TException
+    {
+      getRows_result result = new getRows_result();
+      receiveBase(result, "getRows");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRows failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowsWithColumns(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowsWithColumns(tableName, rows, columns, attributes);
+      return recv_getRowsWithColumns();
+    }
+
+    public void send_getRowsWithColumns(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowsWithColumns_args args = new getRowsWithColumns_args();
+      args.setTableName(tableName);
+      args.setRows(rows);
+      args.setColumns(columns);
+      args.setAttributes(attributes);
+      sendBase("getRowsWithColumns", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowsWithColumns() throws IOError, org.apache.thrift.TException
+    {
+      getRowsWithColumns_result result = new getRowsWithColumns_result();
+      receiveBase(result, "getRowsWithColumns");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowsWithColumns failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowsTs(tableName, rows, timestamp, attributes);
+      return recv_getRowsTs();
+    }
+
+    public void send_getRowsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowsTs_args args = new getRowsTs_args();
+      args.setTableName(tableName);
+      args.setRows(rows);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("getRowsTs", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowsTs() throws IOError, org.apache.thrift.TException
+    {
+      getRowsTs_result result = new getRowsTs_result();
+      receiveBase(result, "getRowsTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowsTs failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> getRowsWithColumnsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_getRowsWithColumnsTs(tableName, rows, columns, timestamp, attributes);
+      return recv_getRowsWithColumnsTs();
+    }
+
+    public void send_getRowsWithColumnsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      getRowsWithColumnsTs_args args = new getRowsWithColumnsTs_args();
+      args.setTableName(tableName);
+      args.setRows(rows);
+      args.setColumns(columns);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("getRowsWithColumnsTs", args);
+    }
+
+    public java.util.List<TRowResult> recv_getRowsWithColumnsTs() throws IOError, org.apache.thrift.TException
+    {
+      getRowsWithColumnsTs_result result = new getRowsWithColumnsTs_result();
+      receiveBase(result, "getRowsWithColumnsTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRowsWithColumnsTs failed: unknown result");
+    }
+
+    public void mutateRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_mutateRow(tableName, row, mutations, attributes);
+      recv_mutateRow();
+    }
+
+    public void send_mutateRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      mutateRow_args args = new mutateRow_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setMutations(mutations);
+      args.setAttributes(attributes);
+      sendBase("mutateRow", args);
+    }
+
+    public void recv_mutateRow() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      mutateRow_result result = new mutateRow_result();
+      receiveBase(result, "mutateRow");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      return;
+    }
+
+    public void mutateRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_mutateRowTs(tableName, row, mutations, timestamp, attributes);
+      recv_mutateRowTs();
+    }
+
+    public void send_mutateRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<Mutation> mutations, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      mutateRowTs_args args = new mutateRowTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setMutations(mutations);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("mutateRowTs", args);
+    }
+
+    public void recv_mutateRowTs() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      mutateRowTs_result result = new mutateRowTs_result();
+      receiveBase(result, "mutateRowTs");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      return;
+    }
+
+    public void mutateRows(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_mutateRows(tableName, rowBatches, attributes);
+      recv_mutateRows();
+    }
+
+    public void send_mutateRows(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      mutateRows_args args = new mutateRows_args();
+      args.setTableName(tableName);
+      args.setRowBatches(rowBatches);
+      args.setAttributes(attributes);
+      sendBase("mutateRows", args);
+    }
+
+    public void recv_mutateRows() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      mutateRows_result result = new mutateRows_result();
+      receiveBase(result, "mutateRows");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      return;
+    }
+
+    public void mutateRowsTs(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_mutateRowsTs(tableName, rowBatches, timestamp, attributes);
+      recv_mutateRowsTs();
+    }
+
+    public void send_mutateRowsTs(java.nio.ByteBuffer tableName, java.util.List<BatchMutation> rowBatches, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      mutateRowsTs_args args = new mutateRowsTs_args();
+      args.setTableName(tableName);
+      args.setRowBatches(rowBatches);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("mutateRowsTs", args);
+    }
+
+    public void recv_mutateRowsTs() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      mutateRowsTs_result result = new mutateRowsTs_result();
+      receiveBase(result, "mutateRowsTs");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      return;
+    }
+
+    public long atomicIncrement(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long value) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_atomicIncrement(tableName, row, column, value);
+      return recv_atomicIncrement();
+    }
+
+    public void send_atomicIncrement(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long value) throws org.apache.thrift.TException
+    {
+      atomicIncrement_args args = new atomicIncrement_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setValue(value);
+      sendBase("atomicIncrement", args);
+    }
+
+    public long recv_atomicIncrement() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      atomicIncrement_result result = new atomicIncrement_result();
+      receiveBase(result, "atomicIncrement");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "atomicIncrement failed: unknown result");
+    }
+
+    public void deleteAll(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_deleteAll(tableName, row, column, attributes);
+      recv_deleteAll();
+    }
+
+    public void send_deleteAll(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      deleteAll_args args = new deleteAll_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setAttributes(attributes);
+      sendBase("deleteAll", args);
+    }
+
+    public void recv_deleteAll() throws IOError, org.apache.thrift.TException
+    {
+      deleteAll_result result = new deleteAll_result();
+      receiveBase(result, "deleteAll");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void deleteAllTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_deleteAllTs(tableName, row, column, timestamp, attributes);
+      recv_deleteAllTs();
+    }
+
+    public void send_deleteAllTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      deleteAllTs_args args = new deleteAllTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("deleteAllTs", args);
+    }
+
+    public void recv_deleteAllTs() throws IOError, org.apache.thrift.TException
+    {
+      deleteAllTs_result result = new deleteAllTs_result();
+      receiveBase(result, "deleteAllTs");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void deleteAllRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_deleteAllRow(tableName, row, attributes);
+      recv_deleteAllRow();
+    }
+
+    public void send_deleteAllRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      deleteAllRow_args args = new deleteAllRow_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setAttributes(attributes);
+      sendBase("deleteAllRow", args);
+    }
+
+    public void recv_deleteAllRow() throws IOError, org.apache.thrift.TException
+    {
+      deleteAllRow_result result = new deleteAllRow_result();
+      receiveBase(result, "deleteAllRow");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void increment(TIncrement increment) throws IOError, org.apache.thrift.TException
+    {
+      send_increment(increment);
+      recv_increment();
+    }
+
+    public void send_increment(TIncrement increment) throws org.apache.thrift.TException
+    {
+      increment_args args = new increment_args();
+      args.setIncrement(increment);
+      sendBase("increment", args);
+    }
+
+    public void recv_increment() throws IOError, org.apache.thrift.TException
+    {
+      increment_result result = new increment_result();
+      receiveBase(result, "increment");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void incrementRows(java.util.List<TIncrement> increments) throws IOError, org.apache.thrift.TException
+    {
+      send_incrementRows(increments);
+      recv_incrementRows();
+    }
+
+    public void send_incrementRows(java.util.List<TIncrement> increments) throws org.apache.thrift.TException
+    {
+      incrementRows_args args = new incrementRows_args();
+      args.setIncrements(increments);
+      sendBase("incrementRows", args);
+    }
+
+    public void recv_incrementRows() throws IOError, org.apache.thrift.TException
+    {
+      incrementRows_result result = new incrementRows_result();
+      receiveBase(result, "incrementRows");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public void deleteAllRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_deleteAllRowTs(tableName, row, timestamp, attributes);
+      recv_deleteAllRowTs();
+    }
+
+    public void send_deleteAllRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      deleteAllRowTs_args args = new deleteAllRowTs_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("deleteAllRowTs", args);
+    }
+
+    public void recv_deleteAllRowTs() throws IOError, org.apache.thrift.TException
+    {
+      deleteAllRowTs_result result = new deleteAllRowTs_result();
+      receiveBase(result, "deleteAllRowTs");
+      if (result.io != null) {
+        throw result.io;
+      }
+      return;
+    }
+
+    public int scannerOpenWithScan(java.nio.ByteBuffer tableName, TScan scan, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpenWithScan(tableName, scan, attributes);
+      return recv_scannerOpenWithScan();
+    }
+
+    public void send_scannerOpenWithScan(java.nio.ByteBuffer tableName, TScan scan, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpenWithScan_args args = new scannerOpenWithScan_args();
+      args.setTableName(tableName);
+      args.setScan(scan);
+      args.setAttributes(attributes);
+      sendBase("scannerOpenWithScan", args);
+    }
+
+    public int recv_scannerOpenWithScan() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpenWithScan_result result = new scannerOpenWithScan_result();
+      receiveBase(result, "scannerOpenWithScan");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpenWithScan failed: unknown result");
+    }
+
+    public int scannerOpen(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpen(tableName, startRow, columns, attributes);
+      return recv_scannerOpen();
+    }
+
+    public void send_scannerOpen(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpen_args args = new scannerOpen_args();
+      args.setTableName(tableName);
+      args.setStartRow(startRow);
+      args.setColumns(columns);
+      args.setAttributes(attributes);
+      sendBase("scannerOpen", args);
+    }
+
+    public int recv_scannerOpen() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpen_result result = new scannerOpen_result();
+      receiveBase(result, "scannerOpen");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpen failed: unknown result");
+    }
+
+    public int scannerOpenWithStop(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpenWithStop(tableName, startRow, stopRow, columns, attributes);
+      return recv_scannerOpenWithStop();
+    }
+
+    public void send_scannerOpenWithStop(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpenWithStop_args args = new scannerOpenWithStop_args();
+      args.setTableName(tableName);
+      args.setStartRow(startRow);
+      args.setStopRow(stopRow);
+      args.setColumns(columns);
+      args.setAttributes(attributes);
+      sendBase("scannerOpenWithStop", args);
+    }
+
+    public int recv_scannerOpenWithStop() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpenWithStop_result result = new scannerOpenWithStop_result();
+      receiveBase(result, "scannerOpenWithStop");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpenWithStop failed: unknown result");
+    }
+
+    public int scannerOpenWithPrefix(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startAndPrefix, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpenWithPrefix(tableName, startAndPrefix, columns, attributes);
+      return recv_scannerOpenWithPrefix();
+    }
+
+    public void send_scannerOpenWithPrefix(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startAndPrefix, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpenWithPrefix_args args = new scannerOpenWithPrefix_args();
+      args.setTableName(tableName);
+      args.setStartAndPrefix(startAndPrefix);
+      args.setColumns(columns);
+      args.setAttributes(attributes);
+      sendBase("scannerOpenWithPrefix", args);
+    }
+
+    public int recv_scannerOpenWithPrefix() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpenWithPrefix_result result = new scannerOpenWithPrefix_result();
+      receiveBase(result, "scannerOpenWithPrefix");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpenWithPrefix failed: unknown result");
+    }
+
+    public int scannerOpenTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpenTs(tableName, startRow, columns, timestamp, attributes);
+      return recv_scannerOpenTs();
+    }
+
+    public void send_scannerOpenTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpenTs_args args = new scannerOpenTs_args();
+      args.setTableName(tableName);
+      args.setStartRow(startRow);
+      args.setColumns(columns);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("scannerOpenTs", args);
+    }
+
+    public int recv_scannerOpenTs() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpenTs_result result = new scannerOpenTs_result();
+      receiveBase(result, "scannerOpenTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpenTs failed: unknown result");
+    }
+
+    public int scannerOpenWithStopTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, org.apache.thrift.TException
+    {
+      send_scannerOpenWithStopTs(tableName, startRow, stopRow, columns, timestamp, attributes);
+      return recv_scannerOpenWithStopTs();
+    }
+
+    public void send_scannerOpenWithStopTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer startRow, java.nio.ByteBuffer stopRow, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      scannerOpenWithStopTs_args args = new scannerOpenWithStopTs_args();
+      args.setTableName(tableName);
+      args.setStartRow(startRow);
+      args.setStopRow(stopRow);
+      args.setColumns(columns);
+      args.setTimestamp(timestamp);
+      args.setAttributes(attributes);
+      sendBase("scannerOpenWithStopTs", args);
+    }
+
+    public int recv_scannerOpenWithStopTs() throws IOError, org.apache.thrift.TException
+    {
+      scannerOpenWithStopTs_result result = new scannerOpenWithStopTs_result();
+      receiveBase(result, "scannerOpenWithStopTs");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerOpenWithStopTs failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> scannerGet(int id) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_scannerGet(id);
+      return recv_scannerGet();
+    }
+
+    public void send_scannerGet(int id) throws org.apache.thrift.TException
+    {
+      scannerGet_args args = new scannerGet_args();
+      args.setId(id);
+      sendBase("scannerGet", args);
+    }
+
+    public java.util.List<TRowResult> recv_scannerGet() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      scannerGet_result result = new scannerGet_result();
+      receiveBase(result, "scannerGet");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerGet failed: unknown result");
+    }
+
+    public java.util.List<TRowResult> scannerGetList(int id, int nbRows) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_scannerGetList(id, nbRows);
+      return recv_scannerGetList();
+    }
+
+    public void send_scannerGetList(int id, int nbRows) throws org.apache.thrift.TException
+    {
+      scannerGetList_args args = new scannerGetList_args();
+      args.setId(id);
+      args.setNbRows(nbRows);
+      sendBase("scannerGetList", args);
+    }
+
+    public java.util.List<TRowResult> recv_scannerGetList() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      scannerGetList_result result = new scannerGetList_result();
+      receiveBase(result, "scannerGetList");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "scannerGetList failed: unknown result");
+    }
+
+    public void scannerClose(int id) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_scannerClose(id);
+      recv_scannerClose();
+    }
+
+    public void send_scannerClose(int id) throws org.apache.thrift.TException
+    {
+      scannerClose_args args = new scannerClose_args();
+      args.setId(id);
+      sendBase("scannerClose", args);
+    }
+
+    public void recv_scannerClose() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      scannerClose_result result = new scannerClose_result();
+      receiveBase(result, "scannerClose");
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      return;
+    }
+
+    public TRegionInfo getRegionInfo(java.nio.ByteBuffer row) throws IOError, org.apache.thrift.TException
+    {
+      send_getRegionInfo(row);
+      return recv_getRegionInfo();
+    }
+
+    public void send_getRegionInfo(java.nio.ByteBuffer row) throws org.apache.thrift.TException
+    {
+      getRegionInfo_args args = new getRegionInfo_args();
+      args.setRow(row);
+      sendBase("getRegionInfo", args);
+    }
+
+    public TRegionInfo recv_getRegionInfo() throws IOError, org.apache.thrift.TException
+    {
+      getRegionInfo_result result = new getRegionInfo_result();
+      receiveBase(result, "getRegionInfo");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getRegionInfo failed: unknown result");
+    }
+
+    public java.util.List<TCell> append(TAppend append) throws IOError, org.apache.thrift.TException
+    {
+      send_append(append);
+      return recv_append();
+    }
+
+    public void send_append(TAppend append) throws org.apache.thrift.TException
+    {
+      append_args args = new append_args();
+      args.setAppend(append);
+      sendBase("append", args);
+    }
+
+    public java.util.List<TCell> recv_append() throws IOError, org.apache.thrift.TException
+    {
+      append_result result = new append_result();
+      receiveBase(result, "append");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "append failed: unknown result");
+    }
+
+    public boolean checkAndPut(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.nio.ByteBuffer value, Mutation mput, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      send_checkAndPut(tableName, row, column, value, mput, attributes);
+      return recv_checkAndPut();
+    }
+
+    public void send_checkAndPut(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.nio.ByteBuffer value, Mutation mput, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes) throws org.apache.thrift.TException
+    {
+      checkAndPut_args args = new checkAndPut_args();
+      args.setTableName(tableName);
+      args.setRow(row);
+      args.setColumn(column);
+      args.setValue(value);
+      args.setMput(mput);
+      args.setAttributes(attributes);
+      sendBase("checkAndPut", args);
+    }
+
+    public boolean recv_checkAndPut() throws IOError, IllegalArgument, org.apache.thrift.TException
+    {
+      checkAndPut_result result = new checkAndPut_result();
+      receiveBase(result, "checkAndPut");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      if (result.ia != null) {
+        throw result.ia;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "checkAndPut failed: unknown result");
+    }
+
+    public TThriftServerType getThriftServerType() throws org.apache.thrift.TException
+    {
+      send_getThriftServerType();
+      return recv_getThriftServerType();
+    }
+
+    public void send_getThriftServerType() throws org.apache.thrift.TException
+    {
+      getThriftServerType_args args = new getThriftServerType_args();
+      sendBase("getThriftServerType", args);
+    }
+
+    public TThriftServerType recv_getThriftServerType() throws org.apache.thrift.TException
+    {
+      getThriftServerType_result result = new getThriftServerType_result();
+      receiveBase(result, "getThriftServerType");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getThriftServerType failed: unknown result");
+    }
+
+    public java.lang.String getClusterId() throws org.apache.thrift.TException
+    {
+      send_getClusterId();
+      return recv_getClusterId();
+    }
+
+    public void send_getClusterId() throws org.apache.thrift.TException
+    {
+      getClusterId_args args = new getClusterId_args();
+      sendBase("getClusterId", args);
+    }
+
+    public java.lang.String recv_getClusterId() throws org.apache.thrift.TException
+    {
+      getClusterId_result result = new getClusterId_result();
+      receiveBase(result, "getClusterId");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getClusterId failed: unknown result");
+    }
+
+    public boolean grant(TAccessControlEntity info) throws IOError, org.apache.thrift.TException
+    {
+      send_grant(info);
+      return recv_grant();
+    }
+
+    public void send_grant(TAccessControlEntity info) throws org.apache.thrift.TException
+    {
+      grant_args args = new grant_args();
+      args.setInfo(info);
+      sendBase("grant", args);
+    }
+
+    public boolean recv_grant() throws IOError, org.apache.thrift.TException
+    {
+      grant_result result = new grant_result();
+      receiveBase(result, "grant");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "grant failed: unknown result");
+    }
+
+    public boolean revoke(TAccessControlEntity info) throws IOError, org.apache.thrift.TException
+    {
+      send_revoke(info);
+      return recv_revoke();
+    }
+
+    public void send_revoke(TAccessControlEntity info) throws org.apache.thrift.TException
+    {
+      revoke_args args = new revoke_args();
+      args.setInfo(info);
+      sendBase("revoke", args);
+    }
+
+    public boolean recv_revoke() throws IOError, org.apache.thrift.TException
+    {
+      revoke_result result = new revoke_result();
+      receiveBase(result, "revoke");
+      if (result.isSetSuccess()) {
+        return result.success;
+      }
+      if (result.io != null) {
+        throw result.io;
+      }
+      throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "revoke failed: unknown result");
+    }
+
+  }
+  public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {
+    public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {
+      private org.apache.thrift.async.TAsyncClientManager clientManager;
+      private org.apache.thrift.protocol.TProtocolFactory protocolFactory;
+      public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {
+        this.clientManager = clientManager;
+        this.protocolFactory = protocolFactory;
+      }
+      public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {
+        return new AsyncClient(protocolFactory, clientManager, transport);
+      }
+    }
+
+    public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {
+      super(protocolFactory, clientManager, transport);
+    }
+
+    public void enableTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      enableTable_call method_call = new enableTable_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class enableTable_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableName;
+      public enableTable_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("enableTable", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        enableTable_args args = new enableTable_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void disableTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      disableTable_call method_call = new disableTable_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class disableTable_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableName;
+      public disableTable_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("disableTable", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        disableTable_args args = new disableTable_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void isTableEnabled(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      isTableEnabled_call method_call = new isTableEnabled_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class isTableEnabled_call extends org.apache.thrift.async.TAsyncMethodCall<java.lang.Boolean> {
+      private java.nio.ByteBuffer tableName;
+      public isTableEnabled_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.lang.Boolean> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("isTableEnabled", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        isTableEnabled_args args = new isTableEnabled_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.lang.Boolean getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_isTableEnabled();
+      }
+    }
+
+    public void compact(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      compact_call method_call = new compact_call(tableNameOrRegionName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class compact_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableNameOrRegionName;
+      public compact_call(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableNameOrRegionName = tableNameOrRegionName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("compact", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        compact_args args = new compact_args();
+        args.setTableNameOrRegionName(tableNameOrRegionName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void majorCompact(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      majorCompact_call method_call = new majorCompact_call(tableNameOrRegionName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class majorCompact_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableNameOrRegionName;
+      public majorCompact_call(java.nio.ByteBuffer tableNameOrRegionName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableNameOrRegionName = tableNameOrRegionName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("majorCompact", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        majorCompact_args args = new majorCompact_args();
+        args.setTableNameOrRegionName(tableNameOrRegionName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void getTableNames(org.apache.thrift.async.AsyncMethodCallback<java.util.List<java.nio.ByteBuffer>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getTableNames_call method_call = new getTableNames_call(resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getTableNames_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<java.nio.ByteBuffer>> {
+      public getTableNames_call(org.apache.thrift.async.AsyncMethodCallback<java.util.List<java.nio.ByteBuffer>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getTableNames", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getTableNames_args args = new getTableNames_args();
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<java.nio.ByteBuffer> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getTableNames();
+      }
+    }
+
+    public void getTableNamesWithIsTableEnabled(org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,java.lang.Boolean>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getTableNamesWithIsTableEnabled_call method_call = new getTableNamesWithIsTableEnabled_call(resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getTableNamesWithIsTableEnabled_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.Map<java.nio.ByteBuffer,java.lang.Boolean>> {
+      public getTableNamesWithIsTableEnabled_call(org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,java.lang.Boolean>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getTableNamesWithIsTableEnabled", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getTableNamesWithIsTableEnabled_args args = new getTableNamesWithIsTableEnabled_args();
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.Map<java.nio.ByteBuffer,java.lang.Boolean> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getTableNamesWithIsTableEnabled();
+      }
+    }
+
+    public void getColumnDescriptors(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,ColumnDescriptor>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getColumnDescriptors_call method_call = new getColumnDescriptors_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getColumnDescriptors_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.Map<java.nio.ByteBuffer,ColumnDescriptor>> {
+      private java.nio.ByteBuffer tableName;
+      public getColumnDescriptors_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.Map<java.nio.ByteBuffer,ColumnDescriptor>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getColumnDescriptors", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getColumnDescriptors_args args = new getColumnDescriptors_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.Map<java.nio.ByteBuffer,ColumnDescriptor> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getColumnDescriptors();
+      }
+    }
+
+    public void getTableRegions(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRegionInfo>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getTableRegions_call method_call = new getTableRegions_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getTableRegions_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRegionInfo>> {
+      private java.nio.ByteBuffer tableName;
+      public getTableRegions_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRegionInfo>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getTableRegions", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getTableRegions_args args = new getTableRegions_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRegionInfo> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getTableRegions();
+      }
+    }
+
+    public void createTable(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      createTable_call method_call = new createTable_call(tableName, columnFamilies, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class createTable_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableName;
+      private java.util.List<ColumnDescriptor> columnFamilies;
+      public createTable_call(java.nio.ByteBuffer tableName, java.util.List<ColumnDescriptor> columnFamilies, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.columnFamilies = columnFamilies;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("createTable", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        createTable_args args = new createTable_args();
+        args.setTableName(tableName);
+        args.setColumnFamilies(columnFamilies);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, IllegalArgument, AlreadyExists, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void deleteTable(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      deleteTable_call method_call = new deleteTable_call(tableName, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class deleteTable_call extends org.apache.thrift.async.TAsyncMethodCall<Void> {
+      private java.nio.ByteBuffer tableName;
+      public deleteTable_call(java.nio.ByteBuffer tableName, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("deleteTable", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        deleteTable_args args = new deleteTable_args();
+        args.setTableName(tableName);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public Void getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return null;
+      }
+    }
+
+    public void get(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      get_call method_call = new get_call(tableName, row, column, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class get_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TCell>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.nio.ByteBuffer column;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public get_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.column = column;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("get", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        get_args args = new get_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setColumn(column);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TCell> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_get();
+      }
+    }
+
+    public void getVer(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getVer_call method_call = new getVer_call(tableName, row, column, numVersions, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getVer_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TCell>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.nio.ByteBuffer column;
+      private int numVersions;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getVer_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.column = column;
+        this.numVersions = numVersions;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getVer", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getVer_args args = new getVer_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setColumn(column);
+        args.setNumVersions(numVersions);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TCell> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getVer();
+      }
+    }
+
+    public void getVerTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getVerTs_call method_call = new getVerTs_call(tableName, row, column, timestamp, numVersions, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getVerTs_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TCell>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.nio.ByteBuffer column;
+      private long timestamp;
+      private int numVersions;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getVerTs_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.nio.ByteBuffer column, long timestamp, int numVersions, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TCell>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.column = column;
+        this.timestamp = timestamp;
+        this.numVersions = numVersions;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getVerTs", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getVerTs_args args = new getVerTs_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setColumn(column);
+        args.setTimestamp(timestamp);
+        args.setNumVersions(numVersions);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TCell> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getVerTs();
+      }
+    }
+
+    public void getRow(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRow_call method_call = new getRow_call(tableName, row, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRow_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRow_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRow", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRow_args args = new getRow_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRow();
+      }
+    }
+
+    public void getRowWithColumns(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRowWithColumns_call method_call = new getRowWithColumns_call(tableName, row, columns, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRowWithColumns_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.util.List<java.nio.ByteBuffer> columns;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRowWithColumns_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.columns = columns;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRowWithColumns", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRowWithColumns_args args = new getRowWithColumns_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setColumns(columns);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRowWithColumns();
+      }
+    }
+
+    public void getRowTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRowTs_call method_call = new getRowTs_call(tableName, row, timestamp, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRowTs_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private long timestamp;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRowTs_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.timestamp = timestamp;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRowTs", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRowTs_args args = new getRowTs_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setTimestamp(timestamp);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRowTs();
+      }
+    }
+
+    public void getRowWithColumnsTs(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRowWithColumnsTs_call method_call = new getRowWithColumnsTs_call(tableName, row, columns, timestamp, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRowWithColumnsTs_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.nio.ByteBuffer row;
+      private java.util.List<java.nio.ByteBuffer> columns;
+      private long timestamp;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRowWithColumnsTs_call(java.nio.ByteBuffer tableName, java.nio.ByteBuffer row, java.util.List<java.nio.ByteBuffer> columns, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apach [...]
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.row = row;
+        this.columns = columns;
+        this.timestamp = timestamp;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRowWithColumnsTs", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRowWithColumnsTs_args args = new getRowWithColumnsTs_args();
+        args.setTableName(tableName);
+        args.setRow(row);
+        args.setColumns(columns);
+        args.setTimestamp(timestamp);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRowWithColumnsTs();
+      }
+    }
+
+    public void getRows(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRows_call method_call = new getRows_call(tableName, rows, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRows_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.util.List<java.nio.ByteBuffer> rows;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRows_call(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.rows = rows;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRows", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRows_args args = new getRows_args();
+        args.setTableName(tableName);
+        args.setRows(rows);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRows();
+      }
+    }
+
+    public void getRowsWithColumns(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRowsWithColumns_call method_call = new getRowsWithColumns_call(tableName, rows, columns, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRowsWithColumns_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.util.List<java.nio.ByteBuffer> rows;
+      private java.util.List<java.nio.ByteBuffer> columns;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRowsWithColumns_call(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, java.util.List<java.nio.ByteBuffer> columns, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apach [...]
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.rows = rows;
+        this.columns = columns;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRowsWithColumns", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRowsWithColumns_args args = new getRowsWithColumns_args();
+        args.setTableName(tableName);
+        args.setRows(rows);
+        args.setColumns(columns);
+        args.setAttributes(attributes);
+        args.write(prot);
+        prot.writeMessageEnd();
+      }
+
+      public java.util.List<TRowResult> getResult() throws IOError, org.apache.thrift.TException {
+        if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) {
+          throw new java.lang.IllegalStateException("Method call not finished!");
+        }
+        org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array());
+        org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);
+        return (new Client(prot)).recv_getRowsWithColumns();
+      }
+    }
+
+    public void getRowsTs(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler) throws org.apache.thrift.TException {
+      checkReady();
+      getRowsTs_call method_call = new getRowsTs_call(tableName, rows, timestamp, attributes, resultHandler, this, ___protocolFactory, ___transport);
+      this.___currentMethod = method_call;
+      ___manager.call(method_call);
+    }
+
+    public static class getRowsTs_call extends org.apache.thrift.async.TAsyncMethodCall<java.util.List<TRowResult>> {
+      private java.nio.ByteBuffer tableName;
+      private java.util.List<java.nio.ByteBuffer> rows;
+      private long timestamp;
+      private java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes;
+      public getRowsTs_call(java.nio.ByteBuffer tableName, java.util.List<java.nio.ByteBuffer> rows, long timestamp, java.util.Map<java.nio.ByteBuffer,java.nio.ByteBuffer> attributes, org.apache.thrift.async.AsyncMethodCallback<java.util.List<TRowResult>> resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+        super(client, protocolFactory, transport, resultHandler, false);
+        this.tableName = tableName;
+        this.rows = rows;
+        this.timestamp = timestamp;
+        this.attributes = attributes;
+      }
+
+      public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
+        prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("getRowsTs", org.apache.thrift.protocol.TMessageType.CALL, 0));
+        getRowsTs_args args = new getRowsTs_args();
+        args.setTableName(tableName);
+        args.setRows(rows);
+        args.setTimestamp(timestamp);
+        args.setAttributes(attributes);
... 160804 lines suppressed ...