You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pegasus.apache.org by la...@apache.org on 2022/04/27 09:52:35 UTC
[incubator-pegasus] branch master updated: chore: Merge repo pegasus-kv/pegic (#960)
This is an automated email from the ASF dual-hosted git repository.
laiyingchun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pegasus.git
The following commit(s) were added to refs/heads/master by this push:
new 2d247a12 chore: Merge repo pegasus-kv/pegic (#960)
2d247a12 is described below
commit 2d247a120af3e48bd8b75e26f9f429d97b41cdeb
Author: Yingchun Lai <ac...@gmail.com>
AuthorDate: Wed Apr 27 17:52:29 2022 +0800
chore: Merge repo pegasus-kv/pegic (#960)
---
...-request-go.yml => lint_and_test_admin-cli.yml} | 6 +-
...yml => lint_and_test_admin-cli_always_pass.yml} | 8 +-
...pull-request-go.yml => lint_and_test_pegic.yml} | 19 +-
...ild.yml => lint_and_test_pegic_always_pass.yml} | 44 ++-
.gitignore | 4 +-
.licenserc.yaml | 1 +
.../.goreleaser.yml | 44 +--
pegic/Makefile | 20 +
pegic/README.md | 253 ++++++++++++
.../check_and_format.sh | 43 +-
pegic/executor/context.go | 137 +++++++
pegic/executor/del.go | 42 ++
pegic/executor/get.go | 59 +++
pegic/executor/partition_index.go | 65 +++
pegic/executor/scan.go | 149 +++++++
pegic/executor/set.go | 42 ++
pegic/executor/util/asciihex.go | 94 +++++
pegic/executor/util/compression.go | 74 ++++
pegic/executor/util/encoding.go | 163 ++++++++
pegic/executor/util/javabytes.go | 57 +++
pegic/go.mod | 34 ++
pegic/go.sum | 439 +++++++++++++++++++++
pegic/interactive/cmd/compression.go | 77 ++++
pegic/interactive/cmd/del.go | 46 +++
pegic/interactive/cmd/encoding.go | 111 ++++++
pegic/interactive/cmd/get.go | 45 +++
pegic/interactive/cmd/init.go | 76 ++++
pegic/interactive/cmd/partition_index.go | 51 +++
pegic/interactive/cmd/scan.go | 117 ++++++
pegic/interactive/cmd/set.go | 47 +++
pegic/interactive/cmd/use.go | 63 +++
pegic/interactive/run.go | 48 +++
pegic/main.go | 45 +++
pegic/shell/app.go | 55 +++
pegic/shell/convert.go | 68 ++++
rdsn | 2 +-
36 files changed, 2544 insertions(+), 104 deletions(-)
diff --git a/.github/workflows/pull-request-go.yml b/.github/workflows/lint_and_test_admin-cli.yml
similarity index 96%
copy from .github/workflows/pull-request-go.yml
copy to .github/workflows/lint_and_test_admin-cli.yml
index b474f812..c6e8dcfe 100644
--- a/.github/workflows/pull-request-go.yml
+++ b/.github/workflows/lint_and_test_admin-cli.yml
@@ -16,7 +16,7 @@
# under the License.
---
# workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - admin-cli
# on events
on:
@@ -37,7 +37,7 @@ on:
# workflow tasks
jobs:
lint:
- name: Golang Lint
+ name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -50,7 +50,7 @@ jobs:
working-directory: ./admin-cli
build:
- name: Golang Test
+ name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
diff --git a/.github/workflows/pull-request-go-always-pass.yml b/.github/workflows/lint_and_test_admin-cli_always_pass.yml
similarity index 93%
copy from .github/workflows/pull-request-go-always-pass.yml
copy to .github/workflows/lint_and_test_admin-cli_always_pass.yml
index bf2a4996..5189678d 100644
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/.github/workflows/lint_and_test_admin-cli_always_pass.yml
@@ -16,7 +16,7 @@
# under the License.
---
# workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - admin-cli
# on events
on:
@@ -28,7 +28,7 @@ on:
- 'v[0-9]+.*' # release branch
- ci-test # testing branch for github action
- '*dev'
- paths:
+ paths-ignore:
- admin-cli/**
# for manually triggering workflow
@@ -37,13 +37,13 @@ on:
# workflow tasks
jobs:
lint:
- name: Golang Lint
+ name: Lint
runs-on: ubuntu-latest
steps:
- run: 'echo "No build required" '
build:
- name: Golang Test
+ name: Test
runs-on: ubuntu-latest
steps:
- run: 'echo "No build required" '
diff --git a/.github/workflows/pull-request-go.yml b/.github/workflows/lint_and_test_pegic.yml
similarity index 83%
rename from .github/workflows/pull-request-go.yml
rename to .github/workflows/lint_and_test_pegic.yml
index b474f812..d193252d 100644
--- a/.github/workflows/pull-request-go.yml
+++ b/.github/workflows/lint_and_test_pegic.yml
@@ -16,20 +16,20 @@
# under the License.
---
# workflow name
-name: Golang Lint and Unit Test
+name: Golang Lint and Unit Test - pegic
# on events
on:
# run on each pull request
pull_request:
- types: [ synchronize, opened, reopened ]
+ types: [ synchronize, reopened, opened ]
branches:
- master
- 'v[0-9]+.*' # release branch
- ci-test # testing branch for github action
- '*dev'
paths:
- - admin-cli/**
+ - pegic/**
# for manually triggering workflow
workflow_dispatch:
@@ -37,7 +37,7 @@ on:
# workflow tasks
jobs:
lint:
- name: Golang Lint
+ name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
@@ -47,10 +47,10 @@ jobs:
uses: golangci/golangci-lint-action@v3
with:
version: v1.29
- working-directory: ./admin-cli
+ working-directory: ./pegic
build:
- name: Golang Test
+ name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -61,9 +61,6 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: 1.14
- - name: Compile
- working-directory: ./admin-cli
+ - name: Compile
+ working-directory: ./pegic
run: make
- - name: Test
- working-directory: ./admin-cli
- run: make test
diff --git a/.github/workflows/cross-build.yml b/.github/workflows/lint_and_test_pegic_always_pass.yml
similarity index 62%
rename from .github/workflows/cross-build.yml
rename to .github/workflows/lint_and_test_pegic_always_pass.yml
index 407e68e2..f4ab4929 100644
--- a/.github/workflows/cross-build.yml
+++ b/.github/workflows/lint_and_test_pegic_always_pass.yml
@@ -16,32 +16,34 @@
# under the License.
---
# workflow name
-name: Generate release-artifacts
+name: Golang Lint and Unit Test - pegic
# on events
on:
- release:
- types:
- - created
+ # run on each pull request
+ pull_request:
+ types: [ synchronize, opened, reopened ]
+ branches:
+ - master
+ - 'v[0-9]+.*' # release branch
+ - ci-test # testing branch for github action
+ - '*dev'
+ paths-ignore:
+ - pegic/**
+
+ # for manually triggering workflow
+ workflow_dispatch:
# workflow tasks
jobs:
- goreleaser:
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+ steps:
+ - run: 'echo "No build required" '
+
+ build:
+ name: Test
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v2
- with:
- fetch-depth: 0
- - name: Set up Go
- uses: actions/setup-go@v2
- with:
- go-version: 1.14
- - name: Run GoReleaser
- uses: goreleaser/goreleaser-action@v2
- with:
- workdir: ./admin-cli
- version: latest
- args: release --rm-dist
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - run: 'echo "No build required" '
diff --git a/.gitignore b/.gitignore
index 749cab97..6ef6753e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,9 +106,8 @@ LOG
.vscode/
.history/
-.admin-cli-history
+.*-history
-.shell-history
PACKAGE
scripts/py_utils/*.pyc
cmake-build-debug
@@ -121,4 +120,5 @@ pegasus-server*
*.log
admin-cli/bin/
+pegic/bin/
golangci-*
diff --git a/.licenserc.yaml b/.licenserc.yaml
index 94ef4d3a..036af421 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -37,5 +37,6 @@ header:
- 'src/shell/sds/sds.h'
- 'src/shell/sds/sdsalloc.h'
- 'admin-cli/go.sum'
+ - 'pegic/go.sum'
comment: on-failure
diff --git a/.github/workflows/pull-request-go-always-pass.yml b/pegic/.goreleaser.yml
similarity index 55%
copy from .github/workflows/pull-request-go-always-pass.yml
copy to pegic/.goreleaser.yml
index bf2a4996..fc721c7d 100644
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/pegic/.goreleaser.yml
@@ -15,35 +15,15 @@
# specific language governing permissions and limitations
# under the License.
---
-# workflow name
-name: Golang Lint and Unit Test
-
-# on events
-on:
- # run on each pull request
- pull_request:
- types: [ synchronize, opened, reopened ]
- branches:
- - master
- - 'v[0-9]+.*' # release branch
- - ci-test # testing branch for github action
- - '*dev'
- paths:
- - admin-cli/**
-
- # for manually triggering workflow
- workflow_dispatch:
-
-# workflow tasks
-jobs:
- lint:
- name: Golang Lint
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required" '
-
- build:
- name: Golang Test
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required" '
+builds:
+ - goos:
+ - linux
+ - darwin
+ - windows
+ goarch:
+ - amd64
+ - arm64
+ goarm:
+ - 7
+ main: ./main.go
+ binary: pegic
diff --git a/pegic/Makefile b/pegic/Makefile
new file mode 100644
index 00000000..00454d5e
--- /dev/null
+++ b/pegic/Makefile
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+build:
+ go mod verify && go mod tidy
+ go build -o bin/pegic main.go
diff --git a/pegic/README.md b/pegic/README.md
new file mode 100644
index 00000000..4f2b6ee0
--- /dev/null
+++ b/pegic/README.md
@@ -0,0 +1,253 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+# pegic, another PEGasus Interactive Cli
+
+Pegic is a user-facing command-line tool to read/write your data on Pegasus.
+
+## Quick Start
+
+To connect to an existing Pegasus cluster, you need to specify the Pegasus address:
+
+```sh
+./pegic --meta 127.0.0.1:34601,127.0.0.2:34601
+```
+
+`127.0.0.1:34601,127.0.0.2:34601` is a list of MetaServer addresses. It's a comma (',') separated string.
+
+Before starting read/write command, you need to firstly select a table to operate.
+
+```
+pegic » use xiaomi_ad_data
+```
+
+This command opens a table called "xiaomi_ad_data". Every operation followed is applied to this table.
+
+## Commands
+
+* [Set/Get/Del](#setgetdel)
+* [Encoding](#encoding)
+* [Scan](#scan)
+
+This is an overview of the commands that pegic provides.
+
+```txt
+Commands:
+ clear clear the screen
+ compression read the current compression algorithm
+ del delete a record
+ encoding read the current encoding
+ exit exit the shell
+ get read a record from Pegasus
+ help use 'help [command]' for command help
+ partition-index ADVANCED: calculate the partition index where the hashkey is routed to
+ scan scan records under the hashkey
+ set write a record into Pegasus
+ use select a table
+```
+
+### Set/Get/Del
+
+```
+pegic » set "hashkey::1" "sortkey" "value::1"
+
+ok
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+```
+
+Set/Get/Del correspond to "Write","Read" and "Delete" to a table. Each manipulates on only single record.
+
+```
+pegic » get "hashkey::1" "sortkey"
+
+hashkey::1 : sortkey : value::1
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+```
+
+The first argument is the "hashkey", which is used for partitioning. The second argument is the "sortkey", that's key-ordering under the hashkey.
+
+`set` command has the third argument, the "value", which is the record body, the main data.
+
+### Encoding
+
+Pegasus stores the entire record in raw bytes, the database is unaware of the actual encoding of the data. By default, when you use pegic, the "hashkey", "sortkey" and "value" will be encoded in UTF-8 from string to bytes.
+
+```
+pegic » set "中国" "北京" "abcdefg"
+
+ok
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+
+pegic » get "中国" "北京"
+
+中国 : 北京 : abcdefg
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+```
+
+However, the fields could also be set with other encodings like `ByteBuffer.allocate(4).putInt(1695609641).array()`, or be encoded via binary-serialization protocols like thrift/protobuf.
+
+Here's an example where hashkey is encoded as an integer:
+
+```
+pegic » encoding hashkey int32
+
+Encoding:
+ - HashKey: INT32
+ - SortKey: UTF8
+ - Value: UTF8
+
+pegic » get 19491001 "sortkey"
+
+19491001 : sortkey : value
+
+Encoding:
+ - HashKey: INT32
+ - SortKey: UTF8
+ - Value: UTF8
+```
+
+If the encoding is not correctly matched to the data, the result will be unexpected.
+
+```
+pegic » encoding hashkey utf8
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+
+pegic » get 19491001 "sortkey"
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+
+error: record not found
+HASH_KEY=19491001
+SORT_KEY=sortkey
+```
+
+### Supported encodings
+
+- `utf8`: The default encoding.
+
+- `int32`: 32-bit integer.
+
+- `int64`: 64-bit integer.
+
+- `bytes`: The golang byte array. Each byte is from range [0, 255]. For example: "104,101,108,108,111,32,119,111,114,108,100".
+
+- `javabytes`: The java byte array. Each byte is from range [-128, 127]. For example: `49,48,52,48,56,10,0,3,-1,-1,0`.
+
+- `asciihex`: For example `\x00\x00\x00e\x0C\x00\x01\x08\x00\x01\x00\x00\x00e\x08`.
+
+Please submit an issue if there's encoding not supported but generally useful.
+
+### Compression
+
+In some use-cases, we need to compress our value in order to improve read/write
+performance and latency stability.
+
+For those data, you need to specify the compression algorithm in pegic:
+
+```
+pegic » compression set zstd
+ok
+
+pegic » get novelcoldstart novelcoldstart
+novelcoldstart : novelcoldstart : abcdef
+
+TTL(Time-To-Live) is not set
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+Compression:
+ zstd
+```
+
+### Scan
+
+```
+pegic » scan "中国"
+中国 : 上海 : {"people_num": 35000000}
+中国 : 北京 : {"people_num": 40000000}
+中国 : 广州 : {"people_num": 28000000}
+中国 : 成都 : {"people_num": 20000000}
+
+Total records count: 4
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: UTF8
+```
+
+`scan` iterates over all the records under the given hashkey. If you only want a subset of
+the records within a given range, or to filter out the records that matched some pattern,
+you can specify the flags according to your needs.
+
+Scan with range:
+
+```
+pegic » scan --from 20200714000000 --to 20200715000000 uid18456112
+uid18456112 : 20200714151429 : {"login": "Beijing"}
+uid18456112 : 20200714152021 : {"login": "Beijing"}
+uid18456112 : 20200714153342 : {"login": "Beijing"}
+
+Total records count: 3
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: INT64
+ - Value: UTF8
+```
+
+Scan with filtering pattern:
+
+```
+pegic » scan --prefix rocksdb pegasus
+pegasus : rocksdb_index_size_mb : 4300
+pegasus : rocksdb_memtable_size_mb : 2000
+pegasus : rocksdb_sst_size_mb : 358000
+
+Total records count: 3
+
+Encoding:
+ - HashKey: UTF8
+ - SortKey: UTF8
+ - Value: INT64
+```
diff --git a/.github/workflows/pull-request-go-always-pass.yml b/pegic/check_and_format.sh
old mode 100644
new mode 100755
similarity index 55%
rename from .github/workflows/pull-request-go-always-pass.yml
rename to pegic/check_and_format.sh
index bf2a4996..f6d6f095
--- a/.github/workflows/pull-request-go-always-pass.yml
+++ b/pegic/check_and_format.sh
@@ -1,3 +1,6 @@
+#!/usr/bin/env bash
+
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -14,36 +17,16 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
----
-# workflow name
-name: Golang Lint and Unit Test
-
-# on events
-on:
- # run on each pull request
- pull_request:
- types: [ synchronize, opened, reopened ]
- branches:
- - master
- - 'v[0-9]+.*' # release branch
- - ci-test # testing branch for github action
- - '*dev'
- paths:
- - admin-cli/**
+#
- # for manually triggering workflow
- workflow_dispatch:
+PROJECT_DIR=$(dirname "${SCRIPT_DIR}")
+cd "${PROJECT_DIR}" || exit 1
-# workflow tasks
-jobs:
- lint:
- name: Golang Lint
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required" '
+if [ ! -f "${PROJECT_DIR}"/golangci-lint-1.35.2-linux-amd64/golangci-lint ]; then
+ wget https://github.com/golangci/golangci-lint/releases/download/v1.35.2/golangci-lint-1.35.2-linux-amd64.tar.gz
+ tar -xzvf golangci-lint-1.35.2-linux-amd64.tar.gz
+fi
- build:
- name: Golang Test
- runs-on: ubuntu-latest
- steps:
- - run: 'echo "No build required" '
+gofmt -l -w .
+go mod tidy
+golangci-lint-1.35.2-linux-amd64/golangci-lint run -v -E gofmt -E golint
diff --git a/pegic/executor/context.go b/pegic/executor/context.go
new file mode 100644
index 00000000..d5bf104d
--- /dev/null
+++ b/pegic/executor/context.go
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/XiaoMi/pegasus-go-client/pegasus"
+ "github.com/XiaoMi/pegasus-go-client/session"
+ "github.com/apache/incubator-pegasus/pegic/executor/util"
+)
+
+type Context struct {
+ // Every command should use Context as the fmt.Fprint's writer.
+ io.Writer
+
+ pegasus.Client
+
+ Meta *session.MetaManager
+
+ // default to nil
+ UseTable pegasus.TableConnector
+ UseTableName string
+ // default to 0
+ UseTablePartitionCount int
+
+ // default to nil
+ Compressor util.BytesCompression
+
+ HashKeyEnc, SortKeyEnc, ValueEnc util.Encoder
+}
+
+func NewContext(writer io.Writer, metaAddrs []string) *Context {
+ c := &Context{
+ Writer: writer,
+ Client: pegasus.NewClient(pegasus.Config{
+ MetaServers: metaAddrs,
+ }),
+ Meta: session.NewMetaManager(metaAddrs, session.NewNodeSession),
+
+ // by default, string uses utf-8 as encoding to bytes
+ HashKeyEnc: util.NewEncoder("utf8"),
+ SortKeyEnc: util.NewEncoder("utf8"),
+ ValueEnc: util.NewEncoder("utf8"),
+ }
+ return c
+}
+
+// String returns a human-readable string of context.
+func (c *Context) String() string {
+ output := "\nEncoding:\n"
+ output += " - HashKey: " + c.HashKeyEnc.String() + "\n"
+ output += " - SortKey: " + c.SortKeyEnc.String() + "\n"
+ output += " - Value: " + c.ValueEnc.String() + "\n"
+ if c.Compressor != nil {
+ output += "Compression:\n"
+ output += " " + c.Compressor.String() + "\n"
+ }
+ return output
+}
+
+// readPegasusArgs assumes the args to be [hashkey, sortkey, value].
+// It returns the bytes encoded from the args if no failure.
+func readPegasusArgs(ctx *Context, args []string) ([][]byte, error) {
+ // the first argument must be hashkey
+ hashkey, err := ctx.HashKeyEnc.EncodeAll(args[0])
+ if err != nil {
+ return nil, err
+ }
+ if len(args) == 1 {
+ return [][]byte{hashkey}, nil
+ }
+
+ sortkey, err := ctx.SortKeyEnc.EncodeAll(args[1])
+ if err != nil {
+ return nil, err
+ }
+ if len(args) == 2 {
+ return [][]byte{hashkey, sortkey}, nil
+ }
+
+ value, err := ctx.ValueEnc.EncodeAll(args[2])
+ if err != nil {
+ return nil, err
+ }
+ if len(args) == 3 {
+ return [][]byte{hashkey, sortkey, value}, nil
+ }
+
+ panic("more than 3 arguments are given")
+}
+
+// printPegasusRecord prints bytes from pegasus in pretty and parsable form.
+func printPegasusRecord(ctx *Context, hashKey, sortKey, value []byte) error {
+ if ctx.Compressor != nil {
+ var err error
+ value, err = ctx.Compressor.Decompress(value)
+ if err != nil {
+ return fmt.Errorf("%s failed to decompress value: %s", ctx.Compressor, err)
+ }
+ }
+
+ hashKeyStr, err := ctx.HashKeyEnc.DecodeAll(hashKey)
+ if err != nil {
+ return fmt.Errorf("HashKey can not be decoded in %s: %s", ctx.HashKeyEnc, err)
+ }
+ sortkeyStr, err := ctx.SortKeyEnc.DecodeAll(sortKey)
+ if err != nil {
+ return fmt.Errorf("SortKey can not be decoded in %s: %s", ctx.SortKeyEnc, err)
+ }
+ valueStr, err := ctx.ValueEnc.DecodeAll(value)
+ if err != nil {
+ bytesEnc := util.NewEncoder("javabytes")
+ valueStr, _ := bytesEnc.DecodeAll(value)
+ return fmt.Errorf("Value can not be decoded in %s: %s [SortKey: \"%s\"]\nValue: [JAVABYTES]\n%s", ctx.ValueEnc, err, sortKey, valueStr)
+ }
+ fmt.Fprintf(ctx, "%s : %s : %s\n", hashKeyStr, sortkeyStr, valueStr)
+ return nil
+}
diff --git a/pegic/executor/del.go b/pegic/executor/del.go
new file mode 100644
index 00000000..18246784
--- /dev/null
+++ b/pegic/executor/del.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "context"
+ "fmt"
+ "time"
+)
+
+func Del(rootCtx *Context, hashKeyStr, sortkeyStr string) error {
+ pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, sortkeyStr})
+ if err != nil {
+ return err
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ err = rootCtx.UseTable.Del(ctx, pegasusArgs[0], pegasusArgs[1])
+ if err != nil {
+ return err
+ }
+ fmt.Fprintln(rootCtx, "\nok")
+ return nil
+}
diff --git a/pegic/executor/get.go b/pegic/executor/get.go
new file mode 100644
index 00000000..b2fadd08
--- /dev/null
+++ b/pegic/executor/get.go
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "context"
+ "fmt"
+ "time"
+)
+
+func Get(rootCtx *Context, hashKeyStr, sortkeyStr string) error {
+ pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, sortkeyStr})
+ if err != nil {
+ return err
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ rawValue, err := rootCtx.UseTable.Get(ctx, pegasusArgs[0], pegasusArgs[1])
+ if err != nil {
+ return err
+ }
+ if rawValue == nil {
+ return fmt.Errorf("record not found\nHASH_KEY=%s\nSORT_KEY=%s", hashKeyStr, sortkeyStr)
+ }
+
+ if err = printPegasusRecord(rootCtx, pegasusArgs[0], pegasusArgs[1], rawValue); err != nil {
+ return err
+ }
+
+ ttl, err := rootCtx.UseTable.TTL(ctx, pegasusArgs[0], pegasusArgs[1])
+ if err != nil {
+ return err
+ }
+ if ttl == -1 {
+ fmt.Fprintf(rootCtx, "\nTTL(Time-To-Live) is not set\n")
+ } else {
+ fmt.Fprintf(rootCtx, "\nTTL(Time-To-Live) : %d seconds\n", ttl)
+ }
+
+ return nil
+}
diff --git a/pegic/executor/partition_index.go b/pegic/executor/partition_index.go
new file mode 100644
index 00000000..31ac3b53
--- /dev/null
+++ b/pegic/executor/partition_index.go
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "context"
+ "fmt"
+ "hash/crc64"
+ "time"
+
+ "github.com/XiaoMi/pegasus-go-client/idl/base"
+)
+
+var crc64Table = crc64.MakeTable(0x9a6c9329ac4bc9b5)
+
+func crc64Hash(data []byte) uint64 {
+ return crc64.Checksum(data, crc64Table)
+}
+
+func getPartitionIndex(hashKey []byte, partitionCount int) int32 {
+ return int32(crc64Hash(hashKey) % uint64(partitionCount))
+}
+
+func PartitionIndex(rootCtx *Context, hashKeyStr string) error {
+ pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr})
+ if err != nil {
+ return err
+ }
+
+ if rootCtx.UseTablePartitionCount == 0 {
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+
+ resp, err := rootCtx.Meta.QueryConfig(ctx, rootCtx.UseTableName)
+ if err != nil {
+ return err
+ }
+ if resp.GetErr().Errno != base.ERR_OK.String() {
+ return fmt.Errorf("QueryConfig failed: %s", resp.GetErr().String())
+ }
+ rootCtx.UseTablePartitionCount = int(resp.PartitionCount)
+ }
+
+ partIdx := getPartitionIndex(pegasusArgs[0], rootCtx.UseTablePartitionCount)
+ fmt.Fprintf(rootCtx, "\nPartition index : %d\n", partIdx)
+
+ return nil
+}
diff --git a/pegic/executor/scan.go b/pegic/executor/scan.go
new file mode 100644
index 00000000..e169b922
--- /dev/null
+++ b/pegic/executor/scan.go
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/XiaoMi/pegasus-go-client/pegasus"
+)
+
+// ScanCommand wraps scan command input.
+type ScanCommand struct {
+ HashKey string
+
+ // optional
+ From, To *string
+ Prefix, Suffix, Contains *string
+
+ // only calculate the count of sortkeys under this hashkey.
+ // default to false.
+ CountOnly bool
+}
+
+// IterateAll iterates over the table according to the command.
+func (s *ScanCommand) IterateAll(rootCtx *Context) error {
+ hashkey, err := rootCtx.HashKeyEnc.EncodeAll(s.HashKey)
+ if err != nil {
+ return fmt.Errorf("invalid hashkey: %s", err)
+ }
+
+ var startSortKey, stopSortKey, filterPattern []byte
+ var filterType pegasus.FilterType
+
+ if s.From != nil {
+ startSortKey, err = rootCtx.SortKeyEnc.EncodeAll(*s.From)
+ if err != nil {
+ return fmt.Errorf("invalid startSortKey: %s", err)
+ }
+ }
+ if s.To != nil {
+ stopSortKey, err = rootCtx.SortKeyEnc.EncodeAll(*s.To)
+ if err != nil {
+ return fmt.Errorf("invalid stopSortKey: %s", err)
+ }
+ }
+
+ var filterStr *string
+ if s.Prefix != nil {
+ filterStr = s.Prefix
+ filterType = pegasus.FilterTypeMatchPrefix
+ }
+ if s.Suffix != nil {
+ filterStr = s.Suffix
+ filterType = pegasus.FilterTypeMatchPostfix
+ }
+ if s.Contains != nil {
+ filterStr = s.Contains
+ filterType = pegasus.FilterTypeMatchAnywhere
+ }
+ if filterStr != nil {
+ filterPattern, err = rootCtx.SortKeyEnc.EncodeAll(*filterStr)
+ if err != nil {
+ return fmt.Errorf("invalid filter: %s", err)
+ }
+ }
+
+ sopts := &pegasus.ScannerOptions{
+ BatchSize: 5,
+ SortKeyFilter: pegasus.Filter{
+ Type: filterType,
+ Pattern: filterPattern,
+ },
+ // TODO(wutao): provide options
+ StartInclusive: true,
+ StopInclusive: true,
+ NoValue: s.CountOnly,
+ }
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ scanner, err := rootCtx.UseTable.GetScanner(ctx, hashkey, startSortKey, stopSortKey, sopts)
+ if err != nil {
+ return err
+ }
+ return s.iterateAllWithScanner(rootCtx, scanner)
+}
+
+// Validate if ScanCommand is valid.
+func (s *ScanCommand) Validate() error {
+ cnt := 0
+ if s.Prefix != nil {
+ cnt++
+ }
+ if s.Suffix != nil {
+ cnt++
+ }
+ if s.Contains != nil {
+ cnt++
+ }
+ if cnt > 1 {
+ return fmt.Errorf("should specify only one of prefix|suffix|contains")
+ }
+ return nil
+}
+
+// iterateAllWithScanner prints all entries owned by scanner.
+func (s *ScanCommand) iterateAllWithScanner(rootCtx *Context, scanner pegasus.Scanner) error {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+
+ recordsCnt := uint64(0)
+ for {
+ completed, hashKey, sortKey, value, err := scanner.Next(ctx)
+ if err != nil {
+ return err
+ }
+ if completed {
+ break
+ }
+ recordsCnt++
+ if s.CountOnly {
+ continue
+ }
+ err = printPegasusRecord(rootCtx, hashKey, sortKey, value)
+ if err != nil {
+ return err
+ }
+ }
+ fmt.Fprintf(rootCtx, "\nTotal records count: %d\n", recordsCnt)
+ return nil
+}
diff --git a/pegic/executor/set.go b/pegic/executor/set.go
new file mode 100644
index 00000000..2b6dd716
--- /dev/null
+++ b/pegic/executor/set.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package executor
+
+import (
+ "context"
+ "fmt"
+ "time"
+)
+
+func Set(rootCtx *Context, hashKeyStr, sortkeyStr, valueStr string) error {
+ pegasusArgs, err := readPegasusArgs(rootCtx, []string{hashKeyStr, sortkeyStr, valueStr})
+ if err != nil {
+ return err
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ err = rootCtx.UseTable.Set(ctx, pegasusArgs[0], pegasusArgs[1], pegasusArgs[2])
+ if err != nil {
+ return err
+ }
+ fmt.Fprintln(rootCtx, "\nok")
+ return nil
+}
diff --git a/pegic/executor/util/asciihex.go b/pegic/executor/util/asciihex.go
new file mode 100644
index 00000000..3cf88182
--- /dev/null
+++ b/pegic/executor/util/asciihex.go
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package util
+
+import (
+ "encoding/hex"
+ "fmt"
+)
+
+type asciiHexEncoder struct {
+}
+
+func (*asciiHexEncoder) EncodeAll(s string) ([]byte, error) {
+ var bs []byte
+
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\\' {
+ if i+1 >= len(s) {
+ return nil, fmt.Errorf("invalid asciihex string: %s", s)
+ }
+
+ i++
+ switch s[i] {
+ case 'n':
+ bs = append(bs, '\n')
+ case 'r':
+ bs = append(bs, '\r')
+ case 't':
+ bs = append(bs, '\t')
+ case '"':
+ bs = append(bs, '"')
+ case '\'':
+ bs = append(bs, '\'')
+ case '\\':
+ bs = append(bs, '\\')
+ case 'x', 'X':
+ if i+2 >= len(s) {
+ return nil, fmt.Errorf("invalid asciihex string: %s", s)
+ }
+ digit1 := s[i+1]
+ digit2 := s[i+2]
+ i += 2
+
+ var hexStr string
+ hexStr += string(digit1) + string(digit2)
+ bytes, err := hex.DecodeString(hexStr)
+ if err != nil {
+ return nil, err
+ }
+ if len(bytes) != 1 {
+ panic("two hex digits should be 1 byte")
+ }
+
+ bs = append(bs, bytes[0])
+ }
+ } else if s[i] >= 32 && s[i] <= 126 {
+ // valid ascii character
+ bs = append(bs, s[i])
+ } else {
+ return nil, fmt.Errorf("invalid asciihex string: %s", s)
+ }
+ }
+ return bs, nil
+}
+
+func (*asciiHexEncoder) DecodeAll(bytes []byte) (string, error) {
+ var s string
+ for _, c := range bytes {
+ hexByte := hex.EncodeToString([]byte{c})
+ s += "\\x" + hexByte
+ }
+ return s, nil
+}
+
+func (*asciiHexEncoder) String() string {
+ return "ASCIIHEX"
+}
diff --git a/pegic/executor/util/compression.go b/pegic/executor/util/compression.go
new file mode 100644
index 00000000..c3b66fc3
--- /dev/null
+++ b/pegic/executor/util/compression.go
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package util
+
+import (
+ "strings"
+
+ "github.com/klauspost/compress/zstd"
+)
+
+// BytesCompression is an interface of algorithm for compressing bytes.
+type BytesCompression interface {
+ Compress([]byte) ([]byte, error)
+
+ Decompress([]byte) ([]byte, error)
+
+ // String returns name of the algorithm.
+ String() string
+}
+
+// NewCompression returns nil if the given name is invalid.
+func NewCompression(name string) BytesCompression {
+ name = strings.ToLower(name)
+ switch name {
+ case "zstd":
+ return newZstdCompression()
+ default:
+ return nil
+ }
+}
+
+type zstdCompression struct {
+ encoder *zstd.Encoder
+ decoder *zstd.Decoder
+}
+
+func (z *zstdCompression) Compress(data []byte) ([]byte, error) {
+ return z.encoder.EncodeAll(data, make([]byte, 0, len(data))), nil
+}
+
+func (z *zstdCompression) Decompress(data []byte) ([]byte, error) {
+ return z.decoder.DecodeAll(data, nil)
+}
+
+func (z *zstdCompression) String() string {
+ return "zstd"
+}
+
+func newZstdCompression() BytesCompression {
+ decoder, _ := zstd.NewReader(nil)
+ encoder, _ := zstd.NewWriter(nil)
+
+ return &zstdCompression{
+ encoder: encoder,
+ decoder: decoder,
+ }
+}
diff --git a/pegic/executor/util/encoding.go b/pegic/executor/util/encoding.go
new file mode 100644
index 00000000..cf97e35f
--- /dev/null
+++ b/pegic/executor/util/encoding.go
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package util
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+)
+
+type Encoder interface {
+ // encode string into a bytes
+ EncodeAll(string) ([]byte, error)
+
+ // decode from bytes to string
+ DecodeAll([]byte) (string, error)
+
+ // String returns name of the encoding.
+ String() string
+}
+
+type utf8Encoder struct {
+}
+
+func (*utf8Encoder) EncodeAll(s string) ([]byte, error) {
+ if !utf8.ValidString(s) {
+ return nil, errors.New("invalid utf8 string")
+ }
+ return []byte(s), nil // go uses utf8 by default.
+}
+
+func (*utf8Encoder) DecodeAll(s []byte) (string, error) {
+ if !utf8.Valid(s) {
+ return "", errors.New("invalid utf8 bytes")
+ }
+ return string(s), nil
+}
+
+func (*utf8Encoder) String() string {
+ return "UTF8"
+}
+
+type int32Encoder struct {
+}
+
+func (*int32Encoder) EncodeAll(s string) ([]byte, error) {
+ i, err := strconv.ParseInt(s, 10, 32 /*bits*/)
+ if err != nil {
+ return nil, errors.New("invalid INT32")
+ }
+ value := make([]byte, 4 /*bytes*/)
+ binary.BigEndian.PutUint32(value, uint32(i))
+ return value, nil
+}
+
+func (*int32Encoder) DecodeAll(s []byte) (string, error) {
+ if len(s) != 4 {
+ return "", fmt.Errorf("bytes is not a valid INT32")
+ }
+ i := binary.BigEndian.Uint32(s)
+ return fmt.Sprint(int32(i)), nil
+}
+
+func (*int32Encoder) String() string {
+ return "INT32"
+}
+
+type int64Encoder struct {
+}
+
+func (*int64Encoder) EncodeAll(s string) ([]byte, error) {
+ i, err := strconv.ParseInt(s, 10, 64 /*bits*/)
+ if err != nil {
+ return nil, errors.New("invalid INT64")
+ }
+ value := make([]byte, 8 /*bytes*/)
+ binary.BigEndian.PutUint64(value, uint64(i))
+ return value, nil
+}
+
+func (*int64Encoder) DecodeAll(s []byte) (string, error) {
+ if len(s) != 8 {
+ return "", fmt.Errorf("bytes is not a valid INT64")
+ }
+ i := binary.BigEndian.Uint64(s)
+ return fmt.Sprint(int64(i)), nil
+}
+
+func (*int64Encoder) String() string {
+ return "INT64"
+}
+
+type goBytesEncoder struct {
+}
+
+func (*goBytesEncoder) EncodeAll(s string) ([]byte, error) {
+ bytesInStrList := strings.Split(s, " ")
+
+ value := make([]byte, len(bytesInStrList))
+ for i, byteStr := range bytesInStrList {
+ b, err := strconv.Atoi(byteStr)
+ if err != nil || b > 255 || b < 0 { // byte ranges from [0, 255]
+ return nil, fmt.Errorf("invalid go byte \"%s\"", byteStr)
+ }
+ value[i] = byte(b)
+ }
+
+ return value, nil
+}
+
+func (*goBytesEncoder) DecodeAll(bytes []byte) (string, error) {
+ s := make([]string, len(bytes))
+ for i, c := range bytes {
+ s[i] = fmt.Sprint(uint8(c))
+ }
+ return strings.Join(s, ","), nil
+}
+
+func (*goBytesEncoder) String() string {
+ return "BYTES"
+}
+
+// NewEncoder returns nil if the given name is invalid.
+func NewEncoder(name string) Encoder {
+ name = strings.ToLower(name)
+ switch name {
+ case "utf8", "utf-8":
+ return &utf8Encoder{}
+ case "int32":
+ return &int32Encoder{}
+ case "int64":
+ return &int64Encoder{}
+ case "bytes":
+ return &goBytesEncoder{}
+ case "javabytes":
+ return &javaBytesEncoder{}
+ case "asciihex":
+ return &asciiHexEncoder{}
+ // TODO(wutao): support hex array, such as 0x37, 0xFF, ...
+ default:
+ return nil
+ }
+}
diff --git a/pegic/executor/util/javabytes.go b/pegic/executor/util/javabytes.go
new file mode 100644
index 00000000..ae16d278
--- /dev/null
+++ b/pegic/executor/util/javabytes.go
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package util
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// javabytes is like '0,0,101,12,0,1,8,-1,-1,-1', delimited by ',' and each byte ranges from [-128, 127]
+type javaBytesEncoder struct {
+}
+
+func (*javaBytesEncoder) EncodeAll(s string) ([]byte, error) {
+ bytesInStrList := strings.Split(s, ",")
+
+ value := make([]byte, len(bytesInStrList))
+ for i, byteStr := range bytesInStrList {
+ b, err := strconv.Atoi(byteStr)
+ if err != nil || b > 127 || b < -128 { // byte ranges from [-128, 127]
+ return nil, fmt.Errorf("invalid java byte \"%s\"", byteStr)
+ }
+ value[i] = byte(b)
+ }
+
+ return value, nil
+}
+
+func (*javaBytesEncoder) DecodeAll(bytes []byte) (string, error) {
+ s := make([]string, len(bytes))
+ for i, c := range bytes {
+ s[i] = fmt.Sprint(int8(c))
+ }
+ return strings.Join(s, ","), nil
+}
+
+func (*javaBytesEncoder) String() string {
+ return "JAVABYTES"
+}
diff --git a/pegic/go.mod b/pegic/go.mod
new file mode 100644
index 00000000..eac79d3f
--- /dev/null
+++ b/pegic/go.mod
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+module github.com/apache/incubator-pegasus/pegic
+
+go 1.14
+
+require (
+ github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37
+ github.com/desertbit/grumble v1.1.1
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ github.com/klauspost/compress v1.12.1
+ github.com/sirupsen/logrus v1.8.1
+ github.com/spf13/cobra v1.1.3
+ golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d // indirect
+ golang.org/x/sys v0.0.0-20210415045647-66c3f260301c // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.0.0
+ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+)
diff --git a/pegic/go.sum b/pegic/go.sum
new file mode 100644
index 00000000..e6cbcc3b
--- /dev/null
+++ b/pegic/go.sum
@@ -0,0 +1,439 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37 h1:h1be834SkoleMU2rDxpQuWp4FQhXCPbV1t8yr/fXzXo=
+github.com/XiaoMi/pegasus-go-client v0.0.0-20211126055700-5ae2deb75c37/go.mod h1:VrfgKISflRhFm32m3e0SXLccvNJTyG8PRywWbUuGEfY=
+github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
+github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc=
+github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/desertbit/closer/v3 v3.1.2 h1:a6+2DmwIcNygW04XXWYq+Qp2X9uIk9QbZCP9//qEkb0=
+github.com/desertbit/closer/v3 v3.1.2/go.mod h1:AAC4KRd8DC40nwvV967J/kDFhujMEiuwIKQfN0IDxXw=
+github.com/desertbit/columnize v2.1.0+incompatible h1:h55rYmdrWoTj7w9aAnCkxzM3C2Eb8zuFa2W41t0o5j0=
+github.com/desertbit/columnize v2.1.0+incompatible/go.mod h1:5kPrzQwKbQ8E5D28nvTVPqIBJyj+8jvJzwt6HXZvXgI=
+github.com/desertbit/go-shlex v0.1.1 h1:c65HnbgX1QyC6kPL1dMzUpZ4puNUE6ai/eVucWNLNsk=
+github.com/desertbit/go-shlex v0.1.1/go.mod h1:Qbb+mJNud5AypgHZ81EL8syOGaWlwvAOTqS7XmWI4pQ=
+github.com/desertbit/grumble v1.1.1 h1:1wxy6ka1aqbtA3kZIHaPfB/DD91HSM2m4Kx2QIIGfpE=
+github.com/desertbit/grumble v1.1.1/go.mod h1:r7j3ShNy5EmOsegRD2DzTutIaGiLiA3M5yBTXXeLwcs=
+github.com/desertbit/readline v1.5.1 h1:/wOIZkWYl1s+IvJm/5bOknfUgs6MhS9svRNZpFM53Os=
+github.com/desertbit/readline v1.5.1/go.mod h1:pHQgTsCFs9Cpfh5mlSUFi9Xa5kkL4d8L1Jo4UVWzPw0=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
+github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
+github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.12.1 h1:/+xsCsk06wE38cyiqOR/o7U2fSftcH72xD+BQXmja/g=
+github.com/klauspost/compress v1.12.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
+github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pegasus-kv/thrift v0.13.0 h1:4ESwaNoHImfbHa9RUGJiJZ4hrxorihZHk5aarYwY8d4=
+github.com/pegasus-kv/thrift v0.13.0/go.mod h1:Gl9NT/WHG6ABm6NsrbfE8LiJN0sAyneCrvB4qN4NPqQ=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs=
+golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210415045647-66c3f260301c h1:6L+uOeS3OQt/f4eFHXZcTxeZrGCuz+CLElgEBjbcTA4=
+golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
+gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3 h1:FErmbNIJruD5GT2oVEjtPn5Ar5+rcWJsC8/PPUkR0s4=
+k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
+k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
diff --git a/pegic/interactive/cmd/compression.go b/pegic/interactive/cmd/compression.go
new file mode 100644
index 00000000..4ab35e7b
--- /dev/null
+++ b/pegic/interactive/cmd/compression.go
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/apache/incubator-pegasus/pegic/executor/util"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ rootCmd := &grumble.Command{
+ Name: "compression",
+ Help: "read the current compression algorithm",
+ Run: func(c *grumble.Context) error {
+ if globalContext.Compressor == nil {
+ c.App.Println("No compression is used")
+ } else {
+ c.App.Printf("Compression: %s\n", globalContext.Compressor.String())
+ }
+ return nil
+ },
+ }
+
+ rootCmd.AddCommand(&grumble.Command{
+ Name: "set",
+ Aliases: []string{"SET"},
+ Help: "reset the compression algorithm, default no",
+ Run: func(c *grumble.Context) error {
+ algo := strings.TrimSpace(c.Args.String("ALGORITHM"))
+ if algo == "" || algo == "no" {
+ c.App.Println("Reset to no compression mode")
+ globalContext.Compressor = nil
+ return nil
+ }
+ globalContext.Compressor = util.NewCompression(algo)
+ if globalContext.Compressor == nil {
+ return fmt.Errorf("Invalid compression algorithm \"%s\"", algo)
+ }
+ c.App.Println("ok")
+ return nil
+ },
+ Args: func(a *grumble.Args) {
+ a.String("ALGORITHM", "Compression algorithm. By default no compression is used. Options: zstd", grumble.Default(""))
+ },
+ Completer: compressionCompleter,
+ })
+
+ interactive.App.AddCommand(rootCmd)
+}
+
+func compressionCompleter(prefix string, args []string) []string {
+ return filterStringWithPrefix([]string{
+ "zstd",
+ "no",
+ }, prefix)
+}
diff --git a/pegic/interactive/cmd/del.go b/pegic/interactive/cmd/del.go
new file mode 100644
index 00000000..bb140541
--- /dev/null
+++ b/pegic/interactive/cmd/del.go
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ interactive.App.AddCommand(&grumble.Command{
+ Name: "del",
+ Help: "delete a record",
+ Usage: "del <HASHKEY> <SORTKEY>",
+ Run: requireUseTable(printEndingContext(func(c *grumble.Context) error {
+ if len(c.Args) != 2 {
+ return fmt.Errorf("invalid number (%d) of arguments for `del`", len(c.Args))
+ }
+ return executor.Del(globalContext, c.Args.String("HASHKEY"), c.Args.String("SORTKEY"))
+ })),
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ a.String("SORTKEY", "SortKey")
+ },
+ })
+}
diff --git a/pegic/interactive/cmd/encoding.go b/pegic/interactive/cmd/encoding.go
new file mode 100644
index 00000000..98bad43b
--- /dev/null
+++ b/pegic/interactive/cmd/encoding.go
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/apache/incubator-pegasus/pegic/executor/util"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+var supportedEncodings = []string{
+ "utf8",
+ "int32",
+ "int64",
+ "bytes",
+ "javabytes",
+ "asciihex",
+}
+
+func init() {
+ rootCmd := &grumble.Command{
+ Name: "encoding",
+ Help: "read the current encoding",
+ Run: func(c *grumble.Context) error {
+ c.App.Println(globalContext)
+ return nil
+ },
+ }
+
+ rootCmd.AddCommand(&grumble.Command{
+ Name: "hashkey",
+ Help: fmt.Sprintf("Set encoding for hashkey. Supported encodings: %s", supportedEncodingsToString()),
+ Run: func(c *grumble.Context) error {
+ return resetEncoding(c, &globalContext.HashKeyEnc)
+ },
+ Args: registerArgs,
+ Completer: encodingCompleter,
+ })
+
+ rootCmd.AddCommand(&grumble.Command{
+ Name: "sortkey",
+ Help: fmt.Sprintf("Set encoding for sortkey. Supported encodings: %s", supportedEncodingsToString()),
+ Run: func(c *grumble.Context) error {
+ return resetEncoding(c, &globalContext.SortKeyEnc)
+ },
+ Args: registerArgs,
+ Completer: encodingCompleter,
+ })
+
+ rootCmd.AddCommand(&grumble.Command{
+ Name: "value",
+ Help: fmt.Sprintf("Set encoding for value. Supported encodings: %s", supportedEncodingsToString()),
+ Run: func(c *grumble.Context) error {
+ return resetEncoding(c, &globalContext.ValueEnc)
+ },
+ Args: registerArgs,
+ Completer: encodingCompleter,
+ })
+
+ interactive.App.AddCommand(rootCmd)
+}
+
+// resetEncoding is the generic executor for the encoding-reset commands
+func resetEncoding(c *grumble.Context, encPtr *util.Encoder) error {
+ if len(c.Args) != 1 {
+ return fmt.Errorf("invalid number (%d) of arguments for `encoding %s`", len(c.Args), c.Command.Name)
+ }
+
+ encoding := c.Args.String("ENCODING")
+ enc := util.NewEncoder(encoding)
+ if enc == nil {
+ return fmt.Errorf("uncognized encoding: %s", encoding)
+ }
+ *encPtr = enc
+ c.App.Println(globalContext)
+ return nil
+}
+
+func encodingCompleter(prefix string, args []string) []string {
+ return filterStringWithPrefix(supportedEncodings, prefix)
+}
+
+func supportedEncodingsToString() string {
+ return strings.Join(supportedEncodings, ",")
+}
+
+func registerArgs(a *grumble.Args) {
+ a.String("ENCODING",
+ fmt.Sprintf("The encoding from user string to raw bytes. Supported encodings: %s", supportedEncodingsToString()),
+ grumble.Default("utf8"))
+}
diff --git a/pegic/interactive/cmd/get.go b/pegic/interactive/cmd/get.go
new file mode 100644
index 00000000..8cda53f3
--- /dev/null
+++ b/pegic/interactive/cmd/get.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ interactive.App.AddCommand(&grumble.Command{
+ Name: "get",
+ Help: "read a record from Pegasus",
+ Usage: "get <HASHKEY> <SORTKEY>",
+ Run: requireUseTable(printEndingContext(func(c *grumble.Context) error {
+ if len(c.Args) != 2 {
+ return fmt.Errorf("invalid number (%d) of arguments for `get`", len(c.Args))
+ }
+ return executor.Get(globalContext, c.Args.String("HASHKEY"), c.Args.String("SORTKEY"))
+ })),
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ a.String("SORTKEY", "SortKey")
+ }})
+}
diff --git a/pegic/interactive/cmd/init.go b/pegic/interactive/cmd/init.go
new file mode 100644
index 00000000..0614801a
--- /dev/null
+++ b/pegic/interactive/cmd/init.go
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "errors"
+ "os"
+ "strings"
+
+ "github.com/XiaoMi/pegasus-go-client/session"
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/desertbit/grumble"
+)
+
+var globalContext *executor.Context
+
+func Init(metaAddrs []string) error {
+ // validate meta addresses
+ _, err := session.ResolveMetaAddr(metaAddrs)
+ if err != nil {
+ return err
+ }
+
+ globalContext = executor.NewContext(os.Stdout, metaAddrs)
+ return nil
+}
+
+func requireUseTable(run func(*grumble.Context) error) func(c *grumble.Context) error {
+ grumbleRun := func(c *grumble.Context) error {
+ if globalContext.UseTable == nil {
+ c.App.PrintError(errors.New("please USE a table first"))
+ c.App.Println("Usage: USE <TABLE_NAME>")
+ return nil
+ }
+ return run(c)
+ }
+ return grumbleRun
+}
+
+// filterStringWithPrefix returns strings with the same prefix.
+// This function is commonly used for the auto-completion of commands.
+func filterStringWithPrefix(strs []string, prefix string) []string {
+ var result []string
+ for _, s := range strs {
+ if strings.HasPrefix(s, prefix) {
+ result = append(result, s)
+ }
+ }
+ return result
+}
+
+func printEndingContext(run func(*grumble.Context) error) func(c *grumble.Context) error {
+ grumbleRun := func(c *grumble.Context) error {
+ err := run(c)
+ c.App.Println(globalContext)
+ return err
+ }
+ return grumbleRun
+}
diff --git a/pegic/interactive/cmd/partition_index.go b/pegic/interactive/cmd/partition_index.go
new file mode 100644
index 00000000..48d64b8e
--- /dev/null
+++ b/pegic/interactive/cmd/partition_index.go
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ rootCmd := &grumble.Command{
+ Name: "partition-index",
+ Help: "ADVANCED: calculate the partition index where the hashkey is routed to",
+ Usage: "partition-index <HASHKEY>",
+ Run: requireUseTable(func(c *grumble.Context) error {
+ if len(c.Args) != 1 {
+ return fmt.Errorf("invalid number (%d) of arguments for `partition-index`", len(c.Args))
+ }
+ err := executor.PartitionIndex(globalContext, c.Args.String("HASHKEY"))
+ if err != nil {
+ return err
+ }
+ c.App.Println(globalContext)
+ return nil
+ }),
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ },
+ }
+ interactive.App.AddCommand(rootCmd)
+}
diff --git a/pegic/interactive/cmd/scan.go b/pegic/interactive/cmd/scan.go
new file mode 100644
index 00000000..466dc9b2
--- /dev/null
+++ b/pegic/interactive/cmd/scan.go
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ usage := `<hashKey>
+[ --from <startSortKey> ]
+[ --to <stopSortKey> ]
+[
+ --prefix <filter>
+ --suffix <filter>
+ --contains <filter>
+]`
+
+ scanCmd := &grumble.Command{
+ Name: "scan",
+ Help: "scan records under the hashkey",
+ Usage: "\nscan " + usage,
+ Run: requireUseTable(printEndingContext(func(c *grumble.Context) error {
+ cmd, err := newScanCommand(c)
+ if err != nil {
+ return err
+ }
+ return cmd.IterateAll(globalContext)
+ })),
+ Flags: scanFlags,
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ },
+ }
+
+ scanCmd.AddCommand(&grumble.Command{
+ Name: "count",
+ Help: "scan records under the hashkey",
+ Usage: "\nscan " + usage,
+ Run: requireUseTable(printEndingContext(func(c *grumble.Context) error {
+ cmd, err := newScanCommand(c)
+ if err != nil {
+ return err
+ }
+ cmd.CountOnly = true
+ return cmd.IterateAll(globalContext)
+ })),
+ Flags: scanFlags,
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ },
+ })
+
+ interactive.App.AddCommand(scanCmd)
+}
+
+func newScanCommand(c *grumble.Context) (*executor.ScanCommand, error) {
+ if len(c.Args) < 1 {
+ return nil, fmt.Errorf("missing <hashkey> for `scan`")
+ }
+
+ from := c.Flags.String("from")
+ to := c.Flags.String("to")
+ suffix := c.Flags.String("suffix")
+ prefix := c.Flags.String("prefix")
+ contains := c.Flags.String("contains")
+
+ cmd := &executor.ScanCommand{HashKey: c.Args.String("HASHKEY")}
+ if from != "" {
+ cmd.From = &from
+ }
+ if to != "" {
+ cmd.To = &to
+ }
+ if suffix != "" {
+ cmd.Suffix = &suffix
+ }
+ if prefix != "" {
+ cmd.Prefix = &prefix
+ }
+ if contains != "" {
+ cmd.Contains = &contains
+ }
+ if err := cmd.Validate(); err != nil {
+ return nil, err
+ }
+ return cmd, nil
+}
+
+func scanFlags(f *grumble.Flags) {
+ f.StringL("from", "", "<startSortKey>")
+ f.StringL("to", "", "<stopSortKey>")
+ f.StringL("prefix", "", "<filter>")
+ f.StringL("suffix", "", "<filter>")
+ f.StringL("contains", "", "<filter>")
+}
diff --git a/pegic/interactive/cmd/set.go b/pegic/interactive/cmd/set.go
new file mode 100644
index 00000000..1313796f
--- /dev/null
+++ b/pegic/interactive/cmd/set.go
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "fmt"
+
+ "github.com/apache/incubator-pegasus/pegic/executor"
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ interactive.App.AddCommand(&grumble.Command{
+ Name: "set",
+ Help: "write a record into Pegasus",
+ Usage: "set <HASHKEY> <SORTKEY> <VALUE>",
+ Run: requireUseTable(printEndingContext(func(c *grumble.Context) error {
+ if len(c.Args) != 3 {
+ return fmt.Errorf("invalid number (%d) of arguments for `set`", len(c.Args))
+ }
+ return executor.Set(globalContext, c.Args.String("HASHKEY"), c.Args.String("SORTKEY"), c.Args.String("VALUE"))
+ })),
+ Args: func(a *grumble.Args) {
+ a.String("HASHKEY", "HashKey")
+ a.String("SORTKEY", "SortKey")
+ a.String("VALUE", "Value of the record")
+ },
+ })
+}
diff --git a/pegic/interactive/cmd/use.go b/pegic/interactive/cmd/use.go
new file mode 100644
index 00000000..bf4b4772
--- /dev/null
+++ b/pegic/interactive/cmd/use.go
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package cmd
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/desertbit/grumble"
+)
+
+func init() {
+ interactive.App.AddCommand(&grumble.Command{
+ Name: "use",
+ Help: "select a table",
+ Usage: "use <TABLE_NAME>",
+ Run: func(c *grumble.Context) error {
+ if len(c.Args) != 1 {
+ return fmt.Errorf("invalid number (%d) of arguments for `use`", len(c.Args))
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
+ defer cancel()
+ var tableName = c.Args.String("TABLE")
+ var err error
+ globalContext.UseTable, err = globalContext.OpenTable(ctx, tableName)
+ if err != nil && strings.Contains(err.Error(), "ERR_OBJECT_NOT_FOUND") {
+ // give a simple prompt to this special error
+ return fmt.Errorf("table \"%s\" does not exist", tableName)
+ }
+ if err != nil {
+ return err
+ }
+ globalContext.UseTableName = tableName
+
+ c.App.Println("ok")
+ return nil
+ },
+ Args: func(a *grumble.Args) {
+ a.String("TABLE", "The table name to access.")
+ },
+ })
+}
diff --git a/pegic/interactive/run.go b/pegic/interactive/run.go
new file mode 100644
index 00000000..7c3c5155
--- /dev/null
+++ b/pegic/interactive/run.go
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package interactive
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/desertbit/grumble"
+)
+
+// App is the global interactive application.
+var App *grumble.App
+
+func init() {
+ App = grumble.New(&grumble.Config{
+ Name: "pegic",
+ HistoryFile: ".pegic-history",
+ Flags: func(f *grumble.Flags) {
+ f.String("m", "meta", "127.0.0.1:34601,127.0.0.1:34602", "the list of MetaServer addresses")
+ },
+ })
+}
+
+func Run() {
+ err := App.Run()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/pegic/main.go b/pegic/main.go
new file mode 100644
index 00000000..a6f15804
--- /dev/null
+++ b/pegic/main.go
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/XiaoMi/pegasus-go-client/pegalog"
+ "github.com/apache/incubator-pegasus/pegic/shell"
+ "github.com/sirupsen/logrus"
+ "gopkg.in/natefinch/lumberjack.v2"
+)
+
+func main() {
+ // pegasus-go-client's logs use the same logger as ours.
+ pegalog.SetLogger(logrus.StandardLogger())
+ // configure log destination
+ logrus.SetOutput(&lumberjack.Logger{
+ Filename: "./pegic.log",
+ LocalTime: true,
+ })
+
+ if err := shell.Root.Execute(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/pegic/shell/app.go b/pegic/shell/app.go
new file mode 100644
index 00000000..db30e9dd
--- /dev/null
+++ b/pegic/shell/app.go
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package shell
+
+import (
+ "os"
+ "strings"
+
+ "github.com/apache/incubator-pegasus/pegic/interactive"
+ "github.com/apache/incubator-pegasus/pegic/interactive/cmd"
+ "github.com/spf13/cobra"
+)
+
+// Root command for pegic.
+var Root *cobra.Command
+
+func init() {
+ var metaList *string
+
+ Root = &cobra.Command{
+ Use: "pegic [--meta|-m <meta-list>]",
+ Short: "pegic: Pegasus Interactive Command-Line tool",
+ PreRun: func(c *cobra.Command, args []string) {
+ metaAddrs := strings.Split(*metaList, ",")
+ err := cmd.Init(metaAddrs)
+ if err != nil {
+ c.PrintErrln(err)
+ os.Exit(1)
+ }
+ },
+ Run: func(cmd *cobra.Command, args []string) {
+ // the default entrance is interactive
+ interactive.Run()
+ },
+ }
+
+ metaList = Root.Flags().StringP("meta", "m", "127.0.0.1:34601,127.0.0.1:34602", "the list of MetaServer addresses")
+}
diff --git a/pegic/shell/convert.go b/pegic/shell/convert.go
new file mode 100644
index 00000000..4226b561
--- /dev/null
+++ b/pegic/shell/convert.go
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package shell
+
+import (
+ "github.com/apache/incubator-pegasus/pegic/executor/util"
+ "github.com/spf13/cobra"
+)
+
+func init() {
+ // flags
+ var from *string
+ var to *string
+
+ cmd := &cobra.Command{
+ Use: "convert",
+ Short: "convert bytes from one encoding to the other",
+ Args: cobra.ExactArgs(1),
+ Run: func(c *cobra.Command, args []string) {
+ fromEnc := util.NewEncoder(*from)
+ if fromEnc == nil {
+ c.PrintErrf("invalid encoding: \"%s\"", *from)
+ return
+ }
+ toEnc := util.NewEncoder(*to)
+ if toEnc == nil {
+ c.PrintErrf("invalid encoding: \"%s\"", *to)
+ return
+ }
+
+ data, err := fromEnc.EncodeAll(args[0])
+ if err != nil {
+ c.PrintErr(err)
+ return
+ }
+ result, err := toEnc.DecodeAll(data)
+ if err != nil {
+ c.PrintErr(err)
+ return
+ }
+ c.Println(result)
+ },
+ }
+
+ from = cmd.Flags().String("from", "", "the original encoding of the given bytes")
+ to = cmd.Flags().String("to", "", "the original encoding of the given bytes")
+ _ = cmd.MarkFlagRequired("from")
+ _ = cmd.MarkFlagRequired("to")
+
+ Root.AddCommand(cmd)
+}
diff --git a/rdsn b/rdsn
index da843900..47fd85c2 160000
--- a/rdsn
+++ b/rdsn
@@ -1 +1 @@
-Subproject commit da843900f4d89e658038048775d9adf9604bd5ec
+Subproject commit 47fd85c29bd446495388e1ab3a46bd741c99c443
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pegasus.apache.org
For additional commands, e-mail: commits-help@pegasus.apache.org