blob: 108afed35ca72a6ba17ddcd7e55dea6e8ff6c508 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pegasus | Java Client</title>
<link rel="stylesheet" href="/zh/assets/css/app.css">
<link rel="shortcut icon" href="/zh/assets/images/favicon.ico">
<link rel="stylesheet" href="/zh/assets/css/utilities.min.css">
<link rel="stylesheet" href="/zh/assets/css/docsearch.v3.css">
<script src="/assets/js/jquery.min.js"></script>
<script src="/assets/js/all.min.js"></script>
<script src="/assets/js/docsearch.v3.js"></script>
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Java Client | Pegasus</title>
<meta name="generator" content="Jekyll v4.3.3" />
<meta property="og:title" content="Java Client" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="获取Java客户端" />
<meta property="og:description" content="获取Java客户端" />
<meta property="og:site_name" content="Pegasus" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2024-04-22T06:39:52+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Java Client" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2024-04-22T06:39:52+00:00","datePublished":"2024-04-22T06:39:52+00:00","description":"获取Java客户端","headline":"Java Client","mainEntityOfPage":{"@type":"WebPage","@id":"/clients/java-client"},"url":"/clients/java-client"}</script>
<!-- End Jekyll SEO tag -->
</head>
<body>
<div class="dashboard is-full-height">
<!-- left panel -->
<div class="dashboard-panel is-medium is-hidden-mobile pl-0">
<div class="dashboard-panel-header has-text-centered">
<a href="/zh/">
<img src="/assets/images/pegasus-logo-inv.png" style="width: 80%;">
</a>
</div>
<div class="dashboard-panel-main is-scrollable pl-6">
<aside class="menu">
<p class="menu-label">Pegasus 产品文档</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/downloads"
class="">
下载
</a>
</li>
</ul>
<p class="menu-label">编译构建</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/build/compile-by-docker"
class="">
使用 Docker 完成编译(推荐)
</a>
</li>
<li>
<a href="/zh/docs/build/compile-from-source"
class="">
从源码编译
</a>
</li>
</ul>
<p class="menu-label">客户端库</p>
<ul class="menu-list">
<li>
<a href="/zh/clients/java-client"
class="is-active">
Java 客户端
</a>
</li>
<li>
<a href="/zh/clients/cpp-client"
class="">
C++ 客户端
</a>
</li>
<li>
<a href="https://github.com/apache/incubator-pegasus/tree/master/go-client"
class="">
Golang 客户端
</a>
</li>
<li>
<a href="/zh/clients/python-client"
class="">
Python 客户端
</a>
</li>
<li>
<a href="/zh/clients/node-client"
class="">
NodeJS 客户端
</a>
</li>
<li>
<a href="/zh/clients/scala-client"
class="">
Scala 客户端
</a>
</li>
</ul>
<p class="menu-label">生态工具</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/tools/shell"
class="">
Pegasus Shell 工具
</a>
</li>
<li>
<a href="https://github.com/pegasus-kv/admin-cli"
class="">
集群管理命令行
</a>
</li>
<li>
<a href="https://github.com/pegasus-kv/pegic"
class="">
数据访问命令行
</a>
</li>
</ul>
<p class="menu-label">用户接口</p>
<ul class="menu-list">
<li>
<a href="/zh/api/ttl"
class="">
TTL
</a>
</li>
<li>
<a href="/zh/api/single-atomic"
class="">
单行原子操作
</a>
</li>
<li>
<a href="/zh/api/redis"
class="">
Redis 适配
</a>
</li>
<li>
<a href="/zh/api/geo"
class="">
GEO 支持
</a>
</li>
<li>
<a href="/zh/api/http"
class="">
HTTP 接口
</a>
</li>
</ul>
<p class="menu-label">高效运维</p>
<ul class="menu-list">
<li>
<a href="/zh/administration/deployment"
class="">
集群部署
</a>
</li>
<li>
<a href="/zh/administration/config"
class="">
配置说明
</a>
</li>
<li>
<a href="/zh/administration/rebalance"
class="">
负载均衡
</a>
</li>
<li>
<a href="/zh/administration/monitoring"
class="">
可视化监控
</a>
</li>
<li>
<a href="/zh/administration/rolling-update"
class="">
集群重启和升级
</a>
</li>
<li>
<a href="/zh/administration/scale-in-out"
class="">
集群扩容缩容
</a>
</li>
<li>
<a href="/zh/administration/resource-management"
class="">
资源管理
</a>
</li>
<li>
<a href="/zh/administration/cold-backup"
class="">
冷备份
</a>
</li>
<li>
<a href="/zh/administration/meta-recovery"
class="">
元数据恢复
</a>
</li>
<li>
<a href="/zh/administration/replica-recovery"
class="">
Replica 数据恢复
</a>
</li>
<li>
<a href="/zh/administration/zk-migration"
class="">
Zookeeper 迁移
</a>
</li>
<li>
<a href="/zh/administration/table-migration"
class="">
Table 迁移
</a>
</li>
<li>
<a href="/zh/administration/table-soft-delete"
class="">
Table 软删除
</a>
</li>
<li>
<a href="/zh/administration/table-env"
class="">
Table 环境变量
</a>
</li>
<li>
<a href="/zh/administration/remote-commands"
class="">
远程命令
</a>
</li>
<li>
<a href="/zh/administration/partition-split"
class="">
Partition-Split
</a>
</li>
<li>
<a href="/zh/administration/duplication"
class="">
跨机房同步
</a>
</li>
<li>
<a href="/zh/administration/compression"
class="">
数据压缩
</a>
</li>
<li>
<a href="/zh/administration/throttling"
class="">
流量控制
</a>
</li>
<li>
<a href="/zh/administration/experiences"
class="">
运维经验
</a>
</li>
<li>
<a href="/zh/administration/manual-compact"
class="">
Manual Compact 功能
</a>
</li>
<li>
<a href="/zh/administration/usage-scenario"
class="">
Usage Scenario 功能
</a>
</li>
<li>
<a href="/zh/administration/bad-disk"
class="">
坏盘检修
</a>
</li>
<li>
<a href="/zh/administration/whitelist"
class="">
Replica Server 白名单
</a>
</li>
<li>
<a href="/zh/administration/backup-request"
class="">
Backup Request
</a>
</li>
<li>
<a href="/zh/administration/hotspot-detection"
class="">
热点检测
</a>
</li>
</ul>
</aside>
</div>
</div>
<!-- main section -->
<div class="dashboard-main is-scrollable">
<nav class="navbar is-hidden-desktop">
<div class="navbar-brand">
<a href="/zh/" class="navbar-item">
<!-- Pegasus Icon -->
<img src="/assets/images/pegasus-square.png">
</a>
<div class="navbar-item">
<!--A simple language switch button that only supports zh and en.-->
<!--IF its language is zh, then switches to en.-->
<!--If you don't want a url to be relativized, you can add a space explicitly into the href to
prevents a url from being relativized by polyglot.-->
<a class="button is-light is-outlined is-inverted" href=" /clients/java-client"><strong>En</strong></a>
</div>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navMenu">
<!-- Appears in mobile mode only -->
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" id="navMenu">
<div class="navbar-end">
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
Pegasus 产品文档
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/downloads"
class="navbar-item ">
下载
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
编译构建
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/build/compile-by-docker"
class="navbar-item ">
使用 Docker 完成编译(推荐)
</a>
<a href="/zh/docs/build/compile-from-source"
class="navbar-item ">
从源码编译
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
客户端库
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/clients/java-client"
class="navbar-item is-active">
Java 客户端
</a>
<a href="/zh/clients/cpp-client"
class="navbar-item ">
C++ 客户端
</a>
<a href="https://github.com/apache/incubator-pegasus/tree/master/go-client"
class="navbar-item ">
Golang 客户端
</a>
<a href="/zh/clients/python-client"
class="navbar-item ">
Python 客户端
</a>
<a href="/zh/clients/node-client"
class="navbar-item ">
NodeJS 客户端
</a>
<a href="/zh/clients/scala-client"
class="navbar-item ">
Scala 客户端
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
生态工具
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/tools/shell"
class="navbar-item ">
Pegasus Shell 工具
</a>
<a href="https://github.com/pegasus-kv/admin-cli"
class="navbar-item ">
集群管理命令行
</a>
<a href="https://github.com/pegasus-kv/pegic"
class="navbar-item ">
数据访问命令行
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
用户接口
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/api/ttl"
class="navbar-item ">
TTL
</a>
<a href="/zh/api/single-atomic"
class="navbar-item ">
单行原子操作
</a>
<a href="/zh/api/redis"
class="navbar-item ">
Redis 适配
</a>
<a href="/zh/api/geo"
class="navbar-item ">
GEO 支持
</a>
<a href="/zh/api/http"
class="navbar-item ">
HTTP 接口
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
高效运维
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/administration/deployment"
class="navbar-item ">
集群部署
</a>
<a href="/zh/administration/config"
class="navbar-item ">
配置说明
</a>
<a href="/zh/administration/rebalance"
class="navbar-item ">
负载均衡
</a>
<a href="/zh/administration/monitoring"
class="navbar-item ">
可视化监控
</a>
<a href="/zh/administration/rolling-update"
class="navbar-item ">
集群重启和升级
</a>
<a href="/zh/administration/scale-in-out"
class="navbar-item ">
集群扩容缩容
</a>
<a href="/zh/administration/resource-management"
class="navbar-item ">
资源管理
</a>
<a href="/zh/administration/cold-backup"
class="navbar-item ">
冷备份
</a>
<a href="/zh/administration/meta-recovery"
class="navbar-item ">
元数据恢复
</a>
<a href="/zh/administration/replica-recovery"
class="navbar-item ">
Replica 数据恢复
</a>
<a href="/zh/administration/zk-migration"
class="navbar-item ">
Zookeeper 迁移
</a>
<a href="/zh/administration/table-migration"
class="navbar-item ">
Table 迁移
</a>
<a href="/zh/administration/table-soft-delete"
class="navbar-item ">
Table 软删除
</a>
<a href="/zh/administration/table-env"
class="navbar-item ">
Table 环境变量
</a>
<a href="/zh/administration/remote-commands"
class="navbar-item ">
远程命令
</a>
<a href="/zh/administration/partition-split"
class="navbar-item ">
Partition-Split
</a>
<a href="/zh/administration/duplication"
class="navbar-item ">
跨机房同步
</a>
<a href="/zh/administration/compression"
class="navbar-item ">
数据压缩
</a>
<a href="/zh/administration/throttling"
class="navbar-item ">
流量控制
</a>
<a href="/zh/administration/experiences"
class="navbar-item ">
运维经验
</a>
<a href="/zh/administration/manual-compact"
class="navbar-item ">
Manual Compact 功能
</a>
<a href="/zh/administration/usage-scenario"
class="navbar-item ">
Usage Scenario 功能
</a>
<a href="/zh/administration/bad-disk"
class="navbar-item ">
坏盘检修
</a>
<a href="/zh/administration/whitelist"
class="navbar-item ">
Replica Server 白名单
</a>
<a href="/zh/administration/backup-request"
class="navbar-item ">
Backup Request
</a>
<a href="/zh/administration/hotspot-detection"
class="navbar-item ">
热点检测
</a>
</div>
</div>
</div>
</div>
</nav>
<nav class="navbar is-hidden-mobile">
<div class="navbar-start w-full">
<div class="navbar-item pl-0 w-full">
<!--TODO(wutao): Given the limitation of docsearch that couldn't handle multiple input,
I make searchbox only shown in desktop. Fix this issue when docsearch.js v3 released.
Related issue: https://github.com/algolia/docsearch/issues/230-->
<div id="docsearch"></div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<!--A simple language switch button that only supports zh and en.-->
<!--IF its language is zh, then switches to en.-->
<!--If you don't want a url to be relativized, you can add a space explicitly into the href to
prevents a url from being relativized by polyglot.-->
<a class="button is-light is-outlined is-inverted" href=" /clients/java-client"><strong>En</strong></a>
</div>
</div>
</nav>
<section class="hero is-info lg:mr-3">
<div class="hero-body">
<p class="title is-size-2 is-centered">Java 客户端</p>
</div>
</section>
<section class="section" style="padding-top: 2rem;">
<div class="content">
<h1 id="获取java客户端">获取Java客户端</h1>
<p>项目地址:<a href="https://github.com/apache/incubator-pegasus/tree/master/java-client">Pegasus Java Client</a></p>
<p>下载:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/apache/incubator-pegasus.git
<span class="nb">cd </span>pegasus-java-client
</code></pre></div></div>
<p>选择所使用的版本并构建,建议使用<a href="https://github.com/xiaomi/pegasus-java-client/releases">最新的release版本</a></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout v2.0.0
mvn clean package <span class="nt">-DskipTests</span>
</code></pre></div></div>
<p>安装到本地的maven repository,方便在项目中使用:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mvn clean <span class="nb">install</span> <span class="nt">-DskipTests</span>
</code></pre></div></div>
<p>安装完成后,通过maven配置在项目中使用:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>com.xiaomi.infra<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>pegasus-client<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;version&gt;</span>2.0.0<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
</code></pre></div></div>
<p><strong>注:2.0.0版本仅适用于服务端PegasusServer &gt;= 2.0, 如果服务端版本较低,请使用下面的版本</strong></p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;dependency&gt;</span>
<span class="nt">&lt;groupId&gt;</span>com.xiaomi.infra<span class="nt">&lt;/groupId&gt;</span>
<span class="nt">&lt;artifactId&gt;</span>pegasus-client<span class="nt">&lt;/artifactId&gt;</span>
<span class="nt">&lt;version&gt;</span>1.11.10-thrift-0.11.0-inlined<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
</code></pre></div></div>
<h1 id="客户端配置">客户端配置</h1>
<p>创建Java client实例需要配置相关参数,用户可以选择两种方式进行配置:文件配置方式和参数传递方式</p>
<h2 id="文件配置">文件配置</h2>
<p>Java客户端需要准备配置文件,用以确定Pegasus集群的位置,以及配置默认超时时间等。</p>
<p>配置文件一般命名为<code class="language-plaintext highlighter-rouge">pegasus.properties</code>,样例:</p>
<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">meta_servers</span> <span class="p">=</span> <span class="s">127.0.0.1:34601,127.0.0.1:34602,127.0.0.1:34603</span>
<span class="py">operation_timeout</span> <span class="p">=</span> <span class="s">1000</span>
<span class="c"># 以下参数可以根据需要添加,否则以默认值即可
</span><span class="py">async_workers</span> <span class="p">=</span> <span class="s">4</span>
<span class="py">enable_perf_counter</span> <span class="p">=</span> <span class="s">true</span>
<span class="py">perf_counter_tags</span> <span class="p">=</span> <span class="s">cluster=onebox,app=unit_test</span>
<span class="py">push_counter_interval_secs</span> <span class="p">=</span> <span class="s">10</span>
<span class="py">meta_query_timeout</span> <span class="p">=</span> <span class="s">5000</span>
</code></pre></div></div>
<p>其中:</p>
<ul>
<li>meta_servers: 必选项,表示Pegasus集群的MetaServer地址列表,用于定位集群的位置。</li>
<li>operation_timeout: 可选项,表示各操作的默认超时时间,单位毫秒,默认值为1000。接口中每个操作一般都可以指定单独的超时时间,当指定为0时,使用该默认超时时间。</li>
<li>async_workers:可选项,后台工作线程数,内部实际是Netty NIO处理客户端和replica_server之间RPC的线程,默认:4</li>
<li>enable_perf_counter:可选项,是否开启性能指标监控数据,如果开启则客户端会周期性的上报监控数据,目前仅支持<a href="http://open-falcon.org/">Falcon</a>,默认:true(2.0.0以前默认为false)</li>
<li>perf_counter_tags:可选项,falcon监控数据标签,如果开启监控,建议设置易于区分不同业务的标签名字。默认:空</li>
<li>push_counter_interval_secs:可选值,falcon监控数据上报间隔,默认:10s</li>
<li>meta_query_timeout: 可选项,与MetaServer建立连接的超时时间,一般首次建立连接将需要更多的时间,用户可以根据实际场景配置该参数,以降低服务首次启动后的请求超时问题。连接默认值:5000ms(2.0.0以前没有该参数,默认等于operation_timeout)</li>
</ul>
<p>配置文件在创建Client实例的时候使用,需传入configPath参数:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">PegasusClientInterface</span> <span class="n">client</span> <span class="o">=</span> <span class="nc">PegasusClientFactory</span><span class="o">.</span><span class="na">getSingletonClient</span><span class="o">(</span><span class="n">configPath</span><span class="o">);</span>
</code></pre></div></div>
<p>其中configPath的格式为<code class="language-plaintext highlighter-rouge">type : // path</code>,目前type支持三种类型:</p>
<ul>
<li>本地文件系统
<ul>
<li>格式:file:///path/to/config</li>
<li>样例1:file://./pegasus.properties (表示本地 ./pegasus.properties 文件)</li>
<li>样例2:file:///home/work/pegasus.properties (表示本地 /home/work/pegasus.properties 文件)</li>
</ul>
</li>
<li>Java Resource
<ul>
<li>格式:resource:///path/to/config</li>
<li>样例1:resource:///pegasus.properties</li>
<li>样例2:resource:///com/xiaomi/xxx/pegasus.properties</li>
</ul>
</li>
<li>Zookeeper
<ul>
<li>格式:zk://host1:port1,host2:port2,host3:port3/path/to/config</li>
<li>样例1:zk://127.0.0.1:2181/databases/pegasus/pegasus.properties</li>
<li>样例2:zk://127.0.0.1:2181,127.0.0.1:2182/databases/pegasus/pegasus.properties</li>
</ul>
</li>
</ul>
<h2 id="参数传递">参数传递</h2>
<p>用户可以选择构造ClientOptions实例作为创建客户端实例的参数,ClientOptions包含下列参数:</p>
<ul>
<li>metaServers:必选项,meta_servers地址,默认:127.0.0.1:34601,127.0.0.1:34602,127.0.0.1:34603</li>
<li>operationTimeout:可选项,客户端请求的超时阈值,默认:1000ms</li>
<li>asyncWorkers:可选项,后台工作线程数,内部实际是Netty NIO处理客户端和replica_server之间RPC的线程,默认:4</li>
<li>enablePerfCounter:可选项,是否开启性能指标监控数据,如果开启则客户端会周期性的上报监控数据,目前仅支持<a href="http://open-falcon.org/">Falcon</a>,默认:false</li>
<li>falconPerfCounterTags:可选项,falcon监控数据标签,如果开启监控,建议设置易于区分不同业务的标签名字。默认:空</li>
<li>falconPushInterval:可选项,falcon监控数据上报间隔,默认:10s</li>
<li>metaQueryTimeout: 可选项,与MetaServer建立连接的超时时间,一般首次建立连接将需要更多的时间,用户可以根据实际场景配置该参数,以降低服务首次启动后的请求超时问题。连接默认值:5000ms(2.0.0以前没有该参数,默认等于operation_timeout)</li>
</ul>
<p>其中ClientOptions实例提供两种创建方式,你可以使用:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ClientOptions</span> <span class="n">clientOptions</span> <span class="o">=</span> <span class="nc">ClientOptions</span><span class="o">.</span><span class="na">create</span><span class="o">()</span>
</code></pre></div></div>
<p>创建默认的ClientOptions实例。否则,可以参照下列样例创建自定义的实例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ClientOptions</span> <span class="n">clientOptions</span> <span class="o">=</span>
<span class="nc">ClientOptions</span><span class="o">.</span><span class="na">builder</span><span class="o">()</span>
<span class="o">.</span><span class="na">metaServers</span><span class="o">(</span><span class="s">"127.0.0.1:34601,127.0.0.1:34602,127.0.0.1:34603"</span><span class="o">)</span>
<span class="o">.</span><span class="na">operationTimeout</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">ofMillis</span><span class="o">(</span><span class="mi">1000</span><span class="o">))</span>
<span class="o">.</span><span class="na">asyncWorkers</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span>
<span class="o">.</span><span class="na">enablePerfCounter</span><span class="o">(</span><span class="kc">false</span><span class="o">)</span>
<span class="o">.</span><span class="na">falconPerfCounterTags</span><span class="o">(</span><span class="s">""</span><span class="o">)</span>
<span class="o">.</span><span class="na">falconPushInterval</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">ofSeconds</span><span class="o">(</span><span class="mi">10</span><span class="o">))</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
</code></pre></div></div>
<h1 id="接口定义">接口定义</h1>
<p>Java客户端的类都在<code class="language-plaintext highlighter-rouge">com.xiaomi.infra.pegasus.client</code>包下面,主要提供了三个类:</p>
<table>
<thead>
<tr>
<th>类名</th>
<th>功能</th>
</tr>
</thead>
<tbody>
<tr>
<td>PegasusClientFactory</td>
<td>Client工厂类,用于创建Client实例</td>
</tr>
<tr>
<td>PegasusClientInterface</td>
<td>Client接口类,封装了各种<strong>同步API</strong>,也可用于创建Table实例</td>
</tr>
<tr>
<td>PegasusTableInterface</td>
<td>Table接口类,封装了存取单个Table数据的<strong>同步和异步API</strong></td>
</tr>
</tbody>
</table>
<p>用户可以选择使用Client接口(PegasusClientInterface)或者是Table接(PegasusTableInterface)存取数据,区别如下:</p>
<ul>
<li>Client接口直接在参数中指定表名,省去了打开表的动作,使用更便捷。</li>
<li>Table接口同时支持<strong>同步和异步API</strong>,而Client接口只支持<strong>同步API</strong></li>
<li>Table接口可以为每个操作设置单独的超时,而Client接口无法单独指定超时,只能使用配置文件中的默认超时。</li>
<li>Table接口在2.0.0中增加了backupRequestDelayMs参数,可以开启backup-request功能,以提高读性能,详情参见:<a href="/zh/administration/backup-request">Backup-Request</a></li>
<li>Table接口的超时更准确,而Client接口在首次读写请求时可能需要在内部初始化Table对象,所以首次读写的超时可能不太准确。</li>
<li>推荐用户首选Table接口。</li>
</ul>
<h2 id="创建client实例">创建Client实例</h2>
<p>创建Client实例有两种方式:单例和非单例。</p>
<h3 id="单例">单例</h3>
<p>如果程序中只需要访问<strong>单个集群</strong>,那么用单例是比较合适的,这样可以共享各种资源,譬如线程池、连接等。</p>
<p><strong>注意</strong>:如果在多个地方调用<code class="language-plaintext highlighter-rouge">getSingletonClient()</code>获取单例对象,需要保证传入的configPath或者ClientOptions对象是一致的,不然就会抛出异常,这样是为了保证多次调用获取到的是同一个实例。</p>
<p>调用<code class="language-plaintext highlighter-rouge">PegasusClientFactory::getSingletonClient()</code>方法获取PegasusClientInterface的单例对象:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get the singleton client instance with default config path of "resource:///pegasus.properties".
* After used, should call PegasusClientFactory.closeSingletonClient() to release resource.
*
* @return PegasusClientInterface PegasusClientInterface.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegasusClientInterface</span> <span class="nf">getSingletonClient</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="cm">/**
* Get the singleton client instance with customized config path. After used, should call
* PegasusClientFactory.closeSingletonClient() to release resource.
*
* @param configPath configPath could be:
* - zookeeper path : zk://host1:port1,host2:port2,host3:port3/path/to/config
* - local file path : file:///path/to/config
* - java resource : resource:///path/to/config
*
* @return PegasusClientInterface PegasusClientInterface.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegasusClientInterface</span> <span class="nf">getSingletonClient</span><span class="o">(</span><span class="nc">String</span> <span class="n">configPath</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="cm">/**
* Get the singleton client instance instance with ClientOptions. After used, should call
* PegasusClientFactory.closeSingletonClient() to release resource.
*
* @param options The client option
* @return PegasusClientInterface PegasusClientInterface.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegasusClientInterface</span> <span class="nf">getSingletonClient</span><span class="o">(</span><span class="nc">ClientOptions</span> <span class="n">options</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>使用完毕后,记得close单例以释放资源,譬如:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">PegasusClientInterface</span> <span class="n">client</span> <span class="o">=</span> <span class="nc">PegasusClientFactory</span><span class="o">.</span><span class="na">getSingletonClient</span><span class="o">(</span><span class="n">configPath</span><span class="o">);</span>
<span class="o">...</span> <span class="o">...</span>
<span class="nc">PegasusClientFactory</span><span class="o">.</span><span class="na">closeSingletonClient</span><span class="o">();</span>
</code></pre></div></div>
<h3 id="非单例">非单例</h3>
<p>如果在程序中需要访问多个集群,就不能用单例了。因此我们提供了创建普通实例的接口,创建时传入一个configPath或者ClientOptions对象,不同集群使用不同的configPath或者ClientOptions对象。</p>
<p><strong>注意</strong>:每个实例都拥有自己独立的资源,互不影响,因此要尽量避免重复创建实例,造成资源浪费,并且使用完后要记得调用close()释放资源。</p>
<p>调用<code class="language-plaintext highlighter-rouge">PegasusClientFactory::createClient()</code>方法,获取非单例的client实例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Create a client instance. After used, should call client.close() to release resource.
*
* @param configPath client config path,could be:
* - zookeeper path : zk://host1:port1,host2:port2,host3:port3/path/to/config
* - local file path : file:///path/to/config
* - java resource : resource:///path/to/config
*
* @return PegasusClientInterface.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegasusClientInterface</span> <span class="nf">createClient</span><span class="o">(</span><span class="nc">String</span> <span class="n">configPath</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="cm">/**
* Create a client instance instance with ClientOptions. After used, should call
* client.close() to release resource.
*
* @param options The client option
* @return PegasusClientInterface.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegasusClientInterface</span> <span class="nf">createClient</span><span class="o">(</span><span class="nc">ClientOptions</span> <span class="n">options</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>譬如:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">PegasusClientInterface</span> <span class="n">client</span> <span class="o">=</span> <span class="nc">PegasusClientFactory</span><span class="o">.</span><span class="na">createClient</span><span class="o">(</span><span class="n">configPath</span><span class="o">);</span>
<span class="o">...</span> <span class="o">...</span>
<span class="n">client</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
</code></pre></div></div>
<h2 id="pegasusclientinterface接口">PegasusClientInterface接口</h2>
<h3 id="get">get</h3>
<p>读单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get value.
* @param tableName TableHandler name
* @param hashKey used to decide which partition to get this k-v,
* if null or length == 0, means hash key is "".
* @param sortKey all the k-v under hashKey will be sorted by sortKey,
* if null or length == 0, means sort key is "".
* @return value; null if not found
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">get</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey。</li>
<li>返回值:如果返回null,表示key对应的数据不存在</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="batchget">batchGet</h3>
<p>读取一批数据,对get函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。如果抛出了异常,则values中的结果是未定义的。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch get values of different keys.
* Will terminate immediately if any error occurs.
* @param tableName table name
* @param keys hashKey and sortKey pair list.
* @param values output values; should be created by caller; if succeed, the size of values will
* be same with keys; the value of keys[i] is stored in values[i]; if the value of
* keys[i] is not found, then values[i] will be set to null.
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。</li>
<li>传出参数:Values。该变量需由调用者创建;如果读取成功,Values[i]中存放Keys[i]对应的结果,如果value不存在则为null。</li>
</ul>
</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchget2">batchGet2</h3>
<p>读取一批数据,对get函数的批量封装。该函数并发地向server发送异步请求,但与上面batchGet不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<p>用户可以根据results中的PException是否设置来判断请求成功还是失败,并可以选择只使用成功的结果。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch get values of different keys.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param keys hashKey and sortKey pair list.
* @param results output results; should be created by caller; after call done, the size of results will
* be same with keys; the results[i] is a Pair:
* - if Pair.left != null : means query keys[i] failed, Pair.left is the exception.
* - if Pair.left == null : means query keys[i] succeed, Pair.right is the result value.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchGet2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Keys[i]对应的结果;如果Results[i].left不为null(PException已设置),表示对Keys[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="multiget">multiGet</h3>
<p>读同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get multiple value under the same hash key.
* @param tableName table name
* @param hashKey used to decide which partition to put this k-v,
* should not be null or empty.
* @param sortKeys all the k-v under hashKey will be sorted by sortKey,
* if null or empty, means fetch all sortKeys under the hashKey.
* @param maxFetchCount max count of k-v pairs to be fetched.
* max_fetch_count &lt;= 0 means no limit. default value is 100.
* @param maxFetchSize max size of k-v pairs to be fetched.
* max_fetch_size &lt;= 0 means no limit. default value is 1000000.
* @param values output values; if sortKey is not found, then it will not appear in values.
* the returned sortKey is just the same one in incoming sortKeys.
* @return true if all data is fetched; false if only partial data is fetched.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定maxFetchCount和maxFetchSize。</li>
<li>参数:
<ul>
<li>传入参数:需传入TableName、HashKey、SortKeys;选择性传入maxFetchCount、maxFetchSize。</li>
<li>传出参数:数据通过values传出,values由用户在调用前new出来。</li>
<li>SortKeys如果非空,则只读取指定的数据;SortKeys如果为空,则表示读取该HashKey下的所有数据。</li>
<li>maxFetchCount和maxFetchSize用于限制读取的数据量,maxFetchCount表示最多读取的数据条数,maxFetchSize表示最多读取的数据字节数,两者任一达到限制就停止读取。</li>
</ul>
</li>
<li>返回值:如果用户指定了maxFetchCount或者maxFetchSize,单次查询可能只获取到部分结果。如果所有满足条件的数据都已经获取到,则返回true;否则返回false。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<p>multiGet还有另外一个版本的接口,可以支持SortKey的<strong>范围查询</strong><strong>条件过滤</strong>,只读取满足特定条件的数据。并且从1.8.0开始在MultiGetOptions中增加了reverse参数,支持<strong>逆向扫描</strong>数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="nc">FilterType</span> <span class="o">{</span>
<span class="no">FT_NO_FILTER</span><span class="o">(</span><span class="mi">0</span><span class="o">),</span>
<span class="no">FT_MATCH_ANYWHERE</span><span class="o">(</span><span class="mi">1</span><span class="o">),</span> <span class="c1">// match filter string at any position</span>
<span class="no">FT_MATCH_PREFIX</span><span class="o">(</span><span class="mi">2</span><span class="o">),</span> <span class="c1">// match filter string at prefix</span>
<span class="no">FT_MATCH_POSTFIX</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span> <span class="c1">// match filter string at postfix</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MultiGetOptions</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">// if the startSortKey is included</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// if the stopSortKey is included</span>
<span class="kd">public</span> <span class="nc">FilterType</span> <span class="n">sortKeyFilterType</span> <span class="o">=</span> <span class="nc">FilterType</span><span class="o">.</span><span class="na">FT_NO_FILTER</span><span class="o">;</span> <span class="c1">// filter type for sort key</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKeyFilterPattern</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// filter pattern for sort key</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">noValue</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// only fetch hash_key and sort_key, but not fetch value</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">reverse</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// if search in reverse direction</span>
<span class="o">}</span>
<span class="cm">/**
* Get multiple key-values under the same hashKey with sortKey range limited.
* @param tableName table name
* @param hashKey used to decide which partition the key may exist
* should not be null or empty.
* @param startSortKey the start sort key.
* null means "".
* @param stopSortKey the stop sort key.
* null or "" means fetch to the last sort key.
* @param options multi-get options.
* @param maxFetchCount max count of kv pairs to be fetched
* maxFetchCount &lt;= 0 means no limit. default value is 100
* @param maxFetchSize max size of kv pairs to be fetched.
* maxFetchSize &lt;= 0 means no limit. default value is 1000000.
* @param values output values; if sortKey is not found, then it will not appear in values.
* the returned sortKey is just the same one in incoming sortKeys.
* @return true if all data is fetched; false if only partial data is fetched.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="nc">MultiGetOptions</span> <span class="n">options</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span>
<span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="nc">MultiGetOptions</span> <span class="n">options</span><span class="o">,</span>
<span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定maxFetchCount和maxFetchSize。</li>
<li>参数:
<ul>
<li>传入参数:需传入TableName、HashKey、StartSortKey、StopSortKey、MultiGetOptions;选择性传入maxFetchCount、maxFetchSize。</li>
<li>传出参数:数据通过values传出,values由用户在调用前new出来。</li>
<li>StopSortKeys如果为空,不论stopInclusive为何值,都会读到该HashKey的SortKey结束。</li>
<li>maxFetchCount和maxFetchSize用于限制读取的数据量,maxFetchCount表示最多读取的数据条数,maxFetchSize表示最多读取的数据字节数,两者任一达到限制就停止读取。需要注意的是,PegasusServer从1.12.3开始限制一次性读取的数据(包括过期和条件过滤的数据)为3000条,该接口读取的有效数据可能会小于期望的数值</li>
<li>MultiGetOptions说明:
<ul>
<li>startInclusive:是否包含StartSortKey,默认为true。</li>
<li>stopInclusive:是否包含StopSortKey,默认为false。</li>
<li>sortKeyFilterType:SortKey的过滤类型,包括无过滤、任意位置匹配、前缀匹配和后缀匹配,默认无过滤。</li>
<li>sortKeyFilterPattern:SortKey的过滤模式串,空串相当于无过滤。</li>
<li>noValue:只返回HashKey和SortKey,不返回Value数据,默认为false。</li>
<li>reverse:是否逆向扫描数据库,从后往前查找数据。但是查找得到的结果在list中还是按照SortKey从小到大顺序存放。从Pegasus Server 1.8.0时开始支持。</li>
</ul>
</li>
<li>返回值:如果读取了所有满足条件的数据,返回true;如果只读取了部分满足条件的数据,返回false。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>示例:获取某个HashKey下的所有数据(注意如果数据条数太多容易超时)
<ul>
<li>multiGet(hashKey, null, null, new MultiGetOptions(), -1, -1, values);</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="batchmultiget">batchMultiGet</h3>
<p>对multiGet函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。如果抛出了异常,则values中的结果是未定义的。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch get multiple values under the same hash key.
* Will terminate immediately if any error occurs.
* @param tableName table name
* @param keys List{hashKey,List{sortKey}}; if List{sortKey} is null or empty, means fetch all
* sortKeys under the hashKey.
* @param values output values; should be created by caller; if succeed, the size of values will
* be same with keys; the data for keys[i] is stored in values[i].
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchMultiGet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HashKeyData</span><span class="o">&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。Keys是一个Pair列表,Pair的左值是hashKey,右值是sortKey列表;如果Pair的右值为null或者空列表,则获取该hashKey下的所有数据。</li>
<li>传出参数:Values。该List需由调用者创建;如果读取成功,Values[i]中存放Keys[i]对应的结果。</li>
</ul>
</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchmultiget2">batchMultiGet2</h3>
<p>对multiGet函数的批量封装。该函数并发地向server发送异步请求,并等待结果。但与上面batchMultiGet不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<p>用户可以根据results中的PException是否设置来判断请求成功还是失败,并可以选择只使用成功的结果。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch get multiple values under the same hash key.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param keys List{hashKey,List{sortKey}}; if List{sortKey} is null or empty, means fetch all
* sortKeys under the hashKey.
* @param results output results; should be created by caller; after call done, the size of results will
* be same with keys; the results[i] is a Pair:
* - if Pair.left != null : means query keys[i] failed, Pair.left is the exception.
* - if Pair.left == null : means query keys[i] succeed, Pair.right is the result value.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchMultiGet2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">,</span> <span class="nc">HashKeyData</span><span class="o">&gt;&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。Keys是一个Pair列表,Pair的左值是hashKey,右值是sortKey列表;如果Pair的右值为null或者空列表,则获取该hashKey下的所有数据。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Keys[i]对应的结果;如果Results[i].left不为null(PException已设置),表示对Keys[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="set">set</h3>
<p>写单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Set value.
* @param tableName TableHandler name
* @param hashKey used to decide which partition to put this k-v,
* if null or length == 0, means hash key is "".
* @param sortKey all the k-v under hashKey will be sorted by sortKey,
* if null or length == 0, means sort key is "".
* @param value should not be null
* @param ttl_seconds time to live in seconds,
* 0 means no ttl. default value is 0.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttl_seconds</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">value</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:需传入TableName、HashKey、SortKey、value;选择性传入TTL,TTL必须&gt;=0, 当&lt;0时会抛出PException异常。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误、TTL&lt;0等,会抛出 PException。</li>
</ul>
<h3 id="batchset">batchSet</h3>
<p>写一批数据,对set函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch set lots of values.
* @param tableName TableHandler name
* @param items list of items.
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">SetItem</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、Items。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchset2">batchSet2</h3>
<p>对set函数的批量封装。该函数并发地向server发送异步请求,并等待结果。但与上面batchSet不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<p>用户可以根据results中的PException是否设置来判断请求成功还是失败,并可以选择只使用成功的结果。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch set lots of values.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param items list of items.
* @param results output results; should be created by caller; after call done, the size of results will
* be same with items; the results[i] is a PException:
* - if results[i] != null : means set items[i] failed, results[i] is the exception.
* - if results[i] == null : means set items[i] succeed.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchSet2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">SetItem</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Items。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Items[i]对应的结果;如果Results[i]不为null(PException已设置),表示对Items[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="multiset">multiSet</h3>
<p>写同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Set multiple value under the same hash key.
* @param tableName table name
* @param hashKey used to decide which partition to put this k-v,
* should not be null or empty.
* @param values all &lt;sortkey,value&gt; pairs to be set,
* should not be null or empty.
* @param ttl_seconds time to live in seconds,
* 0 means no ttl. default value is 0.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">multiSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttl_seconds</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">multiSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:需传入TableName、HashKey、Values;选择性传入TTL,TTL必须&gt;=0, 当&lt;0时会抛出PException异常。
<ul>
<li>Values是Pair列表,Pair的第一个元素是SortKey,第二个元素为value。</li>
</ul>
</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误、TTL&lt;0等,会抛出 PException。</li>
</ul>
<h3 id="batchmultiset">batchMultiSet</h3>
<p>对multiSet函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch set multiple value under the same hash key.
* Will terminate immediately if any error occurs.
* @param tableName TableHandler name
* @param items list of items.
* @param ttl_seconds time to live in seconds,
* 0 means no ttl. default value is 0.
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchMultiSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HashKeyData</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttl_seconds</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchMultiSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HashKeyData</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:需传入TableName、Items;选择性传入TTL,TTL必须&gt;=0, 当&lt;0时会抛出PException异常。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误、TTL&lt;0等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchmultiset2">batchMultiSet2</h3>
<p>对multiSet函数的批量封装。该函数并发地向server发送异步请求,并等待结果。但与上面batchMultiSet不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch set multiple value under the same hash key.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param items list of items.
* @param ttl_seconds time to live in seconds,
* 0 means no ttl. default value is 0.
* @param results output results; should be created by caller; after call done, the size of results will
* be same with items; the results[i] is a PException:
* - if results[i] != null : means set items[i] failed, results[i] is the exception.
* - if results[i] == null : means set items[i] succeed.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchMultiSet2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HashKeyData</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttl_seconds</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchMultiSet2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">HashKeyData</span><span class="o">&gt;</span> <span class="n">items</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:
<ul>
<li>传入参数:TableName、Items;选择性传入TTL,TTL必须&gt;=0, 当&lt;0时会抛出PException异常。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Items[i]对应的结果;如果Results[i]不为null(PException已设置),表示对Items[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在、TTL&lt;0等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="del">del</h3>
<p>删单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Delete value.
* @param tableName TableHandler name
* @param hashKey used to decide which partition to put this k-v,
* if null or length == 0, means hash key is "".
* @param sortKey all the k-v under hashKey will be sorted by sortKey,
* if null or length == 0, means sort key is "".
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">del</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="batchdel">batchDel</h3>
<p>删除一批数据,对del函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch delete values of different keys.
* Will terminate immediately if any error occurs.
* @param tableName table name
* @param keys hashKey and sortKey pair list.
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchDel</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">keys</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、Keys。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchdel2">batchDel2</h3>
<p>对del函数的批量封装。该函数并发地向server发送异步请求,并等待结果。但与上面batchDel不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<p>用户可以根据results中的PException是否设置来判断请求成功还是失败,并可以选择只使用成功的结果。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch delete values of different keys.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param keys hashKey and sortKey pair list.
* @param results output results; should be created by caller; after call done, the size of results will
* be same with keys; the results[i] is a PException:
* - if results[i] != null : means del keys[i] failed, results[i] is the exception.
* - if results[i] == null : means del keys[i] succeed.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchDel2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Keys[i]对应的结果;如果Results[i]不为null(PException已设置),表示对Keys[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="multidel">multiDel</h3>
<p>删同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Delete specified sort keys under the same hash key.
* @param tableName table name
* @param hashKey used to decide which partition to put this k-v,
* should not be null or empty.
* @param sortKeys specify sort keys to be deleted.
* should not be empty.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">multiDel</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKeys。
<ul>
<li>SortKeys不允许为空,如果不知道该HashKey下面有哪些SortKey,可以通过下面的multiGetSortKeys方法获取。</li>
</ul>
</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="batchmultidel">batchMultiDel</h3>
<p>对multiDel函数的批量封装。该函数并发地向server发送异步请求,并等待结果。如果有任意一个请求失败,就提前终止并抛出异常。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch delete specified sort keys under the same hash key.
* Will terminate immediately if any error occurs.
* @param tableName table name
* @param keys List{hashKey,List{sortKey}}
* @throws PException throws exception if any error occurs.
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">batchMultiDel</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;&gt;&gt;</span> <span class="n">keys</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、Keys。Keys是一个Pair列表,Pair的左值是hashKey,右值是非空的sortKey列表。</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,只要任意一个失败都会抛出异常。</li>
</ul>
<h3 id="batchmultidel2">batchMultiDel2</h3>
<p>对del函数的批量封装。该函数并发地向server发送异步请求,并等待结果。但与上面batchMultiDel不同的是,无论请求成功还是失败,它都会等待所有请求结束。</p>
<p>用户可以根据results中的PException是否设置来判断请求成功还是失败,并可以选择只使用成功的结果。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Batch delete specified sort keys under the same hash key.
* Will wait for all requests done even if some error occurs.
* @param tableName table name
* @param keys List{hashKey,List{sortKey}}
* @param results output results; should be created by caller; after call done, the size of results will
* be same with keys; the results[i] is a PException:
* - if results[i] != null : means del keys[i] failed, results[i] is the exception.
* - if results[i] == null : means del keys[i] succeed.
* @return succeed count.
* @throws PException
*
* Notice: the method is not atomic, that means, maybe some keys succeed but some keys failed.
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">batchMultiDel2</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;&gt;&gt;</span> <span class="n">keys</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">PException</span><span class="o">&gt;</span> <span class="n">results</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:TableName、Keys。Keys是一个Pair列表,Pair的左值是hashKey,右值是非空的sortKey列表。</li>
<li>传出参数:Results。该变量需由调用者创建;Results[i]中存放Keys[i]对应的结果;如果Results[i]不为null(PException已设置),表示对Keys[i]的请求失败。</li>
</ul>
</li>
<li>返回值:请求成功的个数。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况,用户可以选择只使用成功的结果。</li>
</ul>
<h3 id="delrange">delRange</h3>
<p>删除同一HashKey下,SortKey值在startSortKey和stopSortKey范围内的数据。删除过程中若发生错误,不影响已经删除的数据,同时会标记该范围内未删除的第一个SortKey。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Delete key-values within range of startSortKey and stopSortKey under hashKey. Will terminate
* immediately if any error occurs.
*
* @param tableName table name
* @param hashKey used to decide which partition the key may exist, should not be null or empty.
* @param startSortKey the start sort key. null or "" means fetch to the first sort key.
* @param stopSortKey the stop sort key. null or "" means fetch to the last sort key.
* @param options del range options.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">delRange</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span><span class="nc">DelRangeOptions</span> <span class="n">options</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">DelRangeOptions</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">nextSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">// whether the startSortKey is included</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// whether the stopSortKey is included</span>
<span class="kd">public</span> <span class="nc">FilterType</span> <span class="n">sortKeyFilterType</span> <span class="o">=</span> <span class="nc">FilterType</span><span class="o">.</span><span class="na">FT_NO_FILTER</span><span class="o">;</span> <span class="c1">// filter type for sort key</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKeyFilterPattern</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// filter pattern for sort key</span>
<span class="o">}</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:
<ul>
<li>传入参数:
<ul>
<li>startSortKey和stopSortKey是sortkey的起止key值。</li>
<li>DelRangeOptions:
<ul>
<li>nextSortKey:将要删除的第一个sortKey值,默认为null, 在删除开始后会动态记录下一个要删除的值。特别的,当删除过程中出现错误时,该参数可以记录接下来需要继续删除的sortKey</li>
<li>startInclusive:是否包含StartSortKey,默认为true</li>
<li>stopInclusive:是否包含StopSortKey,默认为false</li>
<li>sortKeyFilterType:SortKey的过滤类型,包括无过滤、任意位置匹配、前缀匹配和后缀匹配,默认无过滤。</li>
<li>sortKeyFilterPattern:SortKey的过滤模式串,空串相当于无过滤。</li>
</ul>
</li>
</ul>
</li>
<li>传出参数:无。</li>
</ul>
</li>
<li>返回值:无。</li>
<li>异常:如果出现异常,譬如参数错误、表名不存在、超时等,会抛出 PException。</li>
<li>注意:该方法不是原子的,有可能出现部分成功部分失败的情况。</li>
</ul>
<h3 id="incr">incr</h3>
<p>单行原子增(减)操作。详细说明参见<a href="/zh/api/single-atomic#原子增减">单行原子操作</a></p>
<p>该操作先将key所指向的value的字节串转换为int64类型(实现上类似于Java的<a href="https://docs.oracle.com/javase/7/docs/api/java/lang/Long.html#parseLong(java.lang.String)">Long.parseLong()</a>函数),然后加上increment,将结果转换为字节串设置为新值。</p>
<p>当参数increment为正数时,即原子加;当参数increment为负数时,即原子减。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Atomically increment value.
*
* @param tableName the table name.
* @param hashKey the hash key to increment.
* @param sortKey the sort key to increment.
* @param increment the increment to be added to the old value.
* @return the new value.
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">incr</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">long</span> <span class="n">increment</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey、Increment。</li>
<li>返回值:操作成功后的新值。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。另外以下情况也会抛出异常:
<ul>
<li>旧值转换为int64时出错,譬如不是合法的数字或者超出int64范围。</li>
<li>旧值加上increment后的结果超出int64范围。</li>
</ul>
</li>
<li>其他说明:
<ul>
<li>如果旧值不存在,则把旧值当做0处理,即新值等于increment。</li>
<li>TTL语义:如果旧值存在,新值的TTL和旧值保持一致;如果旧值不存在,新值将不设TTL。</li>
</ul>
</li>
</ul>
<p>从Pegasus Server v1.11.1版本开始支持在incr操作时修改TTL,需使用<a href="https://github.com/XiaoMi/pegasus-java-client/releases/tag/1.11.2-thrift-0.11.0-inlined-release">Pegasus Java Client 1.11.2-thrift-0.11.0-inlined-release</a>及以上版本来使用这个功能。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/**
* Atomically increment value.
*
* @param tableName the table name.
* @param hashKey the hash key to increment.
* @param sortKey the sort key to increment.
* @param increment the increment to be added to the old value.
* @param ttlSeconds time to live in seconds for the new value.
* should be no less than -1. for the second method, the ttlSeconds is 0.
* - if ttlSeconds == 0, the semantic is the same as redis:
* - normally, increment will preserve the original ttl.
* - if old data is expired by ttl, then set initial value to 0 and set no ttl.
* - if ttlSeconds &gt; 0, then update with the new ttl if increment succeed.
* - if ttlSeconds == -1, then update to no ttl if increment succeed.
* @return the new value.
* @throws PException throws exception if any error occurs.
*/
public long incr(String tableName, byte[] hashKey, byte[] sortKey, long increment, int ttlSeconds) throws PException;
public long incr(String tableName, byte[] hashKey, byte[] sortKey, long increment) throws PException;
</code></pre></div></div>
<p>注:</p>
<ul>
<li>除了TTL之外,其他语义都与前面相同。</li>
<li>TTL操作说明:
<ul>
<li>如果参数ttlSeconds == 0,则和redis语义保持一致:如果旧值存在,新值的TTL和旧值保持一致;如果旧值不存在,新值将不设TTL。</li>
<li>如果参数ttlSeconds &gt; 0,则将TTL设置为新值。</li>
<li>如果参数ttlSeconds == -1,则清理掉TTL,即新值不再设置TTL。</li>
<li>如果参数ttlSeconds &lt; -1,则抛出异常。</li>
</ul>
</li>
</ul>
<h3 id="checkandset">checkAndSet</h3>
<p>单HashKey数据的原子CAS操作(可以理解为<strong>单行原子操作</strong>)。详细说明参见<a href="/zh/api/single-atomic#cas操作">单行原子操作</a></p>
<p>该操作先对某个SortKey(称之为CheckSortKey)的value做条件检查:</p>
<ul>
<li>如果检查的条件满足,则将另一个SortKey(称之为SetSortKey)的value设置为新值。</li>
<li>如果检查的条件不满足,则不执行set操作。</li>
</ul>
<p>CheckSortKey和SetSortKey可以相同也可以不同。</p>
<p>用户还可以设置<code class="language-plaintext highlighter-rouge">CheckAndSetOptions.returnCheckValue</code>来获取CheckSortKey对应的value。如果CheckSortKey和SetSortKey相同并且set成功,则获取set之前的旧值。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="nc">CheckType</span> <span class="o">{</span>
<span class="no">CT_NO_CHECK</span><span class="o">(</span><span class="mi">0</span><span class="o">),</span>
<span class="c1">// appearance</span>
<span class="no">CT_VALUE_NOT_EXIST</span><span class="o">(</span><span class="mi">1</span><span class="o">),</span> <span class="c1">// value is not exist</span>
<span class="no">CT_VALUE_NOT_EXIST_OR_EMPTY</span><span class="o">(</span><span class="mi">2</span><span class="o">),</span> <span class="c1">// value is not exist or value is empty</span>
<span class="no">CT_VALUE_EXIST</span><span class="o">(</span><span class="mi">3</span><span class="o">),</span> <span class="c1">// value is exist</span>
<span class="no">CT_VALUE_NOT_EMPTY</span><span class="o">(</span><span class="mi">4</span><span class="o">),</span> <span class="c1">// value is exist and not empty</span>
<span class="c1">// match</span>
<span class="no">CT_VALUE_MATCH_ANYWHERE</span><span class="o">(</span><span class="mi">5</span><span class="o">),</span> <span class="c1">// operand matches anywhere in value</span>
<span class="no">CT_VALUE_MATCH_PREFIX</span><span class="o">(</span><span class="mi">6</span><span class="o">),</span> <span class="c1">// operand matches prefix in value</span>
<span class="no">CT_VALUE_MATCH_POSTFIX</span><span class="o">(</span><span class="mi">7</span><span class="o">),</span> <span class="c1">// operand matches postfix in value</span>
<span class="c1">// bytes compare</span>
<span class="no">CT_VALUE_BYTES_LESS</span><span class="o">(</span><span class="mi">8</span><span class="o">),</span> <span class="c1">// bytes compare: value &lt; operand</span>
<span class="no">CT_VALUE_BYTES_LESS_OR_EQUAL</span><span class="o">(</span><span class="mi">9</span><span class="o">),</span> <span class="c1">// bytes compare: value &lt;= operand</span>
<span class="no">CT_VALUE_BYTES_EQUAL</span><span class="o">(</span><span class="mi">10</span><span class="o">),</span> <span class="c1">// bytes compare: value == operand</span>
<span class="no">CT_VALUE_BYTES_GREATER_OR_EQUAL</span><span class="o">(</span><span class="mi">11</span><span class="o">),</span> <span class="c1">// bytes compare: value &gt;= operand</span>
<span class="no">CT_VALUE_BYTES_GREATER</span><span class="o">(</span><span class="mi">12</span><span class="o">),</span> <span class="c1">// bytes compare: value &gt; operand</span>
<span class="c1">// int compare: first transfer bytes to int64; then compare by int value</span>
<span class="no">CT_VALUE_INT_LESS</span><span class="o">(</span><span class="mi">13</span><span class="o">),</span> <span class="c1">// int compare: value &lt; operand</span>
<span class="no">CT_VALUE_INT_LESS_OR_EQUAL</span><span class="o">(</span><span class="mi">14</span><span class="o">),</span> <span class="c1">// int compare: value &lt;= operand</span>
<span class="no">CT_VALUE_INT_EQUAL</span><span class="o">(</span><span class="mi">15</span><span class="o">),</span> <span class="c1">// int compare: value == operand</span>
<span class="no">CT_VALUE_INT_GREATER_OR_EQUAL</span><span class="o">(</span><span class="mi">16</span><span class="o">),</span> <span class="c1">// int compare: value &gt;= operand</span>
<span class="no">CT_VALUE_INT_GREATER</span><span class="o">(</span><span class="mi">17</span><span class="o">);</span> <span class="c1">// int compare: value &gt; operand</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CheckAndSetOptions</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">setValueTTLSeconds</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="c1">// time to live in seconds of the set value, 0 means no ttl.</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">returnCheckValue</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// if return the check value in results.</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CheckAndSetResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for checkAndSet
*
* @param setSucceed true if set value succeed.
* @param checkValueReturned true if the check value is returned.
* @param checkValueExist true if the check value is exist; can be used only when checkValueReturned is true.
* @param checkValue return the check value if exist; can be used only when checkValueExist is true.
*/</span>
<span class="kt">boolean</span> <span class="n">setSucceed</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">checkValueReturned</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">checkValueExist</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">checkValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Atomically check and set value by key.
* If the check condition is satisfied, then apply to set value.
*
* @param tableName the table name.
* @param hashKey the hash key to check and set.
* @param checkSortKey the sort key to check.
* @param checkType the check type.
* @param checkOperand the check operand.
* @param setSortKey the sort key to set value if check condition is satisfied.
* @param setValue the value to set if check condition is satisfied.
* @param options the check-and-set options.
* @return CheckAndSetResult
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="nc">PegasusTableInterface</span><span class="o">.</span><span class="na">CheckAndSetResult</span> <span class="nf">checkAndSet</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">checkSortKey</span><span class="o">,</span>
<span class="nc">CheckType</span> <span class="n">checkType</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">checkOperand</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">setSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">setValue</span><span class="o">,</span>
<span class="nc">CheckAndSetOptions</span> <span class="n">options</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、CheckSortKey、CheckType、CheckOperand、SetSortKey、SetValue、Options。
<ul>
<li>checkSortKey、checkType、checkOperand:用于指定检查的条件。</li>
<li>setSortKey、setValue:用于指定条件检查成功后要set的新值。</li>
<li>options:其他选项,包括:
<ul>
<li>setValueTTLSeconds:新值的TTL时间;TTL必须&gt;=0,0表示不设置TTL限制,当&lt;0时将抛出PException异常。</li>
<li>returnCheckValue:是否需要返回CheckSortKey对应的value。</li>
</ul>
</li>
</ul>
</li>
<li>返回值:CheckAndSetResult,包括:
<ul>
<li>setSucceed:是否set成功。</li>
<li>checkValueReturned:是否返回了CheckSortKey对应的value。</li>
<li>checkValueExist:CheckSortKey对应的value是否存在;该域只有在<code class="language-plaintext highlighter-rouge">checkValueReturned=true</code>时有意义。</li>
<li>checkValue:CheckSortKey对应的value值;该域只有在<code class="language-plaintext highlighter-rouge">checkValueExist=true</code>时有意义。</li>
</ul>
</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误、TTL&lt;0等,会抛出 PException。另外以下情况也会抛出异常:
<ul>
<li>如果CheckType为<code class="language-plaintext highlighter-rouge">int compare</code>类型的操作,且CheckOperand或者CheckValue转换为int64时出错,譬如不是合法的数字或者超出int64范围。</li>
</ul>
</li>
</ul>
<h3 id="checkandmutate">checkAndMutate</h3>
<p>checkAndMutate是<a href="#checkandset">checkAndSet</a>的扩展版本:checkAndSet只允许set一个值,而checkAndMutate允许在单个原子操作中set或者del多个值。该接口从<a href="https://github.com/XiaoMi/pegasus-java-client/releases/tag/1.11.0-thrift-0.11.0-inlined-release">Pegasus Java Client 1.11.0-thrift-0.11.0-inlined-release</a>版本开始提供。</p>
<p>为此,我们提供了一个包装类<a href="https://github.com/XiaoMi/pegasus-java-client/blob/thrift-0.11.0-inlined/src/main/java/com/xiaomi/infra/pegasus/client/Mutations.java">Mutations</a>,用户可以预先设置需要实施的set或者del操作。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">CheckAndMutateResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for checkAndMutate
*
* @param mutateSucceed true if mutate succeed.
* @param checkValueReturned true if the check value is returned.
* @param checkValueExist true if the check value is exist; can be used only when
* checkValueReturned is true.
* @param checkValue return the check value if exist; can be used only when checkValueExist is
* true.
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">mutateSucceed</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">checkValueReturned</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">checkValueExist</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">checkValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* atomically check and mutate by key, async version. if the check condition is satisfied, then
* apply to mutate.
*
* @param hashKey the hash key to check and mutate.
* @param checkSortKey the sort key to check.
* @param checkType the check type.
* @param checkOperand the check operand.
* @param mutations the list of mutations to perform if check condition is satisfied.
* @param options the check-and-mutate options.
* @param timeout how long will the operation timeout in milliseconds. if timeout &gt; 0, it is a
* timeout value for current op, else the timeout value in the configuration file will be
* used.
* @return the future for current op
* &lt;p&gt;Future return: On success: return CheckAndMutateResult. On failure: a throwable, which
* is an instance of PException
* &lt;p&gt;Thread safety: All the listeners for the same table are guaranteed to be dispatched in
* the same thread, so all the listeners for the same future are guaranteed to be executed as
* the same order as the listeners added. But listeners for different tables are not
* guaranteed to be dispatched in the same thread.
*/</span>
<span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CheckAndMutateResult</span><span class="o">&gt;</span> <span class="nf">asyncCheckAndMutate</span><span class="o">(</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">checkSortKey</span><span class="o">,</span>
<span class="nc">CheckType</span> <span class="n">checkType</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">checkOperand</span><span class="o">,</span>
<span class="nc">Mutations</span> <span class="n">mutations</span><span class="o">,</span>
<span class="nc">CheckAndMutateOptions</span> <span class="n">options</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">timeout</span> <span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、CheckSortKey、CheckType、CheckOperand、Mutations、Options。
<ul>
<li>checkSortKey、checkType、checkOperand:用于指定检查的条件。</li>
<li>mutations:用于指定条件检查成功后要实施的set或者del操作。</li>
<li>options:其他选项,包括:
<ul>
<li>returnCheckValue:是否需要返回CheckSortKey对应的value。</li>
</ul>
</li>
</ul>
</li>
<li>返回值:CheckAndMutateResult,包括:
<ul>
<li>mutateSucceed:是否实施成功。</li>
<li>checkValueReturned:是否返回了CheckSortKey对应的value。</li>
<li>checkValueExist:CheckSortKey对应的value是否存在;该域只有在<code class="language-plaintext highlighter-rouge">checkValueReturned=true</code>时有意义。</li>
<li>checkValue:CheckSortKey对应的value值;该域只有在<code class="language-plaintext highlighter-rouge">checkValueExist=true</code>时有意义。</li>
</ul>
</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。另外以下情况也会抛出异常:
<ul>
<li>如果CheckType为<code class="language-plaintext highlighter-rouge">int compare</code>类型的操作,且CheckOperand或者CheckValue转换为int64时出错,譬如不是合法的数字或者超出int64范围。</li>
</ul>
</li>
</ul>
<h3 id="compareexchange">compareExchange</h3>
<p>compareExchange是<a href="#checkandset">checkAndSet</a>的特化版本:</p>
<ul>
<li>CheckSortKey和SetSortKey相同。</li>
<li>CheckType为CT_VALUE_BYTES_EQUAL。</li>
</ul>
<p>该方法语义就是:如果SortKey对应的value存在且等于期望的值,则将其设置为新值。详细说明参见<a href="/zh/api/single-atomic#cas操作">单行原子操作</a></p>
<p>该方法与C++库中常见的<a href="https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange">atomic_compare_exchange</a>语义基本保持一致。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">CompareExchangeResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for CompareExchange
*
* @param setSucceed true if set value succeed.
* @param actualValue return the actual value if set value failed; null means the actual value is not exist.
*/</span>
<span class="kt">boolean</span> <span class="n">setSucceed</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">actualValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Atomically compare and exchange value by key.
* &lt;p&gt;
* - if the original value for the key is equal to the expected value, then update it with the desired value,
* set CompareExchangeResult.setSucceed to true, and set CompareExchangeResult.actualValue to null because
* the actual value must be equal to the desired value.
* - if the original value for the key is not exist or not equal to the expected value, then set
* CompareExchangeResult.setSucceed to false, and set the actual value in CompareExchangeResult.actualValue.
* &lt;p&gt;
* This method is very like the C++ function in {https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange}.
*
* @param tableName the table name.
* @param hashKey the hash key to compare and exchange.
* @param sortKey the sort key to compare and exchange.
* @param expectedValue the value expected to be found for the key.
* @param desiredValue the desired value to set if the original value for the key is equal to the expected value.
* @param ttlSeconds time to live in seconds of the desired value, 0 means no ttl.
* @return CompareExchangeResult
* @throws PException throws exception if any error occurs.
*/</span>
<span class="kd">public</span> <span class="nc">PegasusTableInterface</span><span class="o">.</span><span class="na">CompareExchangeResult</span> <span class="nf">compareExchange</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">expectedValue</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">desiredValue</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">ttlSeconds</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey、ExpectedValue、DesiredValue、ttlSeconds。
<ul>
<li>hashKey、sortKey:用于指定数据的key。</li>
<li>expectedValue:期望的旧值。</li>
<li>desiredValue:如果旧值等于expectedValue,需要设置的新值。</li>
<li>ttlSeconds:新值的TTL时间;TTL必须&gt;=0,0表示不设置TTL限制,当TTL&lt;0时将抛出PException异常。</li>
</ul>
</li>
<li>返回值:CompareExchangeResult,包括:
<ul>
<li>setSucceed:是否set成功,如果旧数据不存在,则set失败。</li>
<li>actualValue:如果set失败,返回该value的实际值;null表示不存在。</li>
</ul>
</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误、TTL&lt;0等,会抛出 PException。</li>
</ul>
<h3 id="ttl">ttl</h3>
<p>获取单行数据的TTL时间。TTL表示Time To Live,表示该数据还能存活多久。如果超过存活时间,数据就读不到了。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get ttl time.
* @param tableName TableHandler name
* @param hashKey used to decide which partition to put this k-v,
* if null or length == 0, means hash key is "".
* @param sortKey all the k-v under hashKey will be sorted by sortKey,
* if null or length == 0, means sort key is "".
* @return ttl time in seconds; -1 if no ttl set; -2 if not exist.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">ttl</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey。</li>
<li>返回值:TTL时间,单位为秒。如果该数据没有设置TTL,返回-1;如果该数据不存在,返回-2。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="exist">exist</h3>
<p>检查数据是否存在。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Check value exist by key from the cluster
* @param tableName TableHandler name
* @param hashKey used to decide which partition the key may exist.
* @param sortKey all keys under the same hashKey will be sorted by sortKey
*
* @return true if exist, false if not exist
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">exist</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、SortKey。</li>
<li>返回值:如果存在返回true,否则返回false。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="sortkeycount">sortKeyCount</h3>
<p>获取某个HashKey下所有SortKey的个数。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* @param tableName TableHandler name
* @param hashKey used to decide which partition the key may exist.
* @return the count result for the hashKey
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">sortKeyCount</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey。</li>
<li>返回值:返回HashKey下所有SortKey的个数。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="multigetsortkeys">multiGetSortKeys</h3>
<p>获取某个HashKey下SortKey列表。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get multiple sort keys under the same hash key.
* @param tableName table name
* @param hashKey used to decide which partition to put this k-v,
* should not be null or empty.
* @param maxFetchCount max count of k-v pairs to be fetched.
* max_fetch_count &lt;= 0 means no limit. default value is 100.
* @param maxFetchSize max size of k-v pairs to be fetched.
* max_fetch_size &lt;= 0 means no limit. default value is 1000000.
* @param sortKeys output sort keys.
* @return true if all data is fetched; false if only partial data is fetched.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGetSortKeys</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">multiGetSortKeys</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定maxFetchCount和maxFetchSize。</li>
<li>参数:
<ul>
<li>传入参数:需传入TableName、HashKey;选择性传入maxFetchCount、maxFetchSize。</li>
<li>传出参数:数据通过sortKeys传出,sortKeys由用户在调用前new出来。</li>
<li>maxFetchCount和maxFetchSize用于限制读取的数据量,maxFetchCount表示最多读取的数据条数,maxFetchSize表示最多读取的数据字节数,两者任一达到限制就停止读取。</li>
</ul>
</li>
<li>返回值:如果用户指定了maxFetchCount或者maxFetchSize,单次查询可能只获取到部分结果。如果所有满足条件的数据都已经获取到,则返回true;否则返回false。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="getscanner">getScanner</h3>
<p>获取遍历某个HashKey下所有数据的迭代器,用于局部扫描。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">enum</span> <span class="nc">FilterType</span> <span class="o">{</span>
<span class="no">FT_NO_FILTER</span><span class="o">(</span><span class="mi">0</span><span class="o">),</span>
<span class="no">FT_MATCH_ANYWHERE</span><span class="o">(</span><span class="mi">1</span><span class="o">),</span> <span class="c1">// match filter string at any position</span>
<span class="no">FT_MATCH_PREFIX</span><span class="o">(</span><span class="mi">2</span><span class="o">),</span> <span class="c1">// match filter string at prefix</span>
<span class="no">FT_MATCH_POSTFIX</span><span class="o">(</span><span class="mi">3</span><span class="o">);</span> <span class="c1">// match filter string at postfix</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ScanOptions</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">timeoutMillis</span> <span class="o">=</span> <span class="mi">5000</span><span class="o">;</span> <span class="c1">// operation timeout in milli-seconds.</span>
<span class="c1">// if timeoutMillis &gt; 0, it is a timeout value for current op,</span>
<span class="c1">// else the timeout value in the configuration file will be used.</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">batchSize</span> <span class="o">=</span> <span class="mi">1000</span><span class="o">;</span> <span class="c1">// internal buffer batch size</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">// if the startSortKey is included</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// if the stopSortKey is included</span>
<span class="kd">public</span> <span class="nc">FilterType</span> <span class="n">hashKeyFilterType</span> <span class="o">=</span> <span class="nc">FilterType</span><span class="o">.</span><span class="na">FT_NO_FILTER</span><span class="o">;</span> <span class="c1">// filter type for hash key</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKeyFilterPattern</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// filter pattern for hash key</span>
<span class="kd">public</span> <span class="nc">FilterType</span> <span class="n">sortKeyFilterType</span> <span class="o">=</span> <span class="nc">FilterType</span><span class="o">.</span><span class="na">FT_NO_FILTER</span><span class="o">;</span> <span class="c1">// filter type for sort key</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKeyFilterPattern</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span> <span class="c1">// filter pattern for sort key</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">noValue</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">// only fetch hash_key and sort_key, but not fetch value</span>
<span class="o">}</span>
<span class="cm">/**
* Get Scanner for {startSortKey, stopSortKey} within hashKey
* @param tableName TableHandler name
* @param hashKey used to decide which partition to put this k-v,
* @param startSortKey start sort key scan from
* if null or length == 0, means start from begin
* @param stopSortKey stop sort key scan to
* if null or length == 0, means stop to end
* @param options scan options like endpoint inclusive/exclusive
* @return scanner
* @throws PException
*/</span>
<span class="kd">public</span> <span class="nc">PegasusScannerInterface</span> <span class="nf">getScanner</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="nc">ScanOptions</span> <span class="n">options</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、HashKey、StartSortKey、StopSortKey、ScanOptions。
<ul>
<li>StartSortKey和StopSortKey用于指定scan的返回,并通过ScanOptions指定区间的开闭。</li>
<li>如果StartSortKey为null,表示从头开始;如果StopSortKey为null,表示一直读到尾。</li>
<li>ScanOptions说明:
<ul>
<li>timeoutMillis:从server端读取数据的超时时间,单位毫秒,默认值为5000。</li>
<li>batchSize:从server端读取数据时每批数据的个数,默认值为1000。</li>
<li>startInclusive:是否包含StartSortKey,默认为true。</li>
<li>stopInclusive:是否包含StopSortKey,默认为false。</li>
<li>hashKeyFilterType:HashKey的过滤类型,包括无过滤、任意位置匹配、前缀匹配和后缀匹配,默认无过滤。</li>
<li>hashKeyFilterPattern:HashKey的过滤模式串,空串相当于无过滤。</li>
<li>sortKeyFilterType:SortKey的过滤类型,包括无过滤、任意位置匹配、前缀匹配和后缀匹配,默认无过滤。</li>
<li>sortKeyFilterPattern:SortKey的过滤模式串,空串相当于无过滤。</li>
<li>noValue:只返回HashKey和SortKey,不返回Value数据,默认为false。</li>
</ul>
</li>
</ul>
</li>
<li>返回值:返回迭代器PegasusScannerInterface。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h3 id="getunorderedscanner">getUnorderedScanner</h3>
<p>获取遍历整个表的所有数据的迭代器,用于全局扫描。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/**
* Get Scanners for all data in database
* @param tableName TableHandler name
* @param maxSplitCount how many scanner expected
* @param options scan options like batchSize
* @return scanners, count of which would be no more than maxSplitCount
* @throws PException
*/
public List&lt;PegasusScannerInterface&gt; getUnorderedScanners(String tableName, int maxSplitCount, ScanOptions options) throws PException;
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入TableName、maxSplitCount、ScanOptions。
<ul>
<li>maxSplitCount:用于决定返回的迭代器的个数。当返回多个迭代器时,每个迭代器可以访问表中的部分数据。通过返回迭代器列表,用户可以进行并发scan或者在MapReduce中使用。如果不需要多个迭代器,可以将其设置为1。</li>
<li>ScanOptions同上。</li>
</ul>
</li>
<li>返回值:返回迭代器PegasusScannerInterface列表。</li>
<li>异常:如果出现异常,譬如网络错误、超时错误、服务端错误等,会抛出 PException。</li>
</ul>
<h2 id="创建table实例">创建Table实例</h2>
<p>通过<code class="language-plaintext highlighter-rouge">PegasusClientInterface::openTable()</code>方法获取PegasusTableInterface的对象实例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Open a table. Please notice that pegasus support two kinds of API:
* 1. the client-interface way, which is provided in this class.
* 2. the table-interface way, which is provided by {@link PegasusTableInterface}.
* With the client-interface, you don't need to create PegasusTableInterface by openTable, so
* you can access the pegasus cluster conveniently. However, the client-interface's api also has
* some restrictions:
* 1. we don't provide async methods in client-interface.
* 2. the timeout in client-interface isn't as accurate as the table-interface.
* 3. the client-interface may throw an exception when open table fails. It means that
* you may need to handle this exception in every data access operation, which is annoying.
* 4. You can't specify a per-operation timeout.
* So we recommend you to use the table-interface.
*
* @param tableName the table should be exist on the server, which is created before by
* the system administrator
* @return the table handler
* @throws PException
*/</span>
<span class="kd">public</span> <span class="nc">PegasusTableInterface</span> <span class="nf">openTable</span><span class="o">(</span><span class="nc">String</span> <span class="n">tableName</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>如果网络超时或者表不存在,都会抛出异常。</li>
</ul>
<p>使用示例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">PegasusTableInterface</span> <span class="n">table</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">openTable</span><span class="o">(</span><span class="n">tableName</span><span class="o">);</span>
</code></pre></div></div>
<p>PegasusTableInterface中同时提供了同步和异步的API。</p>
<p>同步API与PegasusClientInterface基本一致,区别在于:不用指定tableName参数;可以单独指定超时时间。</p>
<p>同时,openTable提供了warmup功能,用于解决表的第一次rpc调用过慢的问题,具体可参考最佳实践一节。</p>
<h3 id="基于future的异步api">基于Future的异步API</h3>
<p>异步API使用Future模式,具体来说是使用的 io.netty.util.concurrent.Future (参见 https://netty.io/4.1/api/index.html )。每个异步接口的返回值都是一个Future&lt;T&gt;,其中T是该操作返回结果的类型。Future具有如下特性:</p>
<ul>
<li>可以通过 addListener() 方法设置一个或者多个Listener,即异步回调函数。回调函数会在操作完成时被调用;如果在add时操作已经完成,回调函数就会被立即调用;回调函数被调用的顺序与添加的顺序一致。</li>
<li>可以通过 await() 方法等待操作完成。但是注意的是await()方法只能保证操作完成以及下面的三个方法可用,并不能保证回调函数已经被执行。</li>
<li>在操作完成后,可以通过 isSuccess() 方法判断操作是否成功;如果成功,可以通过 getNow() 方法获取结果;如果失败,可以通过 cause() 方法获取异常。</li>
</ul>
<p><strong>注意</strong>:第一次调用一个表的异步API的时候,函数返回之前可能会有一些额外延迟(典型地10ms左右),这是因为第一次调用时需要从meta-server获取表的信息和路由信息。</p>
<p>一个典型的异步使用样例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 获取Table实例</span>
<span class="nc">PegasusTableInterface</span> <span class="n">table</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">openTable</span><span class="o">(</span><span class="n">tableName</span><span class="o">);</span>
<span class="c1">// 发起异步调用</span>
<span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Boolean</span><span class="o">&gt;</span> <span class="n">future</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">asyncExist</span><span class="o">(</span><span class="n">hashKey</span><span class="o">,</span> <span class="n">sortKey</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
<span class="c1">// 设置回调函数</span>
<span class="n">future</span><span class="o">.</span><span class="na">addListener</span><span class="o">(</span>
<span class="k">new</span> <span class="nf">ExistListener</span><span class="o">()</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Boolean</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">future</span><span class="o">.</span><span class="na">isSuccess</span><span class="o">())</span> <span class="o">{</span>
<span class="nc">Boolean</span> <span class="n">result</span> <span class="o">=</span> <span class="n">future</span><span class="o">.</span><span class="na">getNow</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">else</span> <span class="o">{</span>
<span class="n">future</span><span class="o">.</span><span class="na">cause</span><span class="o">().</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">);</span>
<span class="c1">// 等待操作完成</span>
<span class="n">future</span><span class="o">.</span><span class="na">await</span><span class="o">();</span>
</code></pre></div></div>
<h2 id="pegasustableinterface接口">PegasusTableInterface接口</h2>
<h3 id="asyncget">asyncGet</h3>
<p>异步读单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">GetListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncGet future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Get value for a specific (hashKey, sortKey) pair, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param sortKey all keys under the same hashKey will be sorted by sortKey
* if null or empty, means sort key is "".
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: the got value
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* The api is thread safe.
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="nf">asyncGet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、SortKey、timeout。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;byte[]&gt;。</li>
</ul>
<h3 id="asyncmultiget">asyncMultiGet</h3>
<p>异步读同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">MultiGetResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for multiGet
* @param allFetched true if all data on the server are fetched; false if only partial data are fetched.
* @param values the got values. If sortKey in the input sortKeys is not found, it won't be in values.
* The output values are ordered by the sortKey.
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">allFetched</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">MultiGetListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncMultiGet future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* get multiple key-values under the same hashKey, async version
* @param hashKey used to decide which partition the key may exist
* should not be null or empty.
* @param sortKeys try to get values of sortKeys under the hashKey
* if null or empty, try to get all (sortKey,value) pairs under hashKey
* @param maxFetchCount max count of kv pairs to be fetched
* maxFetchCount &lt;= 0 means no limit. default value is 100
* @param maxFetchSize max size of kv pairs to be fetched.
* maxFetchSize &lt;= 0 means no limit. default value is 1000000.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: An object of type MultiGetResult
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定maxFetchCount和maxFetchSize。</li>
<li>参数:需传入HashKey、SortKeys、timeout;选择性传入maxFetchCount、maxFetchSize。
<ul>
<li>SortKeys如果非空,则只读取指定的数据;SortKeys如果为空,则表示读取该HashKey下的所有数据。</li>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
<li>maxFetchCount和maxFetchSize用于限制读取的数据量,maxFetchCount表示最多读取的数据条数,maxFetchSize表示最多读取的数据字节数,两者任一达到限制就停止读取。</li>
</ul>
</li>
<li>返回值:Future&lt;MultiGetResult&gt;。
<ul>
<li>allFetched:如果用户指定了maxFetchCount或者maxFetchSize,单次查询可能只获取到部分结果。如果所有满足条件的数据都已经获取到,则设置为true;否则设置为false。</li>
</ul>
</li>
</ul>
<p>asyncMultiGet还有另外一个版本的接口,可以支持SortKey的<strong>范围查询</strong><strong>条件过滤</strong>,只读取满足特定条件的数据。并且从1.8.0开始在MultiGetOptions中增加了reverse参数,支持<strong>逆向扫描</strong>数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cm">/**
* get multiple key-values under the same hashKey with sortKey range limited, async version
* @param hashKey used to decide which partition the key may exist
* should not be null or empty.
* @param startSortKey the start sort key.
* null means "".
* @param stopSortKey the stop sort key.
* null or "" means fetch to the last sort key.
* @param options multi-get options.
* @param maxFetchCount max count of kv pairs to be fetched
* maxFetchCount &lt;= 0 means no limit. default value is 100
* @param maxFetchSize max size of kv pairs to be fetched.
* maxFetchSize &lt;= 0 means no limit. default value is 1000000.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: An object of type MultiGetResult
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span>
<span class="nc">MultiGetOptions</span> <span class="n">options</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span><span class="o">,</span>
<span class="nc">MultiGetOptions</span> <span class="n">options</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数使用同<a href="#multiget">multiGet</a></li>
</ul>
<h3 id="asyncset">asyncSet</h3>
<p>异步写单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">SetListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncSet future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Set value for a specific (hashKey, sortKey) pair, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param sortKey all keys under the same hashKey will be sorted by sortKey
* if null or empty, means sort key is "".
* @param value should not be null
* @param ttlSeconds time to live in seconds
* 0 means no ttl, default value is 0
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: no return
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* The api is thread safe.
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncSet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttlSeconds</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncSet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">value</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:需传入HashKey、SortKey、Value、timeout;选择性传入TTL。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
<li>ttlSeconds是数据的TTL时间,单位为秒。TTL必须&gt;=0, 0表示不设置TTL时间,当TTL&lt;0时将抛出PException异常。</li>
</ul>
</li>
<li>返回值:Future&lt;Void&gt;。</li>
</ul>
<h3 id="asyncmultiset">asyncMultiSet</h3>
<p>异步写同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">MultiSetListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncMultiSet future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Set key-values for a specific hashKey, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param values all (sortKey, value) pairs
* should not be null or empty
* @param ttlSeconds time to live in seconds
* 0 means no ttl, default value is 0
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: no return
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncMultiSet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">,</span> <span class="kt">int</span> <span class="n">ttlSeconds</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncMultiSet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定TTL时间。</li>
<li>参数:需传入HashKey、Values、timeout;选择性传入ttlSeconds。
<ul>
<li>Values是Pair列表,Pair的第一个元素是SortKey,第二个元素为value。</li>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
<li>ttlSeconds是数据的TTL时间,单位为秒。TTL必须&gt;=0, 0表示不设置TTL时间,当TTL&lt;0时将抛出PException异常。</li>
</ul>
</li>
<li>返回值:Future&lt;Void&gt;。</li>
</ul>
<h3 id="asyncdel">asyncDel</h3>
<p>异步删单行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">DelListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncDel future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* delete value for a specific (hashKey, sortKey) pair, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param sortKey all keys under the same hashKey will be sorted by sortKey
* if null or empty, means sort key is "".
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: no return
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncDel</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、SortKey、timeout。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;Void&gt;。</li>
</ul>
<h3 id="asyncmultidel">asyncMultiDel</h3>
<p>异步删同一HashKey下的多行数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">MultiDelListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncMultiDel future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* delete mutiple values for a specific hashKey, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param sortKeys all the sortKeys need to be deleted
* should not be null or empty
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: no return
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Void</span><span class="o">&gt;</span> <span class="nf">asyncMultiDel</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">sortKeys</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、SortKeys、timeout。
<ul>
<li>SortKeys不允许为空,如果不知道该HashKey下面有哪些SortKey,可以通过multiGetSortKeys方法获取。</li>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;Void&gt;。</li>
</ul>
<h3 id="asyncincr">asyncIncr</h3>
<p>原子增(减)操作。<a href="#incr">incr</a>的异步版本。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public static interface IncrListener extends GenericFutureListener&lt;Future&lt;Long&gt;&gt; {
/**
* This function will be called when listened asyncIncr future is done.
*
* @param future the listened future
* @throws Exception throw exception if any error occurs.
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/
@Override
public void operationComplete(Future&lt;Long&gt; future) throws Exception;
}
/**
* atomically increment value by key, async version
*
* @param hashKey the hash key to increment.
* @param sortKey the sort key to increment.
* @param increment the increment to be added to the old value.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
* @return the future for current op
* &lt;p&gt;
* Future return:
* On success: return new value.
* On failure: a throwable, which is an instance of PException
* &lt;p&gt;
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/
public Future&lt;Long&gt; asyncIncr(byte[] hashKey, byte[] sortKey, long increment, int timeout/*ms*/);
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数和返回值:参见同步接口<a href="#incr">incr</a></li>
</ul>
<h3 id="asynccheckandset">asyncCheckAndSet</h3>
<p>单HashKey数据的原子CAS操作。<a href="#checkandset">checkAndSet</a>的异步版本。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">CheckAndSetResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for checkAndSet
*
* @param setSucceed true if set value succeed.
* @param checkValueReturned true if the check value is returned.
* @param checkValueExist true if the check value is exist; can be used only when checkValueReturned is true.
* @param checkValue return the check value if exist; can be used only when checkValueExist is true.
*/</span>
<span class="kt">boolean</span> <span class="n">setSucceed</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">checkValueReturned</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">checkValueExist</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">checkValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">CheckAndSetListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CheckAndSetResult</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncCheckAndSet future is done.
*
* @param future the listened future
* @throws Exception throw exception if any error occurs.
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CheckAndSetResult</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* atomically check and set value by key, async version.
* if the check condition is satisfied, then apply to set value.
*
* @param hashKey the hash key to check and set.
* @param checkSortKey the sort key to check.
* @param checkType the check type.
* @param checkOperand the check operand.
* @param setSortKey the sort key to set value if check condition is satisfied.
* @param setValue the value to set if check condition is satisfied.
* @param options the check-and-set options.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
* @return the future for current op
* &lt;p&gt;
* Future return:
* On success: return CheckAndSetResult.
* On failure: a throwable, which is an instance of PException
* &lt;p&gt;
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CheckAndSetResult</span><span class="o">&gt;</span> <span class="nf">asyncCheckAndSet</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">checkSortKey</span><span class="o">,</span> <span class="nc">CheckType</span> <span class="n">checkType</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">checkOperand</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">setSortKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">setValue</span><span class="o">,</span>
<span class="nc">CheckAndSetOptions</span> <span class="n">options</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数和返回值:参见同步接口<a href="#checkandset">checkAndSet</a></li>
</ul>
<h3 id="asynccompareexchange">asyncCompareExchange</h3>
<p>单HashKey数据的原子CAS操作。<a href="#compareexchange">compareExchange</a>的异步版本。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">CompareExchangeResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for CompareExchange
*
* @param setSucceed true if set value succeed.
* @param actualValue return the actual value if set value failed; null means the actual value is not exist.
*/</span>
<span class="kt">boolean</span> <span class="n">setSucceed</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">actualValue</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">CompareExchangeListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CompareExchangeResult</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncCompareExchange future is done.
*
* @param future the listened future
* @throws Exception throw exception if any error occurs.
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CompareExchangeResult</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* atomically compare and exchange value by key, async version.
* &lt;p&gt;
* - if the original value for the key is equal to the expected value, then update it with the desired value,
* set CompareExchangeResult.setSucceed to true, and set CompareExchangeResult.actualValue to null because
* the actual value must be equal to the desired value.
* - if the original value for the key is not exist or not equal to the expected value, then set
* CompareExchangeResult.setSucceed to false, and set the actual value in CompareExchangeResult.actualValue.
* &lt;p&gt;
* this method is very like the C++ function in {https://en.cppreference.com/w/cpp/atomic/atomic_compare_exchange}.
*
* @param hashKey the hash key to compare and exchange.
* @param sortKey the sort key to compare and exchange.
* @param expectedValue the value expected to be found for the key.
* @param desiredValue the desired value to set if the original value for the key is equal to the expected value.
* @param ttlSeconds time to live in seconds of the desired value, 0 means no ttl.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
* @return the future for current op
* &lt;p&gt;
* Future return:
* On success: return CompareExchangeResult.
* On failure: a throwable, which is an instance of PException
* &lt;p&gt;
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">CompareExchangeResult</span><span class="o">&gt;</span> <span class="nf">asyncCompareExchange</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">expectedValue</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">desiredValue</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">ttlSeconds</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数和返回值:参见同步接口<a href="#compareexchange">compareExchange</a></li>
</ul>
<h3 id="asyncttl">asyncTTL</h3>
<p>异步获取单行数据的TTL时间,即该数据还能存活多久,单位为秒。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">TTLListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncTTL future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* get TTL value for a specific (hashKey, sortKey) pair, async version
* @param hashKey used to decide which partition the key may exist
* if null or empty, means hash key is "".
* @param sortKey all keys under the same hashKey will be sorted by sortKey
* if null or empty, means sort key is "".
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: ttl time in seconds; -1 if no ttl set; -2 if not exist.
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">asyncTTL</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、SortKey、timeout。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;Integer&gt;。
<ul>
<li>返回结果为TTL时间,单位为秒。如果该数据没有设置TTL,返回-1;如果该数据不存在,返回-2。</li>
</ul>
</li>
</ul>
<h3 id="asyncexist">asyncExist</h3>
<p>异步检查数据是否存在。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">ExistListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Boolean</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncExist future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Boolean</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Check value existence for a specific (hashKey, sortKey) pair of current table, async version
* @param hashKey used to decide which partition the key may exist
* if null or length == 0, means hash key is "".
* @param sortKey all keys under the same hashKey will be sorted by sortKey
* if null or length == 0, means sort key is "".
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return A future for current op.
*
* Future return:
* On success: true if exist, false if not exist
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* The api is thread safe.
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Boolean</span><span class="o">&gt;</span> <span class="nf">asyncExist</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">sortKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、SortKey、timeout。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;Boolean&gt;。
<ul>
<li>返回结果是个布尔值。如果存在返回true,否则返回false。</li>
</ul>
</li>
</ul>
<h3 id="asyncsortkeycount">asyncSortKeyCount</h3>
<p>异步获取某个HashKey下所有SortKey的个数。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">SortKeyCountListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Long</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncSortKeyCount future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Long</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* Count the sortkeys for a specific hashKey, async version
* @param hashKey used to decide which partition the key may exist
* should not be null or empty
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: the count result for the hashKey
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* The api is thread safe.
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Long</span><span class="o">&gt;</span> <span class="nf">asyncSortKeyCount</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>参数:需传入HashKey、timeout。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
</ul>
</li>
<li>返回值:Future&lt;Long&gt;。
<ul>
<li>返回结果为HashKey下所有SortKey的个数。</li>
</ul>
</li>
</ul>
<h3 id="asyncmultigetsortkeys">asyncMultiGetSortKeys</h3>
<p>异步获取某个HashKey下SortKey列表。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">MultiGetSortKeysResult</span> <span class="o">{</span>
<span class="cm">/**
* return value for multiGetSortkeys
* @param allFetched true if all data on the server are fetched; false if only partial data are fetched.
* @param keys the got keys.
* The output keys are in order.
*/</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">allFetched</span><span class="o">;</span>
<span class="kd">public</span> <span class="nc">List</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">keys</span><span class="o">;</span>
<span class="o">};</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">interface</span> <span class="nc">MultiGetSortKeysListener</span> <span class="kd">extends</span> <span class="nc">GenericFutureListener</span><span class="o">&lt;</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetSortKeysResult</span><span class="o">&gt;&gt;</span> <span class="o">{</span>
<span class="cm">/**
* This function will be called when listened asyncMultiGetSortKeys future is done.
* @param future the listened future
* @throws Exception
*
* Notice: User shouldn't do any operations that may block or time-consuming
*/</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">operationComplete</span><span class="o">(</span><span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetSortKeysResult</span><span class="o">&gt;</span> <span class="n">future</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">Exception</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* get all the sortKeys for the same hashKey
* @param hashKey used to decide which partition the key may exist
* should not be null or empty.
* @param maxFetchCount max count of kv pairs to be fetched
* maxFetchCount &lt;= 0 means no limit. default value is 100
* @param maxFetchSize max size of kv pairs to be fetched.
* maxFetchSize &lt;= 0 means no limit. default value is 1000000.
* @param timeout how long will the operation timeout in milliseconds.
* if timeout &gt; 0, it is a timeout value for current op,
* else the timeout value in the configuration file will be used.
*
* @return the future for current op
*
* Future return:
* On success: An object of type MultiGetSortKeysResult
* On failure: a throwable, which is an instance of PException
*
* Thread safety:
* All the listeners for the same table are guaranteed to be dispatched in the same thread, so all the
* listeners for the same future are guaranteed to be executed as the same order as the listeners added.
* But listeners for different tables are not guaranteed to be dispatched in the same thread.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetSortKeysResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGetSortKeys</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">MultiGetSortKeysResult</span><span class="o">&gt;</span> <span class="nf">asyncMultiGetSortKeys</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">hashKey</span><span class="o">,</span> <span class="kt">int</span> <span class="n">timeout</span><span class="cm">/*ms*/</span><span class="o">);</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>提供了两个版本的接口,其中第一个接口可以指定maxFetchCount和maxFetchSize。</li>
<li>参数:需传入HashKey、timeout;选择性传入maxFetchCount、maxFetchSize。
<ul>
<li>timeout单位为毫秒,如果&lt;=0,表示使用配置文件中的默认超时。</li>
<li>maxFetchCount和maxFetchSize用于限制读取的数据量,maxFetchCount表示最多读取的数据条数,maxFetchSize表示最多读取的数据字节数,两者任一达到限制就停止读取。</li>
</ul>
</li>
<li>返回值:Future&lt;MultiGetSortKeysResult&gt;。
<ul>
<li>allFetched:如果用户指定了maxFetchCount或者maxFetchSize,单次查询可能只获取到部分结果。如果所有满足条件的数据都已经获取到,则设置为true;否则设置为false。</li>
</ul>
</li>
</ul>
<h2 id="pegasusscannerinterface接口">PegasusScannerInterface接口</h2>
<h3 id="next">next</h3>
<p>在scan操作时,同步获取下一条数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get the next item.
* @return item like &lt;&lt;hashKey, sortKey&gt;, value&gt;; null returned if scan completed.
* @throws PException
*/</span>
<span class="kd">public</span> <span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;,</span> <span class="kt">byte</span><span class="o">[]&gt;</span> <span class="nf">next</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">PException</span><span class="o">;</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>返回值:Pair&lt;Pair&lt;byte[], byte[]&gt;, byte[]&gt;。
<ul>
<li>下一条kv-pair;若scan操作完成,则返回null。</li>
</ul>
</li>
</ul>
<h3 id="asyncnext">asyncNext</h3>
<p>在scan操作时,异步获取下一条数据。</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* Get the next item asynchronously.
* @return A future for current op.
*
* Future return:
* On success: if scan haven't reach the end then return the kv-pair, else return null.
* On failure: a throwable, which is an instance of PException.
*/</span>
<span class="kd">public</span> <span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;,</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="nf">asyncNext</span><span class="o">();</span>
</code></pre></div></div>
<p>注:</p>
<ul>
<li>返回值:Future&lt;Pair&lt;Pair&lt;byte[], byte[]&gt;, byte[]&gt;&gt;。</li>
<li>在scan未扫描完成之前,会返回需要的kv-pair;当scan扫描完成之后,返回null。</li>
</ul>
<h2 id="常见异常">常见异常</h2>
<h3 id="err_object_not_found">ERR_OBJECT_NOT_FOUND</h3>
<p>表名不存在。可能原因:</p>
<ul>
<li>集群中没有建表。</li>
<li>访问了错误的集群。在日志中搜索<code class="language-plaintext highlighter-rouge">meta_servers</code>,看集群的配置是否正确。</li>
<li>表名拼写错误。检查代码中的表名是否正确;在日志中搜索<code class="language-plaintext highlighter-rouge">initialize table handler</code>,看表名是否正确。</li>
</ul>
<h3 id="err_timeout">ERR_TIMEOUT</h3>
<p>访问超时。可能原因:</p>
<ul>
<li>网络连接出错。</li>
<li>读写延迟超过了超时时间。</li>
<li>服务出现抖动。</li>
</ul>
<h3 id="err_session_reset">ERR_SESSION_RESET</h3>
<p>服务端状态出错。可能原因:</p>
<ul>
<li>服务端正在做replica迁移,发生了状态切换。</li>
<li>服务端有节点宕机,造成备份数不够,为了保证数据一致性,服务降级,变得不可用。</li>
<li>如果是客户端初始化时得到该错误,可能是由于 meta 配置不正确,请检查配置</li>
</ul>
<h3 id="err_busy">ERR_BUSY</h3>
<p>服务端流控达到限制。原因是:</p>
<ul>
<li>集群服务端对表设置了<a href="/zh/administration/throttling#服务端流控">表级写流量控制</a></li>
<li>此时该表的瞬时流量(在这1秒内的写入操作数)达到了阈值,触发了reject流控操作,返回<code class="language-plaintext highlighter-rouge">ERR_BUSY</code>错误码。</li>
</ul>
<h1 id="最佳实践">最佳实践</h1>
<h2 id="流量控制">流量控制</h2>
<p>经常有业务有集中灌数据的场景,灌数据的过程可能是单机的也可能是分布式的,譬如使用Spark处理后将数据写入Pegasus中。</p>
<p>如果不做流控,很可能产生很高的QPS峰值写,对Pegasus系统造成较大压力:</p>
<ul>
<li>写QPS太大,会影响读性能,造成读操作延迟上升;</li>
<li>写QPS太大,可能会造成集群无法承受压力而停止服务;</li>
</ul>
<p>因此,强烈建议业务方在灌数据的时候对写QPS进行流量控制。</p>
<p>客户端流控的思路就是:</p>
<ul>
<li>首先定好总的QPS限制是多少(譬如10000/s),有多少个并发的客户端访问线程(譬如50个),然后计算出每个线程的QPS限制(譬如10000/50=200)。</li>
<li>对于单个客户端线程,通过流控工具将QPS限制在期望的范围内。如果超过了QPS限制,就采用简单的sleep方式来等待。我们提供了一个流控工具类<a href="https://github.com/XiaoMi/pegasus-java-client/blob/thrift-0.11.0-inlined/src/main/java/com/xiaomi/infra/pegasus/tools/FlowController.java">com.xiaomi.infra.pegasus.tools.FlowController</a>,把计算QPS和执行sleep的逻辑封装起来,方便用户使用。</li>
</ul>
<p>FlowController用法:</p>
<ul>
<li>构造函数接受一个QPS参数,用于指定流量限制,譬如单线程QPS只允许200/s,就传入200;</li>
<li>用户在每次需要执行写操作之前调用cntl.getToken()方法,该方法产生两种可能:
<ul>
<li>如果当前未达到流量控制,则无阻塞直接返回,继续执行后面的写操作;</li>
<li>如果当前已经达到流量限制,则该方法会阻塞(sleep)一段时间才返回,以达到控制流量的效果。</li>
</ul>
</li>
<li>该工具尽量配合同步接口使用,对于异步接口可能效果没那么好。</li>
</ul>
<p>使用方法很简单:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">FlowController</span> <span class="n">cntl</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FlowController</span><span class="o">(</span><span class="n">qps</span><span class="o">);</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// call getToken before operation</span>
<span class="n">cntl</span><span class="o">.</span><span class="na">getToken</span><span class="o">();</span>
<span class="n">client</span><span class="o">.</span><span class="na">set</span><span class="o">(...);</span>
<span class="o">}</span>
<span class="n">cntl</span><span class="o">.</span><span class="na">stop</span><span class="o">();</span>
</code></pre></div></div>
<p>在分布式灌数据的场景下,用户可以先确定分布式的Task并发数,然后通过<code class="language-plaintext highlighter-rouge">总QPS限制 / Task并发数</code>,得到单个Task的QPS限制,再使用FlowController进行控制。</p>
<h2 id="分页查询">分页查询</h2>
<p>类似实现网页列表的分页功能。
典型地,一个HashKey下有很多SortKey,一页只显示固定数量的SortKey,下一页时再显示接下来的固定数量的SortKey。</p>
<p>分页查询在Pegasus下有多种实现方式:</p>
<ol>
<li>一次性获取HaskKey下的全部数据,在业务端缓存下来,由业务端自己实现分页逻辑。</li>
<li><strong>顺序分页</strong>:可以使用<a href="#multiget">multiGet()</a><a href="#getscanner">getScanner()</a>方法,这两者都支持SortKey的范围查询</li>
<li><strong>逆序分页</strong>:请使用<a href="#multiget">multiGet()</a>方法,其支持SortKey的逆序查询</li>
</ol>
<h3 id="顺序分页">顺序分页</h3>
<p>使用 <code class="language-plaintext highlighter-rouge">getScanner</code> 接口:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">ScanOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ScanOptions</span><span class="o">();</span>
<span class="n">options</span><span class="o">.</span><span class="na">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">batchSize</span> <span class="o">=</span> <span class="mi">20</span><span class="o">;</span> <span class="c1">// 限制每页的大小为 20</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">PegasusScannerInterface</span> <span class="n">scanner</span> <span class="o">=</span>
<span class="n">client</span><span class="o">.</span><span class="na">getScanner</span><span class="o">(</span><span class="n">tableName</span><span class="o">,</span> <span class="n">hashKey</span><span class="o">,</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="n">options</span><span class="o">);</span>
<span class="c1">// 同步方式获取</span>
<span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;,</span> <span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">item</span><span class="o">;</span>
<span class="k">while</span> <span class="o">((</span><span class="n">item</span> <span class="o">=</span> <span class="n">scanner</span><span class="o">.</span><span class="na">next</span><span class="o">())</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// ... //</span>
<span class="o">}</span>
<span class="c1">// 异步方式获取</span>
<span class="nc">Future</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;,</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">item</span><span class="o">;</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">scanner</span><span class="o">.</span><span class="na">asyncNext</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">Pair</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;,</span> <span class="kt">byte</span><span class="o">[]&gt;</span> <span class="n">pair</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="na">get</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">pair</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// ... //</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>如果你使用 <code class="language-plaintext highlighter-rouge">multiGet</code>,在 <code class="language-plaintext highlighter-rouge">MultiGetOptions</code> 中还需设置 <code class="language-plaintext highlighter-rouge">maxFetchCount</code>,限制每页条数:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 查第一页</span>
<span class="nc">MultiGetOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultiGetOptions</span><span class="o">();</span>
<span class="n">options</span><span class="o">.</span><span class="na">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">maxFetchCount</span> <span class="o">=</span> <span class="mi">20</span><span class="o">;</span> <span class="c1">// 限制每页的大小为 20</span>
<span class="kt">int</span> <span class="n">maxFetchSize</span> <span class="o">=</span> <span class="mi">20000</span><span class="o">;</span> <span class="c1">// 限制每页的总字节数为 20000</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">startSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">stopSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">List</span><span class="o">&lt;</span><span class="nc">Pair</span><span class="o">&lt;</span><span class="kt">byte</span><span class="o">[],</span> <span class="kt">byte</span><span class="o">[]&gt;&gt;</span> <span class="n">values</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o">&lt;&gt;();</span>
<span class="kt">boolean</span> <span class="n">allFetched</span> <span class="o">=</span>
<span class="n">client</span><span class="o">.</span><span class="na">multiGet</span><span class="o">(</span>
<span class="n">tableName</span><span class="o">,</span> <span class="n">hashKey</span><span class="o">,</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span>
<span class="n">maxFetchCount</span><span class="o">,</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="n">values</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">allFetched</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// ... //</span>
<span class="c1">// 查下一页</span>
<span class="n">options</span><span class="o">.</span><span class="na">startInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">startSortKey</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">values</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">);</span> <span class="c1">// 以上一页的最后(最大)一个值作为下一页查询的开始</span>
<span class="n">stopSortKey</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">allFetched</span> <span class="o">=</span>
<span class="n">client</span><span class="o">.</span><span class="na">multiGet</span><span class="o">(</span>
<span class="n">tableName</span><span class="o">,</span> <span class="n">hashKey</span><span class="o">,</span> <span class="n">startSortKey</span><span class="o">,</span> <span class="n">stopSortKey</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span>
<span class="n">maxFetchCount</span><span class="o">,</span> <span class="n">maxFetchSize</span><span class="o">,</span> <span class="n">values</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">allFetched</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="逆序分页">逆序分页</h3>
<p>逆序分页需要使用<code class="language-plaintext highlighter-rouge">multiGet</code>接口,并在选项中设置<code class="language-plaintext highlighter-rouge">reverse=true</code></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">MultiGetOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultiGetOptions</span><span class="o">();</span>
<span class="n">options</span><span class="o">.</span><span class="na">startInclusive</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">stopInclusive</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="n">options</span><span class="o">.</span><span class="na">reverse</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
</code></pre></div></div>
<h2 id="数据序列化">数据序列化</h2>
<p>Pegasus的key和value都是原始的字节串(Java中就是byte[]),而用户存储数据一般用struct或者class。因此,在将数据存储到Pegasus中时,需要将用户数据转化为字节串,这就是<strong>序列化</strong>;在从Pegasus中读取数据时,又需要将字节串转化为用户的数据结构,这就是<strong>反序列化</strong>。序列化和反序列化通常都是成对出现了,后面我们只描述序列化。</p>
<p>通常序列化有这些方式:</p>
<ul>
<li>json:好处是数据可读性好;坏处是比较占空间。不推荐。</li>
<li>thrift:提供了多种Compact协议,常见的有binary协议。但是推荐用tcompact协议,因为这种协议的压缩率更高。</li>
<li>protobuf:与thrift类似,推荐序列化为binary格式。</li>
</ul>
<p>对于Thrift结构,使用tcompact协议进行序列化的样例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kn">import</span> <span class="nn">org.apache.thrift.TSerializer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.thrift.protocol.TCompactProtocol</span><span class="o">;</span>
<span class="nc">TSerializer</span> <span class="n">serializer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TSerializer</span><span class="o">(</span><span class="k">new</span> <span class="nc">TCompactProtocol</span><span class="o">.</span><span class="na">Factory</span><span class="o">());</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span> <span class="o">=</span> <span class="n">serializer</span><span class="o">.</span><span class="na">serialize</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
</code></pre></div></div>
<h2 id="数据压缩">数据压缩</h2>
<p>对于value较大(&gt;=2kb)的业务,我们推荐在客户端使用<a href="https://github.com/facebook/zstd">facebook/Zstandard</a>压缩算法(简称 Zstd)对数据进行压缩,以减少value的数据长度,提升Pegasus的服务稳定性和读写性能。Zstd算法在压缩比和压缩速率上取得较好的平衡,适合通用场景。</p>
<p>从Java Client 1.11.3版本开始,我们提供了Zstd压缩工具类<a href="https://github.com/XiaoMi/pegasus-java-client/blob/thrift-0.11.0-inlined/src/main/java/com/xiaomi/infra/pegasus/tools/ZstdWrapper.java">com.xiaomi.infra.pegasus.tools.ZstdWrapper</a>,方便用户实现压缩功能。</p>
<p>使用示例:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">byte</span><span class="o">[]</span> <span class="n">value</span> <span class="o">=</span> <span class="s">"xxx"</span><span class="o">;</span>
<span class="c1">// write the record into pegasus</span>
<span class="n">table</span><span class="o">.</span><span class="na">set</span><span class="o">(</span><span class="s">"h"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(),</span> <span class="s">"s"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(),</span> <span class="nc">ZstdWrapper</span><span class="o">.</span><span class="na">compress</span><span class="o">(</span><span class="n">value</span><span class="o">),</span> <span class="mi">1000</span><span class="o">);</span>
<span class="c1">// read the record from pegasus</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">compressedBuf</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"h"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(),</span> <span class="s">"s"</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(),</span> <span class="mi">1000</span><span class="o">);</span>
<span class="c1">// decompress the value</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">orginalValue</span> <span class="o">=</span> <span class="nc">ZstdWrapper</span><span class="o">.</span><span class="na">decompress</span><span class="o">(</span><span class="n">compressedBuf</span><span class="o">);</span>
</code></pre></div></div>
<p>也可以参考测试用例代码 <a href="https://github.com/XiaoMi/pegasus-java-client/blob/thrift-0.11.0-inlined/src/test/java/com/xiaomi/infra/pegasus/tools/TestZstdWrapper.java">TestZstdWrapper.java</a></p>
<p>以上两个优化 <a href="#数据序列化">数据序列化</a><a href="#数据压缩">数据压缩</a> 可以在客户端同时使用,都是用客户端的CPU换取Pegasus集群的稳定性和读写性能。在通常情况下这都是值得的。</p>
<p>有时候,业务方在开始使用Pegasus的时候,没有采用客户端压缩,但是在使用一段时间后,发现单条数据的value比较大,希望能通过压缩的办法改进性能。可以分两步:</p>
<ul>
<li><a href="#评估压缩收益">评估压缩收益</a>:评估通过客户端压缩是否能够获得足够好的压缩率。</li>
<li><a href="#使用兼容性压缩">使用兼容性压缩</a>:升级业务端使用Pegasus Java客户端的逻辑,增加客户端压缩支持,同时兼容原来未压缩的数据。</li>
</ul>
<h3 id="评估压缩收益">评估压缩收益</h3>
<p>对于已经存在的表,原来没有采用客户端压缩,如何快速评估采用客户端压缩后有多大收益?</p>
<p>原料:</p>
<ul>
<li>业务集群:user_cluster,meta配置地址为<code class="language-plaintext highlighter-rouge">${user_cluster_meta_list}</code>,其中用户表为user_table。</li>
<li>测试集群:test_cluster,meta配置地址为<code class="language-plaintext highlighter-rouge">${test_cluster_meta_list}</code></li>
<li><a href="/zh/overview/shell">Shell工具</a>:使用1.11.3及以上版本;修改配置文件<code class="language-plaintext highlighter-rouge">src/shell/config.ini</code>,添加访问test_cluster集群的配置项。</li>
<li><a href="#java客户端工具">Java客户端工具</a>:使用1.11.4及以上版本;修改配置文件<code class="language-plaintext highlighter-rouge">pegasus.properties</code>,设置<code class="language-plaintext highlighter-rouge">meta_servers = ${test_cluster_meta_list}</code></li>
</ul>
<p>步骤:</p>
<ul>
<li>使用Shell工具的create命令,在test_cluster集群中新建测试表user_table_no_compress和user_table_zstd_compress:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./run.sh shell --cluster ${test_cluster_meta_list}
&gt;&gt;&gt; create user_table_no_compress -p 8 -r 3
&gt;&gt;&gt; create user_table_zstd_compress -p 8 -r 3
</code></pre></div> </div>
</li>
<li>使用Shell工具的copy_data命令,将业务集群的user_table表的部分数据复制到测试集群的user_table_no_compress表中(在复制足够条数后通过Ctrl-C中断执行):
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./run.sh shell --cluster ${user_cluster_meta_list}
&gt;&gt;&gt; use user_table
&gt;&gt;&gt; copy_data -c test_cluster -a user_table_no_compress
</code></pre></div> </div>
</li>
<li>使用Java客户端工具的copy_data命令,将测试集群user_table_no_compress表的数据复制到user_table_zstd_compress表中,并设置数据写出时采用zstd压缩:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./PegasusCli file://./pegasus.properties user_table_no_compress \
copy_data file://./pegasus.properties user_table_zstd_compress none zstd
</code></pre></div> </div>
</li>
<li>使用Shell工具的count_data命令,分别统计两个测试表的数据大小,然后计算压缩率:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./run.sh shell --cluster ${test_cluster_meta_list}
&gt;&gt;&gt; use user_table_no_compress
&gt;&gt;&gt; count_data -a
&gt;&gt;&gt; use user_table_zstd_compress
&gt;&gt;&gt; count_data -a
</code></pre></div> </div>
</li>
</ul>
<h3 id="使用兼容性压缩">使用兼容性压缩</h3>
<p>业务表原来已经有未压缩的数据,如果应用了客户端压缩,写入新的已压缩的数据,但是hashKey和sortKey保持不变,就会出现未压缩数据和已压缩数据<strong>混合存在</strong>的情况:有的value存储的是未压缩的数据,有的value存储的是已压缩的数据。</p>
<p>这就要求业务端在读数据的时候<strong>保证兼容性</strong>:既能读取未压缩的数据,又能读取已压缩的数据。</p>
<p>基于<strong>未压缩的数据采用zstd进行解压缩时基本都会失败</strong>这一事实,业务端读取的逻辑可以这样:</p>
<ul>
<li>首先,尝试将客户端读到的value数据进行解压缩,如果成功,则说明是已压缩的数据。</li>
<li>如果上一步解压缩失败,则说明读到的是未压缩的数据,不需要解压。</li>
</ul>
<p>示例代码:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// decompress the value</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">decompressedValue</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">decompressedValue</span> <span class="o">=</span> <span class="nc">ZstdWrapper</span><span class="o">.</span><span class="na">decompress</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">PException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// decompress fail</span>
<span class="n">decompressedValue</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>与此同时,可以使用后台工具将未压缩数据逐渐替换掉为已压缩数据,并在替换过程中保证数据的一致性:扫描表,逐条读取数据,如果数据是未压缩的,则将其转换为已压缩的,使用check_and_set原子操作进行数据替换。</p>
<h2 id="客户端连接预热warm-up">客户端连接预热(Warm Up)</h2>
<p>我们提供了提供了客户端连接预热(warmup)功能,在进行openTable时提前拉取路由表并建立连接。这样可以避免在该表的第一次rpc调用时,由于执行上述步骤而导致的该次rpc调用过慢的问题。</p>
<p>示例代码:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nc">PegasusTableInterface</span> <span class="n">table</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="na">openTable</span><span class="o">(</span><span class="n">tableName</span><span class="o">);</span>
</code></pre></div></div>
<h1 id="常见问题">常见问题</h1>
</div>
</section>
<footer class="footer">
<div class="container">
<div class="content is-small has-text-centered">
<div style="margin-bottom: 20px;">
<a href="http://incubator.apache.org">
<img src="/assets/images/egg-logo.png"
width="15%"
alt="Apache Incubator"/>
</a>
</div>
Copyright &copy; 2023 <a href="http://www.apache.org">The Apache Software Foundation</a>.
Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version
2.0</a>.
<br><br>
Apache Pegasus is an effort undergoing incubation at The Apache Software Foundation (ASF),
sponsored by the Apache Incubator. Incubation is required of all newly accepted projects
until a further review indicates that the infrastructure, communications, and decision making process
have stabilized in a manner consistent with other successful ASF projects. While incubation status is
not necessarily a reflection of the completeness or stability of the code, it does indicate that the
project has yet to be fully endorsed by the ASF.
<br><br>
Apache Pegasus, Pegasus, Apache, the Apache feather logo, and the Apache Pegasus project logo are either
registered trademarks or trademarks of The Apache Software Foundation in the United States and other
countries.
</div>
</div>
</footer>
</div>
<!-- right panel -->
<div class="dashboard-panel is-small is-scrollable is-hidden-mobile">
<p class="menu-label">
<span class="icon">
<i class="fa fa-bars" aria-hidden="true"></i>
</span>
本页导航
</p>
<ul class="menu-list">
<li><a href="#获取java客户端">获取Java客户端</a></li>
<li><a href="#客户端配置">客户端配置</a>
<ul>
<li><a href="#文件配置">文件配置</a></li>
<li><a href="#参数传递">参数传递</a></li>
</ul>
</li>
<li><a href="#接口定义">接口定义</a>
<ul>
<li><a href="#创建client实例">创建Client实例</a>
<ul>
<li><a href="#单例">单例</a></li>
<li><a href="#非单例">非单例</a></li>
</ul>
</li>
<li><a href="#pegasusclientinterface接口">PegasusClientInterface接口</a>
<ul>
<li><a href="#get">get</a></li>
<li><a href="#batchget">batchGet</a></li>
<li><a href="#batchget2">batchGet2</a></li>
<li><a href="#multiget">multiGet</a></li>
<li><a href="#batchmultiget">batchMultiGet</a></li>
<li><a href="#batchmultiget2">batchMultiGet2</a></li>
<li><a href="#set">set</a></li>
<li><a href="#batchset">batchSet</a></li>
<li><a href="#batchset2">batchSet2</a></li>
<li><a href="#multiset">multiSet</a></li>
<li><a href="#batchmultiset">batchMultiSet</a></li>
<li><a href="#batchmultiset2">batchMultiSet2</a></li>
<li><a href="#del">del</a></li>
<li><a href="#batchdel">batchDel</a></li>
<li><a href="#batchdel2">batchDel2</a></li>
<li><a href="#multidel">multiDel</a></li>
<li><a href="#batchmultidel">batchMultiDel</a></li>
<li><a href="#batchmultidel2">batchMultiDel2</a></li>
<li><a href="#delrange">delRange</a></li>
<li><a href="#incr">incr</a></li>
<li><a href="#checkandset">checkAndSet</a></li>
<li><a href="#checkandmutate">checkAndMutate</a></li>
<li><a href="#compareexchange">compareExchange</a></li>
<li><a href="#ttl">ttl</a></li>
<li><a href="#exist">exist</a></li>
<li><a href="#sortkeycount">sortKeyCount</a></li>
<li><a href="#multigetsortkeys">multiGetSortKeys</a></li>
<li><a href="#getscanner">getScanner</a></li>
<li><a href="#getunorderedscanner">getUnorderedScanner</a></li>
</ul>
</li>
<li><a href="#创建table实例">创建Table实例</a>
<ul>
<li><a href="#基于future的异步api">基于Future的异步API</a></li>
</ul>
</li>
<li><a href="#pegasustableinterface接口">PegasusTableInterface接口</a>
<ul>
<li><a href="#asyncget">asyncGet</a></li>
<li><a href="#asyncmultiget">asyncMultiGet</a></li>
<li><a href="#asyncset">asyncSet</a></li>
<li><a href="#asyncmultiset">asyncMultiSet</a></li>
<li><a href="#asyncdel">asyncDel</a></li>
<li><a href="#asyncmultidel">asyncMultiDel</a></li>
<li><a href="#asyncincr">asyncIncr</a></li>
<li><a href="#asynccheckandset">asyncCheckAndSet</a></li>
<li><a href="#asynccompareexchange">asyncCompareExchange</a></li>
<li><a href="#asyncttl">asyncTTL</a></li>
<li><a href="#asyncexist">asyncExist</a></li>
<li><a href="#asyncsortkeycount">asyncSortKeyCount</a></li>
<li><a href="#asyncmultigetsortkeys">asyncMultiGetSortKeys</a></li>
</ul>
</li>
<li><a href="#pegasusscannerinterface接口">PegasusScannerInterface接口</a>
<ul>
<li><a href="#next">next</a></li>
<li><a href="#asyncnext">asyncNext</a></li>
</ul>
</li>
<li><a href="#常见异常">常见异常</a>
<ul>
<li><a href="#err_object_not_found">ERR_OBJECT_NOT_FOUND</a></li>
<li><a href="#err_timeout">ERR_TIMEOUT</a></li>
<li><a href="#err_session_reset">ERR_SESSION_RESET</a></li>
<li><a href="#err_busy">ERR_BUSY</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#最佳实践">最佳实践</a>
<ul>
<li><a href="#流量控制">流量控制</a></li>
<li><a href="#分页查询">分页查询</a>
<ul>
<li><a href="#顺序分页">顺序分页</a></li>
<li><a href="#逆序分页">逆序分页</a></li>
</ul>
</li>
<li><a href="#数据序列化">数据序列化</a></li>
<li><a href="#数据压缩">数据压缩</a>
<ul>
<li><a href="#评估压缩收益">评估压缩收益</a></li>
<li><a href="#使用兼容性压缩">使用兼容性压缩</a></li>
</ul>
</li>
<li><a href="#客户端连接预热warm-up">客户端连接预热(Warm Up)</a></li>
</ul>
</li>
<li><a href="#常见问题">常见问题</a></li>
</ul>
</div>
</div>
<script src="/assets/js/app.js" type="text/javascript"></script>
<script>
docsearch({
container: '#docsearch',
appId: 'QRN30RBW0S',
indexName: 'pegasus-apache',
apiKey: 'd3a3252fa344359766707a106c4ed88f',
debug: true
});
</script>
</body>
</html>