diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml b/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml
index ded814c6ac9..36fc151bba6 100644
--- a/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml
+++ b/.github/workflows/upgrade_downgrade_test_query_serving_queries.yml
@@ -116,46 +116,43 @@ jobs:
# install JUnit report formatter
go install github.com/vitessio/go-junit-report@HEAD
- # Checkout to the last release of Vitess
- - name: Check out other version's code (${{ steps.output-previous-release-ref.outputs.previous_release_ref }})
- if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
- uses: actions/checkout@v4
- with:
- ref: ${{ steps.output-previous-release-ref.outputs.previous_release_ref }}
-
- - name: Get dependencies for the last release
+ # Build current commit's binaries
+ - name: Get dependencies for this commit
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
go mod download
- - name: Building last release's binaries
+ - name: Building the binaries for this commit
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
timeout-minutes: 10
run: |
source build.env
NOVTADMINBUILD=1 make build
- mkdir -p /tmp/vitess-build-other/
- cp -R bin /tmp/vitess-build-other/
+ mkdir -p /tmp/vitess-build-current/
+ cp -R bin /tmp/vitess-build-current/
rm -Rf bin/*
- # Checkout to this build's commit
- - name: Check out commit's code
+ # Checkout to the last release of Vitess
+ - name: Check out other version's code (${{ steps.output-previous-release-ref.outputs.previous_release_ref }})
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
uses: actions/checkout@v4
+ with:
+ ref: ${{ steps.output-previous-release-ref.outputs.previous_release_ref }}
- - name: Get dependencies for this commit
+ - name: Get dependencies for the last release
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
go mod download
- - name: Building the binaries for this commit
+ - name: Building last release's binaries
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
timeout-minutes: 10
run: |
source build.env
NOVTADMINBUILD=1 make build
- mkdir -p /tmp/vitess-build-current/
- cp -R bin /tmp/vitess-build-current/
+ mkdir -p /tmp/vitess-build-other/
+ cp -R bin /tmp/vitess-build-other/
+ rm -Rf bin/*
# Swap the binaries in the bin. Use vtgate version n-1 and keep vttablet at version n
- name: Use last release's VTGate
@@ -163,12 +160,13 @@ jobs:
run: |
source build.env
+ cp -r /tmp/vitess-build-current/bin/* $PWD/bin/
rm -f $PWD/bin/vtgate
cp /tmp/vitess-build-other/bin/vtgate $PWD/bin/vtgate
vtgate --version
- # Running a test with vtgate at version n-1 and vttablet at version n
- - name: Run query serving tests (vtgate=N-1, vttablet=N)
+ # Running a test with vtgate at version n-1 and vttablet/vtctld at version n
+ - name: Run query serving tests (vtgate=N-1, vttablet=N, vtctld=N)
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
rm -rf /tmp/vtdataroot
@@ -177,8 +175,8 @@ jobs:
source build.env
eatmydata -- go run test.go -skip-build -keep-data=false -docker=false -print-log -follow -tag upgrade_downgrade_query_serving_queries
- # Swap the binaries again. This time, vtgate will be at version n, and vttablet will be at version n-1
- - name: Use current version VTGate, and other version VTTablet
+ # Swap the binaries again. This time, vtgate will be at version n, and vttablet/vtctld will be at version n-1
+ - name: Use current version VTGate, and other version VTTablet/VTctld
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
source build.env
@@ -197,8 +195,8 @@ jobs:
vtgate --version
vttablet --version
- # Running a test with vtgate at version n and vttablet at version n-1
- - name: Run query serving tests (vtgate=N, vttablet=N-1)
+ # Running a test with vtgate at version n and vttablet/vtctld at version n-1
+ - name: Run query serving tests (vtgate=N, vttablet=N-1, vtctld=N-1)
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
rm -rf /tmp/vtdataroot
diff --git a/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml b/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml
index 845ab33c6bb..03c9212f449 100644
--- a/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml
+++ b/.github/workflows/upgrade_downgrade_test_query_serving_queries_next_release.yml
@@ -117,46 +117,43 @@ jobs:
# install JUnit report formatter
go install github.com/vitessio/go-junit-report@HEAD
- # Checkout to the next release of Vitess
- - name: Check out other version's code (${{ steps.output-next-release-ref.outputs.next_release_ref }})
- if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
- uses: actions/checkout@v4
- with:
- ref: ${{ steps.output-next-release-ref.outputs.next_release_ref }}
-
- - name: Get dependencies for the next release
+ # Build current commit's binaries
+ - name: Get dependencies for this commit
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
go mod download
- - name: Building next release's binaries
+ - name: Building the binaries for this commit
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
timeout-minutes: 10
run: |
source build.env
NOVTADMINBUILD=1 make build
- mkdir -p /tmp/vitess-build-other/
- cp -R bin /tmp/vitess-build-other/
+ mkdir -p /tmp/vitess-build-current/
+ cp -R bin /tmp/vitess-build-current/
rm -Rf bin/*
- # Checkout to this build's commit
- - name: Check out commit's code
+ # Checkout to the next release of Vitess
+ - name: Check out other version's code (${{ steps.output-next-release-ref.outputs.next_release_ref }})
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
uses: actions/checkout@v4
+ with:
+ ref: ${{ steps.output-next-release-ref.outputs.next_release_ref }}
- - name: Get dependencies for this commit
+ - name: Get dependencies for the next release
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
run: |
go mod download
- - name: Building the binaries for this commit
+ - name: Building next release's binaries
if: steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true'
timeout-minutes: 10
run: |
source build.env
NOVTADMINBUILD=1 make build
- mkdir -p /tmp/vitess-build-current/
- cp -R bin /tmp/vitess-build-current/
+ mkdir -p /tmp/vitess-build-other/
+ cp -R bin /tmp/vitess-build-other/
+ rm -Rf bin/*
# Swap the binaries in the bin. Use vtgate version n+1 and keep vttablet at version n
- name: Use next release's VTGate
@@ -164,6 +161,7 @@ jobs:
run: |
source build.env
+ cp -r /tmp/vitess-build-current/bin/* $PWD/bin/
rm -f $PWD/bin/vtgate
cp /tmp/vitess-build-other/bin/vtgate $PWD/bin/vtgate
vtgate --version
diff --git a/.github/workflows/vitess_tester_vtgate.yml b/.github/workflows/vitess_tester_vtgate.yml
index f2a669289bc..9e11697f778 100644
--- a/.github/workflows/vitess_tester_vtgate.yml
+++ b/.github/workflows/vitess_tester_vtgate.yml
@@ -57,7 +57,7 @@ jobs:
end_to_end:
- 'go/**/*.go'
- 'go/vt/sidecardb/**/*.sql'
- - 'go/test/endtoend/onlineddl/vrepl_suite/**'
+ - 'go/test/endtoend/vtgate/vitess_tester/**'
- 'test.go'
- 'Makefile'
- 'build.env'
@@ -112,7 +112,7 @@ jobs:
go install github.com/vitessio/go-junit-report@HEAD
# install vitess tester
- go install github.com/vitessio/vitess-tester@eb953122baba163ed8ccaa6642458ee984f5d7e4
+ go install github.com/vitessio/vitess-tester@89dd933a9ea0e15f69ca58b9c8ea09a358762cca
- name: Setup launchable dependencies
if: steps.skip-workflow.outputs.is_draft == 'false' && steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true' && github.base_ref == 'main'
@@ -144,9 +144,9 @@ jobs:
# We go over all the directories in the given path.
# If there is a vschema file there, we use it, otherwise we let vitess-tester autogenerate it.
if [ -f $dir/vschema.json ]; then
- vitess-tester --sharded --xunit --test-dir $dir --vschema "$dir"vschema.json
+ vitess-tester --xunit --vschema "$dir"vschema.json $dir/*.test
else
- vitess-tester --sharded --xunit --test-dir $dir
+ vitess-tester --sharded --xunit $dir/*.test
fi
# Number the reports by changing their file names.
mv report.xml report"$i".xml
diff --git a/changelog/21.0/21.0.0/summary.md b/changelog/21.0/21.0.0/summary.md
index 0d046ae9d75..a29e2d286ec 100644
--- a/changelog/21.0/21.0.0/summary.md
+++ b/changelog/21.0/21.0.0/summary.md
@@ -11,6 +11,7 @@
- **[Traffic Mirroring](#traffic-mirroring)**
- **[New VTGate Shutdown Behavior](#new-vtgate-shutdown-behavior)**
- **[Tablet Throttler: Multi-Metric support](#tablet-throttler)**
+ - **[Allow Cross Cell Promotion in PRS](#allow-cross-cell)**
## Major Changes
@@ -96,3 +97,8 @@ Each metric has a factory threshold which can be overridden by the `UpdateThrott
The throttler also supports the catch-all `"all"` app name, and it is thus possible to assign metrics to _all_ apps. Explicit app to metric assignments will override the catch-all configuration.
Metrics are assigned a default _scope_, which could be `self` (isolated to the tablet) or `shard` (max, aka _worst_ value among shard tablets). It is further possible to require a different scope for each metric.
+
+### Allow Cross Cell Promotion in PRS
+Up until now if the users wanted to promote a replica in a different cell than the current primary using `PlannedReparentShard`, they had to specify the new primary with the `--new-primary` flag.
+
+We have now added a new flag `--allow-cross-cell-promotion` that lets `PlannedReparentShard` choose a primary in a different cell even if no new primary is provided explicitly.
diff --git a/go.mod b/go.mod
index 59d0ad29827..1e80e0b9f62 100644
--- a/go.mod
+++ b/go.mod
@@ -4,13 +4,13 @@ go 1.22.5
require (
cloud.google.com/go/storage v1.43.0
- github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24
+ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240716105424-66b64c4bb379
github.com/Azure/azure-pipeline-go v0.2.3
github.com/Azure/azure-storage-blob-go v0.15.0
github.com/HdrHistogram/hdrhistogram-go v0.9.0 // indirect
github.com/aquarapid/vaultlib v0.5.1
github.com/armon/go-metrics v0.4.1 // indirect
- github.com/aws/aws-sdk-go v1.54.19
+ github.com/aws/aws-sdk-go v1.55.5
github.com/buger/jsonparser v1.1.1
github.com/cespare/xxhash/v2 v2.3.0
github.com/corpix/uarand v0.1.1 // indirect
@@ -40,7 +40,7 @@ require (
github.com/minio/minio-go v0.0.0-20190131015406-c8a261de75c1
github.com/montanaflynn/stats v0.7.1
github.com/olekukonko/tablewriter v0.0.5
- github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e
+ github.com/opentracing-contrib/go-grpc v0.0.0-20240724223109-9dec25a38fa8
github.com/opentracing/opentracing-go v1.2.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
@@ -58,15 +58,15 @@ require (
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/tchap/go-patricia v2.3.0+incompatible
- github.com/tidwall/gjson v1.17.1
+ github.com/tidwall/gjson v1.17.3
github.com/tinylib/msgp v1.2.0 // indirect
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82
github.com/z-division/go-zookeeper v1.0.0
- go.etcd.io/etcd/api/v3 v3.5.14
- go.etcd.io/etcd/client/pkg/v3 v3.5.14
- go.etcd.io/etcd/client/v3 v3.5.14
+ go.etcd.io/etcd/api/v3 v3.5.15
+ go.etcd.io/etcd/client/pkg/v3 v3.5.15
+ go.etcd.io/etcd/client/v3 v3.5.15
go.uber.org/mock v0.2.0
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/mod v0.19.0 // indirect
@@ -77,13 +77,13 @@ require (
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0
golang.org/x/tools v0.23.0
- google.golang.org/api v0.188.0
- google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
+ google.golang.org/api v0.189.0
+ google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf // indirect
google.golang.org/grpc v1.65.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
google.golang.org/grpc/examples v0.0.0-20210430044426-28078834f35b
google.golang.org/protobuf v1.34.2
- gopkg.in/DataDog/dd-trace-go.v1 v1.65.1
+ gopkg.in/DataDog/dd-trace-go.v1 v1.66.0
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/ldap.v2 v2.5.1
sigs.k8s.io/yaml v1.4.0
@@ -104,21 +104,21 @@ require (
github.com/spf13/jwalterweatherman v1.1.0
github.com/xlab/treeprint v1.2.0
go.uber.org/goleak v1.3.0
- golang.org/x/exp v0.0.0-20240707233637-46b078467d37
+ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.7.0
gonum.org/v1/gonum v0.14.0
- modernc.org/sqlite v1.30.2
+ modernc.org/sqlite v1.31.1
)
require (
cloud.google.com/go v0.115.0 // indirect
- cloud.google.com/go/auth v0.7.1 // indirect
+ cloud.google.com/go/auth v0.7.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
- cloud.google.com/go/iam v1.1.11 // indirect
+ cloud.google.com/go/iam v1.1.12 // indirect
github.com/DataDog/appsec-internal-go v1.7.0 // indirect
- github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.0 // indirect
- github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0 // indirect
+ github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.2 // indirect
+ github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.2 // indirect
github.com/DataDog/go-libddwaf/v3 v3.3.0 // indirect
github.com/DataDog/go-sqllexer v0.0.12 // indirect
github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect
@@ -137,9 +137,9 @@ require (
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/google/s2a-go v0.1.7 // indirect
+ github.com/google/s2a-go v0.1.8 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
- github.com/googleapis/gax-go/v2 v2.12.5 // indirect
+ github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
@@ -152,7 +152,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-ieproxy v0.0.12 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
@@ -184,14 +184,14 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
- golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
+ golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
+ google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
- modernc.org/libc v1.55.1 // indirect
+ modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect
+ modernc.org/libc v1.55.7 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index 3ff3456402a..2be032bcc92 100644
--- a/go.sum
+++ b/go.sum
@@ -2,20 +2,20 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
-cloud.google.com/go/auth v0.7.1 h1:Iv1bbpzJ2OIg16m94XI9/tlzZZl3cdeR3nGVGj78N7s=
-cloud.google.com/go/auth v0.7.1/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
+cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
+cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
-cloud.google.com/go/iam v1.1.11 h1:0mQ8UKSfdHLut6pH9FM3bI55KWR46ketn0PuXleDyxw=
-cloud.google.com/go/iam v1.1.11/go.mod h1:biXoiLWYIKntto2joP+62sd9uW5EpkZmKIvfNcTWlnQ=
-cloud.google.com/go/longrunning v0.5.9 h1:haH9pAuXdPAMqHvzX0zlWQigXT7B0+CL4/2nXXdBo5k=
-cloud.google.com/go/longrunning v0.5.9/go.mod h1:HD+0l9/OOW0za6UWdKJtXoFAX/BGg/3Wj8p10NeWF7c=
+cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw=
+cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg=
+cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk=
+cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4=
cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs=
cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240716105424-66b64c4bb379 h1:shYAfOpsleWVaSwGxQjmi+BBIwzj5jxB1FTCpVqs0N8=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20240716105424-66b64c4bb379/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk=
@@ -34,10 +34,10 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/appsec-internal-go v1.7.0 h1:iKRNLih83dJeVya3IoUfK+6HLD/hQsIbyBlfvLmAeb0=
github.com/DataDog/appsec-internal-go v1.7.0/go.mod h1:wW0cRfWBo4C044jHGwYiyh5moQV2x0AhnwqMuiX7O/g=
-github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.0 h1:q8n6qVTPATzBL02e0rxCOrLFWDNw4as0GcuKWkJENFk=
-github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.0/go.mod h1:/C99KWKukVnTtIiYCQ55izSNDQceREb8vSPa3zUn6jc=
-github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0 h1:+T+3WXCFC9g8r4AVBaD3v1LOKSLyKAtl/LtXyCTcm7I=
-github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.0/go.mod h1:3yFk56PJ57yS1GqI9HAsS4PSlAeGCC9RQA7jxKzYj6g=
+github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.2 h1:Uc0V20r3BdVdPZ0AjDd8IpRKG9+8GBHW68Sg94aqRlU=
+github.com/DataDog/datadog-agent/pkg/obfuscate v0.55.2/go.mod h1:/C99KWKukVnTtIiYCQ55izSNDQceREb8vSPa3zUn6jc=
+github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.2 h1:Q7aIwDE+aKXclYhHrKRQvEl5IdabmdaFw5+QBp5DlNA=
+github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.55.2/go.mod h1:3yFk56PJ57yS1GqI9HAsS4PSlAeGCC9RQA7jxKzYj6g=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go/v5 v5.5.0 h1:G5KHeB8pWBNXT4Jtw0zAkhdxEAWSpWH00geHI6LDrKU=
github.com/DataDog/datadog-go/v5 v5.5.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw=
@@ -73,8 +73,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/aws/aws-sdk-go v1.54.19 h1:tyWV+07jagrNiCcGRzRhdtVjQs7Vy41NwsuOcl0IbVI=
-github.com/aws/aws-sdk-go v1.54.19/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
+github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
+github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
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=
@@ -142,6 +142,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0=
github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
+github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
+github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
@@ -206,8 +208,8 @@ github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
-github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
-github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
+github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8=
github.com/google/safehtml v0.1.0/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@@ -218,8 +220,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
-github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
-github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
+github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
+github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
@@ -229,7 +231,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hashicorp/consul/api v1.29.2 h1:aYyRn8EdE2mSfG14S1+L9Qkjtz8RzmaWh6AcNGRNwPw=
github.com/hashicorp/consul/api v1.29.2/go.mod h1:0YObcaLNDSbtlgzIRtmRXI1ZkeuK0trCBxwZQ4MYnIk=
github.com/hashicorp/consul/proto-public v0.6.2 h1:+DA/3g/IiKlJZb88NBn0ZgXrxJp2NlvCZdEyl+qxvL0=
@@ -336,8 +337,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@@ -378,8 +379,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
-github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg=
-github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo=
+github.com/opentracing-contrib/go-grpc v0.0.0-20240724223109-9dec25a38fa8 h1:gHTSPFezGeYzTWCvpPM6lBanwXfuksik5Hy5MEHtvUA=
+github.com/opentracing-contrib/go-grpc v0.0.0-20240724223109-9dec25a38fa8/go.mod h1:z1k3YVSdAPSXtMUPS1TBWG5DaNWlT+VCbB0Qm3QJe74=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
@@ -502,8 +503,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tchap/go-patricia v2.3.0+incompatible h1:GkY4dP3cEfEASBPPkWd+AmjYxhmDkqO9/zg7R0lSQRs=
github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
-github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
-github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
+github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
@@ -525,12 +526,12 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/z-division/go-zookeeper v1.0.0 h1:ULsCj0nP6+U1liDFWe+2oEF6o4amixoDcDlwEUghVUY=
github.com/z-division/go-zookeeper v1.0.0/go.mod h1:6X4UioQXpvyezJJl4J9NHAJKsoffCwy5wCaaTktXjOA=
-go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
-go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
-go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
-go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
-go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
+go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
+go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
+go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
+go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
+go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g=
@@ -571,8 +572,8 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
-golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -593,7 +594,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -688,12 +688,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
-golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
+golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
-google.golang.org/api v0.188.0 h1:51y8fJ/b1AaaBRJr4yWm96fPcuxSo0JcegXE3DaHQHw=
-google.golang.org/api v0.188.0/go.mod h1:VR0d+2SIiWOYG3r/jdm7adPW9hI2aRv9ETOSCQ9Beag=
+google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
+google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -701,15 +701,14 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d h1:/hmn0Ku5kWij/kjGsrcJeC1T/MrJi2iNWwgAqrihFwc=
-google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
-google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
-google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d h1:JU0iKnSg02Gmb5ZdV8nYsKEKsP6o/FGVWTrw4i1DA9A=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
+google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf h1:OqdXDEakZCVtDiZTjcxfwbHPCT11ycCEsTKesBVKvyY=
+google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:mCr1K1c8kX+1iSBREvU3Juo11CB+QOEWxbRS01wWl5M=
+google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE=
+google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf h1:liao9UHurZLtiEwBgT9LMOnKYsHze6eA6w1KQCMVN2Q=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
@@ -735,8 +734,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
-gopkg.in/DataDog/dd-trace-go.v1 v1.65.1 h1:Ne7kzWr/br/jwhUJR7CnqPl/mUpNxa6LfgZs0S4htZM=
-gopkg.in/DataDog/dd-trace-go.v1 v1.65.1/go.mod h1:beNFIWd/H04d0k96cfltgiDH2+t0T5sDbyYLF3VTXqk=
+gopkg.in/DataDog/dd-trace-go.v1 v1.66.0 h1:025+lLubGtpiDWrRmSOxoFBPIiVRVYRcqP9oLabVOeg=
+gopkg.in/DataDog/dd-trace-go.v1 v1.66.0/go.mod h1:Av6AXGmQCQAbDnwNoPiuUz1k3GS8TwQjj+vEdwmEpmM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
@@ -771,16 +770,16 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
-modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
-modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
+modernc.org/ccgo/v4 v4.20.5 h1:s04akhT2dysD0DFOlv9fkQ6oUTLPYgMnnDk9oaqjszM=
+modernc.org/ccgo/v4 v4.20.5/go.mod h1:fYXClPUMWxWaz1Xj5sHbzW/ZENEFeuHLToqBxUk41nE=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
-modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
-modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
-modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8=
-modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
-modernc.org/libc v1.55.1 h1:2K/vMbMDGymj0CO4mcQybYW8SW3czB+u9rlghpMkTrI=
-modernc.org/libc v1.55.1/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
+modernc.org/gc/v2 v2.4.3 h1:Ik4ZcMbC7aY4ZDPUhzXVXi7GMub9QcXLTfXn3mWpNw8=
+modernc.org/gc/v2 v2.4.3/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
+modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e h1:WPC4v0rNIFb2PY+nBBEEKyugPPRHPzUgyN3xZPpGK58=
+modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
+modernc.org/libc v1.55.7 h1:/5PMGAF3tyZhK72WpoqeLNtgUUpYMrnhT+Gm/5tVDgs=
+modernc.org/libc v1.55.7/go.mod h1:JXguUpMkbw1gknxspNE9XaG+kk9hDAAnBxpA6KGLiyA=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
@@ -789,8 +788,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
-modernc.org/sqlite v1.30.2 h1:IPVVkhLu5mMVnS1dQgh3h0SAACRWcVk7aoLP9Us3UCk=
-modernc.org/sqlite v1.30.2/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU=
+modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs=
+modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
diff --git a/go/cmd/vtctldclient/command/reparents.go b/go/cmd/vtctldclient/command/reparents.go
index 17b87eaba4f..8888c5a48cd 100644
--- a/go/cmd/vtctldclient/command/reparents.go
+++ b/go/cmd/vtctldclient/command/reparents.go
@@ -187,6 +187,7 @@ var plannedReparentShardOptions = struct {
AvoidPrimaryAliasStr string
WaitReplicasTimeout time.Duration
TolerableReplicationLag time.Duration
+ AllowCrossCellPromotion bool
}{}
func commandPlannedReparentShard(cmd *cobra.Command, args []string) error {
@@ -223,6 +224,7 @@ func commandPlannedReparentShard(cmd *cobra.Command, args []string) error {
AvoidPrimary: avoidPrimaryAlias,
WaitReplicasTimeout: protoutil.DurationToProto(plannedReparentShardOptions.WaitReplicasTimeout),
TolerableReplicationLag: protoutil.DurationToProto(plannedReparentShardOptions.TolerableReplicationLag),
+ AllowCrossCellPromotion: plannedReparentShardOptions.AllowCrossCellPromotion,
})
if err != nil {
return err
@@ -297,6 +299,7 @@ func init() {
PlannedReparentShard.Flags().DurationVar(&plannedReparentShardOptions.TolerableReplicationLag, "tolerable-replication-lag", 0, "Amount of replication lag that is considered acceptable for a tablet to be eligible for promotion when Vitess makes the choice of a new primary.")
PlannedReparentShard.Flags().StringVar(&plannedReparentShardOptions.NewPrimaryAliasStr, "new-primary", "", "Alias of a tablet that should be the new primary.")
PlannedReparentShard.Flags().StringVar(&plannedReparentShardOptions.AvoidPrimaryAliasStr, "avoid-primary", "", "Alias of a tablet that should not be the primary; i.e. \"reparent to any other tablet if this one is the primary\".")
+ PlannedReparentShard.Flags().BoolVar(&plannedReparentShardOptions.AllowCrossCellPromotion, "allow-cross-cell-promotion", false, "Allow cross cell promotion")
Root.AddCommand(PlannedReparentShard)
Root.AddCommand(ReparentTablet)
diff --git a/go/cmd/vtctldclient/command/throttler.go b/go/cmd/vtctldclient/command/throttler.go
index 7a4f6c92653..da8b0763b0d 100644
--- a/go/cmd/vtctldclient/command/throttler.go
+++ b/go/cmd/vtctldclient/command/throttler.go
@@ -37,7 +37,7 @@ import (
var (
// UpdateThrottlerConfig makes a UpdateThrottlerConfig gRPC call to a vtctld.
UpdateThrottlerConfig = &cobra.Command{
- Use: "UpdateThrottlerConfig [--enable|--disable] [--threshold=] [--custom-query=] [--check-as-check-self|--check-as-check-shard] [--throttle-app|unthrottle-app=] [--throttle-app-ratio=] [--throttle-app-duration=] ",
+ Use: "UpdateThrottlerConfig [--enable|--disable] [--metric-name=] [--threshold=] [--custom-query=] [--throttle-app|unthrottle-app=] [--throttle-app-ratio=] [--throttle-app-duration=] [--throttle-app-exempt=] [--app-name= --app-metrics=] ",
Short: "Update the tablet throttler configuration for all tablets in the given keyspace (across all cells)",
DisableFlagsInUseLine: true,
Args: cobra.ExactArgs(1),
@@ -171,6 +171,8 @@ func init() {
UpdateThrottlerConfig.Flags().StringVar(&updateThrottlerConfigOptions.CustomQuery, "custom-query", "", "custom throttler check query")
UpdateThrottlerConfig.Flags().BoolVar(&updateThrottlerConfigOptions.CheckAsCheckSelf, "check-as-check-self", false, "/throttler/check requests behave as is /throttler/check-self was called")
UpdateThrottlerConfig.Flags().BoolVar(&updateThrottlerConfigOptions.CheckAsCheckShard, "check-as-check-shard", false, "use standard behavior for /throttler/check requests")
+ UpdateThrottlerConfig.Flags().MarkDeprecated("check-as-check-self", "specify metric with scope in --app-metrics to apply to all checks, or use --scope in CheckThrottler for a specific check")
+ UpdateThrottlerConfig.Flags().MarkDeprecated("check-as-check-shard", "specify metric with scope in --app-metrics to apply to all checks, or use --scope in CheckThrottler for a specific check")
UpdateThrottlerConfig.Flags().StringVar(&unthrottledAppRule.Name, "unthrottle-app", "", "an app name to unthrottle")
UpdateThrottlerConfig.Flags().StringVar(&throttledAppRule.Name, "throttle-app", "", "an app name to throttle")
@@ -178,7 +180,7 @@ func init() {
UpdateThrottlerConfig.Flags().DurationVar(&throttledAppDuration, "throttle-app-duration", throttle.DefaultAppThrottleDuration, "duration after which throttled app rule expires (app specififed in --throttled-app)")
UpdateThrottlerConfig.Flags().BoolVar(&throttledAppRule.Exempt, "throttle-app-exempt", throttledAppRule.Exempt, "exempt this app from being at all throttled. WARNING: use with extreme care, as this is likely to push metrics beyond the throttler's threshold, and starve other apps")
UpdateThrottlerConfig.Flags().StringVar(&updateThrottlerConfigOptions.AppName, "app-name", "", "app name for which to assign metrics (requires --app-metrics)")
- UpdateThrottlerConfig.Flags().StringSliceVar(&updateThrottlerConfigOptions.AppCheckedMetrics, "app-metrics", nil, "metrics to be used when checking the throttler for the app (requires --app-name). Empty to restore to default metrics")
+ UpdateThrottlerConfig.Flags().StringSliceVar(&updateThrottlerConfigOptions.AppCheckedMetrics, "app-metrics", nil, "metrics to be used when checking the throttler for the app (requires --app-name). Empty to restore to default metrics. Example: --app-metrics=lag,custom,shard/loadavg")
UpdateThrottlerConfig.MarkFlagsMutuallyExclusive("unthrottle-app", "throttle-app")
UpdateThrottlerConfig.MarkFlagsRequiredTogether("app-name", "app-metrics")
diff --git a/go/flags/endtoend/mysqlctl.txt b/go/flags/endtoend/mysqlctl.txt
index 044d12981d5..2b179496fff 100644
--- a/go/flags/endtoend/mysqlctl.txt
+++ b/go/flags/endtoend/mysqlctl.txt
@@ -40,7 +40,7 @@ Flags:
--db-credentials-vault-tls-ca string Path to CA PEM for validating Vault server certificate
--db-credentials-vault-tokenfile string Path to file containing Vault auth token; token can also be passed using VAULT_TOKEN environment variable
--db-credentials-vault-ttl duration How long to cache DB credentials from the Vault server (default 30m0s)
- --db_charset string Character set used for this tablet. (default "utf8mb4")
+ --db_charset string Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment. (default "utf8mb4")
--db_conn_query_info enable parsing and processing of QUERY_OK info fields
--db_connect_timeout_ms int connection timeout to mysqld in milliseconds (0 for no timeout)
--db_dba_password string db dba password
diff --git a/go/flags/endtoend/mysqlctld.txt b/go/flags/endtoend/mysqlctld.txt
index 6bb1beb5bae..d60a91ae65e 100644
--- a/go/flags/endtoend/mysqlctld.txt
+++ b/go/flags/endtoend/mysqlctld.txt
@@ -41,7 +41,7 @@ Flags:
--db-credentials-vault-tls-ca string Path to CA PEM for validating Vault server certificate
--db-credentials-vault-tokenfile string Path to file containing Vault auth token; token can also be passed using VAULT_TOKEN environment variable
--db-credentials-vault-ttl duration How long to cache DB credentials from the Vault server (default 30m0s)
- --db_charset string Character set used for this tablet. (default "utf8mb4")
+ --db_charset string Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment. (default "utf8mb4")
--db_conn_query_info enable parsing and processing of QUERY_OK info fields
--db_connect_timeout_ms int connection timeout to mysqld in milliseconds (0 for no timeout)
--db_dba_password string db dba password
diff --git a/go/flags/endtoend/vtbackup.txt b/go/flags/endtoend/vtbackup.txt
index 004871d7c09..fc00df479f5 100644
--- a/go/flags/endtoend/vtbackup.txt
+++ b/go/flags/endtoend/vtbackup.txt
@@ -92,7 +92,7 @@ Flags:
--db_appdebug_password string db appdebug password
--db_appdebug_use_ssl Set this flag to false to make the appdebug connection to not use ssl (default true)
--db_appdebug_user string db appdebug user userKey (default "vt_appdebug")
- --db_charset string Character set used for this tablet. (default "utf8mb4")
+ --db_charset string Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment. (default "utf8mb4")
--db_conn_query_info enable parsing and processing of QUERY_OK info fields
--db_connect_timeout_ms int connection timeout to mysqld in milliseconds (0 for no timeout)
--db_dba_password string db dba password
diff --git a/go/flags/endtoend/vtcombo.txt b/go/flags/endtoend/vtcombo.txt
index c59cd789ed3..381f7ca48cc 100644
--- a/go/flags/endtoend/vtcombo.txt
+++ b/go/flags/endtoend/vtcombo.txt
@@ -76,7 +76,7 @@ Flags:
--db_appdebug_password string db appdebug password
--db_appdebug_use_ssl Set this flag to false to make the appdebug connection to not use ssl (default true)
--db_appdebug_user string db appdebug user userKey (default "vt_appdebug")
- --db_charset string Character set used for this tablet. (default "utf8mb4")
+ --db_charset string Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment. (default "utf8mb4")
--db_conn_query_info enable parsing and processing of QUERY_OK info fields
--db_connect_timeout_ms int connection timeout to mysqld in milliseconds (0 for no timeout)
--db_dba_password string db dba password
diff --git a/go/flags/endtoend/vttablet.txt b/go/flags/endtoend/vttablet.txt
index f5a7f8e8f51..d3df3c3009f 100644
--- a/go/flags/endtoend/vttablet.txt
+++ b/go/flags/endtoend/vttablet.txt
@@ -110,7 +110,7 @@ Flags:
--db_appdebug_password string db appdebug password
--db_appdebug_use_ssl Set this flag to false to make the appdebug connection to not use ssl (default true)
--db_appdebug_user string db appdebug user userKey (default "vt_appdebug")
- --db_charset string Character set used for this tablet. (default "utf8mb4")
+ --db_charset string Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment. (default "utf8mb4")
--db_conn_query_info enable parsing and processing of QUERY_OK info fields
--db_connect_timeout_ms int connection timeout to mysqld in milliseconds (0 for no timeout)
--db_dba_password string db dba password
diff --git a/go/mysql/capabilities/capability.go b/go/mysql/capabilities/capability.go
index 34995081867..4015059e686 100644
--- a/go/mysql/capabilities/capability.go
+++ b/go/mysql/capabilities/capability.go
@@ -40,6 +40,7 @@ const (
InstantAddDropColumnFlavorCapability // Adding/dropping column in any position/ordinal.
InstantChangeColumnDefaultFlavorCapability //
InstantExpandEnumCapability //
+ InstantChangeColumnVisibilityCapability //
MySQLUpgradeInServerFlavorCapability //
DynamicRedoLogCapacityFlavorCapability // supported in MySQL 8.0.30 and above: https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-30.html
DisableRedoLogFlavorCapability // supported in MySQL 8.0.21 and above: https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-21.html
@@ -106,6 +107,8 @@ func MySQLVersionHasCapability(serverVersion string, capability FlavorCapability
return atLeast(8, 0, 21)
case FastDropTableFlavorCapability:
return atLeast(8, 0, 23)
+ case InstantChangeColumnVisibilityCapability:
+ return atLeast(8, 0, 23)
case InstantAddDropColumnFlavorCapability:
return atLeast(8, 0, 29)
case DynamicRedoLogCapacityFlavorCapability:
diff --git a/go/mysql/datetime/mydate.go b/go/mysql/datetime/mydate.go
index 62cbb3f2524..5b77082055a 100644
--- a/go/mysql/datetime/mydate.go
+++ b/go/mysql/datetime/mydate.go
@@ -89,3 +89,48 @@ func DateFromDayNumber(daynr int) Date {
d.year, d.month, d.day = mysqlDateFromDayNumber(daynr)
return d
}
+
+// ValidatePeriod validates the MySQL period.
+// Returns false if period is non-positive or contains incorrect month value.
+func ValidatePeriod(period int64) bool {
+ if period <= 0 {
+ return false
+ }
+ month := period % 100
+ if month == 0 || month > 12 {
+ return false
+ }
+ return true
+}
+
+// PeriodToMonths converts a MySQL period into number of months.
+// This is an algorithm that has been reverse engineered from MySQL.
+func PeriodToMonths(period int64) int64 {
+ p := uint64(period)
+ if p == 0 {
+ return 0
+ }
+ y := p / 100
+ if y < 70 {
+ y += 2000
+ } else if y < 100 {
+ y += 1900
+ }
+ return int64(y*12 + p%100 - 1)
+}
+
+// MonthsToPeriod converts number of months into MySQL period.
+// This is an algorithm that has been reverse engineered from MySQL.
+func MonthsToPeriod(months int64) int64 {
+ m := uint64(months)
+ if m == 0 {
+ return 0
+ }
+ y := m / 12
+ if y < 70 {
+ y += 2000
+ } else if y < 100 {
+ y += 1900
+ }
+ return int64(y*100 + m%12 + 1)
+}
diff --git a/go/mysql/datetime/mydate_test.go b/go/mysql/datetime/mydate_test.go
index bb5073b8ff8..a743db60709 100644
--- a/go/mysql/datetime/mydate_test.go
+++ b/go/mysql/datetime/mydate_test.go
@@ -65,3 +65,57 @@ func TestDayNumberFields(t *testing.T) {
assert.Equal(t, wantDate, got)
}
}
+
+func TestValidatePeriod(t *testing.T) {
+ testCases := []struct {
+ period int64
+ want bool
+ }{
+ {110112, true},
+ {101122, false},
+ {-1112212, false},
+ {7110, true},
+ }
+
+ for _, tc := range testCases {
+ got := ValidatePeriod(tc.period)
+ assert.Equal(t, tc.want, got)
+ }
+}
+
+func TestPeriodToMonths(t *testing.T) {
+ testCases := []struct {
+ period int64
+ want int64
+ }{
+ {0, 0},
+ {110112, 13223},
+ {100112, 12023},
+ {7112, 23663},
+ {200112, 24023},
+ {112, 24023},
+ }
+
+ for _, tc := range testCases {
+ got := PeriodToMonths(tc.period)
+ assert.Equal(t, tc.want, got)
+ }
+}
+
+func TestMonthsToPeriod(t *testing.T) {
+ testCases := []struct {
+ months int64
+ want int64
+ }{
+ {0, 0},
+ {13223, 110112},
+ {12023, 100112},
+ {23663, 197112},
+ {24023, 200112},
+ }
+
+ for _, tc := range testCases {
+ got := MonthsToPeriod(tc.months)
+ assert.Equal(t, tc.want, got)
+ }
+}
diff --git a/go/mysql/sqlerror/constants.go b/go/mysql/sqlerror/constants.go
index ec5afa5e9c3..15c590b92a8 100644
--- a/go/mysql/sqlerror/constants.go
+++ b/go/mysql/sqlerror/constants.go
@@ -34,8 +34,9 @@ func (e ErrorCode) ToString() string {
// See above reference for more information on each code.
const (
// Vitess specific errors, (100-999)
- ERNotReplica = ErrorCode(100)
- ERNonAtomicCommit = ErrorCode(301)
+ ERNotReplica = ErrorCode(100)
+ ERNonAtomicCommit = ErrorCode(301)
+ ERInAtomicRecovery = ErrorCode(302)
// unknown
ERUnknownError = ErrorCode(1105)
diff --git a/go/test/endtoend/backup/vtbackup/backup_only_test.go b/go/test/endtoend/backup/vtbackup/backup_only_test.go
index 7dada7a77d2..4e018986100 100644
--- a/go/test/endtoend/backup/vtbackup/backup_only_test.go
+++ b/go/test/endtoend/backup/vtbackup/backup_only_test.go
@@ -69,15 +69,10 @@ func TestTabletInitialBackup(t *testing.T) {
// Initialize the tablets
initTablets(t, false, false)
- vtTabletVersion, err := cluster.GetMajorVersion("vttablet")
- require.NoError(t, err)
- // For all version at or above v17.0.0, each replica will start in super_read_only mode. Let's verify that is working correctly.
- if vtTabletVersion >= 17 {
- err := primary.VttabletProcess.CreateDB("testDB")
- require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement")
- err = replica1.VttabletProcess.CreateDB("testDB")
- require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement")
- }
+ err := primary.VttabletProcess.CreateDB("testDB")
+ require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement")
+ err = replica1.VttabletProcess.CreateDB("testDB")
+ require.ErrorContains(t, err, "The MySQL server is running with the --super-read-only option so it cannot execute this statement")
// Restore the Tablet
restore(t, primary, "replica", "NOT_SERVING")
@@ -172,7 +167,7 @@ func firstBackupTest(t *testing.T, tabletType string) {
restore(t, replica2, "replica", "SERVING")
// Replica2 takes time to serve. Sleeping for 5 sec.
time.Sleep(5 * time.Second)
- //check the new replica has the data
+ // check the new replica has the data
cluster.VerifyRowsInTablet(t, replica2, keyspaceName, 2)
removeBackups(t)
diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go
index 707c9010b0c..3a0150cc87c 100644
--- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go
+++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go
@@ -1032,7 +1032,7 @@ func verifySemiSyncStatus(t *testing.T, vttablet *cluster.Vttablet, expectedStat
}
func terminateBackup(t *testing.T, alias string) {
- stopBackupMsg := "Done taking Backup"
+ stopBackupMsg := "Completed backing up"
if useXtrabackup {
stopBackupMsg = "Starting backup with"
useXtrabackup = false
diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go
index 44636b3cdb6..95995903a83 100644
--- a/go/test/endtoend/cluster/cluster_process.go
+++ b/go/test/endtoend/cluster/cluster_process.go
@@ -151,11 +151,12 @@ type Vttablet struct {
// Keyspace : Cluster accepts keyspace to launch it
type Keyspace struct {
- Name string
- SchemaSQL string
- VSchema string
- SidecarDBName string
- Shards []Shard
+ Name string
+ SchemaSQL string
+ VSchema string
+ SidecarDBName string
+ DurabilityPolicy string
+ Shards []Shard
}
// Shard with associated vttablets
@@ -284,9 +285,10 @@ func (cluster *LocalProcessCluster) startPartialKeyspace(keyspace Keyspace, shar
cluster.HasPartialKeyspaces = true
routedKeyspace := &Keyspace{
- Name: fmt.Sprintf("%s_routed", keyspace.Name),
- SchemaSQL: keyspace.SchemaSQL,
- VSchema: keyspace.VSchema,
+ Name: fmt.Sprintf("%s_routed", keyspace.Name),
+ SchemaSQL: keyspace.SchemaSQL,
+ VSchema: keyspace.VSchema,
+ DurabilityPolicy: keyspace.DurabilityPolicy,
}
err = cluster.startKeyspace(*routedKeyspace, shardNames, replicaCount, rdonly, customizers...)
@@ -374,7 +376,7 @@ func (cluster *LocalProcessCluster) startKeyspace(keyspace Keyspace, shardNames
keyspace.SidecarDBName = sidecar.DefaultName
}
// Create the keyspace if it doesn't already exist.
- _ = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName)
+ _ = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName, keyspace.DurabilityPolicy)
for _, shardName := range shardNames {
shard := &Shard{
Name: shardName,
@@ -538,7 +540,7 @@ func (cluster *LocalProcessCluster) StartKeyspaceLegacy(keyspace Keyspace, shard
keyspace.SidecarDBName = sidecar.DefaultName
}
// Create the keyspace if it doesn't already exist.
- _ = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName)
+ _ = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName, keyspace.DurabilityPolicy)
var mysqlctlProcessList []*exec.Cmd
for _, shardName := range shardNames {
shard := &Shard{
@@ -681,7 +683,7 @@ func (cluster *LocalProcessCluster) SetupCluster(keyspace *Keyspace, shards []Sh
if !cluster.ReusingVTDATAROOT {
// Create Keyspace
- err = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName)
+ err = cluster.VtctlProcess.CreateKeyspace(keyspace.Name, keyspace.SidecarDBName, keyspace.DurabilityPolicy)
if err != nil {
log.Error(err)
return
diff --git a/go/test/endtoend/cluster/vtctl_process.go b/go/test/endtoend/cluster/vtctl_process.go
index b9d8a5b46ce..185c3079d34 100644
--- a/go/test/endtoend/cluster/vtctl_process.go
+++ b/go/test/endtoend/cluster/vtctl_process.go
@@ -60,15 +60,15 @@ func (vtctl *VtctlProcess) AddCellInfo(Cell string) (err error) {
}
// CreateKeyspace executes vtctl command to create keyspace
-func (vtctl *VtctlProcess) CreateKeyspace(keyspace, sidecarDBName string) (err error) {
- var output string
- // For upgrade/downgrade tests where an older version is also used.
- if vtctl.VtctlMajorVersion < 17 {
- log.Errorf("CreateKeyspace does not support the --sidecar-db-name flag in vtctl version %d; ignoring...", vtctl.VtctlMajorVersion)
- output, err = vtctl.ExecuteCommandWithOutput("CreateKeyspace", keyspace)
- } else {
- output, err = vtctl.ExecuteCommandWithOutput("CreateKeyspace", keyspace, "--sidecar-db-name", sidecarDBName)
+func (vtctl *VtctlProcess) CreateKeyspace(keyspace, sidecarDBName, durabilityPolicy string) error {
+ args := []string{
+ "CreateKeyspace", keyspace,
+ "--sidecar-db-name", sidecarDBName,
}
+ if durabilityPolicy != "" {
+ args = append(args, "--durability-policy", durabilityPolicy)
+ }
+ output, err := vtctl.ExecuteCommandWithOutput(args...)
if err != nil {
log.Errorf("CreateKeyspace returned err: %s, output: %s", err, output)
}
diff --git a/go/test/endtoend/cluster/vtctld_process.go b/go/test/endtoend/cluster/vtctld_process.go
index d87427af9b9..6ac6ed5d2b0 100644
--- a/go/test/endtoend/cluster/vtctld_process.go
+++ b/go/test/endtoend/cluster/vtctld_process.go
@@ -65,15 +65,10 @@ func (vtctld *VtctldProcess) Setup(cell string, extraArgs ...string) (err error)
"--log_dir", vtctld.LogDir,
"--port", fmt.Sprintf("%d", vtctld.Port),
"--grpc_port", fmt.Sprintf("%d", vtctld.GrpcPort),
+ "--bind-address", "127.0.0.1",
+ "--grpc_bind_address", "127.0.0.1",
)
- if v, err := GetMajorVersion("vtctld"); err != nil {
- return err
- } else if v >= 18 {
- vtctld.proc.Args = append(vtctld.proc.Args, "--bind-address", "127.0.0.1")
- vtctld.proc.Args = append(vtctld.proc.Args, "--grpc_bind_address", "127.0.0.1")
- }
-
if *isCoverage {
vtctld.proc.Args = append(vtctld.proc.Args, "--test.coverprofile="+getCoveragePath("vtctld.out"))
}
diff --git a/go/test/endtoend/cluster/vtgate_process.go b/go/test/endtoend/cluster/vtgate_process.go
index 5143e9ad8a4..d7f5dc3dc01 100644
--- a/go/test/endtoend/cluster/vtgate_process.go
+++ b/go/test/endtoend/cluster/vtgate_process.go
@@ -85,12 +85,8 @@ func (vtgate *VtgateProcess) Setup() (err error) {
"--tablet_types_to_wait", vtgate.TabletTypesToWait,
"--service_map", vtgate.ServiceMap,
"--mysql_auth_server_impl", vtgate.MySQLAuthServerImpl,
- }
- if v, err := GetMajorVersion("vtgate"); err != nil {
- return err
- } else if v >= 18 {
- args = append(args, "--bind-address", "127.0.0.1")
- args = append(args, "--grpc_bind_address", "127.0.0.1")
+ "--bind-address", "127.0.0.1",
+ "--grpc_bind_address", "127.0.0.1",
}
// If no explicit mysql_server_version has been specified then we autodetect
// the MySQL version that will be used for the test and base the vtgate's
diff --git a/go/test/endtoend/cluster/vtorc_process.go b/go/test/endtoend/cluster/vtorc_process.go
index cac5921d01d..31cf03606e5 100644
--- a/go/test/endtoend/cluster/vtorc_process.go
+++ b/go/test/endtoend/cluster/vtorc_process.go
@@ -126,14 +126,9 @@ func (orc *VTOrcProcess) Setup() (err error) {
"--instance-poll-time", "1s",
// Faster topo information refresh speeds up the tests. This doesn't add any significant load either
"--topo-information-refresh-duration", "3s",
+ "--bind-address", "127.0.0.1",
)
- if v, err := GetMajorVersion("vtorc"); err != nil {
- return err
- } else if v >= 18 {
- orc.proc.Args = append(orc.proc.Args, "--bind-address", "127.0.0.1")
- }
-
if *isCoverage {
orc.proc.Args = append(orc.proc.Args, "--test.coverprofile="+getCoveragePath("orc.out"))
}
diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go
index 6bd60b63191..d4f0e3f1963 100644
--- a/go/test/endtoend/cluster/vttablet_process.go
+++ b/go/test/endtoend/cluster/vttablet_process.go
@@ -111,13 +111,9 @@ func (vttablet *VttabletProcess) Setup() (err error) {
"--file_backup_storage_root", vttablet.FileBackupStorageRoot,
"--service_map", vttablet.ServiceMap,
"--db_charset", vttablet.Charset,
+ "--bind-address", "127.0.0.1",
+ "--grpc_bind_address", "127.0.0.1",
)
- if v, err := GetMajorVersion("vttablet"); err != nil {
- return err
- } else if v >= 18 {
- vttablet.proc.Args = append(vttablet.proc.Args, "--bind-address", "127.0.0.1")
- vttablet.proc.Args = append(vttablet.proc.Args, "--grpc_bind_address", "127.0.0.1")
- }
if *isCoverage {
vttablet.proc.Args = append(vttablet.proc.Args, "--test.coverprofile="+getCoveragePath("vttablet.out"))
diff --git a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go
index 4c759ff577a..7dea6cf525f 100644
--- a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go
+++ b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go
@@ -131,7 +131,7 @@ func initializeCluster(t *testing.T) (int, error) {
for _, keyspaceStr := range []string{keyspace} {
KeyspacePtr := &cluster.Keyspace{Name: keyspaceStr}
keyspace := *KeyspacePtr
- if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspace.Name, sidecar.DefaultName); err != nil {
+ if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspace.Name, sidecar.DefaultName, ""); err != nil {
return 1, err
}
shard := &cluster.Shard{
diff --git a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go
index 9147b7b9080..1363e07b2cd 100644
--- a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go
+++ b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go
@@ -350,7 +350,7 @@ func clusterSetUp(t *testing.T) (int, error) {
for _, keyspaceStr := range []string{keyspace} {
KeyspacePtr := &cluster.Keyspace{Name: keyspaceStr}
keyspace := *KeyspacePtr
- if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspace.Name, sidecar.DefaultName); err != nil {
+ if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspace.Name, sidecar.DefaultName, ""); err != nil {
return 1, err
}
shard := &cluster.Shard{
diff --git a/go/test/endtoend/mysqlctl/mysqlctl_test.go b/go/test/endtoend/mysqlctl/mysqlctl_test.go
index 6c3d65226e3..f93724fa4a8 100644
--- a/go/test/endtoend/mysqlctl/mysqlctl_test.go
+++ b/go/test/endtoend/mysqlctl/mysqlctl_test.go
@@ -53,7 +53,7 @@ func TestMain(m *testing.M) {
return 1
}
- if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName); err != nil {
+ if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName, ""); err != nil {
return 1
}
diff --git a/go/test/endtoend/mysqlctld/mysqlctld_test.go b/go/test/endtoend/mysqlctld/mysqlctld_test.go
index 328bc563377..beb155830e2 100644
--- a/go/test/endtoend/mysqlctld/mysqlctld_test.go
+++ b/go/test/endtoend/mysqlctld/mysqlctld_test.go
@@ -57,7 +57,7 @@ func TestMain(m *testing.M) {
return 1
}
- if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName); err != nil {
+ if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName, ""); err != nil {
return 1
}
diff --git a/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go b/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go
index 83fe6bea988..70efe4ec8a4 100644
--- a/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go
+++ b/go/test/endtoend/onlineddl/vrepl/onlineddl_vrepl_test.go
@@ -397,6 +397,8 @@ func TestSchemaChange(t *testing.T) {
assert.GreaterOrEqual(t, lastThrottledTimestamp, startedTimestamp)
component := row.AsString("component_throttled", "")
assert.Contains(t, []string{throttlerapp.VCopierName.String(), throttlerapp.VPlayerName.String()}, component)
+ reason := row.AsString("reason_throttled", "")
+ assert.Contains(t, reason, "is explicitly denied access")
// unthrottle
onlineddl.UnthrottleAllMigrations(t, &vtParams)
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go b/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go
index 57397ec64dd..c82b7f13a0d 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go
+++ b/go/test/endtoend/onlineddl/vrepl_suite/onlineddl_vrepl_suite_test.go
@@ -65,6 +65,7 @@ const (
testFilterEnvVar = "ONLINEDDL_SUITE_TEST_FILTER"
)
+// Use $VREPL_SUITE_TEST_FILTER environment variable to filter tests by name.
func TestMain(m *testing.M) {
defer cluster.PanicHandler(nil)
flag.Parse()
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-different-pk-new-pk-column/expect_failure b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-different-pk-new-pk-column/expect_failure
index ae3584915dd..5e227f16a3c 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-different-pk-new-pk-column/expect_failure
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-different-pk-new-pk-column/expect_failure
@@ -1 +1 @@
-Found no possible
+found no possible
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-drop-pk/expect_failure b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-drop-pk/expect_failure
index ae3584915dd..5e227f16a3c 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-drop-pk/expect_failure
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-drop-pk/expect_failure
@@ -1 +1 @@
-Found no possible
+found no possible
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/create.sql b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/create.sql
index abd7fbd4266..3712a673838 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/create.sql
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/create.sql
@@ -1,6 +1,6 @@
drop table if exists onlineddl_test;
create table onlineddl_test (
- f float,
+ f float not null,
i int not null,
ts timestamp default current_timestamp,
dt datetime,
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/expect_failure b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/expect_failure
index ae3584915dd..5e227f16a3c 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/expect_failure
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-float-unique-key/expect_failure
@@ -1 +1 @@
-Found no possible
+found no possible
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-no-unique-key/expect_failure b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-no-unique-key/expect_failure
index ae3584915dd..5e227f16a3c 100644
--- a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-no-unique-key/expect_failure
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-no-unique-key/expect_failure
@@ -1 +1 @@
-Found no possible
+found no possible
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/alter b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/alter
new file mode 100644
index 00000000000..0d2477f5801
--- /dev/null
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/alter
@@ -0,0 +1 @@
+add column v varchar(32)
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/create.sql b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/create.sql
new file mode 100644
index 00000000000..71f112d33c2
--- /dev/null
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/create.sql
@@ -0,0 +1,11 @@
+drop table if exists onlineddl_test;
+create table onlineddl_test (
+ id int,
+ i int not null,
+ ts timestamp default current_timestamp,
+ dt datetime,
+ key i_idx(i),
+ unique key id_uidx(id)
+) auto_increment=1;
+
+drop event if exists onlineddl_test;
diff --git a/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/expect_failure b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/expect_failure
new file mode 100644
index 00000000000..5e227f16a3c
--- /dev/null
+++ b/go/test/endtoend/onlineddl/vrepl_suite/testdata/fail-nullable-unique-key/expect_failure
@@ -0,0 +1 @@
+found no possible
diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go
index ccfd2eee239..5986056924e 100644
--- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go
+++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go
@@ -125,14 +125,8 @@ func TestReparentReplicaOffline(t *testing.T) {
require.Error(t, err)
// Assert that PRS failed
- if clusterInstance.VtctlMajorVersion <= 17 {
- assert.True(t, utils.SetReplicationSourceFailed(tablets[3], out))
- utils.CheckPrimaryTablet(t, clusterInstance, tablets[1])
- } else {
- assert.Contains(t, out, "rpc error: code = DeadlineExceeded desc")
- utils.CheckPrimaryTablet(t, clusterInstance, tablets[0])
- }
-
+ assert.Contains(t, out, "rpc error: code = DeadlineExceeded desc")
+ utils.CheckPrimaryTablet(t, clusterInstance, tablets[0])
}
func TestReparentAvoid(t *testing.T) {
@@ -155,20 +149,32 @@ func TestReparentAvoid(t *testing.T) {
require.NoError(t, err)
utils.ValidateTopology(t, clusterInstance, false)
- // tablets[1 is in the same cell and tablets[3] is in a different cell, so we must land on tablets[1
+ // tablets[1] is in the same cell and tablets[3] is in a different cell, so we must land on tablets[1]
utils.CheckPrimaryTablet(t, clusterInstance, tablets[1])
// If we kill the tablet in the same cell as primary then reparent --avoid_tablet will fail.
utils.StopTablet(t, tablets[0], true)
out, err := utils.PrsAvoid(t, clusterInstance, tablets[1])
require.Error(t, err)
- if clusterInstance.VtctlMajorVersion <= 17 {
- assert.Contains(t, out, "cannot find a tablet to reparent to in the same cell as the current primary")
- } else {
- assert.Contains(t, out, "rpc error: code = DeadlineExceeded desc = latest balancer error")
- }
+ assert.Contains(t, out, "rpc error: code = DeadlineExceeded desc = latest balancer error")
utils.ValidateTopology(t, clusterInstance, false)
utils.CheckPrimaryTablet(t, clusterInstance, tablets[1])
+
+ t.Run("Allow cross cell promotion", func(t *testing.T) {
+ if clusterInstance.VtctlMajorVersion <= 20 {
+ t.Skip("Allow Cross Cell Promotion was added in v21")
+ }
+ utils.DeleteTablet(t, clusterInstance, tablets[0])
+ // Perform a graceful reparent operation and verify it fails because we have no replicas in the same cell as the primary.
+ out, err = utils.PrsAvoid(t, clusterInstance, tablets[1])
+ require.Error(t, err)
+ assert.Contains(t, out, "is not in the same cell as the previous primary")
+
+ // If we run PRS with allow cross cell promotion then it should succeed and should promote the replica in another cell.
+ _, err = utils.PrsAvoid(t, clusterInstance, tablets[1], "--allow-cross-cell-promotion")
+ require.NoError(t, err)
+ utils.CheckPrimaryTablet(t, clusterInstance, tablets[3])
+ })
}
func TestReparentFromOutside(t *testing.T) {
@@ -199,13 +205,13 @@ func TestReparentFromOutsideWithNoPrimary(t *testing.T) {
}
func reparentFromOutside(t *testing.T, clusterInstance *cluster.LocalProcessCluster, downPrimary bool) {
- //This test will start a primary and 3 replicas.
- //Then:
- //- one replica will be the new primary
- //- one replica will be reparented to that new primary
- //- one replica will be busted and dead in the water and we'll call TabletExternallyReparented.
- //Args:
- //downPrimary: kills the old primary first
+ // This test will start a primary and 3 replicas.
+ // Then:
+ // - one replica will be the new primary
+ // - one replica will be reparented to that new primary
+ // - one replica will be busted and dead in the water and we'll call TabletExternallyReparented.
+ // Args:
+ // downPrimary: kills the old primary first
ctx := context.Background()
tablets := clusterInstance.Keyspaces[0].Shards[0].Vttablets
@@ -218,7 +224,7 @@ func reparentFromOutside(t *testing.T, clusterInstance *cluster.LocalProcessClus
demoteCommands := []string{"SET GLOBAL read_only = ON", "FLUSH TABLES WITH READ LOCK", "UNLOCK TABLES"}
utils.RunSQLs(ctx, t, demoteCommands, tablets[0])
- //Get the position of the old primary and wait for the new one to catch up.
+ // Get the position of the old primary and wait for the new one to catch up.
err := utils.WaitForReplicationPosition(t, tablets[0], tablets[1])
require.NoError(t, err)
}
@@ -454,14 +460,7 @@ func TestFullStatus(t *testing.T) {
assert.Contains(t, primaryStatus.PrimaryStatus.String(), "vt-0000000101-bin")
assert.Equal(t, primaryStatus.GtidPurged, "MySQL56/")
assert.False(t, primaryStatus.ReadOnly)
- vtTabletVersion, err := cluster.GetMajorVersion("vttablet")
- require.NoError(t, err)
- vtcltlVersion, err := cluster.GetMajorVersion("vtctl")
- require.NoError(t, err)
- // For all version at or above v17.0.0, each replica will start in super_read_only mode.
- if vtTabletVersion >= 17 && vtcltlVersion >= 17 {
- assert.False(t, primaryStatus.SuperReadOnly)
- }
+ assert.False(t, primaryStatus.SuperReadOnly)
assert.True(t, primaryStatus.SemiSyncPrimaryEnabled)
assert.True(t, primaryStatus.SemiSyncReplicaEnabled)
assert.True(t, primaryStatus.SemiSyncPrimaryStatus)
@@ -515,10 +514,7 @@ func TestFullStatus(t *testing.T) {
assert.Contains(t, replicaStatus.PrimaryStatus.String(), "vt-0000000102-bin")
assert.Equal(t, replicaStatus.GtidPurged, "MySQL56/")
assert.True(t, replicaStatus.ReadOnly)
- // For all version at or above v17.0.0, each replica will start in super_read_only mode.
- if vtTabletVersion >= 17 && vtcltlVersion >= 17 {
- assert.True(t, replicaStatus.SuperReadOnly)
- }
+ assert.True(t, replicaStatus.SuperReadOnly)
assert.False(t, replicaStatus.SemiSyncPrimaryEnabled)
assert.True(t, replicaStatus.SemiSyncReplicaEnabled)
assert.False(t, replicaStatus.SemiSyncPrimaryStatus)
diff --git a/go/test/endtoend/reparent/utils/utils.go b/go/test/endtoend/reparent/utils/utils.go
index 5038352d721..0d3eddc0464 100644
--- a/go/test/endtoend/reparent/utils/utils.go
+++ b/go/test/endtoend/reparent/utils/utils.go
@@ -293,17 +293,17 @@ func execute(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
// region ers, prs
// Prs runs PRS
-func Prs(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet) (string, error) {
- return PrsWithTimeout(t, clusterInstance, tab, false, "", "")
+func Prs(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet, extraArgs ...string) (string, error) {
+ return PrsWithTimeout(t, clusterInstance, tab, false, "", "", extraArgs...)
}
// PrsAvoid runs PRS
-func PrsAvoid(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet) (string, error) {
- return PrsWithTimeout(t, clusterInstance, tab, true, "", "")
+func PrsAvoid(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet, extraArgs ...string) (string, error) {
+ return PrsWithTimeout(t, clusterInstance, tab, true, "", "", extraArgs...)
}
// PrsWithTimeout runs PRS
-func PrsWithTimeout(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet, avoid bool, actionTimeout, waitTimeout string) (string, error) {
+func PrsWithTimeout(t *testing.T, clusterInstance *cluster.LocalProcessCluster, tab *cluster.Vttablet, avoid bool, actionTimeout, waitTimeout string, extraArgs ...string) (string, error) {
args := []string{
"PlannedReparentShard",
fmt.Sprintf("%s/%s", KeyspaceName, ShardName)}
@@ -319,6 +319,7 @@ func PrsWithTimeout(t *testing.T, clusterInstance *cluster.LocalProcessCluster,
args = append(args, "--new-primary")
}
args = append(args, tab.Alias)
+ args = append(args, extraArgs...)
out, err := clusterInstance.VtctldClientProcess.ExecuteCommandWithOutput(args...)
return out, err
}
diff --git a/go/test/endtoend/sharded/sharded_keyspace_test.go b/go/test/endtoend/sharded/sharded_keyspace_test.go
index f311404ad7e..192355fa6ef 100644
--- a/go/test/endtoend/sharded/sharded_keyspace_test.go
+++ b/go/test/endtoend/sharded/sharded_keyspace_test.go
@@ -84,7 +84,7 @@ func TestMain(m *testing.M) {
if err := clusterInstance.StartTopo(); err != nil {
return 1, err
}
- if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName); err != nil {
+ if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName, sidecar.DefaultName, ""); err != nil {
return 1, err
}
diff --git a/go/test/endtoend/tabletmanager/throttler_topo/throttler_test.go b/go/test/endtoend/tabletmanager/throttler_topo/throttler_test.go
index 89649f2ce4c..08cea643940 100644
--- a/go/test/endtoend/tabletmanager/throttler_topo/throttler_test.go
+++ b/go/test/endtoend/tabletmanager/throttler_topo/throttler_test.go
@@ -38,6 +38,7 @@ import (
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base"
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp"
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
)
@@ -203,18 +204,18 @@ func throttleStatus(t *testing.T, tablet *cluster.Vttablet) string {
return string(b)
}
-func warmUpHeartbeat(t *testing.T) (respStatus int) {
+func warmUpHeartbeat(t *testing.T) tabletmanagerdatapb.CheckThrottlerResponseCode {
// because we run with -heartbeat_on_demand_duration=5s, the heartbeat is "cold" right now.
// Let's warm it up.
resp, err := throttleCheck(primaryTablet, false)
require.NoError(t, err)
time.Sleep(time.Second)
- return int(resp.Check.StatusCode)
+ return throttle.ResponseCodeFromStatus(resp.Check.ResponseCode, int(resp.Check.StatusCode))
}
// waitForThrottleCheckStatus waits for the tablet to return the provided HTTP code in a throttle check
-func waitForThrottleCheckStatus(t *testing.T, tablet *cluster.Vttablet, wantCode int) bool {
+func waitForThrottleCheckStatus(t *testing.T, tablet *cluster.Vttablet, wantCode tabletmanagerdatapb.CheckThrottlerResponseCode) bool {
_ = warmUpHeartbeat(t)
ctx, cancel := context.WithTimeout(context.Background(), onDemandHeartbeatDuration*4)
defer cancel()
@@ -225,7 +226,7 @@ func waitForThrottleCheckStatus(t *testing.T, tablet *cluster.Vttablet, wantCode
resp, err := throttleCheck(tablet, true)
require.NoError(t, err)
- if wantCode == int(resp.Check.StatusCode) {
+ if wantCode == resp.Check.ResponseCode {
// Wait for any cached check values to be cleared and the new
// status value to be in effect everywhere before returning.
return true
@@ -260,7 +261,7 @@ func TestInitialThrottler(t *testing.T) {
defer cluster.PanicHandler(t)
t.Run("validating OK response from disabled throttler", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("enabling throttler with very low threshold", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Enable: true, Threshold: unreasonablyLowThreshold.Seconds()}
@@ -273,7 +274,7 @@ func TestInitialThrottler(t *testing.T) {
}
})
t.Run("validating pushback response from throttler", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("disabling throttler", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Disable: true, Threshold: unreasonablyLowThreshold.Seconds()}
@@ -286,7 +287,7 @@ func TestInitialThrottler(t *testing.T) {
}
})
t.Run("validating OK response from disabled throttler, again", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("enabling throttler, again", func(t *testing.T) {
// Enable the throttler again with the default query which also moves us back
@@ -301,7 +302,7 @@ func TestInitialThrottler(t *testing.T) {
}
})
t.Run("validating pushback response from throttler, again", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("setting high threshold", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: extremelyHighThreshold.Seconds()}
@@ -314,7 +315,7 @@ func TestInitialThrottler(t *testing.T) {
}
})
t.Run("validating OK response from throttler with high threshold", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("setting low threshold", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
@@ -327,11 +328,11 @@ func TestInitialThrottler(t *testing.T) {
}
})
t.Run("validating pushback response from throttler on low threshold", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("requesting heartbeats", func(t *testing.T) {
respStatus := warmUpHeartbeat(t)
- assert.NotEqual(t, http.StatusOK, respStatus)
+ assert.NotEqual(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, respStatus)
})
t.Run("validating OK response from throttler with low threshold, heartbeats running", func(t *testing.T) {
time.Sleep(1 * time.Second)
@@ -350,6 +351,13 @@ func TestInitialThrottler(t *testing.T) {
t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
}
+ if !assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp) {
+ rs, err := replicaTablet.VttabletProcess.QueryTablet("show replica status", keyspaceName, false)
+ assert.NoError(t, err)
+ t.Logf("Seconds_Behind_Source: %s", rs.Named().Row()["Seconds_Behind_Source"].ToString())
+ t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
+ t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
+ }
})
t.Run("validating OK response from throttler with low threshold, heartbeats running still", func(t *testing.T) {
@@ -368,10 +376,17 @@ func TestInitialThrottler(t *testing.T) {
t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
}
+ if !assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp) {
+ rs, err := replicaTablet.VttabletProcess.QueryTablet("show replica status", keyspaceName, false)
+ assert.NoError(t, err)
+ t.Logf("Seconds_Behind_Source: %s", rs.Named().Row()["Seconds_Behind_Source"].ToString())
+ t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
+ t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
+ }
})
t.Run("validating pushback response from throttler on low threshold once heartbeats go stale", func(t *testing.T) {
time.Sleep(2 * onDemandHeartbeatDuration) // just... really wait long enough, make sure on-demand stops
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
}
@@ -424,7 +439,7 @@ func TestThrottlerAfterMetricsCollected(t *testing.T) {
// By this time metrics will have been collected. We expect no lag, and something like:
// {"StatusCode":200,"Value":0.282278,"Threshold":1,"Message":""}
t.Run("validating throttler OK", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("validating throttled apps", func(t *testing.T) {
resp, body, err := throttledApps(primaryTablet)
@@ -437,11 +452,13 @@ func TestThrottlerAfterMetricsCollected(t *testing.T) {
resp, err := throttleCheckSelf(primaryTablet)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("validating replica check self", func(t *testing.T) {
resp, err := throttleCheckSelf(replicaTablet)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
}
@@ -469,6 +486,7 @@ func TestLag(t *testing.T) {
resp, err := throttleCheck(primaryTablet, false)
require.NoError(t, err)
assert.EqualValues(t, http.StatusTooManyRequests, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("primary self-check should still be fine", func(t *testing.T) {
resp, err := throttleCheckSelf(primaryTablet)
@@ -482,6 +500,10 @@ func TestLag(t *testing.T) {
t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
}
+ if !assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp) {
+ t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
+ t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
+ }
})
t.Run("replica self-check should show error", func(t *testing.T) {
resp, err := throttleCheckSelf(replicaTablet)
@@ -491,6 +513,7 @@ func TestLag(t *testing.T) {
assert.Equal(t, base.SelfScope.String(), metrics.Scope)
}
assert.EqualValues(t, http.StatusTooManyRequests, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("exempting test app", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -501,7 +524,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("unexempting test app", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -511,7 +534,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("exempting all apps", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -522,7 +545,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("throttling test app", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -533,7 +556,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusExpectationFailed)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED)
})
t.Run("unthrottling test app", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -543,7 +566,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("unexempting all apps", func(t *testing.T) {
appRule := &topodatapb.ThrottledAppRule{
@@ -553,7 +576,7 @@ func TestLag(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
_, err := throttler.UpdateThrottlerTopoConfig(clusterInstance, req, appRule, nil)
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("starting replication", func(t *testing.T) {
@@ -561,18 +584,20 @@ func TestLag(t *testing.T) {
assert.NoError(t, err)
})
t.Run("expecting replication to catch up and throttler check to return OK", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("primary self-check should be fine", func(t *testing.T) {
resp, err := throttleCheckSelf(primaryTablet)
require.NoError(t, err)
// self (on primary) is unaffected by replication lag
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("replica self-check should be fine", func(t *testing.T) {
resp, err := throttleCheckSelf(replicaTablet)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
}
@@ -584,13 +609,13 @@ func TestNoReplicas(t *testing.T) {
// This makes no REPLICA servers available. We expect something like:
// {"StatusCode":200,"Value":0,"Threshold":1,"Message":""}
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("restoring to REPLICA", func(t *testing.T) {
err := clusterInstance.VtctldClientProcess.ExecuteCommand("ChangeTabletType", replicaTablet.Alias, "REPLICA")
assert.NoError(t, err)
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
}
@@ -617,6 +642,7 @@ func TestCustomQuery(t *testing.T) {
resp, err := throttleCheck(primaryTablet, false)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("test threads running", func(t *testing.T) {
sleepDuration := 20 * time.Second
@@ -638,22 +664,24 @@ func TestCustomQuery(t *testing.T) {
// Now we should be reporting ~ customThreshold+1 threads_running, and we should
// hit the threshold. For example:
// {"StatusCode":429,"Value":6,"Threshold":5,"Message":"Threshold exceeded"}
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
{
resp, err := throttleCheckSelf(primaryTablet)
require.NoError(t, err)
assert.EqualValues(t, http.StatusTooManyRequests, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
}
})
t.Run("wait for queries to terminate", func(t *testing.T) {
wg.Wait()
})
t.Run("restored below threshold", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
{
resp, err := throttleCheckSelf(primaryTablet)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
}
})
})
@@ -677,10 +705,11 @@ func TestRestoreDefaultQuery(t *testing.T) {
resp, err := throttleCheck(primaryTablet, false)
require.NoError(t, err)
assert.EqualValues(t, http.StatusOK, resp.Check.StatusCode, "Unexpected response from throttler: %+v", resp)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, resp.Check.ResponseCode, "Unexpected response from throttler: %+v", resp)
})
t.Run("validating pushback response from throttler on default threshold once heartbeats go stale", func(t *testing.T) {
time.Sleep(2 * onDemandHeartbeatDuration) // just... really wait long enough, make sure on-demand stops
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
}
@@ -693,7 +722,7 @@ func TestUpdateMetricThresholds(t *testing.T) {
for _, tablet := range []cluster.Vttablet{*primaryTablet, *replicaTablet} {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: throttler.DefaultThreshold.Seconds()}, throttlerEnabledTimeout)
}
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("setting low general threshold, and high threshold for 'lag' metric", func(t *testing.T) {
{
@@ -713,7 +742,7 @@ func TestUpdateMetricThresholds(t *testing.T) {
})
t.Run("validating OK response from throttler thanks to high 'lag' threshold", func(t *testing.T) {
// Note that the default threshold is extremely low, but gets overriden.
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK)
})
t.Run("removing explicit 'lag' threshold", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{MetricName: "lag", Threshold: 0}
@@ -721,7 +750,7 @@ func TestUpdateMetricThresholds(t *testing.T) {
assert.NoError(t, err)
})
t.Run("validating pushback from throttler again", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("restoring standard threshold", func(t *testing.T) {
req := &vtctldatapb.UpdateThrottlerConfigRequest{Threshold: throttler.DefaultThreshold.Seconds()}
@@ -731,7 +760,7 @@ func TestUpdateMetricThresholds(t *testing.T) {
for _, tablet := range []cluster.Vttablet{*primaryTablet, *replicaTablet} {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: throttler.DefaultThreshold.Seconds()}, throttlerEnabledTimeout)
}
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
}
@@ -748,7 +777,7 @@ func TestUpdateAppCheckedMetrics(t *testing.T) {
for _, tablet := range []cluster.Vttablet{*primaryTablet, *replicaTablet} {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: throttler.DefaultThreshold.Seconds()}, throttlerEnabledTimeout)
}
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
t.Run("assigning 'loadavg' metrics to 'test' app", func(t *testing.T) {
{
@@ -774,7 +803,7 @@ func TestUpdateAppCheckedMetrics(t *testing.T) {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: unreasonablyLowThreshold.Seconds()}, throttlerEnabledTimeout)
}
t.Run("validating OK response from throttler since it's checking loadavg", func(t *testing.T) {
- if !waitForThrottleCheckStatus(t, primaryTablet, http.StatusOK) {
+ if !waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_OK) {
t.Logf("throttler primary status: %+v", throttleStatus(t, primaryTablet))
t.Logf("throttler replica status: %+v", throttleStatus(t, replicaTablet))
}
@@ -799,7 +828,7 @@ func TestUpdateAppCheckedMetrics(t *testing.T) {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: unreasonablyLowThreshold.Seconds()}, throttlerEnabledTimeout)
}
t.Run("validating pushback from throttler since lag is above threshold", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
})
t.Run("removing assignment from 'test' app and restoring defaults", func(t *testing.T) {
@@ -826,7 +855,7 @@ func TestUpdateAppCheckedMetrics(t *testing.T) {
throttler.WaitForThrottlerStatusEnabled(t, &clusterInstance.VtctldClientProcess, &tablet, true, &throttler.Config{Query: throttler.DefaultQuery, Threshold: throttler.DefaultThreshold.Seconds()}, throttlerEnabledTimeout)
}
t.Run("validating error response from throttler since lag is still high", func(t *testing.T) {
- waitForThrottleCheckStatus(t, primaryTablet, http.StatusTooManyRequests)
+ waitForThrottleCheckStatus(t, primaryTablet, tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED)
})
})
}
diff --git a/go/test/endtoend/transaction/twopc/fuzzer/fuzzer_test.go b/go/test/endtoend/transaction/twopc/fuzzer/fuzzer_test.go
new file mode 100644
index 00000000000..ff440164042
--- /dev/null
+++ b/go/test/endtoend/transaction/twopc/fuzzer/fuzzer_test.go
@@ -0,0 +1,310 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 fuzzer
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "golang.org/x/exp/rand"
+
+ "vitess.io/vitess/go/mysql"
+)
+
+var (
+ // updateRowBaseVals is the base row values that we use to ensure 1 update on each shard with the same increment.
+ updateRowBaseVals = [3]int{
+ 4, // 4 maps to 0x20 and ends up in the first shard (-40)
+ 6, // 6 maps to 0x60 and ends up in the second shard (40-80)
+ 9, // 9 maps to 0x90 and ends up in the third shard (80-)
+ // We can increment all of these values by multiples of 16 and they'll always be in the same shard.
+ }
+
+ insertIntoFuzzUpdate = "INSERT INTO twopc_fuzzer_update (id, col) VALUES (%d, %d)"
+ updateFuzzUpdate = "UPDATE twopc_fuzzer_update SET col = col + %d WHERE id = %d"
+ insertIntoFuzzInsert = "INSERT INTO twopc_fuzzer_insert (id, updateSet, threadId) VALUES (%d, %d, %d)"
+ selectFromFuzzUpdate = "SELECT col FROM twopc_fuzzer_update WHERE id = %d"
+ selectIdFromFuzzInsert = "SELECT threadId FROM twopc_fuzzer_insert WHERE updateSet = %d AND id = %d ORDER BY col"
+)
+
+// TestTwoPCFuzzTest tests 2PC transactions in a fuzzer environment.
+// The testing strategy involves running many transactions and checking that they all must be atomic.
+// To this end, we have a very unique strategy. We have two sharded tables `twopc_fuzzer_update`, and `twopc_fuzzer_insert` with the following columns.
+// - id: This is the sharding column. We use reverse_bits as the sharding vindex because it is easy to reason about where a row will end up.
+// - col in `twopc_fuzzer_insert`: An auto-increment column.
+// - col in `twopc_fuzzer_update`: This is a bigint value that we will use to increment on updates.
+// - updateSet: This column will store which update set the inserts where done for.
+// - threadId: It stores the thread id of the fuzzer thread that inserted the row.
+//
+// The testing strategy is as follows -
+// Every transaction will do 2 things -
+// - One, it will increment the `col` on 1 row in each of the shards of the `twopc_fuzzer_update` table.
+// To do this, we have sets of rows that each map to one shard. We prepopulate this before the test starts.
+// These sets are stored in the fuzzer in updateRowsVals.
+// - Two, it will insert one row in each of the shards of the `twopc_fuzzer_insert` table and it will also store the update set that it updated the rows off.
+//
+// We can check that a transaction was atomic by basically checking that the `col` value for all the rows that were updated together should match.
+// If any transaction was partially successful, then it would have missed an increment on one of the rows.
+// Moreover, the threadIDs of rows for a given update set in the 3 shards should be the same to ensure that conflicting transactions got committed in the same exact order.
+func TestTwoPCFuzzTest(t *testing.T) {
+ testcases := []struct {
+ name string
+ threads int
+ updateSets int
+ timeForTesting time.Duration
+ }{
+ {
+ name: "Single Thread - Single Set",
+ threads: 1,
+ updateSets: 1,
+ timeForTesting: 5 * time.Second,
+ },
+ {
+ name: "Multiple Threads - Single Set",
+ threads: 2,
+ updateSets: 1,
+ timeForTesting: 5 * time.Second,
+ },
+ {
+ name: "Multiple Threads - Multiple Set",
+ threads: 15,
+ updateSets: 15,
+ timeForTesting: 5 * time.Second,
+ },
+ }
+
+ for _, tt := range testcases {
+ t.Run(tt.name, func(t *testing.T) {
+ conn, closer := start(t)
+ defer closer()
+ fz := newFuzzer(tt.threads, tt.updateSets)
+
+ fz.initialize(t, conn)
+ // Start the fuzzer.
+ fz.start(t)
+
+ // Wait for the timeForTesting so that the threads continue to run.
+ time.Sleep(tt.timeForTesting)
+
+ // Signal the fuzzer to stop.
+ fz.stop()
+
+ // Verify that all the transactions run were actually atomic and no data issues have occurred.
+ fz.verifyTransactionsWereAtomic(t)
+ })
+ }
+}
+
+// verifyTransactionsWereAtomic verifies that the invariants of test are held.
+// It checks the heuristics to ensure that the transactions run were atomic.
+func (fz *fuzzer) verifyTransactionsWereAtomic(t *testing.T) {
+ conn, err := mysql.Connect(context.Background(), &vtParams)
+ require.NoError(t, err)
+ for updateSetIdx, updateSet := range fz.updateRowsVals {
+ // All the three values of the update set must be equal.
+ shard1Val := getColValueForIdFromFuzzUpdate(t, conn, updateSet[0])
+ shard2Val := getColValueForIdFromFuzzUpdate(t, conn, updateSet[1])
+ shard3Val := getColValueForIdFromFuzzUpdate(t, conn, updateSet[2])
+ require.EqualValues(t, shard1Val, shard2Val)
+ require.EqualValues(t, shard3Val, shard2Val)
+
+ // Next we get the IDs from all the three shards for the given update set index.
+ shard1IDs := getThreadIDsForUpdateSetFromFuzzInsert(t, conn, updateSetIdx, 1)
+ shard2IDs := getThreadIDsForUpdateSetFromFuzzInsert(t, conn, updateSetIdx, 2)
+ shard3IDs := getThreadIDsForUpdateSetFromFuzzInsert(t, conn, updateSetIdx, 3)
+ require.EqualValues(t, shard1IDs, shard2IDs)
+ require.EqualValues(t, shard3IDs, shard2IDs)
+ }
+}
+
+// getColValueForIdFromFuzzUpdate gets the col column value for the given id in the twopc_fuzzer_update table.
+func getColValueForIdFromFuzzUpdate(t *testing.T, conn *mysql.Conn, id int) uint64 {
+ res, err := conn.ExecuteFetch(fmt.Sprintf(selectFromFuzzUpdate, id), 1, false)
+ require.NoError(t, err)
+ require.Len(t, res.Rows, 1)
+ require.Len(t, res.Rows[0], 1)
+ val, err := res.Rows[0][0].ToUint64()
+ require.NoError(t, err)
+ return val
+}
+
+// getThreadIDsForUpdateSetFromFuzzInsert gets the thread IDs for the given update set ordered by the col column from the twopc_fuzzer_insert table.
+func getThreadIDsForUpdateSetFromFuzzInsert(t *testing.T, conn *mysql.Conn, updateSet int, shard int) []int {
+ // We will select all the rows for the given update set for the given shard. To get all the rows for the given shard,
+ // we can use the id column for filtering, since we know that the first shard will have all the values of id as 4, second shard as 6 and the last one as 9.
+ res, err := conn.ExecuteFetch(fmt.Sprintf(selectIdFromFuzzInsert, updateSet, updateRowBaseVals[shard-1]), 10000, false)
+ require.NoError(t, err)
+ var ids []int
+ for _, row := range res.Rows {
+ require.Len(t, row, 1)
+ threadId, err := row[0].ToInt()
+ require.NoError(t, err)
+ ids = append(ids, threadId)
+ }
+ return ids
+}
+
+// fuzzer runs threads that runs queries against the databases.
+// It has parameters that define the way the queries are constructed.
+type fuzzer struct {
+ threads int
+ updateSets int
+
+ // shouldStop is an internal state variable, that tells the fuzzer
+ // whether it should stop or not.
+ shouldStop atomic.Bool
+ // wg is an internal state variable, that used to know whether the fuzzer threads are running or not.
+ wg sync.WaitGroup
+ // updateRowVals are the rows that we use to ensure 1 update on each shard with the same increment.
+ updateRowsVals [][]int
+}
+
+// newFuzzer creates a new fuzzer struct.
+func newFuzzer(threads int, updateSets int) *fuzzer {
+ fz := &fuzzer{
+ threads: threads,
+ updateSets: updateSets,
+ wg: sync.WaitGroup{},
+ }
+ // Initially the fuzzer thread is stopped.
+ fz.shouldStop.Store(true)
+ return fz
+}
+
+// stop stops the fuzzer and waits for it to finish execution.
+func (fz *fuzzer) stop() {
+ // Mark the thread to be stopped.
+ fz.shouldStop.Store(true)
+ // Wait for the fuzzer thread to stop.
+ fz.wg.Wait()
+}
+
+// start starts running the fuzzer.
+func (fz *fuzzer) start(t *testing.T) {
+ // We mark the fuzzer thread to be running now.
+ fz.shouldStop.Store(false)
+ fz.wg.Add(fz.threads)
+ for i := 0; i < fz.threads; i++ {
+ go func() {
+ fz.runFuzzerThread(t, i)
+ }()
+ }
+}
+
+// runFuzzerThread is used to run a thread of the fuzzer.
+func (fz *fuzzer) runFuzzerThread(t *testing.T, threadId int) {
+ // Whenever we finish running this thread, we should mark the thread has stopped.
+ defer func() {
+ fz.wg.Done()
+ }()
+
+ for {
+ // If fuzzer thread is marked to be stopped, then we should exit this go routine.
+ if fz.shouldStop.Load() == true {
+ return
+ }
+ // Run an atomic transaction
+ fz.generateAndExecuteTransaction(threadId)
+ }
+
+}
+
+// initialize initializes all the variables that will be needed for running the fuzzer.
+// It also creates the rows for the `twopc_fuzzer_update` table.
+func (fz *fuzzer) initialize(t *testing.T, conn *mysql.Conn) {
+ for i := 0; i < fz.updateSets; i++ {
+ fz.updateRowsVals = append(fz.updateRowsVals, []int{
+ updateRowBaseVals[0] + i*16,
+ updateRowBaseVals[1] + i*16,
+ updateRowBaseVals[2] + i*16,
+ })
+ }
+
+ for _, updateSet := range fz.updateRowsVals {
+ for _, id := range updateSet {
+ _, err := conn.ExecuteFetch(fmt.Sprintf(insertIntoFuzzUpdate, id, 0), 0, false)
+ require.NoError(t, err)
+ }
+ }
+}
+
+// generateAndExecuteTransaction generates the queries of the transaction and then executes them.
+func (fz *fuzzer) generateAndExecuteTransaction(threadId int) {
+ // Create a connection to the vtgate to run transactions.
+ conn, err := mysql.Connect(context.Background(), &vtParams)
+ if err != nil {
+ return
+ }
+ defer conn.Close()
+ // randomly generate an update set to use and the value to increment it by.
+ updateSetVal := rand.Intn(fz.updateSets)
+ incrementVal := rand.Int31()
+ // We have to generate the update queries first. We can run the inserts only after the update queries.
+ // Otherwise, our check to see that the ids in the twopc_fuzzer_insert table in all the shards are the exact same
+ // for each update set ordered by the auto increment column will not be true.
+ // That assertion depends on all the transactions running updates first to ensure that for any given update set,
+ // no two transactions are running the insert queries.
+ queries := []string{"begin"}
+ queries = append(queries, fz.generateUpdateQueries(updateSetVal, incrementVal)...)
+ queries = append(queries, fz.generateInsertQueries(updateSetVal, threadId)...)
+ finalCommand := "commit"
+ for _, query := range queries {
+ _, err := conn.ExecuteFetch(query, 0, false)
+ // If any command fails because of deadlocks or timeout or whatever, then we need to rollback the transaction.
+ if err != nil {
+ finalCommand = "rollback"
+ break
+ }
+ }
+ _, _ = conn.ExecuteFetch(finalCommand, 0, false)
+}
+
+// generateUpdateQueries generates the queries to run updates on the twopc_fuzzer_update table.
+// It takes the update set index and the value to increment the set by.
+func (fz *fuzzer) generateUpdateQueries(updateSet int, incrementVal int32) []string {
+ var queries []string
+ for _, id := range fz.updateRowsVals[updateSet] {
+ queries = append(queries, fmt.Sprintf(updateFuzzUpdate, incrementVal, id))
+ }
+ rand.Shuffle(len(queries), func(i, j int) {
+ queries[i], queries[j] = queries[j], queries[i]
+ })
+ return queries
+}
+
+// generateInsertQueries generates the queries to run inserts on the twopc_fuzzer_insert table.
+// It takes the update set index and the thread id that is generating these inserts.
+func (fz *fuzzer) generateInsertQueries(updateSet int, threadId int) []string {
+ var queries []string
+ for _, baseVal := range updateRowBaseVals {
+ // In the twopc_fuzzer_insert table we are going to be inserting the following values -
+ // - id: We use the updateRowBaseVals to ensure that the 3 insertions happen on 3 different shards.
+ // This also allows us to read rows any of the shards without shard targeting by just filtering by this column.
+ // - updateSet: The update set index that these insertions correspond too.
+ // - threadId: The thread ID of the fuzzer thread that is running the transaction.
+ queries = append(queries, fmt.Sprintf(insertIntoFuzzInsert, baseVal, updateSet, threadId))
+ }
+ rand.Shuffle(len(queries), func(i, j int) {
+ queries[i], queries[j] = queries[j], queries[i]
+ })
+ return queries
+}
diff --git a/go/test/endtoend/transaction/twopc/fuzzer/main_test.go b/go/test/endtoend/transaction/twopc/fuzzer/main_test.go
new file mode 100644
index 00000000000..e0affde186a
--- /dev/null
+++ b/go/test/endtoend/transaction/twopc/fuzzer/main_test.go
@@ -0,0 +1,116 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 fuzzer
+
+import (
+ "context"
+ _ "embed"
+ "flag"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "vitess.io/vitess/go/mysql"
+ "vitess.io/vitess/go/test/endtoend/cluster"
+ "vitess.io/vitess/go/test/endtoend/transaction/twopc/utils"
+)
+
+var (
+ clusterInstance *cluster.LocalProcessCluster
+ vtParams mysql.ConnParams
+ vtgateGrpcAddress string
+ keyspaceName = "ks"
+ cell = "zone1"
+ hostname = "localhost"
+ sidecarDBName = "vt_ks"
+
+ //go:embed schema.sql
+ SchemaSQL string
+
+ //go:embed vschema.json
+ VSchema string
+)
+
+func TestMain(m *testing.M) {
+ defer cluster.PanicHandler(nil)
+ flag.Parse()
+
+ exitcode := func() int {
+ clusterInstance = cluster.NewCluster(cell, hostname)
+ defer clusterInstance.Teardown()
+
+ // Start topo server
+ if err := clusterInstance.StartTopo(); err != nil {
+ return 1
+ }
+
+ // Reserve vtGate port in order to pass it to vtTablet
+ clusterInstance.VtgateGrpcPort = clusterInstance.GetAndReservePort()
+
+ // Set extra args for twopc
+ clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs,
+ "--transaction_mode", "TWOPC",
+ "--grpc_use_effective_callerid",
+ )
+ clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs,
+ "--twopc_enable",
+ "--twopc_abandon_age", "1",
+ )
+
+ // Start keyspace
+ keyspace := &cluster.Keyspace{
+ Name: keyspaceName,
+ SchemaSQL: SchemaSQL,
+ VSchema: VSchema,
+ SidecarDBName: sidecarDBName,
+ }
+ if err := clusterInstance.StartKeyspace(*keyspace, []string{"-40", "40-80", "80-"}, 0, false); err != nil {
+ return 1
+ }
+
+ // Start Vtgate
+ if err := clusterInstance.StartVtgate(); err != nil {
+ return 1
+ }
+ vtParams = clusterInstance.GetVTParams(keyspaceName)
+ vtgateGrpcAddress = fmt.Sprintf("%s:%d", clusterInstance.Hostname, clusterInstance.VtgateGrpcPort)
+
+ return m.Run()
+ }()
+ os.Exit(exitcode)
+}
+
+func start(t *testing.T) (*mysql.Conn, func()) {
+ ctx := context.Background()
+ conn, err := mysql.Connect(ctx, &vtParams)
+ require.NoError(t, err)
+ cleanup(t)
+
+ return conn, func() {
+ conn.Close()
+ cleanup(t)
+ }
+}
+
+func cleanup(t *testing.T) {
+ cluster.PanicHandler(t)
+
+ utils.ClearOutTable(t, vtParams, "twopc_fuzzer_insert")
+ utils.ClearOutTable(t, vtParams, "twopc_fuzzer_update")
+}
diff --git a/go/test/endtoend/transaction/twopc/fuzzer/schema.sql b/go/test/endtoend/transaction/twopc/fuzzer/schema.sql
new file mode 100644
index 00000000000..290da808991
--- /dev/null
+++ b/go/test/endtoend/transaction/twopc/fuzzer/schema.sql
@@ -0,0 +1,14 @@
+create table twopc_fuzzer_update (
+ id bigint,
+ col bigint,
+ primary key (id)
+) Engine=InnoDB;
+
+create table twopc_fuzzer_insert (
+ id bigint,
+ updateSet bigint,
+ threadId bigint,
+ col bigint auto_increment,
+ key(col),
+ primary key (id, col)
+) Engine=InnoDB;
diff --git a/go/test/endtoend/transaction/twopc/fuzzer/vschema.json b/go/test/endtoend/transaction/twopc/fuzzer/vschema.json
new file mode 100644
index 00000000000..e3854f8f101
--- /dev/null
+++ b/go/test/endtoend/transaction/twopc/fuzzer/vschema.json
@@ -0,0 +1,26 @@
+{
+ "sharded":true,
+ "vindexes": {
+ "reverse_bits": {
+ "type": "reverse_bits"
+ }
+ },
+ "tables": {
+ "twopc_fuzzer_update": {
+ "column_vindexes": [
+ {
+ "column": "id",
+ "name": "reverse_bits"
+ }
+ ]
+ },
+ "twopc_fuzzer_insert": {
+ "column_vindexes": [
+ {
+ "column": "id",
+ "name": "reverse_bits"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/go/test/endtoend/transaction/twopc/main_test.go b/go/test/endtoend/transaction/twopc/main_test.go
index 8ac7cfc1f21..4c5e2715563 100644
--- a/go/test/endtoend/transaction/twopc/main_test.go
+++ b/go/test/endtoend/transaction/twopc/main_test.go
@@ -33,7 +33,7 @@ import (
"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/test/endtoend/cluster"
- "vitess.io/vitess/go/test/endtoend/utils"
+ "vitess.io/vitess/go/test/endtoend/transaction/twopc/utils"
binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
querypb "vitess.io/vitess/go/vt/proto/query"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
@@ -85,12 +85,13 @@ func TestMain(m *testing.M) {
// Start keyspace
keyspace := &cluster.Keyspace{
- Name: keyspaceName,
- SchemaSQL: SchemaSQL,
- VSchema: VSchema,
- SidecarDBName: sidecarDBName,
+ Name: keyspaceName,
+ SchemaSQL: SchemaSQL,
+ VSchema: VSchema,
+ SidecarDBName: sidecarDBName,
+ DurabilityPolicy: "semi_sync",
}
- if err := clusterInstance.StartKeyspace(*keyspace, []string{"-40", "40-80", "80-"}, 0, false); err != nil {
+ if err := clusterInstance.StartKeyspace(*keyspace, []string{"-40", "40-80", "80-"}, 2, false); err != nil {
return 1
}
@@ -119,13 +120,8 @@ func start(t *testing.T) (*mysql.Conn, func()) {
func cleanup(t *testing.T) {
cluster.PanicHandler(t)
-
- ctx := context.Background()
- conn, err := mysql.Connect(ctx, &vtParams)
- require.NoError(t, err)
- defer conn.Close()
-
- _, _ = utils.ExecAllowError(t, conn, "delete from twopc_user")
+ utils.ClearOutTable(t, vtParams, "twopc_user")
+ utils.ClearOutTable(t, vtParams, "twopc_t1")
}
type extractInterestingValues func(dtidMap map[string]string, vals []sqltypes.Value) []sqltypes.Value
diff --git a/go/test/endtoend/transaction/twopc/schema.sql b/go/test/endtoend/transaction/twopc/schema.sql
index 60a7c19837c..de9e3ef0656 100644
--- a/go/test/endtoend/transaction/twopc/schema.sql
+++ b/go/test/endtoend/transaction/twopc/schema.sql
@@ -9,4 +9,10 @@ create table twopc_music (
user_id bigint,
title varchar(64),
primary key (id)
+) Engine=InnoDB;
+
+create table twopc_t1 (
+ id bigint,
+ col bigint,
+ primary key (id, col)
) Engine=InnoDB;
\ No newline at end of file
diff --git a/go/test/endtoend/transaction/twopc/twopc_test.go b/go/test/endtoend/transaction/twopc/twopc_test.go
index dc2aba61b1b..53c1780f373 100644
--- a/go/test/endtoend/transaction/twopc/twopc_test.go
+++ b/go/test/endtoend/transaction/twopc/twopc_test.go
@@ -20,6 +20,8 @@ import (
"context"
_ "embed"
"fmt"
+ "os"
+ "path"
"reflect"
"sort"
"strings"
@@ -31,11 +33,19 @@ import (
"github.com/stretchr/testify/require"
"vitess.io/vitess/go/mysql"
+ "vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/test/endtoend/utils"
"vitess.io/vitess/go/vt/callerid"
+ "vitess.io/vitess/go/vt/log"
binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
querypb "vitess.io/vitess/go/vt/proto/query"
+ "vitess.io/vitess/go/vt/vtgate/vtgateconn"
+)
+
+const (
+ DebugDelayCommitShard = "VT_DELAY_COMMIT_SHARD"
+ DebugDelayCommitTime = "VT_DELAY_COMMIT_TIME"
)
// TestDTCommit tests distributed transaction commit for insert, update and delete operations
@@ -580,6 +590,10 @@ func TestDTResolveAfterMMCommit(t *testing.T) {
_, err = conn.Execute(newCtx, "commit", nil)
require.ErrorContains(t, err, "Fail After MM commit")
+ testWarningAndTransactionStatus(t, conn,
+ "distributed transaction ID failed during metadata manager commit; transaction will be committed/rollbacked based on the state on recovery",
+ false, "COMMIT", "ks:40-80,ks:-40")
+
// Below check ensures that the transaction is resolved by the resolver on receiving unresolved transaction signal from MM.
tableMap := make(map[string][]*querypb.Field)
dtMap := make(map[string]string)
@@ -656,6 +670,10 @@ func TestDTResolveAfterRMPrepare(t *testing.T) {
_, err = conn.Execute(newCtx, "commit", nil)
require.ErrorContains(t, err, "Fail After RM prepared")
+ testWarningAndTransactionStatus(t, conn,
+ "distributed transaction ID failed during transaction prepare phase; prepare transaction rollback attempted; conclude on recovery",
+ true /* transaction concluded */, "", "")
+
// Below check ensures that the transaction is resolved by the resolver on receiving unresolved transaction signal from MM.
tableMap := make(map[string][]*querypb.Field)
dtMap := make(map[string]string)
@@ -714,6 +732,10 @@ func TestDTResolveDuringRMPrepare(t *testing.T) {
_, err = conn.Execute(newCtx, "commit", nil)
require.ErrorContains(t, err, "Fail During RM prepare")
+ testWarningAndTransactionStatus(t, conn,
+ "distributed transaction ID failed during transaction prepare phase; prepare transaction rollback attempted; conclude on recovery",
+ true, "", "")
+
// Below check ensures that the transaction is resolved by the resolver on receiving unresolved transaction signal from MM.
tableMap := make(map[string][]*querypb.Field)
dtMap := make(map[string]string)
@@ -776,6 +798,10 @@ func TestDTResolveDuringRMCommit(t *testing.T) {
_, err = conn.Execute(newCtx, "commit", nil)
require.ErrorContains(t, err, "Fail During RM commit")
+ testWarningAndTransactionStatus(t, conn,
+ "distributed transaction ID failed during resource manager commit; transaction will be committed on recovery",
+ false, "COMMIT", "ks:40-80,ks:-40")
+
// Below check ensures that the transaction is resolved by the resolver on receiving unresolved transaction signal from MM.
tableMap := make(map[string][]*querypb.Field)
dtMap := make(map[string]string)
@@ -851,18 +877,9 @@ func TestDTResolveAfterTransactionRecord(t *testing.T) {
_, err = conn.Execute(newCtx, "commit", nil)
require.ErrorContains(t, err, "Fail After TR created")
- t.Run("ReadTransactionState", func(t *testing.T) {
- errStr := err.Error()
- indx := strings.Index(errStr, "Fail")
- require.Greater(t, indx, 0)
- dtid := errStr[0 : indx-2]
- res, err := conn.Execute(context.Background(), fmt.Sprintf(`show transaction status for '%v'`, dtid), nil)
- require.NoError(t, err)
- resStr := fmt.Sprintf("%v", res.Rows)
- require.Contains(t, resStr, `[[VARCHAR("ks:80-`)
- require.Contains(t, resStr, `VARCHAR("PREPARE") DATETIME("`)
- require.Contains(t, resStr, `+0000 UTC") VARCHAR("ks:40-80")]]`)
- })
+ testWarningAndTransactionStatus(t, conn,
+ "distributed transaction ID failed during transaction record creation; rollback attempted; conclude on recovery",
+ false, "PREPARE", "ks:40-80")
// Below check ensures that the transaction is resolved by the resolver on receiving unresolved transaction signal from MM.
tableMap := make(map[string][]*querypb.Field)
@@ -882,3 +899,185 @@ func TestDTResolveAfterTransactionRecord(t *testing.T) {
assert.Equal(t, expectations, logTable,
"mismatch expected: \n got: %s, want: %s", prettyPrint(logTable), prettyPrint(expectations))
}
+
+type warn struct {
+ level string
+ code uint16
+ msg string
+}
+
+func toWarn(row sqltypes.Row) warn {
+ code, _ := row[1].ToUint16()
+ return warn{
+ level: row[0].ToString(),
+ code: code,
+ msg: row[2].ToString(),
+ }
+}
+
+type txStatus struct {
+ dtid string
+ state string
+ rTime string
+ participants string
+}
+
+func toTxStatus(row sqltypes.Row) txStatus {
+ return txStatus{
+ dtid: row[0].ToString(),
+ state: row[1].ToString(),
+ rTime: row[2].ToString(),
+ participants: row[3].ToString(),
+ }
+}
+
+func testWarningAndTransactionStatus(t *testing.T, conn *vtgateconn.VTGateSession, warnMsg string,
+ txConcluded bool, txState string, txParticipants string) {
+ t.Helper()
+
+ qr, err := conn.Execute(context.Background(), "show warnings", nil)
+ require.NoError(t, err)
+ require.Len(t, qr.Rows, 1)
+
+ // validate warning output
+ w := toWarn(qr.Rows[0])
+ assert.Equal(t, "Warning", w.level)
+ assert.EqualValues(t, 302, w.code)
+ assert.Contains(t, w.msg, warnMsg)
+
+ // extract transaction ID
+ indx := strings.Index(w.msg, " ")
+ require.Greater(t, indx, 0)
+ dtid := w.msg[:indx]
+
+ qr, err = conn.Execute(context.Background(), fmt.Sprintf(`show transaction status for '%v'`, dtid), nil)
+ require.NoError(t, err)
+
+ // validate transaction status
+ if txConcluded {
+ require.Empty(t, qr.Rows)
+ } else {
+ tx := toTxStatus(qr.Rows[0])
+ assert.Equal(t, dtid, tx.dtid)
+ assert.Equal(t, txState, tx.state)
+ assert.Equal(t, txParticipants, tx.participants)
+ }
+}
+
+// TestDisruptions tests that atomic transactions persevere through various disruptions.
+func TestDisruptions(t *testing.T) {
+ testcases := []struct {
+ disruptionName string
+ commitDelayTime string
+ disruption func() error
+ }{
+ {
+ disruptionName: "No Disruption",
+ commitDelayTime: "1",
+ disruption: func() error {
+ return nil
+ },
+ },
+ {
+ disruptionName: "PlannedReparentShard",
+ commitDelayTime: "5",
+ disruption: prsShard3,
+ },
+ }
+ for _, tt := range testcases {
+ t.Run(fmt.Sprintf("%s-%ss timeout", tt.disruptionName, tt.commitDelayTime), func(t *testing.T) {
+ // Reparent all the shards to first tablet being the primary.
+ reparentToFistTablet(t)
+ // cleanup all the old data.
+ conn, closer := start(t)
+ defer closer()
+ // Start an atomic transaction.
+ utils.Exec(t, conn, "begin")
+ // Insert rows such that they go to all the three shards. Given that we have sharded the table `twopc_t1` on reverse_bits
+ // it is very easy to figure out what value will end up in which shard.
+ utils.Exec(t, conn, "insert into twopc_t1(id, col) values(4, 4)")
+ utils.Exec(t, conn, "insert into twopc_t1(id, col) values(6, 4)")
+ utils.Exec(t, conn, "insert into twopc_t1(id, col) values(9, 4)")
+ // We want to delay the commit on one of the shards to simulate slow commits on a shard.
+ writeTestCommunicationFile(t, DebugDelayCommitShard, "80-")
+ defer deleteFile(DebugDelayCommitShard)
+ writeTestCommunicationFile(t, DebugDelayCommitTime, tt.commitDelayTime)
+ defer deleteFile(DebugDelayCommitTime)
+ // We will execute a commit in a go routine, because we know it will take some time to complete.
+ // While the commit is ongoing, we would like to run the disruption.
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ _, err := utils.ExecAllowError(t, conn, "commit")
+ if err != nil {
+ log.Errorf("Error in commit - %v", err)
+ }
+ }()
+ // Allow enough time for the commit to have started.
+ time.Sleep(1 * time.Second)
+ // Run the disruption.
+ err := tt.disruption()
+ require.NoError(t, err)
+ // Wait for the commit to have returned. We don't actually check for an error in the commit because the user might receive an error.
+ // But since we are waiting in CommitPrepared, the decision to commit the transaction should have already been taken.
+ wg.Wait()
+ // Check the data in the table.
+ waitForResults(t, "select id, col from twopc_t1 where col = 4 order by id", `[[INT64(4) INT64(4)] [INT64(6) INT64(4)] [INT64(9) INT64(4)]]`, 10*time.Second)
+ })
+ }
+}
+
+// reparentToFistTablet reparents all the shards to first tablet being the primary.
+func reparentToFistTablet(t *testing.T) {
+ ks := clusterInstance.Keyspaces[0]
+ for _, shard := range ks.Shards {
+ primary := shard.Vttablets[0]
+ err := clusterInstance.VtctldClientProcess.PlannedReparentShard(keyspaceName, shard.Name, primary.Alias)
+ require.NoError(t, err)
+ }
+}
+
+// writeTestCommunicationFile writes the content to the file with the given name.
+// We use these files to coordinate with the vttablets running in the debug mode.
+func writeTestCommunicationFile(t *testing.T, fileName string, content string) {
+ err := os.WriteFile(path.Join(os.Getenv("VTDATAROOT"), fileName), []byte(content), 0644)
+ require.NoError(t, err)
+}
+
+// deleteFile deletes the file specified.
+func deleteFile(fileName string) {
+ _ = os.Remove(path.Join(os.Getenv("VTDATAROOT"), fileName))
+}
+
+// waitForResults waits for the results of the query to be as expected.
+func waitForResults(t *testing.T, query string, resultExpected string, waitTime time.Duration) {
+ timeout := time.After(waitTime)
+ for {
+ select {
+ case <-timeout:
+ t.Fatalf("didn't reach expected results for %s", query)
+ default:
+ ctx := context.Background()
+ conn, err := mysql.Connect(ctx, &vtParams)
+ require.NoError(t, err)
+ res := utils.Exec(t, conn, query)
+ conn.Close()
+ if fmt.Sprintf("%v", res.Rows) == resultExpected {
+ return
+ }
+ time.Sleep(100 * time.Millisecond)
+ }
+ }
+}
+
+/*
+Cluster Level Disruptions for the fuzzer
+*/
+
+// prsShard3 runs a PRS in shard 3 of the keyspace. It promotes the second tablet to be the new primary.
+func prsShard3() error {
+ shard := clusterInstance.Keyspaces[0].Shards[2]
+ newPrimary := shard.Vttablets[1]
+ return clusterInstance.VtctldClientProcess.PlannedReparentShard(keyspaceName, shard.Name, newPrimary.Alias)
+}
diff --git a/go/test/endtoend/transaction/twopc/utils/utils.go b/go/test/endtoend/transaction/twopc/utils/utils.go
new file mode 100644
index 00000000000..7311375ee55
--- /dev/null
+++ b/go/test/endtoend/transaction/twopc/utils/utils.go
@@ -0,0 +1,59 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 utils
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "vitess.io/vitess/go/mysql"
+ "vitess.io/vitess/go/vt/log"
+)
+
+// ClearOutTable deletes everything from a table. Sometimes the table might have more rows than allowed in a single delete query,
+// so we have to do the deletions iteratively.
+func ClearOutTable(t *testing.T, vtParams mysql.ConnParams, tableName string) {
+ ctx := context.Background()
+ for {
+ conn, err := mysql.Connect(ctx, &vtParams)
+ require.NoError(t, err)
+
+ res, err := conn.ExecuteFetch(fmt.Sprintf("SELECT count(*) FROM %v", tableName), 1, false)
+ if err != nil {
+ log.Errorf("Error in selecting - %v", err)
+ conn.Close()
+ continue
+ }
+ require.Len(t, res.Rows, 1)
+ require.Len(t, res.Rows[0], 1)
+ rowCount, err := res.Rows[0][0].ToInt()
+ require.NoError(t, err)
+ if rowCount == 0 {
+ conn.Close()
+ return
+ }
+ _, err = conn.ExecuteFetch(fmt.Sprintf("DELETE FROM %v LIMIT 10000", tableName), 10000, false)
+ if err != nil {
+ log.Errorf("Error in cleanup deletion - %v", err)
+ conn.Close()
+ continue
+ }
+ }
+}
diff --git a/go/test/endtoend/transaction/twopc/vschema.json b/go/test/endtoend/transaction/twopc/vschema.json
index 4ff62df6808..bca58b05c1e 100644
--- a/go/test/endtoend/transaction/twopc/vschema.json
+++ b/go/test/endtoend/transaction/twopc/vschema.json
@@ -3,6 +3,9 @@
"vindexes": {
"xxhash": {
"type": "xxhash"
+ },
+ "reverse_bits": {
+ "type": "reverse_bits"
}
},
"tables": {
@@ -21,6 +24,14 @@
"name": "xxhash"
}
]
+ },
+ "twopc_t1": {
+ "column_vindexes": [
+ {
+ "column": "id",
+ "name": "reverse_bits"
+ }
+ ]
}
}
}
\ No newline at end of file
diff --git a/go/test/endtoend/vreplication/materialize_test.go b/go/test/endtoend/vreplication/materialize_test.go
index 486692a58ba..3f2e3451a64 100644
--- a/go/test/endtoend/vreplication/materialize_test.go
+++ b/go/test/endtoend/vreplication/materialize_test.go
@@ -108,7 +108,6 @@ const smMaterializeSchemaSource = `
const smMaterializeVSchemaSource = `
{
- "sharded": true,
"tables": {
"mat": {
"column_vindexes": [
@@ -197,6 +196,8 @@ func testMaterialize(t *testing.T, useVtctldClient bool) {
_, err = ks2Primary.QueryTablet(customFunc, targetKs, true)
require.NoError(t, err)
+ testMaterializeWithNonExistentTable(t)
+
materialize(t, smMaterializeSpec2, useVtctldClient)
catchup(t, ks2Primary, "wf1", "Materialize")
diff --git a/go/test/endtoend/vreplication/multi_tenant_test.go b/go/test/endtoend/vreplication/multi_tenant_test.go
index eda245ee597..b10395b08c8 100644
--- a/go/test/endtoend/vreplication/multi_tenant_test.go
+++ b/go/test/endtoend/vreplication/multi_tenant_test.go
@@ -203,6 +203,7 @@ func TestMultiTenantSimple(t *testing.T) {
lastIndex = insertRows(lastIndex, sourceKeyspace)
waitForWorkflowState(t, vc, fmt.Sprintf("%s.%s", targetKeyspace, mt.workflowName), binlogdatapb.VReplicationWorkflowState_Running.String())
+ vdiff(t, targetKeyspace, workflowName, defaultCellName, false, true, nil)
mt.SwitchReads()
confirmOnlyReadsSwitched(t)
@@ -362,6 +363,7 @@ func TestMultiTenantSharded(t *testing.T) {
// Note: we cannot insert into the target keyspace since that is never routed to the source keyspace.
lastIndex = insertRows(lastIndex, sourceKeyspace)
waitForWorkflowState(t, vc, fmt.Sprintf("%s.%s", targetKeyspace, mt.workflowName), binlogdatapb.VReplicationWorkflowState_Running.String())
+ vdiff(t, targetKeyspace, workflowName, defaultCellName, false, true, nil)
mt.SwitchReadsAndWrites()
// Note: here we have already switched, and we can insert into the target keyspace, and it should get reverse
// replicated to the source keyspace. The source keyspace is routed to the target keyspace at this point.
@@ -558,6 +560,7 @@ func (mtm *multiTenantMigration) switchTraffic(tenantId int64) {
mt := mtm.getActiveMoveTables(tenantId)
ksWorkflow := fmt.Sprintf("%s.%s", mtm.targetKeyspace, mt.workflowName)
waitForWorkflowState(t, vc, ksWorkflow, binlogdatapb.VReplicationWorkflowState_Running.String())
+ vdiff(t, mt.targetKeyspace, mt.workflowName, defaultCellName, false, true, nil)
mtm.insertSomeData(t, tenantId, sourceKeyspaceName, numAdditionalRowsPerTenant)
mt.SwitchReadsAndWrites()
mtm.insertSomeData(t, tenantId, sourceKeyspaceName, numAdditionalRowsPerTenant)
diff --git a/go/test/endtoend/vreplication/vreplication_test.go b/go/test/endtoend/vreplication/vreplication_test.go
index 52874b5839c..c3f3e4e6557 100644
--- a/go/test/endtoend/vreplication/vreplication_test.go
+++ b/go/test/endtoend/vreplication/vreplication_test.go
@@ -1183,6 +1183,18 @@ func materialize(t *testing.T, spec string, useVtctldClient bool) {
}
}
+func testMaterializeWithNonExistentTable(t *testing.T) {
+ t.Run("vtctldclient materialize with nonexistent table", func(t *testing.T) {
+ tableSettings := `[{"target_table": "table_that_doesnt_exist", "create_ddl": "create table mat_val_counts (mat_val varbinary(10), cnt int unsigned, primary key (mat_val))", "source_expression": "select val, count(*) as cnt from mat group by val"}]`
+ output, err := vc.VtctldClient.ExecuteCommandWithOutput("materialize", "--workflow=tablenogood", "--target-keyspace=source",
+ "create", "--source-keyspace=source", "--table-settings", tableSettings)
+ require.NoError(t, err, "Materialize create failed, err: %v, output: %s", err, output)
+ waitForWorkflowState(t, vc, "source.tablenogood", binlogdatapb.VReplicationWorkflowState_Stopped.String())
+ output, err = vc.VtctldClient.ExecuteCommandWithOutput("materialize", "--workflow=tablenogood", "--target-keyspace=source", "cancel")
+ require.NoError(t, err, "Materialize cancel failed, err: %v, output: %s", err, output)
+ })
+}
+
func materializeProduct(t *testing.T, useVtctldClient bool) {
t.Run("materializeProduct", func(t *testing.T) {
// Materializing from "product" keyspace to "customer" keyspace.
diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go
index 128d930718c..bcb4f68a935 100644
--- a/go/test/endtoend/vtgate/misc_test.go
+++ b/go/test/endtoend/vtgate/misc_test.go
@@ -95,10 +95,13 @@ func TestShowTables(t *testing.T) {
conn, closer := start(t)
defer closer()
- query := "show tables;"
- qr := utils.Exec(t, conn, query)
-
+ qr := utils.Exec(t, conn, "show tables")
assert.Equal(t, "Tables_in_ks", qr.Fields[0].Name)
+
+ // no error on executing `show tables` on system schema
+ utils.Exec(t, conn, `use mysql`)
+ utils.Exec(t, conn, "show tables")
+ utils.Exec(t, conn, "show tables from information_schema")
}
func TestCastConvert(t *testing.T) {
diff --git a/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go b/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
index 9a6ad90cc5b..d206f58e17c 100644
--- a/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
+++ b/go/test/endtoend/vtgate/queries/aggregation/aggregation_test.go
@@ -71,7 +71,6 @@ func start(t *testing.T) (utils.MySQLCompare, func()) {
}
func TestAggrWithLimit(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -101,11 +100,9 @@ func TestAggregateTypes(t *testing.T) {
mcmp.AssertMatches("select val1 as a, count(*) from aggr_test group by a order by 2, a", `[[VARCHAR("b") INT64(1)] [VARCHAR("d") INT64(1)] [VARCHAR("a") INT64(2)] [VARCHAR("c") INT64(2)] [VARCHAR("e") INT64(2)]]`)
mcmp.AssertMatches("select sum(val1) from aggr_test", `[[FLOAT64(0)]]`)
mcmp.Run("Average for sharded keyspaces", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches("select avg(val1) from aggr_test", `[[FLOAT64(0)]]`)
})
mcmp.Run("Average with group by without selecting the grouped columns", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(20, "vtgate")
mcmp.AssertMatches("select avg(val2) from aggr_test group by val1 order by val1", `[[DECIMAL(1.0000)] [DECIMAL(1.0000)] [DECIMAL(3.5000)] [NULL] [DECIMAL(1.0000)]]`)
})
}
@@ -214,7 +211,6 @@ func TestAggrOnJoin(t *testing.T) {
`[[VARCHAR("a")]]`)
mcmp.Run("Average in join for sharded", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches(`select avg(a1.val2), avg(a2.val2) from aggr_test a1 join aggr_test a2 on a1.val2 = a2.id join t3 t on a2.val2 = t.id7`,
"[[DECIMAL(1.5000) DECIMAL(1.0000)]]")
@@ -372,7 +368,6 @@ func TestAggOnTopOfLimit(t *testing.T) {
mcmp.AssertMatches("select val1, count(*) from (select id, val1 from aggr_test where val2 < 4 order by val1 limit 2) as x group by val1", `[[NULL INT64(1)] [VARCHAR("a") INT64(1)]]`)
mcmp.AssertMatchesNoOrder("select val1, count(val2) from (select val1, val2 from aggr_test limit 8) as x group by val1", `[[NULL INT64(1)] [VARCHAR("a") INT64(2)] [VARCHAR("b") INT64(1)] [VARCHAR("c") INT64(2)]]`)
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches("select avg(val2) from (select id, val2 from aggr_test where val2 is null limit 2) as x", "[[NULL]]")
mcmp.AssertMatchesNoOrder("select val1, avg(val2) from (select val1, val2 from aggr_test limit 8) as x group by val1", `[[NULL DECIMAL(2.0000)] [VARCHAR("a") DECIMAL(3.5000)] [VARCHAR("b") DECIMAL(1.0000)] [VARCHAR("c") DECIMAL(3.5000)]]`)
})
@@ -384,7 +379,6 @@ func TestAggOnTopOfLimit(t *testing.T) {
mcmp.AssertMatches("select count(val2), sum(val2) from (select id, val2 from aggr_test where val2 is null limit 2) as x", "[[INT64(0) NULL]]")
mcmp.AssertMatches("select val1, count(*), sum(id) from (select id, val1 from aggr_test where val2 < 4 order by val1 limit 2) as x group by val1", `[[NULL INT64(1) DECIMAL(7)] [VARCHAR("a") INT64(1) DECIMAL(2)]]`)
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches("select count(*), sum(val1), avg(val1) from (select id, val1 from aggr_test where val2 < 4 order by val1 desc limit 2) as x", "[[INT64(2) FLOAT64(0) FLOAT64(0)]]")
mcmp.AssertMatches("select count(val1), sum(id), avg(id) from (select id, val1 from aggr_test where val2 < 4 order by val1 desc limit 2) as x", "[[INT64(2) DECIMAL(7) DECIMAL(3.5000)]]")
mcmp.AssertMatchesNoOrder("select val1, count(val2), sum(val2), avg(val2) from (select val1, val2 from aggr_test limit 8) as x group by val1",
@@ -406,7 +400,6 @@ func TestEmptyTableAggr(t *testing.T) {
mcmp.AssertMatches(" select t1.`name`, count(*) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo' group by t1.`name`", "[]")
mcmp.AssertMatches(" select t1.`name`, count(*) from t1 inner join t2 on (t1.t1_id = t2.id) where t1.value = 'foo' group by t1.`name`", "[]")
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches(" select count(t1.value) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo'", "[[INT64(0)]]")
mcmp.AssertMatches(" select avg(t1.value) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo'", "[[NULL]]")
})
@@ -422,7 +415,6 @@ func TestEmptyTableAggr(t *testing.T) {
mcmp.AssertMatches(" select count(*) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo'", "[[INT64(0)]]")
mcmp.AssertMatches(" select t1.`name`, count(*) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo' group by t1.`name`", "[]")
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches(" select count(t1.value) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo'", "[[INT64(0)]]")
mcmp.AssertMatches(" select avg(t1.value) from t2 inner join t1 on (t1.t1_id = t2.id) where t1.value = 'foo'", "[[NULL]]")
mcmp.AssertMatches(" select t1.`name`, count(*) from t1 inner join t2 on (t1.t1_id = t2.id) where t1.value = 'foo' group by t1.`name`", "[]")
@@ -471,7 +463,6 @@ func TestAggregateLeftJoin(t *testing.T) {
mcmp.AssertMatches("SELECT count(*) FROM t2 LEFT JOIN t1 ON t1.t1_id = t2.id WHERE IFNULL(t1.name, 'NOTSET') = 'r'", `[[INT64(1)]]`)
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches("SELECT avg(t1.shardkey) FROM t1 LEFT JOIN t2 ON t1.t1_id = t2.id", `[[DECIMAL(0.5000)]]`)
mcmp.AssertMatches("SELECT avg(t2.shardkey) FROM t1 LEFT JOIN t2 ON t1.t1_id = t2.id", `[[DECIMAL(1.0000)]]`)
aggregations := []string{
@@ -528,7 +519,6 @@ func TestScalarAggregate(t *testing.T) {
mcmp.Exec("insert into aggr_test(id, val1, val2) values(1,'a',1), (2,'A',1), (3,'b',1), (4,'c',3), (5,'c',4)")
mcmp.AssertMatches("select count(distinct val1) from aggr_test", `[[INT64(3)]]`)
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.AssertMatches("select avg(val1) from aggr_test", `[[FLOAT64(0)]]`)
})
}
@@ -588,15 +578,11 @@ func TestComplexAggregation(t *testing.T) {
mcmp.Exec(`SELECT name+COUNT(t1_id)+1 FROM t1 GROUP BY name`)
mcmp.Exec(`SELECT COUNT(*)+shardkey+MIN(t1_id)+1+MAX(t1_id)*SUM(t1_id)+1+name FROM t1 GROUP BY shardkey, name`)
mcmp.Run("Average in sharded query", func(mcmp *utils.MySQLCompare) {
- mcmp.SkipIfBinaryIsBelowVersion(19, "vtgate")
mcmp.Exec(`SELECT COUNT(t1_id)+MAX(shardkey)+AVG(t1_id) FROM t1`)
})
}
func TestJoinAggregation(t *testing.T) {
- // This is new functionality in Vitess 20
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -793,7 +779,6 @@ func TestHavingQueries(t *testing.T) {
// TestJsonAggregation tests that json aggregation works for single sharded queries.
func TestJsonAggregation(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/derived/cte_test.go b/go/test/endtoend/vtgate/queries/derived/cte_test.go
index 54d97261ae6..131342a8562 100644
--- a/go/test/endtoend/vtgate/queries/derived/cte_test.go
+++ b/go/test/endtoend/vtgate/queries/derived/cte_test.go
@@ -18,12 +18,9 @@ package misc
import (
"testing"
-
- "vitess.io/vitess/go/test/endtoend/utils"
)
func TestCTEWithOrderByLimit(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -31,7 +28,6 @@ func TestCTEWithOrderByLimit(t *testing.T) {
}
func TestCTEAggregationOnRHS(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -40,7 +36,6 @@ func TestCTEAggregationOnRHS(t *testing.T) {
}
func TestCTERemoveInnerOrderBy(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -48,7 +43,6 @@ func TestCTERemoveInnerOrderBy(t *testing.T) {
}
func TestCTEWithHaving(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -59,7 +53,6 @@ func TestCTEWithHaving(t *testing.T) {
}
func TestCTEColumns(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -68,7 +61,6 @@ func TestCTEColumns(t *testing.T) {
}
func TestCTEAggregationsInUnion(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/derived/derived_test.go b/go/test/endtoend/vtgate/queries/derived/derived_test.go
index c41161d9bcf..cb106564b2f 100644
--- a/go/test/endtoend/vtgate/queries/derived/derived_test.go
+++ b/go/test/endtoend/vtgate/queries/derived/derived_test.go
@@ -92,7 +92,6 @@ func TestDerivedTableColumns(t *testing.T) {
// We do this by not using the apply join we usually use, and instead use the hash join engine primitive
// These tests exercise these situations
func TestDerivedTablesWithLimit(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
// We need full type info before planning this, so we wait for the schema tracker
require.NoError(t,
utils.WaitForAuthoritative(t, keyspaceName, "user", clusterInstance.VtgateProcess.ReadVSchema))
@@ -116,7 +115,6 @@ func TestDerivedTablesWithLimit(t *testing.T) {
// TestDerivedTableColumnAliasWithJoin tests the derived table having alias column and using it in the join condition
func TestDerivedTableColumnAliasWithJoin(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/dml/dml_test.go b/go/test/endtoend/vtgate/queries/dml/dml_test.go
index 4383f59e6c4..061cc4b9b36 100644
--- a/go/test/endtoend/vtgate/queries/dml/dml_test.go
+++ b/go/test/endtoend/vtgate/queries/dml/dml_test.go
@@ -47,8 +47,6 @@ func TestMultiEqual(t *testing.T) {
// TestMultiTableDelete executed multi-table delete queries
func TestMultiTableDelete(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -78,8 +76,6 @@ func TestMultiTableDelete(t *testing.T) {
// TestDeleteWithLimit executed delete queries with limit
func TestDeleteWithLimit(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -133,8 +129,6 @@ func TestDeleteWithLimit(t *testing.T) {
// TestUpdateWithLimit executed update queries with limit
func TestUpdateWithLimit(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -191,8 +185,6 @@ func TestUpdateWithLimit(t *testing.T) {
// TestMultiTableUpdate executed multi-table update queries
func TestMultiTableUpdate(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -222,8 +214,6 @@ func TestMultiTableUpdate(t *testing.T) {
// TestDeleteWithSubquery executed delete queries with subqueries
func TestDeleteWithSubquery(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -268,8 +258,6 @@ func TestDeleteWithSubquery(t *testing.T) {
// TestMultiTargetDelete executed multi-target delete queries
func TestMultiTargetDelete(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -299,8 +287,6 @@ func TestMultiTargetDelete(t *testing.T) {
// TestMultiTargetDeleteMore executed multi-target delete queries with additional cases
func TestMultiTargetDeleteMore(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -337,8 +323,6 @@ func TestMultiTargetDeleteMore(t *testing.T) {
// TestMultiTargetUpdate executed multi-target update queries
func TestMultiTargetUpdate(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -368,8 +352,6 @@ func TestMultiTargetUpdate(t *testing.T) {
// TestMultiTargetNonLiteralUpdate executed multi-target update queries with non-literal values.
func TestMultiTargetNonLiteralUpdate(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -400,8 +382,6 @@ func TestMultiTargetNonLiteralUpdate(t *testing.T) {
// TestDMLInUnique for update/delete statement using an IN clause with the Vindexes,
// the query is correctly split according to the corresponding values in the IN list.
func TestDMLInUnique(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/dml/insert_test.go b/go/test/endtoend/vtgate/queries/dml/insert_test.go
index 026f53fe961..9e89f4f5f3e 100644
--- a/go/test/endtoend/vtgate/queries/dml/insert_test.go
+++ b/go/test/endtoend/vtgate/queries/dml/insert_test.go
@@ -21,9 +21,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "vitess.io/vitess/go/test/endtoend/cluster"
"vitess.io/vitess/go/test/endtoend/utils"
)
@@ -56,8 +54,6 @@ func TestSimpleInsertSelect(t *testing.T) {
// TestInsertOnDup test the insert on duplicate key update feature with argument and list argument.
func TestInsertOnDup(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -92,19 +88,10 @@ func TestFailureInsertSelect(t *testing.T) {
// primary key same
mcmp.AssertContainsError("insert into s_tbl(id, num) select id, num*20 from s_tbl where id = 1", `AlreadyExists desc = Duplicate entry '1' for key`)
// lookup key same (does not fail on MySQL as there is no lookup, and we have not put unique constraint on num column)
- vtgateVersion, err := cluster.GetMajorVersion("vtgate")
- require.NoError(t, err)
- if vtgateVersion >= 19 {
- utils.AssertContainsError(t, mcmp.VtConn, "insert into s_tbl(id, num) select id*20, num from s_tbl where id = 1", `(errno 1062) (sqlstate 23000)`)
- // mismatch column count
- mcmp.AssertContainsError("insert into s_tbl(id, num) select 100,200,300", `column count does not match value count with the row`)
- mcmp.AssertContainsError("insert into s_tbl(id, num) select 100", `column count does not match value count with the row`)
- } else {
- utils.AssertContainsError(t, mcmp.VtConn, "insert into s_tbl(id, num) select id*20, num from s_tbl where id = 1", `lookup.Create: Code: ALREADY_EXISTS`)
- // mismatch column count
- mcmp.AssertContainsError("insert into s_tbl(id, num) select 100,200,300", `column count does not match value count at row 1`)
- mcmp.AssertContainsError("insert into s_tbl(id, num) select 100", `column count does not match value count at row 1`)
- }
+ utils.AssertContainsError(t, mcmp.VtConn, "insert into s_tbl(id, num) select id*20, num from s_tbl where id = 1", `(errno 1062) (sqlstate 23000)`)
+ // mismatch column count
+ mcmp.AssertContainsError("insert into s_tbl(id, num) select 100,200,300", `column count does not match value count with the row`)
+ mcmp.AssertContainsError("insert into s_tbl(id, num) select 100", `column count does not match value count with the row`)
})
}
}
@@ -486,9 +473,6 @@ func TestMixedCases(t *testing.T) {
// TestInsertAlias test the alias feature in insert statement.
func TestInsertAlias(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vttablet")
-
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/informationschema/informationschema_test.go b/go/test/endtoend/vtgate/queries/informationschema/informationschema_test.go
index ec55711a31f..c696e7b0a9d 100644
--- a/go/test/endtoend/vtgate/queries/informationschema/informationschema_test.go
+++ b/go/test/endtoend/vtgate/queries/informationschema/informationschema_test.go
@@ -225,8 +225,6 @@ func TestInfrSchemaAndUnionAll(t *testing.T) {
}
func TestInfoschemaTypes(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
-
require.NoError(t,
utils.WaitForAuthoritative(t, "ks", "t1", clusterInstance.VtgateProcess.ReadVSchema))
@@ -245,9 +243,7 @@ func TestInfoschemaTypes(t *testing.T) {
}
func TestTypeORMQuery(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
// This test checks that we can run queries similar to the ones that the TypeORM framework uses
-
require.NoError(t,
utils.WaitForAuthoritative(t, "ks", "t1", clusterInstance.VtgateProcess.ReadVSchema))
@@ -294,7 +290,6 @@ WHERE TABLE_SCHEMA = 'ks' AND TABLE_NAME = 't2';
}
func TestJoinWithSingleShardQueryOnRHS(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
// This test checks that we can run queries like this, where the RHS is a single shard query
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/misc/misc_test.go b/go/test/endtoend/vtgate/queries/misc/misc_test.go
index e43171b6701..8e47bb8581a 100644
--- a/go/test/endtoend/vtgate/queries/misc/misc_test.go
+++ b/go/test/endtoend/vtgate/queries/misc/misc_test.go
@@ -60,15 +60,8 @@ func TestBitVals(t *testing.T) {
mcmp.AssertMatches(`select b'1001', 0x9, B'010011011010'`, `[[VARBINARY("\t") VARBINARY("\t") VARBINARY("\x04\xda")]]`)
mcmp.AssertMatches(`select b'1001', 0x9, B'010011011010' from t1`, `[[VARBINARY("\t") VARBINARY("\t") VARBINARY("\x04\xda")]]`)
- vtgateVersion, err := cluster.GetMajorVersion("vtgate")
- require.NoError(t, err)
- if vtgateVersion >= 19 {
- mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010'`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[INT64(10) UINT64(11) INT64(1245)]]`)
- mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010' from t1`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[INT64(10) UINT64(11) INT64(1245)]]`)
- } else {
- mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010'`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[UINT64(10) UINT64(11) UINT64(1245)]]`)
- mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010' from t1`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[UINT64(10) UINT64(11) UINT64(1245)]]`)
- }
+ mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010'`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[INT64(10) UINT64(11) INT64(1245)]]`)
+ mcmp.AssertMatchesNoCompare(`select 1 + b'1001', 2 + 0x9, 3 + B'010011011010' from t1`, `[[INT64(10) UINT64(11) INT64(1245)]]`, `[[INT64(10) UINT64(11) INT64(1245)]]`)
}
// TestTimeFunctionWithPrecision tests that inserting data with NOW(1) works as intended.
@@ -140,7 +133,6 @@ func TestCast(t *testing.T) {
// TestVindexHints tests that vindex hints work as intended.
func TestVindexHints(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -323,8 +315,6 @@ func TestAnalyze(t *testing.T) {
// TestTransactionModeVar executes SELECT on `transaction_mode` variable
func TestTransactionModeVar(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -356,8 +346,6 @@ func TestTransactionModeVar(t *testing.T) {
// TestAliasesInOuterJoinQueries tests that aliases work in queries that have outer join clauses.
func TestAliasesInOuterJoinQueries(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
@@ -371,10 +359,12 @@ func TestAliasesInOuterJoinQueries(t *testing.T) {
mcmp.ExecWithColumnCompare("select t1.id1 as t0, t1.id1 as t1, tbl.unq_col as col from t1 left outer join tbl on t1.id2 = tbl.nonunq_col order by t1.id2 limit 2 offset 2")
mcmp.ExecWithColumnCompare("select t1.id1 as t0, t1.id1 as t1, count(*) as leCount from t1 left outer join tbl on t1.id2 = tbl.nonunq_col group by 1, t1")
mcmp.ExecWithColumnCompare("select t.id1, t.id2, derived.unq_col from t1 t join (select id, unq_col, nonunq_col from tbl) as derived on t.id2 = derived.nonunq_col")
+ if utils.BinaryIsAtLeastAtVersion(21, "vtgate") {
+ mcmp.ExecWithColumnCompare("select * from t1 t left join tbl on t.id1 = 666 and t.id2 = tbl.id")
+ }
}
func TestAlterTableWithView(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -428,7 +418,6 @@ func TestAlterTableWithView(t *testing.T) {
// TestStraightJoin tests that Vitess respects the ordering of join in a STRAIGHT JOIN query.
func TestStraightJoin(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -454,7 +443,6 @@ func TestStraightJoin(t *testing.T) {
}
func TestColumnAliases(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -463,7 +451,6 @@ func TestColumnAliases(t *testing.T) {
}
func TestHandleNullableColumn(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
require.NoError(t,
utils.WaitForAuthoritative(t, keyspaceName, "tbl", clusterInstance.VtgateProcess.ReadVSchema))
mcmp, closer := start(t)
@@ -477,8 +464,6 @@ func TestHandleNullableColumn(t *testing.T) {
}
func TestEnumSetVals(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "tbl_enum_set", clusterInstance.VtgateProcess.ReadVSchema))
diff --git a/go/test/endtoend/vtgate/queries/orderby/orderby_test.go b/go/test/endtoend/vtgate/queries/orderby/orderby_test.go
index e8d8d4bfef1..c36b52a4e6a 100644
--- a/go/test/endtoend/vtgate/queries/orderby/orderby_test.go
+++ b/go/test/endtoend/vtgate/queries/orderby/orderby_test.go
@@ -86,8 +86,6 @@ func TestOrderBy(t *testing.T) {
func TestOrderByComplex(t *testing.T) {
// tests written to try to trick the ORDER BY engine and planner
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/reference/main_test.go b/go/test/endtoend/vtgate/queries/reference/main_test.go
index 4c9440ca4ff..c350038bf6e 100644
--- a/go/test/endtoend/vtgate/queries/reference/main_test.go
+++ b/go/test/endtoend/vtgate/queries/reference/main_test.go
@@ -18,6 +18,7 @@ package reference
import (
"context"
+ _ "embed"
"flag"
"fmt"
"os"
@@ -39,68 +40,16 @@ var (
vtParams mysql.ConnParams
unshardedKeyspaceName = "uks"
- unshardedSQLSchema = `
- CREATE TABLE IF NOT EXISTS zip(
- id BIGINT NOT NULL AUTO_INCREMENT,
- code5 INT(5) NOT NULL,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB;
+ //go:embed uschema.sql
+ unshardedSQLSchema string
+ //go:embed uvschema.json
+ unshardedVSchema string
- INSERT INTO zip(id, code5)
- VALUES (1, 47107),
- (2, 82845),
- (3, 11237);
-
- CREATE TABLE IF NOT EXISTS zip_detail(
- id BIGINT NOT NULL AUTO_INCREMENT,
- zip_id BIGINT NOT NULL,
- discontinued_at DATE,
- PRIMARY KEY(id)
- ) ENGINE=InnoDB;
-
- `
- unshardedVSchema = `
- {
- "sharded":false,
- "tables": {
- "zip": {},
- "zip_detail": {}
- }
- }
- `
shardedKeyspaceName = "sks"
- shardedSQLSchema = `
- CREATE TABLE IF NOT EXISTS delivery_failure (
- id BIGINT NOT NULL,
- zip_detail_id BIGINT NOT NULL,
- reason VARCHAR(255),
- PRIMARY KEY(id)
- ) ENGINE=InnoDB;
- `
- shardedVSchema = `
- {
- "sharded": true,
- "vindexes": {
- "hash": {
- "type": "hash"
- }
- },
- "tables": {
- "delivery_failure": {
- "columnVindexes": [
- {
- "column": "id",
- "name": "hash"
- }
- ]
- },
- "zip_detail": {
- "type": "reference",
- "source": "` + unshardedKeyspaceName + `.zip_detail"
- }
- }
- }
- `
+ //go:embed sschema.sql
+ shardedSQLSchema string
+ //go:embed svschema.json
+ shardedVSchema string
)
func TestMain(m *testing.M) {
diff --git a/go/test/endtoend/vtgate/queries/reference/reference_test.go b/go/test/endtoend/vtgate/queries/reference/reference_test.go
index 0e3096e6064..08e9cbe13b1 100644
--- a/go/test/endtoend/vtgate/queries/reference/reference_test.go
+++ b/go/test/endtoend/vtgate/queries/reference/reference_test.go
@@ -84,20 +84,19 @@ func TestReferenceRouting(t *testing.T) {
)
t.Run("Complex reference query", func(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
// Verify a complex query using reference tables with a left join having a derived table with an order by clause works as intended.
utils.AssertMatches(
t,
conn,
`SELECT t.id FROM (
- SELECT zd.id, zd.zip_id
- FROM `+shardedKeyspaceName+`.zip_detail AS zd
- WHERE zd.id IN (2)
- ORDER BY zd.discontinued_at
- LIMIT 1
- ) AS t
- LEFT JOIN `+shardedKeyspaceName+`.zip_detail AS t0 ON t.zip_id = t0.zip_id
- ORDER BY t.id`,
+ SELECT zd.id, zd.zip_id
+ FROM `+shardedKeyspaceName+`.zip_detail AS zd
+ WHERE zd.id IN (2)
+ ORDER BY zd.discontinued_at
+ LIMIT 1
+ ) AS t
+ LEFT JOIN `+shardedKeyspaceName+`.zip_detail AS t0 ON t.zip_id = t0.zip_id
+ ORDER BY t.id`,
`[[INT64(2)]]`,
)
})
@@ -156,3 +155,19 @@ func TestReferenceRouting(t *testing.T) {
`[[INT64(2)]]`,
)
}
+
+// TestMultiReferenceQuery tests that a query with multiple references with unsharded keyspace and sharded keyspace works with join.
+func TestMultiReferenceQuery(t *testing.T) {
+ utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
+ conn, closer := start(t)
+ defer closer()
+
+ query :=
+ `select 1
+ from delivery_failure df1
+ join delivery_failure df2 on df1.id = df2.id
+ join uks.zip_detail zd1 on df1.zip_detail_id = zd1.zip_id
+ join uks.zip_detail zd2 on zd1.zip_id = zd2.zip_id`
+
+ utils.Exec(t, conn, query)
+}
diff --git a/go/test/endtoend/vtgate/queries/reference/sschema.sql b/go/test/endtoend/vtgate/queries/reference/sschema.sql
new file mode 100644
index 00000000000..0fcaf63a422
--- /dev/null
+++ b/go/test/endtoend/vtgate/queries/reference/sschema.sql
@@ -0,0 +1,6 @@
+CREATE TABLE IF NOT EXISTS delivery_failure (
+ id BIGINT NOT NULL,
+ zip_detail_id BIGINT NOT NULL,
+ reason VARCHAR(255),
+ PRIMARY KEY(id)
+) ENGINE=InnoDB;
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/queries/reference/svschema.json b/go/test/endtoend/vtgate/queries/reference/svschema.json
new file mode 100644
index 00000000000..815e0e8d21c
--- /dev/null
+++ b/go/test/endtoend/vtgate/queries/reference/svschema.json
@@ -0,0 +1,22 @@
+{
+ "sharded": true,
+ "vindexes": {
+ "hash": {
+ "type": "hash"
+ }
+ },
+ "tables": {
+ "delivery_failure": {
+ "columnVindexes": [
+ {
+ "column": "id",
+ "name": "hash"
+ }
+ ]
+ },
+ "zip_detail": {
+ "type": "reference",
+ "source": "uks.zip_detail"
+ }
+ }
+}
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/queries/reference/uschema.sql b/go/test/endtoend/vtgate/queries/reference/uschema.sql
new file mode 100644
index 00000000000..52737928469
--- /dev/null
+++ b/go/test/endtoend/vtgate/queries/reference/uschema.sql
@@ -0,0 +1,17 @@
+CREATE TABLE IF NOT EXISTS zip(
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ code5 INT(5) NOT NULL,
+ PRIMARY KEY(id)
+) ENGINE=InnoDB;
+
+INSERT INTO zip(id, code5)
+VALUES (1, 47107),
+ (2, 82845),
+ (3, 11237);
+
+CREATE TABLE IF NOT EXISTS zip_detail(
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ zip_id BIGINT NOT NULL,
+ discontinued_at DATE,
+ PRIMARY KEY(id)
+) ENGINE=InnoDB;
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/queries/reference/uvschema.json b/go/test/endtoend/vtgate/queries/reference/uvschema.json
new file mode 100644
index 00000000000..fdcfca0d7a9
--- /dev/null
+++ b/go/test/endtoend/vtgate/queries/reference/uvschema.json
@@ -0,0 +1,6 @@
+{
+ "tables": {
+ "zip": {},
+ "zip_detail": {}
+ }
+}
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/queries/subquery/subquery_test.go b/go/test/endtoend/vtgate/queries/subquery/subquery_test.go
index eb949e1c697..74af6634198 100644
--- a/go/test/endtoend/vtgate/queries/subquery/subquery_test.go
+++ b/go/test/endtoend/vtgate/queries/subquery/subquery_test.go
@@ -162,7 +162,6 @@ func TestSubqueryInReference(t *testing.T) {
// TestSubqueryInAggregation validates that subquery work inside aggregation functions.
func TestSubqueryInAggregation(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -180,7 +179,6 @@ func TestSubqueryInAggregation(t *testing.T) {
// TestSubqueryInDerivedTable tests that subqueries and derived tables
// are handled correctly when there are joins inside the derived table
func TestSubqueryInDerivedTable(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
@@ -194,7 +192,6 @@ func TestSubqueries(t *testing.T) {
// This method tests many types of subqueries. The queries should move to a vitess-tester test file once we have a way to run them.
// The commented out queries are failing because of wrong types being returned.
// The tests are commented out until the issue is fixed.
- utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
mcmp, closer := start(t)
defer closer()
queries := []string{
@@ -234,8 +231,6 @@ func TestSubqueries(t *testing.T) {
}
func TestProperTypesOfPullOutValue(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 21, "vtgate")
-
query := "select (select sum(id) from user) from user_extra"
mcmp, closer := start(t)
diff --git a/go/test/endtoend/vtgate/queries/timeout/timeout_test.go b/go/test/endtoend/vtgate/queries/timeout/timeout_test.go
index f7bd96dca13..d5e116e155b 100644
--- a/go/test/endtoend/vtgate/queries/timeout/timeout_test.go
+++ b/go/test/endtoend/vtgate/queries/timeout/timeout_test.go
@@ -100,8 +100,6 @@ func TestQueryTimeoutWithTables(t *testing.T) {
// TestQueryTimeoutWithShardTargeting tests the query timeout with shard targeting.
func TestQueryTimeoutWithShardTargeting(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
-
mcmp, closer := start(t)
defer closer()
diff --git a/go/test/endtoend/vtgate/queries/tpch/tpch_test.go b/go/test/endtoend/vtgate/queries/tpch/tpch_test.go
index bd35fe3f67c..c4bf71cafa1 100644
--- a/go/test/endtoend/vtgate/queries/tpch/tpch_test.go
+++ b/go/test/endtoend/vtgate/queries/tpch/tpch_test.go
@@ -48,7 +48,6 @@ func start(t *testing.T) (utils.MySQLCompare, func()) {
}
func TestTPCHQueries(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()
err := utils.WaitForColumn(t, clusterInstance.VtgateProcess, keyspaceName, "region", `R_COMMENT`)
diff --git a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go
index 564cc671d5f..e7e0cfb0259 100644
--- a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go
+++ b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go
@@ -461,3 +461,35 @@ func TestSysVarTxIsolation(t *testing.T) {
// second run, to ensuring the setting is applied on the session and not just on next query after settings.
utils.AssertContains(t, conn, "select @@transaction_isolation, connection_id()", `SERIALIZABLE`)
}
+
+// TestSysVarInnodbWaitTimeout tests the innodb_lock_wait_timeout system variable
+func TestSysVarInnodbWaitTimeout(t *testing.T) {
+ conn, err := mysql.Connect(context.Background(), &vtParams)
+ require.NoError(t, err)
+ defer conn.Close()
+
+ // default from mysql
+ utils.AssertMatches(t, conn, "select @@innodb_lock_wait_timeout", `[[UINT64(20)]]`)
+ utils.AssertMatches(t, conn, "select @@global.innodb_lock_wait_timeout", `[[UINT64(20)]]`)
+ // ensuring it goes to mysql
+ utils.AssertContains(t, conn, "select @@innodb_lock_wait_timeout", `UINT64(20)`)
+ utils.AssertContains(t, conn, "select @@global.innodb_lock_wait_timeout", `UINT64(20)`)
+
+ // setting to different value.
+ utils.Exec(t, conn, "set @@innodb_lock_wait_timeout = 120")
+ utils.AssertMatches(t, conn, "select @@innodb_lock_wait_timeout", `[[INT64(120)]]`)
+ // ensuring it goes to mysql
+ utils.AssertContains(t, conn, "select @@global.innodb_lock_wait_timeout, connection_id()", `UINT64(20)`)
+ utils.AssertContains(t, conn, "select @@innodb_lock_wait_timeout, connection_id()", `INT64(120)`)
+ // second run, to ensuring the setting is applied on the session and not just on next query after settings.
+ utils.AssertContains(t, conn, "select @@innodb_lock_wait_timeout, connection_id()", `INT64(120)`)
+
+ // changing setting to different value.
+ utils.Exec(t, conn, "set @@innodb_lock_wait_timeout = 240")
+ utils.AssertMatches(t, conn, "select @@innodb_lock_wait_timeout", `[[INT64(240)]]`)
+ // ensuring it goes to mysql
+ utils.AssertContains(t, conn, "select @@global.innodb_lock_wait_timeout, connection_id()", `UINT64(20)`)
+ utils.AssertContains(t, conn, "select @@innodb_lock_wait_timeout, connection_id()", `INT64(240)`)
+ // second run, to ensuring the setting is applied on the session and not just on next query after settings.
+ utils.AssertContains(t, conn, "select @@innodb_lock_wait_timeout, connection_id()", `INT64(240)`)
+}
diff --git a/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_test.go b/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_test.go
index 4c495d257b5..50042f3142a 100644
--- a/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_test.go
+++ b/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_test.go
@@ -178,13 +178,7 @@ func TestInitAndUpdate(t *testing.T) {
require.NoError(t, err)
defer conn.Close()
- vtgateVersion, err := cluster.GetMajorVersion("vtgate")
- require.NoError(t, err)
-
- expected := `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- if vtgateVersion >= 17 {
- expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- }
+ expected := `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
utils.AssertMatchesWithTimeout(t, conn,
"SHOW VSCHEMA TABLES",
expected,
@@ -192,18 +186,13 @@ func TestInitAndUpdate(t *testing.T) {
30*time.Second,
"initial table list not complete")
- if vtgateVersion >= 19 {
- utils.AssertMatches(t, conn,
- "SHOW VSCHEMA KEYSPACES",
- `[[VARCHAR("ks") VARCHAR("true") VARCHAR("unmanaged") VARCHAR("")]]`)
- }
+ utils.AssertMatches(t, conn,
+ "SHOW VSCHEMA KEYSPACES",
+ `[[VARCHAR("ks") VARCHAR("true") VARCHAR("unmanaged") VARCHAR("")]]`)
// Init
_ = utils.Exec(t, conn, "create table test_sc (id bigint primary key)")
- expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]`
- if vtgateVersion >= 17 {
- expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]`
- }
+ expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]`
utils.AssertMatchesWithTimeout(t, conn,
"SHOW VSCHEMA TABLES",
expected,
@@ -213,10 +202,7 @@ func TestInitAndUpdate(t *testing.T) {
// Tables Update via health check.
_ = utils.Exec(t, conn, "create table test_sc1 (id bigint primary key)")
- expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]`
- if vtgateVersion >= 17 {
- expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]`
- }
+ expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]`
utils.AssertMatchesWithTimeout(t, conn,
"SHOW VSCHEMA TABLES",
expected,
@@ -225,10 +211,7 @@ func TestInitAndUpdate(t *testing.T) {
"test_sc1 not in vschema tables")
_ = utils.Exec(t, conn, "drop table test_sc, test_sc1")
- expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- if vtgateVersion >= 17 {
- expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- }
+ expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
utils.AssertMatchesWithTimeout(t, conn,
"SHOW VSCHEMA TABLES",
expected,
@@ -247,12 +230,7 @@ func TestDMLOnNewTable(t *testing.T) {
// create a new table which is not part of the VSchema
utils.Exec(t, conn, `create table new_table_tracked(id bigint, name varchar(100), primary key(id)) Engine=InnoDB`)
- vtgateVersion, err := cluster.GetMajorVersion("vtgate")
- require.NoError(t, err)
- expected := `[[VARCHAR("dual")] [VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- if vtgateVersion >= 17 {
- expected = `[[VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
- }
+ expected := `[[VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
// wait for vttablet's schema reload interval to pass
utils.AssertMatchesWithTimeout(t, conn,
"SHOW VSCHEMA TABLES",
diff --git a/go/test/endtoend/vtgate/schematracker/unsharded/st_unsharded_test.go b/go/test/endtoend/vtgate/schematracker/unsharded/st_unsharded_test.go
index 257dd7238f3..5ecf89a5db7 100644
--- a/go/test/endtoend/vtgate/schematracker/unsharded/st_unsharded_test.go
+++ b/go/test/endtoend/vtgate/schematracker/unsharded/st_unsharded_test.go
@@ -182,7 +182,6 @@ func TestNewUnshardedTable(t *testing.T) {
// creating two tables having the same name differing only in casing, but other operating systems don't.
// More information at https://dev.mysql.com/doc/refman/8.0/en/identifier-case-sensitivity.html#:~:text=Table%20names%20are%20stored%20in,lowercase%20on%20storage%20and%20lookup.
func TestCaseSensitiveSchemaTracking(t *testing.T) {
- utils.SkipIfBinaryIsBelowVersion(t, 19, "vttablet")
defer cluster.PanicHandler(t)
// create a sql connection
diff --git a/go/test/endtoend/vtgate/vitess_tester/join/join.test b/go/test/endtoend/vtgate/vitess_tester/join/join.test
index cffd3a1b3aa..72d79a1206e 100644
--- a/go/test/endtoend/vtgate/vitess_tester/join/join.test
+++ b/go/test/endtoend/vtgate/vitess_tester/join/join.test
@@ -25,6 +25,15 @@ CREATE TABLE `t3`
CHARSET utf8mb4,
COLLATE utf8mb4_unicode_ci;
+CREATE TABLE `t4`
+(
+ `id` bigint unsigned NOT NULL AUTO_INCREMENT,
+ `col` int unsigned NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE InnoDB,
+ CHARSET utf8mb4,
+ COLLATE utf8mb4_unicode_ci;
+
insert into t1 (id, name)
values (1, 'A'),
(2, 'B'),
@@ -43,7 +52,28 @@ values (1, 'A'),
(4, 'B'),
(5, 'B');
+insert into t4 (id, col)
+values (1, 1),
+ (2, 2),
+ (3, 3);
+
-- wait_authoritative t1
-- wait_authoritative t2
-- wait_authoritative t3
-select 42 from t1 join t2 on t1.id = t2.t1_id join t3 on t1.id = t3.id where t1.name or t2.id or t3.name;
+select 42
+from t1
+ join t2 on t1.id = t2.t1_id
+ join t3 on t1.id = t3.id
+where t1.name
+ or t2.id
+ or t3.name;
+
+# Complex query that requires hash join underneath a memory sort and ordered aggregate
+select 1
+from t1
+ join t2 on t1.id = t2.t1_id
+ join t4 on t4.col = t2.id
+ left join (select t4.col, count(*) as count from t4 group by t4.col) t3 on t3.col = t2.id
+where t1.id IN (1, 2)
+group by t2.id, t4.col;
+
diff --git a/go/test/endtoend/vtgate/vitess_tester/join/vschema.json b/go/test/endtoend/vtgate/vitess_tester/join/vschema.json
index b922d3f760c..1105b951e61 100644
--- a/go/test/endtoend/vtgate/vitess_tester/join/vschema.json
+++ b/go/test/endtoend/vtgate/vitess_tester/join/vschema.json
@@ -31,6 +31,14 @@
"name": "hash"
}
]
+ },
+ "t4": {
+ "column_vindexes": [
+ {
+ "column": "id",
+ "name": "hash"
+ }
+ ]
}
}
}
diff --git a/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/queries.test b/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/queries.test
new file mode 100644
index 00000000000..28c55e559c9
--- /dev/null
+++ b/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/queries.test
@@ -0,0 +1,39 @@
+use customer;
+create table if not exists customer
+(
+ customer_id bigint not null,
+ email varbinary(128),
+ primary key (customer_id)
+) ENGINE = InnoDB;
+
+insert into customer.customer(customer_id, email)
+values (1, '[alice@domain.com](mailto:alice@domain.com)'),
+ (2, '[bob@domain.com](mailto:bob@domain.com)'),
+ (3, '[charlie@domain.com](mailto:charlie@domain.com)'),
+ (4, '[dan@domain.com](mailto:dan@domain.com)'),
+ (5, '[eve@domain.com](mailto:eve@domain.com)');
+use corder;
+create table if not exists corder
+(
+ order_id bigint not null,
+ customer_id bigint,
+ sku varbinary(128),
+ price bigint,
+ primary key (order_id)
+) ENGINE = InnoDB;
+insert into corder.corder(order_id, customer_id, sku, price)
+values (1, 1, 'SKU-1001', 100),
+ (2, 2, 'SKU-1002', 30),
+ (3, 3, 'SKU-1002', 30),
+ (4, 4, 'SKU-1002', 30),
+ (5, 5, 'SKU-1002', 30);
+
+select co.order_id, co.customer_id, co.price
+from corder.corder co
+ left join customer.customer cu on co.customer_id = cu.customer_id
+where cu.customer_id = 1;
+
+# This query was accidentally disallowed by https://github.com/vitessio/vitess/pull/16520
+select 1
+from customer.customer
+where customer_id in (select customer_id from corder.corder where price > 50);
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/vschema.json b/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/vschema.json
new file mode 100644
index 00000000000..5672042bace
--- /dev/null
+++ b/go/test/endtoend/vtgate/vitess_tester/two_sharded_keyspaces/vschema.json
@@ -0,0 +1,72 @@
+{
+ "keyspaces": {
+ "customer": {
+ "sharded": true,
+ "vindexes": {
+ "hash": {
+ "type": "hash",
+ "params": {},
+ "owner": ""
+ }
+ },
+ "tables": {
+ "customer": {
+ "type": "",
+ "column_vindexes": [
+ {
+ "column": "customer_id",
+ "name": "hash",
+ "columns": []
+ }
+ ],
+ "columns": [],
+ "pinned": "",
+ "column_list_authoritative": false,
+ "source": ""
+ }
+ },
+ "require_explicit_routing": false,
+ "foreign_key_mode": 0,
+ "multi_tenant_spec": null
+ },
+ "corder": {
+ "sharded": true,
+ "vindexes": {
+ "hash": {
+ "type": "hash",
+ "params": {},
+ "owner": ""
+ }
+ },
+ "tables": {
+ "corder": {
+ "type": "",
+ "column_vindexes": [
+ {
+ "column": "customer_id",
+ "name": "hash",
+ "columns": []
+ }
+ ],
+ "columns": [],
+ "pinned": "",
+ "column_list_authoritative": false,
+ "source": ""
+ }
+ },
+ "require_explicit_routing": false,
+ "foreign_key_mode": 0,
+ "multi_tenant_spec": null
+ }
+ },
+ "routing_rules": {
+ "rules": []
+ },
+ "shard_routing_rules": {
+ "rules": []
+ },
+ "keyspace_routing_rules": null,
+ "mirror_rules": {
+ "rules": []
+ }
+}
\ No newline at end of file
diff --git a/go/test/endtoend/vtgate/vschema/vschema_test.go b/go/test/endtoend/vtgate/vschema/vschema_test.go
index 92863ff7dc8..eec54f8f47f 100644
--- a/go/test/endtoend/vtgate/vschema/vschema_test.go
+++ b/go/test/endtoend/vtgate/vschema/vschema_test.go
@@ -110,16 +110,7 @@ func TestVSchema(t *testing.T) {
`[[INT64(1) VARCHAR("test1")] [INT64(2) VARCHAR("test2")] [INT64(3) VARCHAR("test3")] [INT64(4) VARCHAR("test4")]]`)
utils.AssertMatches(t, conn, "delete from vt_user", `[]`)
-
- vtgateVersion, err := cluster.GetMajorVersion("vtgate")
- require.NoError(t, err)
-
- // Test empty vschema
- if vtgateVersion >= 17 {
- utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[]`)
- } else {
- utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[[VARCHAR("dual")]]`)
- }
+ utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[]`)
// Use the DDL to create an unsharded vschema and test again
@@ -135,11 +126,7 @@ func TestVSchema(t *testing.T) {
utils.Exec(t, conn, "commit")
// Test Showing Tables
- if vtgateVersion >= 17 {
- utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[[VARCHAR("main")] [VARCHAR("vt_user")]]`)
- } else {
- utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[[VARCHAR("dual")] [VARCHAR("main")] [VARCHAR("vt_user")]]`)
- }
+ utils.AssertMatches(t, conn, "SHOW VSCHEMA TABLES", `[[VARCHAR("main")] [VARCHAR("vt_user")]]`)
// Test Showing Vindexes
utils.AssertMatches(t, conn, "SHOW VSCHEMA VINDEXES", `[]`)
diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go
index 05685a54d3e..7936a0760c9 100644
--- a/go/vt/binlog/binlogplayer/binlog_player.go
+++ b/go/vt/binlog/binlogplayer/binlog_player.go
@@ -669,11 +669,11 @@ func GenerateUpdateHeartbeat(uid int32, timeUpdated int64) (string, error) {
}
// GenerateUpdateTimeThrottled returns a statement to record the latest throttle time in the _vt.vreplication table.
-func GenerateUpdateTimeThrottled(uid int32, timeThrottledUnix int64, componentThrottled string) (string, error) {
+func GenerateUpdateTimeThrottled(uid int32, timeThrottledUnix int64, componentThrottled string, reasonThrottled string) (string, error) {
if timeThrottledUnix == 0 {
return "", fmt.Errorf("timeUpdated cannot be zero")
}
- return fmt.Sprintf("update _vt.vreplication set time_updated=%v, time_throttled=%v, component_throttled='%v' where id=%v", timeThrottledUnix, timeThrottledUnix, componentThrottled, uid), nil
+ return fmt.Sprintf("update _vt.vreplication set time_updated=%v, time_throttled=%v, component_throttled='%v', reason_throttled=%v where id=%v", timeThrottledUnix, timeThrottledUnix, componentThrottled, encodeString(MessageTruncate(reasonThrottled)), uid), nil
}
// StartVReplicationUntil returns a statement to start the replication with a stop position.
diff --git a/go/vt/binlog/binlogplayer/binlog_player_test.go b/go/vt/binlog/binlogplayer/binlog_player_test.go
index 99b0ef496b3..697733a6d18 100644
--- a/go/vt/binlog/binlogplayer/binlog_player_test.go
+++ b/go/vt/binlog/binlogplayer/binlog_player_test.go
@@ -22,6 +22,8 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+
"vitess.io/vitess/go/mysql/replication"
"vitess.io/vitess/go/mysql/sqlerror"
querypb "vitess.io/vitess/go/vt/proto/query"
@@ -454,3 +456,36 @@ func TestReadVReplicationStatus(t *testing.T) {
t.Errorf("ReadVReplicationStatus(482821) = %#v, want %#v", got, want)
}
}
+
+func TestEncodeString(t *testing.T) {
+ tcases := []struct {
+ in, out string
+ }{
+ {
+ in: "",
+ out: "''",
+ },
+ {
+ in: "a",
+ out: "'a'",
+ },
+ {
+ in: "here's",
+ out: "'here\\'s'",
+ },
+ {
+ in: "online-ddl is denied access due to lag metric value 94.821447 exceeding threshold 5",
+ out: "'online-ddl is denied access due to lag metric value 94.821447 exceeding threshold 5'",
+ },
+ {
+ in: "'a','b','c'",
+ out: "'\\'a\\',\\'b\\',\\'c\\''",
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run(tcase.in, func(t *testing.T) {
+ out := encodeString(tcase.in)
+ assert.Equal(t, tcase.out, out)
+ })
+ }
+}
diff --git a/go/vt/dbconfigs/dbconfigs.go b/go/vt/dbconfigs/dbconfigs.go
index 82c322e7ae9..32fb2435286 100644
--- a/go/vt/dbconfigs/dbconfigs.go
+++ b/go/vt/dbconfigs/dbconfigs.go
@@ -133,7 +133,7 @@ func registerBaseFlags(fs *pflag.FlagSet) {
fs.StringVar(&GlobalDBConfigs.Socket, "db_socket", "", "The unix socket to connect on. If this is specified, host and port will not be used.")
fs.StringVar(&GlobalDBConfigs.Host, "db_host", "", "The host name for the tcp connection.")
fs.IntVar(&GlobalDBConfigs.Port, "db_port", 0, "tcp port")
- fs.StringVar(&GlobalDBConfigs.Charset, "db_charset", "utf8mb4", "Character set used for this tablet.")
+ fs.StringVar(&GlobalDBConfigs.Charset, "db_charset", "utf8mb4", "Character set/collation used for this tablet. Make sure to configure this to a charset/collation supported by the lowest MySQL version in your environment.")
fs.Uint64Var(&GlobalDBConfigs.Flags, "db_flags", 0, "Flag values as defined by MySQL.")
fs.StringVar(&GlobalDBConfigs.Flavor, "db_flavor", "", "Flavor overrid. Valid value is FilePos.")
fs.Var(&GlobalDBConfigs.SslMode, "db_ssl_mode", "SSL mode to connect with. One of disabled, preferred, required, verify_ca & verify_identity.")
diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go
index 70799b0f6bc..2a467301eaf 100644
--- a/go/vt/discovery/healthcheck.go
+++ b/go/vt/discovery/healthcheck.go
@@ -470,7 +470,20 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) {
// delete from healthy list
healthy, ok := hc.healthy[key]
if ok && len(healthy) > 0 {
- hc.recomputeHealthy(key)
+ if tabletType == topodata.TabletType_PRIMARY {
+ // If the deleted tablet was a primary,
+ // and it matches what we think is the current active primary,
+ // clear the healthy list for the primary.
+ //
+ // See the logic in `updateHealth` for more details.
+ alias := tabletAliasString(topoproto.TabletAliasString(healthy[0].Tablet.Alias))
+ if alias == tabletAlias {
+ hc.healthy[key] = []*TabletHealth{}
+ }
+ } else {
+ // Simply recompute the list of healthy tablets for all other tablet types.
+ hc.recomputeHealthy(key)
+ }
}
}
}()
@@ -586,6 +599,13 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, prevTarget *query.Targ
hc.broadcast(th)
}
+// recomputeHealthy recomputes the healthy tablets for the given key.
+//
+// This filters out tablets that might be healthy, but are not part of the current
+// cell or cell alias. It also performs filtering of tablets based on replication lag,
+// if configured to do so.
+//
+// This should not be called for primary tablets.
func (hc *HealthCheckImpl) recomputeHealthy(key KeyspaceShardTabletType) {
all := hc.healthData[key]
allArray := make([]*TabletHealth, 0, len(all))
diff --git a/go/vt/discovery/healthcheck_test.go b/go/vt/discovery/healthcheck_test.go
index c87ba699234..35c55354fb7 100644
--- a/go/vt/discovery/healthcheck_test.go
+++ b/go/vt/discovery/healthcheck_test.go
@@ -784,6 +784,127 @@ func TestRemoveTablet(t *testing.T) {
assert.Empty(t, a, "wrong result, expected empty list")
}
+// When an external primary failover is performed,
+// the demoted primary will advertise itself as a `PRIMARY`
+// tablet until it recognizes that it was demoted,
+// and until all in-flight operations have either finished
+// (successfully or unsuccessfully, see `--shutdown_grace_period` flag).
+//
+// During this time, operations like `RemoveTablet` should not lead
+// to multiple tablets becoming valid targets for `PRIMARY`.
+func TestRemoveTabletDuringExternalReparenting(t *testing.T) {
+ ctx := utils.LeakCheckContext(t)
+
+ // reset error counters
+ hcErrorCounters.ResetAll()
+ ts := memorytopo.NewServer(ctx, "cell")
+ defer ts.Close()
+ hc := createTestHc(ctx, ts)
+ // close healthcheck
+ defer hc.Close()
+
+ firstTablet := createTestTablet(0, "cell", "a")
+ firstTablet.Type = topodatapb.TabletType_PRIMARY
+
+ secondTablet := createTestTablet(1, "cell", "b")
+ secondTablet.Type = topodatapb.TabletType_REPLICA
+
+ thirdTablet := createTestTablet(2, "cell", "c")
+ thirdTablet.Type = topodatapb.TabletType_REPLICA
+
+ firstTabletHealthStream := make(chan *querypb.StreamHealthResponse)
+ firstTabletConn := createFakeConn(firstTablet, firstTabletHealthStream)
+ firstTabletConn.errCh = make(chan error)
+
+ secondTabletHealthStream := make(chan *querypb.StreamHealthResponse)
+ secondTabletConn := createFakeConn(secondTablet, secondTabletHealthStream)
+ secondTabletConn.errCh = make(chan error)
+
+ thirdTabletHealthStream := make(chan *querypb.StreamHealthResponse)
+ thirdTabletConn := createFakeConn(thirdTablet, thirdTabletHealthStream)
+ thirdTabletConn.errCh = make(chan error)
+
+ resultChan := hc.Subscribe()
+
+ hc.AddTablet(firstTablet)
+ <-resultChan
+
+ hc.AddTablet(secondTablet)
+ <-resultChan
+
+ hc.AddTablet(thirdTablet)
+ <-resultChan
+
+ firstTabletPrimaryTermStartTimestamp := time.Now().Unix() - 10
+
+ firstTabletHealthStream <- &querypb.StreamHealthResponse{
+ TabletAlias: firstTablet.Alias,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_PRIMARY},
+ Serving: true,
+
+ PrimaryTermStartTimestamp: firstTabletPrimaryTermStartTimestamp,
+ RealtimeStats: &querypb.RealtimeStats{ReplicationLagSeconds: 0, CpuUsage: 0.5},
+ }
+ <-resultChan
+
+ secondTabletHealthStream <- &querypb.StreamHealthResponse{
+ TabletAlias: secondTablet.Alias,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
+ Serving: true,
+
+ PrimaryTermStartTimestamp: 0,
+ RealtimeStats: &querypb.RealtimeStats{ReplicationLagSeconds: 1, CpuUsage: 0.5},
+ }
+ <-resultChan
+
+ thirdTabletHealthStream <- &querypb.StreamHealthResponse{
+ TabletAlias: thirdTablet.Alias,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_REPLICA},
+ Serving: true,
+
+ PrimaryTermStartTimestamp: 0,
+ RealtimeStats: &querypb.RealtimeStats{ReplicationLagSeconds: 1, CpuUsage: 0.5},
+ }
+ <-resultChan
+
+ secondTabletPrimaryTermStartTimestamp := time.Now().Unix()
+
+ // Simulate a failover
+ firstTabletHealthStream <- &querypb.StreamHealthResponse{
+ TabletAlias: firstTablet.Alias,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_PRIMARY},
+ Serving: true,
+
+ PrimaryTermStartTimestamp: firstTabletPrimaryTermStartTimestamp,
+ RealtimeStats: &querypb.RealtimeStats{ReplicationLagSeconds: 0, CpuUsage: 0.5},
+ }
+ <-resultChan
+
+ secondTabletHealthStream <- &querypb.StreamHealthResponse{
+ TabletAlias: secondTablet.Alias,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_PRIMARY},
+ Serving: true,
+
+ PrimaryTermStartTimestamp: secondTabletPrimaryTermStartTimestamp,
+ RealtimeStats: &querypb.RealtimeStats{ReplicationLagSeconds: 0, CpuUsage: 0.5},
+ }
+ <-resultChan
+
+ hc.RemoveTablet(thirdTablet)
+
+ // `secondTablet` should be the primary now
+ expectedTabletStats := []*TabletHealth{{
+ Tablet: secondTablet,
+ Target: &querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_PRIMARY},
+ Serving: true,
+ Stats: &querypb.RealtimeStats{ReplicationLagSeconds: 0, CpuUsage: 0.5},
+ PrimaryTermStartTime: secondTabletPrimaryTermStartTimestamp,
+ }}
+
+ actualTabletStats := hc.GetHealthyTabletStats(&querypb.Target{Keyspace: "k", Shard: "s", TabletType: topodatapb.TabletType_PRIMARY})
+ mustMatch(t, expectedTabletStats, actualTabletStats, "unexpected result")
+}
+
// TestGetHealthyTablets tests the functionality of GetHealthyTabletStats.
func TestGetHealthyTablets(t *testing.T) {
ctx := utils.LeakCheckContext(t)
diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go
index e388912783a..494d765f2a9 100644
--- a/go/vt/mysqlctl/builtinbackupengine.go
+++ b/go/vt/mysqlctl/builtinbackupengine.go
@@ -766,21 +766,25 @@ func (bp *backupPipe) HashString() string {
return hex.EncodeToString(bp.crc32.Sum(nil))
}
-func (bp *backupPipe) ReportProgress(period time.Duration, logger logutil.Logger) {
+func (bp *backupPipe) ReportProgress(period time.Duration, logger logutil.Logger, restore bool) {
+ messageStr := "restoring "
+ if !restore {
+ messageStr = "backing up "
+ }
tick := time.NewTicker(period)
defer tick.Stop()
for {
select {
case <-bp.done:
- logger.Infof("Done taking Backup %q", bp.filename)
+ logger.Infof("Completed %s %q", messageStr, bp.filename)
return
case <-tick.C:
written := float64(atomic.LoadInt64(&bp.nn))
if bp.maxSize == 0 {
- logger.Infof("Backup %q: %.02fkb", bp.filename, written/1024.0)
+ logger.Infof("%s %q: %.02fkb", messageStr, bp.filename, written/1024.0)
} else {
maxSize := float64(bp.maxSize)
- logger.Infof("Backup %q: %.02f%% (%.02f/%.02fkb)", bp.filename, 100.0*written/maxSize, written/1024.0, maxSize/1024.0)
+ logger.Infof("%s %q: %.02f%% (%.02f/%.02fkb)", messageStr, bp.filename, 100.0*written/maxSize, written/1024.0, maxSize/1024.0)
}
}
}
@@ -813,7 +817,7 @@ func (be *BuiltinBackupEngine) backupFile(ctx context.Context, params BackupPara
}
br := newBackupReader(fe.Name, fi.Size(), timedSource)
- go br.ReportProgress(builtinBackupProgress, params.Logger)
+ go br.ReportProgress(builtinBackupProgress, params.Logger, false /*restore*/)
// Open the destination file for writing, and a buffer.
params.Logger.Infof("Backing up file: %v", fe.Name)
@@ -1078,7 +1082,7 @@ func (be *BuiltinBackupEngine) restoreFile(ctx context.Context, params RestorePa
}()
br := newBackupReader(name, 0, timedSource)
- go br.ReportProgress(builtinBackupProgress, params.Logger)
+ go br.ReportProgress(builtinBackupProgress, params.Logger, true /*restore*/)
var reader io.Reader = br
// Open the destination file for writing.
diff --git a/go/vt/proto/binlogdata/binlogdata.pb.go b/go/vt/proto/binlogdata/binlogdata.pb.go
index aade1d049f8..8374a4a2733 100644
--- a/go/vt/proto/binlogdata/binlogdata.pb.go
+++ b/go/vt/proto/binlogdata/binlogdata.pb.go
@@ -1913,6 +1913,8 @@ type VEvent struct {
Shard string `protobuf:"bytes,23,opt,name=shard,proto3" json:"shard,omitempty"`
// indicate that we are being throttled right now
Throttled bool `protobuf:"varint,24,opt,name=throttled,proto3" json:"throttled,omitempty"`
+ // ThrottledReason is a human readable string that explains why the stream is throttled
+ ThrottledReason string `protobuf:"bytes,25,opt,name=throttled_reason,json=throttledReason,proto3" json:"throttled_reason,omitempty"`
}
func (x *VEvent) Reset() {
@@ -2045,6 +2047,13 @@ func (x *VEvent) GetThrottled() bool {
return false
}
+func (x *VEvent) GetThrottledReason() string {
+ if x != nil {
+ return x.ThrottledReason
+ }
+ return ""
+}
+
type MinimalTable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -2397,6 +2406,8 @@ type VStreamRowsResponse struct {
Throttled bool `protobuf:"varint,6,opt,name=throttled,proto3" json:"throttled,omitempty"`
// Heartbeat indicates that this is a heartbeat message
Heartbeat bool `protobuf:"varint,7,opt,name=heartbeat,proto3" json:"heartbeat,omitempty"`
+ // ThrottledReason is a human readable string that explains why the stream is throttled
+ ThrottledReason string `protobuf:"bytes,8,opt,name=throttled_reason,json=throttledReason,proto3" json:"throttled_reason,omitempty"`
}
func (x *VStreamRowsResponse) Reset() {
@@ -2480,6 +2491,13 @@ func (x *VStreamRowsResponse) GetHeartbeat() bool {
return false
}
+func (x *VStreamRowsResponse) GetThrottledReason() string {
+ if x != nil {
+ return x.ThrottledReason
+ }
+ return ""
+}
+
// VStreamTablesRequest is the payload for VStreamTables
type VStreamTablesRequest struct {
state protoimpl.MessageState
@@ -3247,7 +3265,7 @@ var file_binlogdata_proto_rawDesc = []byte{
0x68, 0x61, 0x72, 0x64, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e,
0x74, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x77, 0x6f, 0x72,
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x22, 0x8b, 0x04,
+ 0x75, 0x72, 0x63, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x22, 0xb6, 0x04,
0x0a, 0x06, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
@@ -3280,183 +3298,189 @@ var file_binlogdata_proto_rawDesc = []byte{
0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64,
0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x1c, 0x0a,
0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x22, 0x8d, 0x01, 0x0a, 0x0c,
- 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
- 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06,
- 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x70, 0x5f, 0x6b, 0x5f, 0x63, 0x6f,
- 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x70, 0x4b, 0x43,
- 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0e, 0x70, 0x5f, 0x6b, 0x5f, 0x69, 0x6e,
- 0x64, 0x65, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
- 0x70, 0x4b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x41, 0x0a, 0x0d, 0x4d,
- 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x30, 0x0a, 0x06,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62,
- 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x61,
- 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x22, 0xc7,
- 0x02, 0x0a, 0x0e, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63,
- 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f,
- 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52,
- 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72,
- 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f,
- 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61,
- 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
- 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72,
- 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x06,
- 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62,
- 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x5f, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
+ 0x52, 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x74,
+ 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18,
+ 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64,
+ 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x8d, 0x01, 0x0a, 0x0c, 0x4d, 0x69, 0x6e, 0x69, 0x6d,
+ 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66,
+ 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75,
+ 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64,
+ 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x70, 0x5f, 0x6b, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73,
+ 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x09, 0x70, 0x4b, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e,
+ 0x73, 0x12, 0x23, 0x0a, 0x0e, 0x70, 0x5f, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x4b, 0x49, 0x6e, 0x64,
+ 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x41, 0x0a, 0x0d, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x61,
+ 0x6c, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c,
+ 0x65, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x22, 0xc7, 0x02, 0x0a, 0x0e, 0x56, 0x53,
+ 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13,
+ 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72,
+ 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70,
+ 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65,
+ 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a,
+ 0x13, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65,
+ 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65,
+ 0x72, 0x79, 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49,
+ 0x44, 0x52, 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c,
+ 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72,
+ 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x61, 0x73,
+ 0x74, 0x5f, 0x70, 0x5f, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62,
+ 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x4c,
+ 0x61, 0x73, 0x74, 0x50, 0x4b, 0x52, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x73, 0x74,
+ 0x50, 0x4b, 0x73, 0x22, 0x3d, 0x0a, 0x0f, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73,
+ 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e,
+ 0x74, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x12, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x6f,
+ 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66, 0x66,
+ 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43,
+ 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69,
+ 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69, 0x6d,
+ 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e,
+ 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11,
+ 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49,
+ 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
+ 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72,
+ 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2a,
+ 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,
+ 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75,
+ 0x6c, 0x74, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x22, 0xa4, 0x02, 0x0a, 0x13, 0x56,
+ 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,
+ 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x6b, 0x66, 0x69,
+ 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65,
+ 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x08, 0x70, 0x6b, 0x66, 0x69, 0x65, 0x6c,
+ 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x67, 0x74, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x04,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77,
+ 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x22, 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52,
+ 0x6f, 0x77, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68,
+ 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74,
+ 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x72,
+ 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x65, 0x61,
+ 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74,
+ 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0f, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f,
+ 0x6e, 0x22, 0xc5, 0x01, 0x0a, 0x14, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x61, 0x62,
+ 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66,
+ 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69,
+ 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e,
+ 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74,
+ 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69,
+ 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f,
+ 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79,
+ 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52,
+ 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72,
+ 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xde, 0x01, 0x0a, 0x15, 0x56, 0x53,
+ 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61,
+ 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,
+ 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x6b, 0x66, 0x69,
+ 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65,
+ 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x08, 0x70, 0x6b, 0x66, 0x69, 0x65, 0x6c,
+ 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x74, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x67, 0x74, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x05,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77,
+ 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x22, 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52,
+ 0x6f, 0x77, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x22, 0x69, 0x0a, 0x0b, 0x4c, 0x61,
+ 0x73, 0x74, 0x50, 0x4b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x5f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x17, 0x2e, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x52, 0x0c, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x73, 0x22, 0x3d, 0x0a, 0x0f, 0x56, 0x53, 0x74, 0x72,
- 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x65,
- 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x62, 0x69,
- 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
- 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x12, 0x56, 0x53, 0x74, 0x72,
- 0x65, 0x61, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f,
- 0x0a, 0x13, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c,
- 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74,
- 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x65, 0x66,
- 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12,
- 0x45, 0x0a, 0x13, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c,
- 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65,
- 0x72, 0x49, 0x44, 0x52, 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x61,
- 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x14, 0x0a,
- 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75,
- 0x65, 0x72, 0x79, 0x12, 0x2a, 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x05, 0x20,
+ 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c,
+ 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c,
+ 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70,
+ 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, 0x58, 0x0a, 0x0b, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61,
+ 0x73, 0x74, 0x50, 0x4b, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61,
+ 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e,
+ 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x03, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72,
0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x22,
- 0xf9, 0x01, 0x0a, 0x13, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64,
- 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e,
- 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x28, 0x0a,
- 0x08, 0x70, 0x6b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x08, 0x70,
- 0x6b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x74, 0x69, 0x64, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x74, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x72,
- 0x6f, 0x77, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x22, 0x0a, 0x06, 0x6c,
- 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75,
- 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x12,
- 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x09, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a,
- 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x22, 0xc5, 0x01, 0x0a, 0x14,
- 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76,
- 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72,
- 0x49, 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c,
- 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61,
- 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74,
- 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64,
- 0x69, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06,
- 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72,
- 0x67, 0x65, 0x74, 0x22, 0xde, 0x01, 0x0a, 0x15, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a,
- 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x06,
- 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c,
- 0x64, 0x73, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x6b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65,
- 0x6c, 0x64, 0x52, 0x08, 0x70, 0x6b, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04,
- 0x67, 0x74, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x74, 0x69, 0x64,
- 0x12, 0x1e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a,
- 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73,
- 0x12, 0x22, 0x0a, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x06, 0x6c, 0x61,
- 0x73, 0x74, 0x70, 0x6b, 0x22, 0x69, 0x0a, 0x0b, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x45, 0x76,
- 0x65, 0x6e, 0x74, 0x12, 0x3c, 0x0a, 0x0e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x61, 0x73,
- 0x74, 0x5f, 0x70, 0x5f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x62, 0x69,
- 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61,
- 0x73, 0x74, 0x50, 0x4b, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50,
- 0x4b, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22,
- 0x58, 0x0a, 0x0b, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x4b, 0x12, 0x1d,
- 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a,
- 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e,
- 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x52, 0x06, 0x6c, 0x61, 0x73, 0x74, 0x70, 0x6b, 0x22, 0xdc, 0x01, 0x0a, 0x15, 0x56, 0x53,
- 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65,
- 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49,
- 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c,
- 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
- 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x56, 0x54, 0x47, 0x61, 0x74, 0x65,
- 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69,
- 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75,
- 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67,
- 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x72, 0x0a, 0x16, 0x56, 0x53, 0x74, 0x72,
- 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64,
- 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x74, 0x69, 0x64,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x74, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04,
- 0x72, 0x6f, 0x77, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65,
- 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x2a, 0x3e, 0x0a, 0x0b,
- 0x4f, 0x6e, 0x44, 0x44, 0x4c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x49,
- 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10,
- 0x01, 0x12, 0x08, 0x0a, 0x04, 0x45, 0x58, 0x45, 0x43, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x45,
- 0x58, 0x45, 0x43, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x03, 0x2a, 0x7b, 0x0a, 0x18,
- 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x61, 0x74, 0x65,
- 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x6f, 0x76,
- 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x72, 0x65,
- 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x02,
- 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x65, 0x10, 0x03, 0x12, 0x0b, 0x0a,
- 0x07, 0x52, 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x4f, 0x6e,
- 0x6c, 0x69, 0x6e, 0x65, 0x44, 0x44, 0x4c, 0x10, 0x05, 0x2a, 0x44, 0x0a, 0x1b, 0x56, 0x52, 0x65,
- 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
- 0x77, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65,
- 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x10, 0x01, 0x12,
- 0x0e, 0x0a, 0x0a, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x43, 0x6f, 0x70, 0x79, 0x10, 0x02, 0x2a,
- 0x71, 0x0a, 0x19, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57,
- 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07,
- 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x6e, 0x69,
- 0x74, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x10, 0x02,
- 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x70, 0x79, 0x69, 0x6e, 0x67, 0x10, 0x03, 0x12, 0x0b, 0x0a,
- 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x72,
- 0x72, 0x6f, 0x72, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x61, 0x67, 0x67, 0x69, 0x6e, 0x67,
- 0x10, 0x06, 0x2a, 0x8d, 0x02, 0x0a, 0x0a, 0x56, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
- 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08,
- 0x0a, 0x04, 0x47, 0x54, 0x49, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x45, 0x47, 0x49,
- 0x4e, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x03, 0x12,
- 0x0c, 0x0a, 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x04, 0x12, 0x07, 0x0a,
- 0x03, 0x44, 0x44, 0x4c, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54,
- 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x10, 0x07, 0x12,
- 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x44,
- 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x09, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x45, 0x54, 0x10, 0x0a,
- 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x0b, 0x12, 0x07, 0x0a, 0x03, 0x52,
- 0x4f, 0x57, 0x10, 0x0c, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x10, 0x0d, 0x12,
- 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x0e, 0x12, 0x09,
- 0x0a, 0x05, 0x56, 0x47, 0x54, 0x49, 0x44, 0x10, 0x0f, 0x12, 0x0b, 0x0a, 0x07, 0x4a, 0x4f, 0x55,
- 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,
- 0x4e, 0x10, 0x11, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x53, 0x54, 0x50, 0x4b, 0x10, 0x12, 0x12,
- 0x0d, 0x0a, 0x09, 0x53, 0x41, 0x56, 0x45, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x13, 0x12, 0x12,
- 0x0a, 0x0e, 0x43, 0x4f, 0x50, 0x59, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44,
- 0x10, 0x14, 0x2a, 0x27, 0x0a, 0x0d, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54,
- 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x53, 0x10, 0x00, 0x12,
- 0x0a, 0x0a, 0x06, 0x53, 0x48, 0x41, 0x52, 0x44, 0x53, 0x10, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x76,
- 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f,
- 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x62, 0x69, 0x6e, 0x6c,
- 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0xdc, 0x01, 0x0a, 0x15, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x13, 0x65, 0x66, 0x66,
+ 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x76, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43,
+ 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69,
+ 0x76, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x13, 0x69, 0x6d,
+ 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x5f, 0x69,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e,
+ 0x56, 0x54, 0x47, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49, 0x44, 0x52, 0x11,
+ 0x69, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x49,
+ 0x64, 0x12, 0x25, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x0d, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74,
+ 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72,
+ 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x72,
+ 0x0a, 0x16, 0x56, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c,
+ 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79,
+ 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x12,
+ 0x0a, 0x04, 0x67, 0x74, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x67, 0x74,
+ 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
+ 0x32, 0x0a, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x6f, 0x77, 0x52, 0x04, 0x72, 0x6f,
+ 0x77, 0x73, 0x2a, 0x3e, 0x0a, 0x0b, 0x4f, 0x6e, 0x44, 0x44, 0x4c, 0x41, 0x63, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a,
+ 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x45, 0x58, 0x45, 0x43, 0x10,
+ 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x58, 0x45, 0x43, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45,
+ 0x10, 0x03, 0x2a, 0x7b, 0x0a, 0x18, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f,
+ 0x0a, 0x0b, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x10, 0x00, 0x12,
+ 0x0e, 0x0a, 0x0a, 0x4d, 0x6f, 0x76, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x10, 0x01, 0x12,
+ 0x15, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x49,
+ 0x6e, 0x64, 0x65, 0x78, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74,
+ 0x65, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x10, 0x04,
+ 0x12, 0x0d, 0x0a, 0x09, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x44, 0x44, 0x4c, 0x10, 0x05, 0x2a,
+ 0x44, 0x0a, 0x1b, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57,
+ 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x75, 0x62, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08,
+ 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x74,
+ 0x69, 0x61, 0x6c, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x74, 0x6f, 0x6d, 0x69, 0x63, 0x43,
+ 0x6f, 0x70, 0x79, 0x10, 0x02, 0x2a, 0x71, 0x0a, 0x19, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61,
+ 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12,
+ 0x08, 0x0a, 0x04, 0x49, 0x6e, 0x69, 0x74, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x74, 0x6f,
+ 0x70, 0x70, 0x65, 0x64, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6f, 0x70, 0x79, 0x69, 0x6e,
+ 0x67, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x10, 0x04,
+ 0x12, 0x09, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x4c,
+ 0x61, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x10, 0x06, 0x2a, 0x8d, 0x02, 0x0a, 0x0a, 0x56, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
+ 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x47, 0x54, 0x49, 0x44, 0x10, 0x01, 0x12, 0x09,
+ 0x0a, 0x05, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4d,
+ 0x4d, 0x49, 0x54, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43,
+ 0x4b, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x44, 0x4c, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06,
+ 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x50, 0x4c,
+ 0x41, 0x43, 0x45, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10,
+ 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x09, 0x12, 0x07, 0x0a,
+ 0x03, 0x53, 0x45, 0x54, 0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10,
+ 0x0b, 0x12, 0x07, 0x0a, 0x03, 0x52, 0x4f, 0x57, 0x10, 0x0c, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x49,
+ 0x45, 0x4c, 0x44, 0x10, 0x0d, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x45, 0x41, 0x52, 0x54, 0x42, 0x45,
+ 0x41, 0x54, 0x10, 0x0e, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x47, 0x54, 0x49, 0x44, 0x10, 0x0f, 0x12,
+ 0x0b, 0x0a, 0x07, 0x4a, 0x4f, 0x55, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07,
+ 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x11, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x53,
+ 0x54, 0x50, 0x4b, 0x10, 0x12, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x41, 0x56, 0x45, 0x50, 0x4f, 0x49,
+ 0x4e, 0x54, 0x10, 0x13, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x50, 0x59, 0x5f, 0x43, 0x4f, 0x4d,
+ 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x14, 0x2a, 0x27, 0x0a, 0x0d, 0x4d, 0x69, 0x67, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x41, 0x42,
+ 0x4c, 0x45, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x48, 0x41, 0x52, 0x44, 0x53, 0x10,
+ 0x01, 0x42, 0x29, 0x5a, 0x27, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76,
+ 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+ 0x6f, 0x2f, 0x62, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/go/vt/proto/binlogdata/binlogdata_vtproto.pb.go b/go/vt/proto/binlogdata/binlogdata_vtproto.pb.go
index 1332681a976..ea15c40a992 100644
--- a/go/vt/proto/binlogdata/binlogdata_vtproto.pb.go
+++ b/go/vt/proto/binlogdata/binlogdata_vtproto.pb.go
@@ -512,20 +512,21 @@ func (m *VEvent) CloneVT() *VEvent {
return (*VEvent)(nil)
}
r := &VEvent{
- Type: m.Type,
- Timestamp: m.Timestamp,
- Gtid: m.Gtid,
- Statement: m.Statement,
- RowEvent: m.RowEvent.CloneVT(),
- FieldEvent: m.FieldEvent.CloneVT(),
- Vgtid: m.Vgtid.CloneVT(),
- Journal: m.Journal.CloneVT(),
- Dml: m.Dml,
- CurrentTime: m.CurrentTime,
- LastPKEvent: m.LastPKEvent.CloneVT(),
- Keyspace: m.Keyspace,
- Shard: m.Shard,
- Throttled: m.Throttled,
+ Type: m.Type,
+ Timestamp: m.Timestamp,
+ Gtid: m.Gtid,
+ Statement: m.Statement,
+ RowEvent: m.RowEvent.CloneVT(),
+ FieldEvent: m.FieldEvent.CloneVT(),
+ Vgtid: m.Vgtid.CloneVT(),
+ Journal: m.Journal.CloneVT(),
+ Dml: m.Dml,
+ CurrentTime: m.CurrentTime,
+ LastPKEvent: m.LastPKEvent.CloneVT(),
+ Keyspace: m.Keyspace,
+ Shard: m.Shard,
+ Throttled: m.Throttled,
+ ThrottledReason: m.ThrottledReason,
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
@@ -671,10 +672,11 @@ func (m *VStreamRowsResponse) CloneVT() *VStreamRowsResponse {
return (*VStreamRowsResponse)(nil)
}
r := &VStreamRowsResponse{
- Gtid: m.Gtid,
- Lastpk: m.Lastpk.CloneVT(),
- Throttled: m.Throttled,
- Heartbeat: m.Heartbeat,
+ Gtid: m.Gtid,
+ Lastpk: m.Lastpk.CloneVT(),
+ Throttled: m.Throttled,
+ Heartbeat: m.Heartbeat,
+ ThrottledReason: m.ThrottledReason,
}
if rhs := m.Fields; rhs != nil {
tmpContainer := make([]*query.Field, len(rhs))
@@ -2131,6 +2133,15 @@ func (m *VEvent) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if len(m.ThrottledReason) > 0 {
+ i -= len(m.ThrottledReason)
+ copy(dAtA[i:], m.ThrottledReason)
+ i = encodeVarint(dAtA, i, uint64(len(m.ThrottledReason)))
+ i--
+ dAtA[i] = 0x1
+ i--
+ dAtA[i] = 0xca
+ }
if m.Throttled {
i--
if m.Throttled {
@@ -2626,6 +2637,13 @@ func (m *VStreamRowsResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if len(m.ThrottledReason) > 0 {
+ i -= len(m.ThrottledReason)
+ copy(dAtA[i:], m.ThrottledReason)
+ i = encodeVarint(dAtA, i, uint64(len(m.ThrottledReason)))
+ i--
+ dAtA[i] = 0x42
+ }
if m.Heartbeat {
i--
if m.Heartbeat {
@@ -3739,6 +3757,10 @@ func (m *VEvent) SizeVT() (n int) {
if m.Throttled {
n += 3
}
+ l = len(m.ThrottledReason)
+ if l > 0 {
+ n += 2 + l + sov(uint64(l))
+ }
n += len(m.unknownFields)
return n
}
@@ -3910,6 +3932,10 @@ func (m *VStreamRowsResponse) SizeVT() (n int) {
if m.Heartbeat {
n += 2
}
+ l = len(m.ThrottledReason)
+ if l > 0 {
+ n += 1 + l + sov(uint64(l))
+ }
n += len(m.unknownFields)
return n
}
@@ -7951,6 +7977,38 @@ func (m *VEvent) UnmarshalVT(dAtA []byte) error {
}
}
m.Throttled = bool(v != 0)
+ case 25:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ThrottledReason", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLength
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLength
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ThrottledReason = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
@@ -9116,6 +9174,38 @@ func (m *VStreamRowsResponse) UnmarshalVT(dAtA []byte) error {
}
}
m.Heartbeat = bool(v != 0)
+ case 8:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ThrottledReason", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLength
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLength
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ThrottledReason = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go
index c0896882735..b324845cec1 100644
--- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go
+++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go
@@ -96,6 +96,64 @@ func (TabletSelectionPreference) EnumDescriptor() ([]byte, []int) {
return file_tabletmanagerdata_proto_rawDescGZIP(), []int{0}
}
+type CheckThrottlerResponseCode int32
+
+const (
+ CheckThrottlerResponseCode_UNDEFINED CheckThrottlerResponseCode = 0
+ CheckThrottlerResponseCode_OK CheckThrottlerResponseCode = 1
+ CheckThrottlerResponseCode_THRESHOLD_EXCEEDED CheckThrottlerResponseCode = 2
+ CheckThrottlerResponseCode_APP_DENIED CheckThrottlerResponseCode = 3
+ CheckThrottlerResponseCode_UNKNOWN_METRIC CheckThrottlerResponseCode = 4
+ CheckThrottlerResponseCode_INTERNAL_ERROR CheckThrottlerResponseCode = 5
+)
+
+// Enum value maps for CheckThrottlerResponseCode.
+var (
+ CheckThrottlerResponseCode_name = map[int32]string{
+ 0: "UNDEFINED",
+ 1: "OK",
+ 2: "THRESHOLD_EXCEEDED",
+ 3: "APP_DENIED",
+ 4: "UNKNOWN_METRIC",
+ 5: "INTERNAL_ERROR",
+ }
+ CheckThrottlerResponseCode_value = map[string]int32{
+ "UNDEFINED": 0,
+ "OK": 1,
+ "THRESHOLD_EXCEEDED": 2,
+ "APP_DENIED": 3,
+ "UNKNOWN_METRIC": 4,
+ "INTERNAL_ERROR": 5,
+ }
+)
+
+func (x CheckThrottlerResponseCode) Enum() *CheckThrottlerResponseCode {
+ p := new(CheckThrottlerResponseCode)
+ *p = x
+ return p
+}
+
+func (x CheckThrottlerResponseCode) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CheckThrottlerResponseCode) Descriptor() protoreflect.EnumDescriptor {
+ return file_tabletmanagerdata_proto_enumTypes[1].Descriptor()
+}
+
+func (CheckThrottlerResponseCode) Type() protoreflect.EnumType {
+ return &file_tabletmanagerdata_proto_enumTypes[1]
+}
+
+func (x CheckThrottlerResponseCode) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CheckThrottlerResponseCode.Descriptor instead.
+func (CheckThrottlerResponseCode) EnumDescriptor() ([]byte, []int) {
+ return file_tabletmanagerdata_proto_rawDescGZIP(), []int{1}
+}
+
type TableDefinition struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -6636,6 +6694,12 @@ type CheckThrottlerResponse struct {
// Metrics is a map (metric name -> metric value/error) so that the client has as much
// information as possible about all the checked metrics.
Metrics map[string]*CheckThrottlerResponse_Metric `protobuf:"bytes,7,rep,name=metrics,proto3" json:"metrics,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+ // AppName is the name of app that was matched by the throttler
+ AppName string `protobuf:"bytes,8,opt,name=app_name,json=appName,proto3" json:"app_name,omitempty"`
+ // Summary is a human readable analysis of the result
+ Summary string `protobuf:"bytes,9,opt,name=summary,proto3" json:"summary,omitempty"`
+ // ResponseCode is the enum representation of the response
+ ResponseCode CheckThrottlerResponseCode `protobuf:"varint,10,opt,name=response_code,json=responseCode,proto3,enum=tabletmanagerdata.CheckThrottlerResponseCode" json:"response_code,omitempty"`
}
func (x *CheckThrottlerResponse) Reset() {
@@ -6719,6 +6783,27 @@ func (x *CheckThrottlerResponse) GetMetrics() map[string]*CheckThrottlerResponse
return nil
}
+func (x *CheckThrottlerResponse) GetAppName() string {
+ if x != nil {
+ return x.AppName
+ }
+ return ""
+}
+
+func (x *CheckThrottlerResponse) GetSummary() string {
+ if x != nil {
+ return x.Summary
+ }
+ return ""
+}
+
+func (x *CheckThrottlerResponse) GetResponseCode() CheckThrottlerResponseCode {
+ if x != nil {
+ return x.ResponseCode
+ }
+ return CheckThrottlerResponseCode_UNDEFINED
+}
+
type GetThrottlerStatusRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -7128,6 +7213,8 @@ type CheckThrottlerResponse_Metric struct {
Message string `protobuf:"bytes,6,opt,name=message,proto3" json:"message,omitempty"`
// Scope used in this check
Scope string `protobuf:"bytes,7,opt,name=scope,proto3" json:"scope,omitempty"`
+ // ResponseCode is the enum representation of the response
+ ResponseCode CheckThrottlerResponseCode `protobuf:"varint,8,opt,name=response_code,json=responseCode,proto3,enum=tabletmanagerdata.CheckThrottlerResponseCode" json:"response_code,omitempty"`
}
func (x *CheckThrottlerResponse_Metric) Reset() {
@@ -7211,6 +7298,13 @@ func (x *CheckThrottlerResponse_Metric) GetScope() string {
return ""
}
+func (x *CheckThrottlerResponse_Metric) GetResponseCode() CheckThrottlerResponseCode {
+ if x != nil {
+ return x.ResponseCode
+ }
+ return CheckThrottlerResponseCode_UNDEFINED
+}
+
type GetThrottlerStatusResponse_MetricResult struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -7328,6 +7422,8 @@ type GetThrottlerStatusResponse_RecentApp struct {
CheckedAt *vttime.Time `protobuf:"bytes,1,opt,name=checked_at,json=checkedAt,proto3" json:"checked_at,omitempty"`
StatusCode int32 `protobuf:"varint,2,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"`
+ // ResponseCode is the enum representation of the response
+ ResponseCode CheckThrottlerResponseCode `protobuf:"varint,3,opt,name=response_code,json=responseCode,proto3,enum=tabletmanagerdata.CheckThrottlerResponseCode" json:"response_code,omitempty"`
}
func (x *GetThrottlerStatusResponse_RecentApp) Reset() {
@@ -7376,6 +7472,13 @@ func (x *GetThrottlerStatusResponse_RecentApp) GetStatusCode() int32 {
return 0
}
+func (x *GetThrottlerStatusResponse_RecentApp) GetResponseCode() CheckThrottlerResponseCode {
+ if x != nil {
+ return x.ResponseCode
+ }
+ return CheckThrottlerResponseCode_UNDEFINED
+}
+
var File_tabletmanagerdata_proto protoreflect.FileDescriptor
var file_tabletmanagerdata_proto_rawDesc = []byte{
@@ -8211,7 +8314,7 @@ var file_tabletmanagerdata_proto_rawDesc = []byte{
0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x75, 0x6c, 0x74, 0x69,
0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0xc2, 0x04, 0x0a, 0x16,
+ 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x9f, 0x06, 0x0a, 0x16,
0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61,
@@ -8229,161 +8332,189 @@ var file_tabletmanagerdata_proto_rawDesc = []byte{
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63,
0x6b, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
- 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0xb7, 0x01, 0x0a, 0x06, 0x4d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74,
- 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c,
- 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
- 0x01, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05,
- 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72,
- 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05,
- 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f,
- 0x70, 0x65, 0x1a, 0x6c, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74,
- 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61,
- 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72,
- 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
- 0x22, 0x1b, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72,
- 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe1, 0x0f,
- 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74,
- 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x17,
- 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x06, 0x69, 0x73, 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x6e,
- 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45,
- 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x6f, 0x72,
- 0x6d, 0x61, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x6f,
- 0x72, 0x6d, 0x61, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x67, 0x5f, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0e, 0x6c, 0x61, 0x67, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12,
- 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x75,
- 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12,
- 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73,
- 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61,
- 0x75, 0x6c, 0x74, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x3c, 0x0a, 0x1b,
- 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64,
- 0x5f, 0x61, 0x73, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x17, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65,
- 0x64, 0x41, 0x73, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x73, 0x0a, 0x12, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d,
+ 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x70, 0x4e,
+ 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x52, 0x0a,
+ 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0a,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e,
+ 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68,
+ 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43,
+ 0x6f, 0x64, 0x65, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64,
+ 0x65, 0x1a, 0x8b, 0x02, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+ 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64,
+ 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73,
+ 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65,
+ 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d,
+ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
+ 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x07,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x72,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01,
+ 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67,
+ 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72, 0x6f,
+ 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64,
+ 0x65, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x1a,
+ 0x6c, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x30, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74,
+ 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1b, 0x0a,
+ 0x19, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb6, 0x10, 0x0a, 0x1a, 0x47,
+ 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x1b,
+ 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x6c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x08, 0x69, 0x73, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x69,
+ 0x73, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73,
+ 0x4f, 0x70, 0x65, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c,
+ 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x6e, 0x61, 0x62,
+ 0x6c, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x64, 0x6f, 0x72, 0x6d, 0x61, 0x6e,
+ 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x44, 0x6f, 0x72, 0x6d, 0x61,
+ 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x61, 0x67, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x61,
+ 0x67, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2e, 0x0a, 0x13,
+ 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x71, 0x75,
+ 0x65, 0x72, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x75, 0x73, 0x74, 0x6f,
+ 0x6d, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x2b, 0x0a, 0x11,
+ 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c,
+ 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x01, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
+ 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x3c, 0x0a, 0x1b, 0x6d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x61, 0x73,
+ 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17,
+ 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x55, 0x73, 0x65, 0x64, 0x41, 0x73,
+ 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x73, 0x0a, 0x12, 0x61, 0x67, 0x67, 0x72, 0x65,
+ 0x67, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x0c, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61,
+ 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74,
+ 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65,
+ 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x70, 0x0a, 0x11,
+ 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64,
+ 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54,
+ 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72,
+ 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x6d, 0x65,
+ 0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x12, 0x67,
+ 0x0a, 0x0e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68,
+ 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d,
0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68,
0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64,
- 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
- 0x70, 0x0a, 0x11, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68,
- 0x6f, 0x6c, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47,
- 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
- 0x10, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64,
- 0x73, 0x12, 0x67, 0x0a, 0x0e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x68, 0x65, 0x61,
- 0x6c, 0x74, 0x68, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x74, 0x61, 0x62, 0x6c,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x65, 0x61,
+ 0x6c, 0x74, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x67, 0x0a, 0x0e, 0x74, 0x68, 0x72, 0x6f, 0x74,
+ 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x40, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54,
+ 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x52, 0x0d, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x73,
+ 0x12, 0x74, 0x0a, 0x13, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x5f,
+ 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74,
+ 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74,
+ 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x70, 0x70,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x52, 0x11, 0x61, 0x70, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x4d,
+ 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74,
+ 0x6c, 0x79, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65,
+ 0x64, 0x12, 0x5e, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x70, 0x70, 0x73,
+ 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d,
+ 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68,
+ 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x73,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70,
+ 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x80, 0x01,
+ 0x0a, 0x16, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72,
+ 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x50, 0x0a, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x61, 0x62, 0x6c,
0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65,
0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x6d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x67, 0x0a, 0x0e, 0x74, 0x68,
- 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67,
- 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74,
- 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x2e, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x73, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x74, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41,
- 0x70, 0x70, 0x73, 0x12, 0x74, 0x0a, 0x13, 0x61, 0x70, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b,
- 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b,
- 0x32, 0x44, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52,
+ 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+ 0x1a, 0x43, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68,
+ 0x6f, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x81, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x34, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68,
+ 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x0c, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x0d, 0x6c,
+ 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x41, 0x74, 0x12, 0x3b, 0x0a, 0x1a,
+ 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x6c, 0x61,
+ 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x17, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x4c, 0x61,
+ 0x73, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x1a, 0x7c, 0x0a, 0x12, 0x4d, 0x65, 0x74,
+ 0x72, 0x69, 0x63, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x50, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x3a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65,
0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
- 0x41, 0x70, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
- 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x61, 0x70, 0x70, 0x43, 0x68, 0x65, 0x63, 0x6b,
- 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x63,
- 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x11, 0x20,
- 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x43, 0x68, 0x65,
- 0x63, 0x6b, 0x65, 0x64, 0x12, 0x5e, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x61,
- 0x70, 0x70, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65,
- 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41,
- 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74,
- 0x41, 0x70, 0x70, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x65,
- 0x73, 0x75, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72,
- 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
- 0x1a, 0x80, 0x01, 0x0a, 0x16, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x4d,
- 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
- 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x50, 0x0a,
- 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61,
- 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72,
- 0x69, 0x63, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x1a, 0x43, 0x0a, 0x15, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x68, 0x72,
- 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
- 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
- 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x81, 0x01, 0x0a, 0x0c, 0x4d, 0x65, 0x74,
- 0x72, 0x69, 0x63, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x34, 0x0a, 0x0f, 0x6c, 0x61, 0x73,
- 0x74, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65,
- 0x52, 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x41, 0x74, 0x12,
- 0x3b, 0x0a, 0x1a, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x5f, 0x73, 0x69, 0x6e, 0x63, 0x65,
- 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x03, 0x52, 0x17, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x53, 0x69, 0x6e, 0x63,
- 0x65, 0x4c, 0x61, 0x73, 0x74, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x79, 0x1a, 0x7c, 0x0a, 0x12,
- 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x45, 0x6e, 0x74,
- 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x03, 0x6b, 0x65, 0x79, 0x12, 0x50, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61,
- 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74,
- 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52,
- 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5c, 0x0a, 0x12, 0x54, 0x68,
- 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
- 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x68, 0x72,
- 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x44, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x43,
- 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74,
- 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59,
- 0x0a, 0x09, 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x12, 0x2b, 0x0a, 0x0a, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x0c, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x09, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x1a, 0x76, 0x0a, 0x0f, 0x52, 0x65, 0x63,
- 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
- 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x4d,
- 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74,
- 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x53, 0x74,
- 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x63,
- 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
- 0x01, 0x2a, 0x3e, 0x0a, 0x19, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x07,
- 0x0a, 0x03, 0x41, 0x4e, 0x59, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x4f, 0x52, 0x44,
- 0x45, 0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
- 0x03, 0x42, 0x30, 0x5a, 0x2e, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76,
- 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74,
- 0x6f, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64,
- 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5c, 0x0a, 0x12, 0x54, 0x68, 0x72, 0x6f, 0x74,
+ 0x74, 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
+ 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74,
+ 0x6c, 0x65, 0x64, 0x41, 0x70, 0x70, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x44, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x43, 0x68, 0x65, 0x63,
+ 0x6b, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xad, 0x01, 0x0a, 0x09,
+ 0x52, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x12, 0x2b, 0x0a, 0x0a, 0x63, 0x68, 0x65,
+ 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
+ 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x09, 0x63, 0x68, 0x65,
+ 0x63, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61,
+ 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d,
+ 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61,
+ 0x74, 0x61, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65,
+ 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0c, 0x72,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x1a, 0x76, 0x0a, 0x0f, 0x52,
+ 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x4d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x37, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x68, 0x72, 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72,
+ 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52,
+ 0x65, 0x63, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x2a, 0x3e, 0x0a, 0x19, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c,
+ 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
+ 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x59, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x4f,
+ 0x52, 0x44, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
+ 0x4e, 0x10, 0x03, 0x2a, 0x83, 0x01, 0x0a, 0x1a, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x68, 0x72,
+ 0x6f, 0x74, 0x74, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x43, 0x6f,
+ 0x64, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10,
+ 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x48, 0x52,
+ 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x5f, 0x45, 0x58, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10,
+ 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x50, 0x50, 0x5f, 0x44, 0x45, 0x4e, 0x49, 0x45, 0x44, 0x10,
+ 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x4d, 0x45, 0x54,
+ 0x52, 0x49, 0x43, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41,
+ 0x4c, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x42, 0x30, 0x5a, 0x2e, 0x76, 0x69, 0x74,
+ 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f,
+ 0x2f, 0x76, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
@@ -8398,263 +8529,267 @@ func file_tabletmanagerdata_proto_rawDescGZIP() []byte {
return file_tabletmanagerdata_proto_rawDescData
}
-var file_tabletmanagerdata_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_tabletmanagerdata_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_tabletmanagerdata_proto_msgTypes = make([]protoimpl.MessageInfo, 142)
var file_tabletmanagerdata_proto_goTypes = []any{
(TabletSelectionPreference)(0), // 0: tabletmanagerdata.TabletSelectionPreference
- (*TableDefinition)(nil), // 1: tabletmanagerdata.TableDefinition
- (*SchemaDefinition)(nil), // 2: tabletmanagerdata.SchemaDefinition
- (*SchemaChangeResult)(nil), // 3: tabletmanagerdata.SchemaChangeResult
- (*UserPermission)(nil), // 4: tabletmanagerdata.UserPermission
- (*DbPermission)(nil), // 5: tabletmanagerdata.DbPermission
- (*Permissions)(nil), // 6: tabletmanagerdata.Permissions
- (*PingRequest)(nil), // 7: tabletmanagerdata.PingRequest
- (*PingResponse)(nil), // 8: tabletmanagerdata.PingResponse
- (*SleepRequest)(nil), // 9: tabletmanagerdata.SleepRequest
- (*SleepResponse)(nil), // 10: tabletmanagerdata.SleepResponse
- (*ExecuteHookRequest)(nil), // 11: tabletmanagerdata.ExecuteHookRequest
- (*ExecuteHookResponse)(nil), // 12: tabletmanagerdata.ExecuteHookResponse
- (*GetSchemaRequest)(nil), // 13: tabletmanagerdata.GetSchemaRequest
- (*GetSchemaResponse)(nil), // 14: tabletmanagerdata.GetSchemaResponse
- (*GetPermissionsRequest)(nil), // 15: tabletmanagerdata.GetPermissionsRequest
- (*GetPermissionsResponse)(nil), // 16: tabletmanagerdata.GetPermissionsResponse
- (*GetGlobalStatusVarsRequest)(nil), // 17: tabletmanagerdata.GetGlobalStatusVarsRequest
- (*GetGlobalStatusVarsResponse)(nil), // 18: tabletmanagerdata.GetGlobalStatusVarsResponse
- (*SetReadOnlyRequest)(nil), // 19: tabletmanagerdata.SetReadOnlyRequest
- (*SetReadOnlyResponse)(nil), // 20: tabletmanagerdata.SetReadOnlyResponse
- (*SetReadWriteRequest)(nil), // 21: tabletmanagerdata.SetReadWriteRequest
- (*SetReadWriteResponse)(nil), // 22: tabletmanagerdata.SetReadWriteResponse
- (*ChangeTypeRequest)(nil), // 23: tabletmanagerdata.ChangeTypeRequest
- (*ChangeTypeResponse)(nil), // 24: tabletmanagerdata.ChangeTypeResponse
- (*RefreshStateRequest)(nil), // 25: tabletmanagerdata.RefreshStateRequest
- (*RefreshStateResponse)(nil), // 26: tabletmanagerdata.RefreshStateResponse
- (*RunHealthCheckRequest)(nil), // 27: tabletmanagerdata.RunHealthCheckRequest
- (*RunHealthCheckResponse)(nil), // 28: tabletmanagerdata.RunHealthCheckResponse
- (*ReloadSchemaRequest)(nil), // 29: tabletmanagerdata.ReloadSchemaRequest
- (*ReloadSchemaResponse)(nil), // 30: tabletmanagerdata.ReloadSchemaResponse
- (*PreflightSchemaRequest)(nil), // 31: tabletmanagerdata.PreflightSchemaRequest
- (*PreflightSchemaResponse)(nil), // 32: tabletmanagerdata.PreflightSchemaResponse
- (*ApplySchemaRequest)(nil), // 33: tabletmanagerdata.ApplySchemaRequest
- (*ApplySchemaResponse)(nil), // 34: tabletmanagerdata.ApplySchemaResponse
- (*LockTablesRequest)(nil), // 35: tabletmanagerdata.LockTablesRequest
- (*LockTablesResponse)(nil), // 36: tabletmanagerdata.LockTablesResponse
- (*UnlockTablesRequest)(nil), // 37: tabletmanagerdata.UnlockTablesRequest
- (*UnlockTablesResponse)(nil), // 38: tabletmanagerdata.UnlockTablesResponse
- (*ExecuteQueryRequest)(nil), // 39: tabletmanagerdata.ExecuteQueryRequest
- (*ExecuteQueryResponse)(nil), // 40: tabletmanagerdata.ExecuteQueryResponse
- (*ExecuteFetchAsDbaRequest)(nil), // 41: tabletmanagerdata.ExecuteFetchAsDbaRequest
- (*ExecuteFetchAsDbaResponse)(nil), // 42: tabletmanagerdata.ExecuteFetchAsDbaResponse
- (*ExecuteMultiFetchAsDbaRequest)(nil), // 43: tabletmanagerdata.ExecuteMultiFetchAsDbaRequest
- (*ExecuteMultiFetchAsDbaResponse)(nil), // 44: tabletmanagerdata.ExecuteMultiFetchAsDbaResponse
- (*ExecuteFetchAsAllPrivsRequest)(nil), // 45: tabletmanagerdata.ExecuteFetchAsAllPrivsRequest
- (*ExecuteFetchAsAllPrivsResponse)(nil), // 46: tabletmanagerdata.ExecuteFetchAsAllPrivsResponse
- (*ExecuteFetchAsAppRequest)(nil), // 47: tabletmanagerdata.ExecuteFetchAsAppRequest
- (*ExecuteFetchAsAppResponse)(nil), // 48: tabletmanagerdata.ExecuteFetchAsAppResponse
- (*ReplicationStatusRequest)(nil), // 49: tabletmanagerdata.ReplicationStatusRequest
- (*ReplicationStatusResponse)(nil), // 50: tabletmanagerdata.ReplicationStatusResponse
- (*PrimaryStatusRequest)(nil), // 51: tabletmanagerdata.PrimaryStatusRequest
- (*PrimaryStatusResponse)(nil), // 52: tabletmanagerdata.PrimaryStatusResponse
- (*PrimaryPositionRequest)(nil), // 53: tabletmanagerdata.PrimaryPositionRequest
- (*PrimaryPositionResponse)(nil), // 54: tabletmanagerdata.PrimaryPositionResponse
- (*WaitForPositionRequest)(nil), // 55: tabletmanagerdata.WaitForPositionRequest
- (*WaitForPositionResponse)(nil), // 56: tabletmanagerdata.WaitForPositionResponse
- (*StopReplicationRequest)(nil), // 57: tabletmanagerdata.StopReplicationRequest
- (*StopReplicationResponse)(nil), // 58: tabletmanagerdata.StopReplicationResponse
- (*StopReplicationMinimumRequest)(nil), // 59: tabletmanagerdata.StopReplicationMinimumRequest
- (*StopReplicationMinimumResponse)(nil), // 60: tabletmanagerdata.StopReplicationMinimumResponse
- (*StartReplicationRequest)(nil), // 61: tabletmanagerdata.StartReplicationRequest
- (*StartReplicationResponse)(nil), // 62: tabletmanagerdata.StartReplicationResponse
- (*StartReplicationUntilAfterRequest)(nil), // 63: tabletmanagerdata.StartReplicationUntilAfterRequest
- (*StartReplicationUntilAfterResponse)(nil), // 64: tabletmanagerdata.StartReplicationUntilAfterResponse
- (*GetReplicasRequest)(nil), // 65: tabletmanagerdata.GetReplicasRequest
- (*GetReplicasResponse)(nil), // 66: tabletmanagerdata.GetReplicasResponse
- (*ResetReplicationRequest)(nil), // 67: tabletmanagerdata.ResetReplicationRequest
- (*ResetReplicationResponse)(nil), // 68: tabletmanagerdata.ResetReplicationResponse
- (*VReplicationExecRequest)(nil), // 69: tabletmanagerdata.VReplicationExecRequest
- (*VReplicationExecResponse)(nil), // 70: tabletmanagerdata.VReplicationExecResponse
- (*VReplicationWaitForPosRequest)(nil), // 71: tabletmanagerdata.VReplicationWaitForPosRequest
- (*VReplicationWaitForPosResponse)(nil), // 72: tabletmanagerdata.VReplicationWaitForPosResponse
- (*InitPrimaryRequest)(nil), // 73: tabletmanagerdata.InitPrimaryRequest
- (*InitPrimaryResponse)(nil), // 74: tabletmanagerdata.InitPrimaryResponse
- (*PopulateReparentJournalRequest)(nil), // 75: tabletmanagerdata.PopulateReparentJournalRequest
- (*PopulateReparentJournalResponse)(nil), // 76: tabletmanagerdata.PopulateReparentJournalResponse
- (*InitReplicaRequest)(nil), // 77: tabletmanagerdata.InitReplicaRequest
- (*InitReplicaResponse)(nil), // 78: tabletmanagerdata.InitReplicaResponse
- (*DemotePrimaryRequest)(nil), // 79: tabletmanagerdata.DemotePrimaryRequest
- (*DemotePrimaryResponse)(nil), // 80: tabletmanagerdata.DemotePrimaryResponse
- (*UndoDemotePrimaryRequest)(nil), // 81: tabletmanagerdata.UndoDemotePrimaryRequest
- (*UndoDemotePrimaryResponse)(nil), // 82: tabletmanagerdata.UndoDemotePrimaryResponse
- (*ReplicaWasPromotedRequest)(nil), // 83: tabletmanagerdata.ReplicaWasPromotedRequest
- (*ReplicaWasPromotedResponse)(nil), // 84: tabletmanagerdata.ReplicaWasPromotedResponse
- (*ResetReplicationParametersRequest)(nil), // 85: tabletmanagerdata.ResetReplicationParametersRequest
- (*ResetReplicationParametersResponse)(nil), // 86: tabletmanagerdata.ResetReplicationParametersResponse
- (*FullStatusRequest)(nil), // 87: tabletmanagerdata.FullStatusRequest
- (*FullStatusResponse)(nil), // 88: tabletmanagerdata.FullStatusResponse
- (*SetReplicationSourceRequest)(nil), // 89: tabletmanagerdata.SetReplicationSourceRequest
- (*SetReplicationSourceResponse)(nil), // 90: tabletmanagerdata.SetReplicationSourceResponse
- (*ReplicaWasRestartedRequest)(nil), // 91: tabletmanagerdata.ReplicaWasRestartedRequest
- (*ReplicaWasRestartedResponse)(nil), // 92: tabletmanagerdata.ReplicaWasRestartedResponse
- (*StopReplicationAndGetStatusRequest)(nil), // 93: tabletmanagerdata.StopReplicationAndGetStatusRequest
- (*StopReplicationAndGetStatusResponse)(nil), // 94: tabletmanagerdata.StopReplicationAndGetStatusResponse
- (*PromoteReplicaRequest)(nil), // 95: tabletmanagerdata.PromoteReplicaRequest
- (*PromoteReplicaResponse)(nil), // 96: tabletmanagerdata.PromoteReplicaResponse
- (*BackupRequest)(nil), // 97: tabletmanagerdata.BackupRequest
- (*BackupResponse)(nil), // 98: tabletmanagerdata.BackupResponse
- (*RestoreFromBackupRequest)(nil), // 99: tabletmanagerdata.RestoreFromBackupRequest
- (*RestoreFromBackupResponse)(nil), // 100: tabletmanagerdata.RestoreFromBackupResponse
- (*CreateVReplicationWorkflowRequest)(nil), // 101: tabletmanagerdata.CreateVReplicationWorkflowRequest
- (*CreateVReplicationWorkflowResponse)(nil), // 102: tabletmanagerdata.CreateVReplicationWorkflowResponse
- (*DeleteVReplicationWorkflowRequest)(nil), // 103: tabletmanagerdata.DeleteVReplicationWorkflowRequest
- (*DeleteVReplicationWorkflowResponse)(nil), // 104: tabletmanagerdata.DeleteVReplicationWorkflowResponse
- (*HasVReplicationWorkflowsRequest)(nil), // 105: tabletmanagerdata.HasVReplicationWorkflowsRequest
- (*HasVReplicationWorkflowsResponse)(nil), // 106: tabletmanagerdata.HasVReplicationWorkflowsResponse
- (*ReadVReplicationWorkflowsRequest)(nil), // 107: tabletmanagerdata.ReadVReplicationWorkflowsRequest
- (*ReadVReplicationWorkflowsResponse)(nil), // 108: tabletmanagerdata.ReadVReplicationWorkflowsResponse
- (*ReadVReplicationWorkflowRequest)(nil), // 109: tabletmanagerdata.ReadVReplicationWorkflowRequest
- (*ReadVReplicationWorkflowResponse)(nil), // 110: tabletmanagerdata.ReadVReplicationWorkflowResponse
- (*VDiffRequest)(nil), // 111: tabletmanagerdata.VDiffRequest
- (*VDiffResponse)(nil), // 112: tabletmanagerdata.VDiffResponse
- (*VDiffPickerOptions)(nil), // 113: tabletmanagerdata.VDiffPickerOptions
- (*VDiffReportOptions)(nil), // 114: tabletmanagerdata.VDiffReportOptions
- (*VDiffCoreOptions)(nil), // 115: tabletmanagerdata.VDiffCoreOptions
- (*VDiffOptions)(nil), // 116: tabletmanagerdata.VDiffOptions
- (*UpdateVReplicationWorkflowRequest)(nil), // 117: tabletmanagerdata.UpdateVReplicationWorkflowRequest
- (*UpdateVReplicationWorkflowResponse)(nil), // 118: tabletmanagerdata.UpdateVReplicationWorkflowResponse
- (*UpdateVReplicationWorkflowsRequest)(nil), // 119: tabletmanagerdata.UpdateVReplicationWorkflowsRequest
- (*UpdateVReplicationWorkflowsResponse)(nil), // 120: tabletmanagerdata.UpdateVReplicationWorkflowsResponse
- (*ResetSequencesRequest)(nil), // 121: tabletmanagerdata.ResetSequencesRequest
- (*ResetSequencesResponse)(nil), // 122: tabletmanagerdata.ResetSequencesResponse
- (*CheckThrottlerRequest)(nil), // 123: tabletmanagerdata.CheckThrottlerRequest
- (*CheckThrottlerResponse)(nil), // 124: tabletmanagerdata.CheckThrottlerResponse
- (*GetThrottlerStatusRequest)(nil), // 125: tabletmanagerdata.GetThrottlerStatusRequest
- (*GetThrottlerStatusResponse)(nil), // 126: tabletmanagerdata.GetThrottlerStatusResponse
- nil, // 127: tabletmanagerdata.UserPermission.PrivilegesEntry
- nil, // 128: tabletmanagerdata.DbPermission.PrivilegesEntry
- nil, // 129: tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry
- nil, // 130: tabletmanagerdata.GetGlobalStatusVarsResponse.StatusValuesEntry
- (*ReadVReplicationWorkflowResponse_Stream)(nil), // 131: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream
- (*CheckThrottlerResponse_Metric)(nil), // 132: tabletmanagerdata.CheckThrottlerResponse.Metric
- nil, // 133: tabletmanagerdata.CheckThrottlerResponse.MetricsEntry
- (*GetThrottlerStatusResponse_MetricResult)(nil), // 134: tabletmanagerdata.GetThrottlerStatusResponse.MetricResult
- nil, // 135: tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry
- nil, // 136: tabletmanagerdata.GetThrottlerStatusResponse.MetricThresholdsEntry
- (*GetThrottlerStatusResponse_MetricHealth)(nil), // 137: tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth
- nil, // 138: tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry
- nil, // 139: tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry
- nil, // 140: tabletmanagerdata.GetThrottlerStatusResponse.AppCheckedMetricsEntry
- (*GetThrottlerStatusResponse_RecentApp)(nil), // 141: tabletmanagerdata.GetThrottlerStatusResponse.RecentApp
- nil, // 142: tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry
- (*query.Field)(nil), // 143: query.Field
- (topodata.TabletType)(0), // 144: topodata.TabletType
- (*vtrpc.CallerID)(nil), // 145: vtrpc.CallerID
- (*query.QueryResult)(nil), // 146: query.QueryResult
- (*replicationdata.Status)(nil), // 147: replicationdata.Status
- (*replicationdata.PrimaryStatus)(nil), // 148: replicationdata.PrimaryStatus
- (*topodata.TabletAlias)(nil), // 149: topodata.TabletAlias
- (*replicationdata.FullStatus)(nil), // 150: replicationdata.FullStatus
- (replicationdata.StopReplicationMode)(0), // 151: replicationdata.StopReplicationMode
- (*replicationdata.StopReplicationStatus)(nil), // 152: replicationdata.StopReplicationStatus
- (*logutil.Event)(nil), // 153: logutil.Event
- (*vttime.Time)(nil), // 154: vttime.Time
- (*binlogdata.BinlogSource)(nil), // 155: binlogdata.BinlogSource
- (binlogdata.VReplicationWorkflowType)(0), // 156: binlogdata.VReplicationWorkflowType
- (binlogdata.VReplicationWorkflowSubType)(0), // 157: binlogdata.VReplicationWorkflowSubType
- (binlogdata.VReplicationWorkflowState)(0), // 158: binlogdata.VReplicationWorkflowState
- (binlogdata.OnDDLAction)(0), // 159: binlogdata.OnDDLAction
- (*topodata.ThrottledAppRule)(nil), // 160: topodata.ThrottledAppRule
+ (CheckThrottlerResponseCode)(0), // 1: tabletmanagerdata.CheckThrottlerResponseCode
+ (*TableDefinition)(nil), // 2: tabletmanagerdata.TableDefinition
+ (*SchemaDefinition)(nil), // 3: tabletmanagerdata.SchemaDefinition
+ (*SchemaChangeResult)(nil), // 4: tabletmanagerdata.SchemaChangeResult
+ (*UserPermission)(nil), // 5: tabletmanagerdata.UserPermission
+ (*DbPermission)(nil), // 6: tabletmanagerdata.DbPermission
+ (*Permissions)(nil), // 7: tabletmanagerdata.Permissions
+ (*PingRequest)(nil), // 8: tabletmanagerdata.PingRequest
+ (*PingResponse)(nil), // 9: tabletmanagerdata.PingResponse
+ (*SleepRequest)(nil), // 10: tabletmanagerdata.SleepRequest
+ (*SleepResponse)(nil), // 11: tabletmanagerdata.SleepResponse
+ (*ExecuteHookRequest)(nil), // 12: tabletmanagerdata.ExecuteHookRequest
+ (*ExecuteHookResponse)(nil), // 13: tabletmanagerdata.ExecuteHookResponse
+ (*GetSchemaRequest)(nil), // 14: tabletmanagerdata.GetSchemaRequest
+ (*GetSchemaResponse)(nil), // 15: tabletmanagerdata.GetSchemaResponse
+ (*GetPermissionsRequest)(nil), // 16: tabletmanagerdata.GetPermissionsRequest
+ (*GetPermissionsResponse)(nil), // 17: tabletmanagerdata.GetPermissionsResponse
+ (*GetGlobalStatusVarsRequest)(nil), // 18: tabletmanagerdata.GetGlobalStatusVarsRequest
+ (*GetGlobalStatusVarsResponse)(nil), // 19: tabletmanagerdata.GetGlobalStatusVarsResponse
+ (*SetReadOnlyRequest)(nil), // 20: tabletmanagerdata.SetReadOnlyRequest
+ (*SetReadOnlyResponse)(nil), // 21: tabletmanagerdata.SetReadOnlyResponse
+ (*SetReadWriteRequest)(nil), // 22: tabletmanagerdata.SetReadWriteRequest
+ (*SetReadWriteResponse)(nil), // 23: tabletmanagerdata.SetReadWriteResponse
+ (*ChangeTypeRequest)(nil), // 24: tabletmanagerdata.ChangeTypeRequest
+ (*ChangeTypeResponse)(nil), // 25: tabletmanagerdata.ChangeTypeResponse
+ (*RefreshStateRequest)(nil), // 26: tabletmanagerdata.RefreshStateRequest
+ (*RefreshStateResponse)(nil), // 27: tabletmanagerdata.RefreshStateResponse
+ (*RunHealthCheckRequest)(nil), // 28: tabletmanagerdata.RunHealthCheckRequest
+ (*RunHealthCheckResponse)(nil), // 29: tabletmanagerdata.RunHealthCheckResponse
+ (*ReloadSchemaRequest)(nil), // 30: tabletmanagerdata.ReloadSchemaRequest
+ (*ReloadSchemaResponse)(nil), // 31: tabletmanagerdata.ReloadSchemaResponse
+ (*PreflightSchemaRequest)(nil), // 32: tabletmanagerdata.PreflightSchemaRequest
+ (*PreflightSchemaResponse)(nil), // 33: tabletmanagerdata.PreflightSchemaResponse
+ (*ApplySchemaRequest)(nil), // 34: tabletmanagerdata.ApplySchemaRequest
+ (*ApplySchemaResponse)(nil), // 35: tabletmanagerdata.ApplySchemaResponse
+ (*LockTablesRequest)(nil), // 36: tabletmanagerdata.LockTablesRequest
+ (*LockTablesResponse)(nil), // 37: tabletmanagerdata.LockTablesResponse
+ (*UnlockTablesRequest)(nil), // 38: tabletmanagerdata.UnlockTablesRequest
+ (*UnlockTablesResponse)(nil), // 39: tabletmanagerdata.UnlockTablesResponse
+ (*ExecuteQueryRequest)(nil), // 40: tabletmanagerdata.ExecuteQueryRequest
+ (*ExecuteQueryResponse)(nil), // 41: tabletmanagerdata.ExecuteQueryResponse
+ (*ExecuteFetchAsDbaRequest)(nil), // 42: tabletmanagerdata.ExecuteFetchAsDbaRequest
+ (*ExecuteFetchAsDbaResponse)(nil), // 43: tabletmanagerdata.ExecuteFetchAsDbaResponse
+ (*ExecuteMultiFetchAsDbaRequest)(nil), // 44: tabletmanagerdata.ExecuteMultiFetchAsDbaRequest
+ (*ExecuteMultiFetchAsDbaResponse)(nil), // 45: tabletmanagerdata.ExecuteMultiFetchAsDbaResponse
+ (*ExecuteFetchAsAllPrivsRequest)(nil), // 46: tabletmanagerdata.ExecuteFetchAsAllPrivsRequest
+ (*ExecuteFetchAsAllPrivsResponse)(nil), // 47: tabletmanagerdata.ExecuteFetchAsAllPrivsResponse
+ (*ExecuteFetchAsAppRequest)(nil), // 48: tabletmanagerdata.ExecuteFetchAsAppRequest
+ (*ExecuteFetchAsAppResponse)(nil), // 49: tabletmanagerdata.ExecuteFetchAsAppResponse
+ (*ReplicationStatusRequest)(nil), // 50: tabletmanagerdata.ReplicationStatusRequest
+ (*ReplicationStatusResponse)(nil), // 51: tabletmanagerdata.ReplicationStatusResponse
+ (*PrimaryStatusRequest)(nil), // 52: tabletmanagerdata.PrimaryStatusRequest
+ (*PrimaryStatusResponse)(nil), // 53: tabletmanagerdata.PrimaryStatusResponse
+ (*PrimaryPositionRequest)(nil), // 54: tabletmanagerdata.PrimaryPositionRequest
+ (*PrimaryPositionResponse)(nil), // 55: tabletmanagerdata.PrimaryPositionResponse
+ (*WaitForPositionRequest)(nil), // 56: tabletmanagerdata.WaitForPositionRequest
+ (*WaitForPositionResponse)(nil), // 57: tabletmanagerdata.WaitForPositionResponse
+ (*StopReplicationRequest)(nil), // 58: tabletmanagerdata.StopReplicationRequest
+ (*StopReplicationResponse)(nil), // 59: tabletmanagerdata.StopReplicationResponse
+ (*StopReplicationMinimumRequest)(nil), // 60: tabletmanagerdata.StopReplicationMinimumRequest
+ (*StopReplicationMinimumResponse)(nil), // 61: tabletmanagerdata.StopReplicationMinimumResponse
+ (*StartReplicationRequest)(nil), // 62: tabletmanagerdata.StartReplicationRequest
+ (*StartReplicationResponse)(nil), // 63: tabletmanagerdata.StartReplicationResponse
+ (*StartReplicationUntilAfterRequest)(nil), // 64: tabletmanagerdata.StartReplicationUntilAfterRequest
+ (*StartReplicationUntilAfterResponse)(nil), // 65: tabletmanagerdata.StartReplicationUntilAfterResponse
+ (*GetReplicasRequest)(nil), // 66: tabletmanagerdata.GetReplicasRequest
+ (*GetReplicasResponse)(nil), // 67: tabletmanagerdata.GetReplicasResponse
+ (*ResetReplicationRequest)(nil), // 68: tabletmanagerdata.ResetReplicationRequest
+ (*ResetReplicationResponse)(nil), // 69: tabletmanagerdata.ResetReplicationResponse
+ (*VReplicationExecRequest)(nil), // 70: tabletmanagerdata.VReplicationExecRequest
+ (*VReplicationExecResponse)(nil), // 71: tabletmanagerdata.VReplicationExecResponse
+ (*VReplicationWaitForPosRequest)(nil), // 72: tabletmanagerdata.VReplicationWaitForPosRequest
+ (*VReplicationWaitForPosResponse)(nil), // 73: tabletmanagerdata.VReplicationWaitForPosResponse
+ (*InitPrimaryRequest)(nil), // 74: tabletmanagerdata.InitPrimaryRequest
+ (*InitPrimaryResponse)(nil), // 75: tabletmanagerdata.InitPrimaryResponse
+ (*PopulateReparentJournalRequest)(nil), // 76: tabletmanagerdata.PopulateReparentJournalRequest
+ (*PopulateReparentJournalResponse)(nil), // 77: tabletmanagerdata.PopulateReparentJournalResponse
+ (*InitReplicaRequest)(nil), // 78: tabletmanagerdata.InitReplicaRequest
+ (*InitReplicaResponse)(nil), // 79: tabletmanagerdata.InitReplicaResponse
+ (*DemotePrimaryRequest)(nil), // 80: tabletmanagerdata.DemotePrimaryRequest
+ (*DemotePrimaryResponse)(nil), // 81: tabletmanagerdata.DemotePrimaryResponse
+ (*UndoDemotePrimaryRequest)(nil), // 82: tabletmanagerdata.UndoDemotePrimaryRequest
+ (*UndoDemotePrimaryResponse)(nil), // 83: tabletmanagerdata.UndoDemotePrimaryResponse
+ (*ReplicaWasPromotedRequest)(nil), // 84: tabletmanagerdata.ReplicaWasPromotedRequest
+ (*ReplicaWasPromotedResponse)(nil), // 85: tabletmanagerdata.ReplicaWasPromotedResponse
+ (*ResetReplicationParametersRequest)(nil), // 86: tabletmanagerdata.ResetReplicationParametersRequest
+ (*ResetReplicationParametersResponse)(nil), // 87: tabletmanagerdata.ResetReplicationParametersResponse
+ (*FullStatusRequest)(nil), // 88: tabletmanagerdata.FullStatusRequest
+ (*FullStatusResponse)(nil), // 89: tabletmanagerdata.FullStatusResponse
+ (*SetReplicationSourceRequest)(nil), // 90: tabletmanagerdata.SetReplicationSourceRequest
+ (*SetReplicationSourceResponse)(nil), // 91: tabletmanagerdata.SetReplicationSourceResponse
+ (*ReplicaWasRestartedRequest)(nil), // 92: tabletmanagerdata.ReplicaWasRestartedRequest
+ (*ReplicaWasRestartedResponse)(nil), // 93: tabletmanagerdata.ReplicaWasRestartedResponse
+ (*StopReplicationAndGetStatusRequest)(nil), // 94: tabletmanagerdata.StopReplicationAndGetStatusRequest
+ (*StopReplicationAndGetStatusResponse)(nil), // 95: tabletmanagerdata.StopReplicationAndGetStatusResponse
+ (*PromoteReplicaRequest)(nil), // 96: tabletmanagerdata.PromoteReplicaRequest
+ (*PromoteReplicaResponse)(nil), // 97: tabletmanagerdata.PromoteReplicaResponse
+ (*BackupRequest)(nil), // 98: tabletmanagerdata.BackupRequest
+ (*BackupResponse)(nil), // 99: tabletmanagerdata.BackupResponse
+ (*RestoreFromBackupRequest)(nil), // 100: tabletmanagerdata.RestoreFromBackupRequest
+ (*RestoreFromBackupResponse)(nil), // 101: tabletmanagerdata.RestoreFromBackupResponse
+ (*CreateVReplicationWorkflowRequest)(nil), // 102: tabletmanagerdata.CreateVReplicationWorkflowRequest
+ (*CreateVReplicationWorkflowResponse)(nil), // 103: tabletmanagerdata.CreateVReplicationWorkflowResponse
+ (*DeleteVReplicationWorkflowRequest)(nil), // 104: tabletmanagerdata.DeleteVReplicationWorkflowRequest
+ (*DeleteVReplicationWorkflowResponse)(nil), // 105: tabletmanagerdata.DeleteVReplicationWorkflowResponse
+ (*HasVReplicationWorkflowsRequest)(nil), // 106: tabletmanagerdata.HasVReplicationWorkflowsRequest
+ (*HasVReplicationWorkflowsResponse)(nil), // 107: tabletmanagerdata.HasVReplicationWorkflowsResponse
+ (*ReadVReplicationWorkflowsRequest)(nil), // 108: tabletmanagerdata.ReadVReplicationWorkflowsRequest
+ (*ReadVReplicationWorkflowsResponse)(nil), // 109: tabletmanagerdata.ReadVReplicationWorkflowsResponse
+ (*ReadVReplicationWorkflowRequest)(nil), // 110: tabletmanagerdata.ReadVReplicationWorkflowRequest
+ (*ReadVReplicationWorkflowResponse)(nil), // 111: tabletmanagerdata.ReadVReplicationWorkflowResponse
+ (*VDiffRequest)(nil), // 112: tabletmanagerdata.VDiffRequest
+ (*VDiffResponse)(nil), // 113: tabletmanagerdata.VDiffResponse
+ (*VDiffPickerOptions)(nil), // 114: tabletmanagerdata.VDiffPickerOptions
+ (*VDiffReportOptions)(nil), // 115: tabletmanagerdata.VDiffReportOptions
+ (*VDiffCoreOptions)(nil), // 116: tabletmanagerdata.VDiffCoreOptions
+ (*VDiffOptions)(nil), // 117: tabletmanagerdata.VDiffOptions
+ (*UpdateVReplicationWorkflowRequest)(nil), // 118: tabletmanagerdata.UpdateVReplicationWorkflowRequest
+ (*UpdateVReplicationWorkflowResponse)(nil), // 119: tabletmanagerdata.UpdateVReplicationWorkflowResponse
+ (*UpdateVReplicationWorkflowsRequest)(nil), // 120: tabletmanagerdata.UpdateVReplicationWorkflowsRequest
+ (*UpdateVReplicationWorkflowsResponse)(nil), // 121: tabletmanagerdata.UpdateVReplicationWorkflowsResponse
+ (*ResetSequencesRequest)(nil), // 122: tabletmanagerdata.ResetSequencesRequest
+ (*ResetSequencesResponse)(nil), // 123: tabletmanagerdata.ResetSequencesResponse
+ (*CheckThrottlerRequest)(nil), // 124: tabletmanagerdata.CheckThrottlerRequest
+ (*CheckThrottlerResponse)(nil), // 125: tabletmanagerdata.CheckThrottlerResponse
+ (*GetThrottlerStatusRequest)(nil), // 126: tabletmanagerdata.GetThrottlerStatusRequest
+ (*GetThrottlerStatusResponse)(nil), // 127: tabletmanagerdata.GetThrottlerStatusResponse
+ nil, // 128: tabletmanagerdata.UserPermission.PrivilegesEntry
+ nil, // 129: tabletmanagerdata.DbPermission.PrivilegesEntry
+ nil, // 130: tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry
+ nil, // 131: tabletmanagerdata.GetGlobalStatusVarsResponse.StatusValuesEntry
+ (*ReadVReplicationWorkflowResponse_Stream)(nil), // 132: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream
+ (*CheckThrottlerResponse_Metric)(nil), // 133: tabletmanagerdata.CheckThrottlerResponse.Metric
+ nil, // 134: tabletmanagerdata.CheckThrottlerResponse.MetricsEntry
+ (*GetThrottlerStatusResponse_MetricResult)(nil), // 135: tabletmanagerdata.GetThrottlerStatusResponse.MetricResult
+ nil, // 136: tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry
+ nil, // 137: tabletmanagerdata.GetThrottlerStatusResponse.MetricThresholdsEntry
+ (*GetThrottlerStatusResponse_MetricHealth)(nil), // 138: tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth
+ nil, // 139: tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry
+ nil, // 140: tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry
+ nil, // 141: tabletmanagerdata.GetThrottlerStatusResponse.AppCheckedMetricsEntry
+ (*GetThrottlerStatusResponse_RecentApp)(nil), // 142: tabletmanagerdata.GetThrottlerStatusResponse.RecentApp
+ nil, // 143: tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry
+ (*query.Field)(nil), // 144: query.Field
+ (topodata.TabletType)(0), // 145: topodata.TabletType
+ (*vtrpc.CallerID)(nil), // 146: vtrpc.CallerID
+ (*query.QueryResult)(nil), // 147: query.QueryResult
+ (*replicationdata.Status)(nil), // 148: replicationdata.Status
+ (*replicationdata.PrimaryStatus)(nil), // 149: replicationdata.PrimaryStatus
+ (*topodata.TabletAlias)(nil), // 150: topodata.TabletAlias
+ (*replicationdata.FullStatus)(nil), // 151: replicationdata.FullStatus
+ (replicationdata.StopReplicationMode)(0), // 152: replicationdata.StopReplicationMode
+ (*replicationdata.StopReplicationStatus)(nil), // 153: replicationdata.StopReplicationStatus
+ (*logutil.Event)(nil), // 154: logutil.Event
+ (*vttime.Time)(nil), // 155: vttime.Time
+ (*binlogdata.BinlogSource)(nil), // 156: binlogdata.BinlogSource
+ (binlogdata.VReplicationWorkflowType)(0), // 157: binlogdata.VReplicationWorkflowType
+ (binlogdata.VReplicationWorkflowSubType)(0), // 158: binlogdata.VReplicationWorkflowSubType
+ (binlogdata.VReplicationWorkflowState)(0), // 159: binlogdata.VReplicationWorkflowState
+ (binlogdata.OnDDLAction)(0), // 160: binlogdata.OnDDLAction
+ (*topodata.ThrottledAppRule)(nil), // 161: topodata.ThrottledAppRule
}
var file_tabletmanagerdata_proto_depIdxs = []int32{
- 143, // 0: tabletmanagerdata.TableDefinition.fields:type_name -> query.Field
- 1, // 1: tabletmanagerdata.SchemaDefinition.table_definitions:type_name -> tabletmanagerdata.TableDefinition
- 2, // 2: tabletmanagerdata.SchemaChangeResult.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 2, // 3: tabletmanagerdata.SchemaChangeResult.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 127, // 4: tabletmanagerdata.UserPermission.privileges:type_name -> tabletmanagerdata.UserPermission.PrivilegesEntry
- 128, // 5: tabletmanagerdata.DbPermission.privileges:type_name -> tabletmanagerdata.DbPermission.PrivilegesEntry
- 4, // 6: tabletmanagerdata.Permissions.user_permissions:type_name -> tabletmanagerdata.UserPermission
- 5, // 7: tabletmanagerdata.Permissions.db_permissions:type_name -> tabletmanagerdata.DbPermission
- 129, // 8: tabletmanagerdata.ExecuteHookRequest.extra_env:type_name -> tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry
- 2, // 9: tabletmanagerdata.GetSchemaResponse.schema_definition:type_name -> tabletmanagerdata.SchemaDefinition
- 6, // 10: tabletmanagerdata.GetPermissionsResponse.permissions:type_name -> tabletmanagerdata.Permissions
- 130, // 11: tabletmanagerdata.GetGlobalStatusVarsResponse.status_values:type_name -> tabletmanagerdata.GetGlobalStatusVarsResponse.StatusValuesEntry
- 144, // 12: tabletmanagerdata.ChangeTypeRequest.tablet_type:type_name -> topodata.TabletType
- 3, // 13: tabletmanagerdata.PreflightSchemaResponse.change_results:type_name -> tabletmanagerdata.SchemaChangeResult
- 2, // 14: tabletmanagerdata.ApplySchemaRequest.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 2, // 15: tabletmanagerdata.ApplySchemaRequest.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 2, // 16: tabletmanagerdata.ApplySchemaResponse.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 2, // 17: tabletmanagerdata.ApplySchemaResponse.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
- 145, // 18: tabletmanagerdata.ExecuteQueryRequest.caller_id:type_name -> vtrpc.CallerID
- 146, // 19: tabletmanagerdata.ExecuteQueryResponse.result:type_name -> query.QueryResult
- 146, // 20: tabletmanagerdata.ExecuteFetchAsDbaResponse.result:type_name -> query.QueryResult
- 146, // 21: tabletmanagerdata.ExecuteMultiFetchAsDbaResponse.results:type_name -> query.QueryResult
- 146, // 22: tabletmanagerdata.ExecuteFetchAsAllPrivsResponse.result:type_name -> query.QueryResult
- 146, // 23: tabletmanagerdata.ExecuteFetchAsAppResponse.result:type_name -> query.QueryResult
- 147, // 24: tabletmanagerdata.ReplicationStatusResponse.status:type_name -> replicationdata.Status
- 148, // 25: tabletmanagerdata.PrimaryStatusResponse.status:type_name -> replicationdata.PrimaryStatus
- 146, // 26: tabletmanagerdata.VReplicationExecResponse.result:type_name -> query.QueryResult
- 149, // 27: tabletmanagerdata.PopulateReparentJournalRequest.primary_alias:type_name -> topodata.TabletAlias
- 149, // 28: tabletmanagerdata.InitReplicaRequest.parent:type_name -> topodata.TabletAlias
- 148, // 29: tabletmanagerdata.DemotePrimaryResponse.primary_status:type_name -> replicationdata.PrimaryStatus
- 150, // 30: tabletmanagerdata.FullStatusResponse.status:type_name -> replicationdata.FullStatus
- 149, // 31: tabletmanagerdata.SetReplicationSourceRequest.parent:type_name -> topodata.TabletAlias
- 149, // 32: tabletmanagerdata.ReplicaWasRestartedRequest.parent:type_name -> topodata.TabletAlias
- 151, // 33: tabletmanagerdata.StopReplicationAndGetStatusRequest.stop_replication_mode:type_name -> replicationdata.StopReplicationMode
- 152, // 34: tabletmanagerdata.StopReplicationAndGetStatusResponse.status:type_name -> replicationdata.StopReplicationStatus
- 153, // 35: tabletmanagerdata.BackupResponse.event:type_name -> logutil.Event
- 154, // 36: tabletmanagerdata.RestoreFromBackupRequest.backup_time:type_name -> vttime.Time
- 154, // 37: tabletmanagerdata.RestoreFromBackupRequest.restore_to_timestamp:type_name -> vttime.Time
- 153, // 38: tabletmanagerdata.RestoreFromBackupResponse.event:type_name -> logutil.Event
- 155, // 39: tabletmanagerdata.CreateVReplicationWorkflowRequest.binlog_source:type_name -> binlogdata.BinlogSource
- 144, // 40: tabletmanagerdata.CreateVReplicationWorkflowRequest.tablet_types:type_name -> topodata.TabletType
+ 144, // 0: tabletmanagerdata.TableDefinition.fields:type_name -> query.Field
+ 2, // 1: tabletmanagerdata.SchemaDefinition.table_definitions:type_name -> tabletmanagerdata.TableDefinition
+ 3, // 2: tabletmanagerdata.SchemaChangeResult.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 3, // 3: tabletmanagerdata.SchemaChangeResult.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 128, // 4: tabletmanagerdata.UserPermission.privileges:type_name -> tabletmanagerdata.UserPermission.PrivilegesEntry
+ 129, // 5: tabletmanagerdata.DbPermission.privileges:type_name -> tabletmanagerdata.DbPermission.PrivilegesEntry
+ 5, // 6: tabletmanagerdata.Permissions.user_permissions:type_name -> tabletmanagerdata.UserPermission
+ 6, // 7: tabletmanagerdata.Permissions.db_permissions:type_name -> tabletmanagerdata.DbPermission
+ 130, // 8: tabletmanagerdata.ExecuteHookRequest.extra_env:type_name -> tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry
+ 3, // 9: tabletmanagerdata.GetSchemaResponse.schema_definition:type_name -> tabletmanagerdata.SchemaDefinition
+ 7, // 10: tabletmanagerdata.GetPermissionsResponse.permissions:type_name -> tabletmanagerdata.Permissions
+ 131, // 11: tabletmanagerdata.GetGlobalStatusVarsResponse.status_values:type_name -> tabletmanagerdata.GetGlobalStatusVarsResponse.StatusValuesEntry
+ 145, // 12: tabletmanagerdata.ChangeTypeRequest.tablet_type:type_name -> topodata.TabletType
+ 4, // 13: tabletmanagerdata.PreflightSchemaResponse.change_results:type_name -> tabletmanagerdata.SchemaChangeResult
+ 3, // 14: tabletmanagerdata.ApplySchemaRequest.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 3, // 15: tabletmanagerdata.ApplySchemaRequest.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 3, // 16: tabletmanagerdata.ApplySchemaResponse.before_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 3, // 17: tabletmanagerdata.ApplySchemaResponse.after_schema:type_name -> tabletmanagerdata.SchemaDefinition
+ 146, // 18: tabletmanagerdata.ExecuteQueryRequest.caller_id:type_name -> vtrpc.CallerID
+ 147, // 19: tabletmanagerdata.ExecuteQueryResponse.result:type_name -> query.QueryResult
+ 147, // 20: tabletmanagerdata.ExecuteFetchAsDbaResponse.result:type_name -> query.QueryResult
+ 147, // 21: tabletmanagerdata.ExecuteMultiFetchAsDbaResponse.results:type_name -> query.QueryResult
+ 147, // 22: tabletmanagerdata.ExecuteFetchAsAllPrivsResponse.result:type_name -> query.QueryResult
+ 147, // 23: tabletmanagerdata.ExecuteFetchAsAppResponse.result:type_name -> query.QueryResult
+ 148, // 24: tabletmanagerdata.ReplicationStatusResponse.status:type_name -> replicationdata.Status
+ 149, // 25: tabletmanagerdata.PrimaryStatusResponse.status:type_name -> replicationdata.PrimaryStatus
+ 147, // 26: tabletmanagerdata.VReplicationExecResponse.result:type_name -> query.QueryResult
+ 150, // 27: tabletmanagerdata.PopulateReparentJournalRequest.primary_alias:type_name -> topodata.TabletAlias
+ 150, // 28: tabletmanagerdata.InitReplicaRequest.parent:type_name -> topodata.TabletAlias
+ 149, // 29: tabletmanagerdata.DemotePrimaryResponse.primary_status:type_name -> replicationdata.PrimaryStatus
+ 151, // 30: tabletmanagerdata.FullStatusResponse.status:type_name -> replicationdata.FullStatus
+ 150, // 31: tabletmanagerdata.SetReplicationSourceRequest.parent:type_name -> topodata.TabletAlias
+ 150, // 32: tabletmanagerdata.ReplicaWasRestartedRequest.parent:type_name -> topodata.TabletAlias
+ 152, // 33: tabletmanagerdata.StopReplicationAndGetStatusRequest.stop_replication_mode:type_name -> replicationdata.StopReplicationMode
+ 153, // 34: tabletmanagerdata.StopReplicationAndGetStatusResponse.status:type_name -> replicationdata.StopReplicationStatus
+ 154, // 35: tabletmanagerdata.BackupResponse.event:type_name -> logutil.Event
+ 155, // 36: tabletmanagerdata.RestoreFromBackupRequest.backup_time:type_name -> vttime.Time
+ 155, // 37: tabletmanagerdata.RestoreFromBackupRequest.restore_to_timestamp:type_name -> vttime.Time
+ 154, // 38: tabletmanagerdata.RestoreFromBackupResponse.event:type_name -> logutil.Event
+ 156, // 39: tabletmanagerdata.CreateVReplicationWorkflowRequest.binlog_source:type_name -> binlogdata.BinlogSource
+ 145, // 40: tabletmanagerdata.CreateVReplicationWorkflowRequest.tablet_types:type_name -> topodata.TabletType
0, // 41: tabletmanagerdata.CreateVReplicationWorkflowRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference
- 156, // 42: tabletmanagerdata.CreateVReplicationWorkflowRequest.workflow_type:type_name -> binlogdata.VReplicationWorkflowType
- 157, // 43: tabletmanagerdata.CreateVReplicationWorkflowRequest.workflow_sub_type:type_name -> binlogdata.VReplicationWorkflowSubType
- 146, // 44: tabletmanagerdata.CreateVReplicationWorkflowResponse.result:type_name -> query.QueryResult
- 146, // 45: tabletmanagerdata.DeleteVReplicationWorkflowResponse.result:type_name -> query.QueryResult
- 158, // 46: tabletmanagerdata.ReadVReplicationWorkflowsRequest.include_states:type_name -> binlogdata.VReplicationWorkflowState
- 158, // 47: tabletmanagerdata.ReadVReplicationWorkflowsRequest.exclude_states:type_name -> binlogdata.VReplicationWorkflowState
- 110, // 48: tabletmanagerdata.ReadVReplicationWorkflowsResponse.workflows:type_name -> tabletmanagerdata.ReadVReplicationWorkflowResponse
- 144, // 49: tabletmanagerdata.ReadVReplicationWorkflowResponse.tablet_types:type_name -> topodata.TabletType
+ 157, // 42: tabletmanagerdata.CreateVReplicationWorkflowRequest.workflow_type:type_name -> binlogdata.VReplicationWorkflowType
+ 158, // 43: tabletmanagerdata.CreateVReplicationWorkflowRequest.workflow_sub_type:type_name -> binlogdata.VReplicationWorkflowSubType
+ 147, // 44: tabletmanagerdata.CreateVReplicationWorkflowResponse.result:type_name -> query.QueryResult
+ 147, // 45: tabletmanagerdata.DeleteVReplicationWorkflowResponse.result:type_name -> query.QueryResult
+ 159, // 46: tabletmanagerdata.ReadVReplicationWorkflowsRequest.include_states:type_name -> binlogdata.VReplicationWorkflowState
+ 159, // 47: tabletmanagerdata.ReadVReplicationWorkflowsRequest.exclude_states:type_name -> binlogdata.VReplicationWorkflowState
+ 111, // 48: tabletmanagerdata.ReadVReplicationWorkflowsResponse.workflows:type_name -> tabletmanagerdata.ReadVReplicationWorkflowResponse
+ 145, // 49: tabletmanagerdata.ReadVReplicationWorkflowResponse.tablet_types:type_name -> topodata.TabletType
0, // 50: tabletmanagerdata.ReadVReplicationWorkflowResponse.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference
- 156, // 51: tabletmanagerdata.ReadVReplicationWorkflowResponse.workflow_type:type_name -> binlogdata.VReplicationWorkflowType
- 157, // 52: tabletmanagerdata.ReadVReplicationWorkflowResponse.workflow_sub_type:type_name -> binlogdata.VReplicationWorkflowSubType
- 131, // 53: tabletmanagerdata.ReadVReplicationWorkflowResponse.streams:type_name -> tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream
- 116, // 54: tabletmanagerdata.VDiffRequest.options:type_name -> tabletmanagerdata.VDiffOptions
- 146, // 55: tabletmanagerdata.VDiffResponse.output:type_name -> query.QueryResult
- 113, // 56: tabletmanagerdata.VDiffOptions.picker_options:type_name -> tabletmanagerdata.VDiffPickerOptions
- 115, // 57: tabletmanagerdata.VDiffOptions.core_options:type_name -> tabletmanagerdata.VDiffCoreOptions
- 114, // 58: tabletmanagerdata.VDiffOptions.report_options:type_name -> tabletmanagerdata.VDiffReportOptions
- 144, // 59: tabletmanagerdata.UpdateVReplicationWorkflowRequest.tablet_types:type_name -> topodata.TabletType
+ 157, // 51: tabletmanagerdata.ReadVReplicationWorkflowResponse.workflow_type:type_name -> binlogdata.VReplicationWorkflowType
+ 158, // 52: tabletmanagerdata.ReadVReplicationWorkflowResponse.workflow_sub_type:type_name -> binlogdata.VReplicationWorkflowSubType
+ 132, // 53: tabletmanagerdata.ReadVReplicationWorkflowResponse.streams:type_name -> tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream
+ 117, // 54: tabletmanagerdata.VDiffRequest.options:type_name -> tabletmanagerdata.VDiffOptions
+ 147, // 55: tabletmanagerdata.VDiffResponse.output:type_name -> query.QueryResult
+ 114, // 56: tabletmanagerdata.VDiffOptions.picker_options:type_name -> tabletmanagerdata.VDiffPickerOptions
+ 116, // 57: tabletmanagerdata.VDiffOptions.core_options:type_name -> tabletmanagerdata.VDiffCoreOptions
+ 115, // 58: tabletmanagerdata.VDiffOptions.report_options:type_name -> tabletmanagerdata.VDiffReportOptions
+ 145, // 59: tabletmanagerdata.UpdateVReplicationWorkflowRequest.tablet_types:type_name -> topodata.TabletType
0, // 60: tabletmanagerdata.UpdateVReplicationWorkflowRequest.tablet_selection_preference:type_name -> tabletmanagerdata.TabletSelectionPreference
- 159, // 61: tabletmanagerdata.UpdateVReplicationWorkflowRequest.on_ddl:type_name -> binlogdata.OnDDLAction
- 158, // 62: tabletmanagerdata.UpdateVReplicationWorkflowRequest.state:type_name -> binlogdata.VReplicationWorkflowState
- 146, // 63: tabletmanagerdata.UpdateVReplicationWorkflowResponse.result:type_name -> query.QueryResult
- 158, // 64: tabletmanagerdata.UpdateVReplicationWorkflowsRequest.state:type_name -> binlogdata.VReplicationWorkflowState
- 146, // 65: tabletmanagerdata.UpdateVReplicationWorkflowsResponse.result:type_name -> query.QueryResult
- 133, // 66: tabletmanagerdata.CheckThrottlerResponse.metrics:type_name -> tabletmanagerdata.CheckThrottlerResponse.MetricsEntry
- 135, // 67: tabletmanagerdata.GetThrottlerStatusResponse.aggregated_metrics:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry
- 136, // 68: tabletmanagerdata.GetThrottlerStatusResponse.metric_thresholds:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricThresholdsEntry
- 138, // 69: tabletmanagerdata.GetThrottlerStatusResponse.metrics_health:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry
- 139, // 70: tabletmanagerdata.GetThrottlerStatusResponse.throttled_apps:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry
- 140, // 71: tabletmanagerdata.GetThrottlerStatusResponse.app_checked_metrics:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.AppCheckedMetricsEntry
- 142, // 72: tabletmanagerdata.GetThrottlerStatusResponse.recent_apps:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry
- 155, // 73: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.bls:type_name -> binlogdata.BinlogSource
- 154, // 74: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_updated:type_name -> vttime.Time
- 154, // 75: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.transaction_timestamp:type_name -> vttime.Time
- 158, // 76: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.state:type_name -> binlogdata.VReplicationWorkflowState
- 154, // 77: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_heartbeat:type_name -> vttime.Time
- 154, // 78: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_throttled:type_name -> vttime.Time
- 132, // 79: tabletmanagerdata.CheckThrottlerResponse.MetricsEntry.value:type_name -> tabletmanagerdata.CheckThrottlerResponse.Metric
- 134, // 80: tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricResult
- 154, // 81: tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth.last_healthy_at:type_name -> vttime.Time
- 137, // 82: tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth
- 160, // 83: tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry.value:type_name -> topodata.ThrottledAppRule
- 154, // 84: tabletmanagerdata.GetThrottlerStatusResponse.RecentApp.checked_at:type_name -> vttime.Time
- 141, // 85: tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.RecentApp
- 86, // [86:86] is the sub-list for method output_type
- 86, // [86:86] is the sub-list for method input_type
- 86, // [86:86] is the sub-list for extension type_name
- 86, // [86:86] is the sub-list for extension extendee
- 0, // [0:86] is the sub-list for field type_name
+ 160, // 61: tabletmanagerdata.UpdateVReplicationWorkflowRequest.on_ddl:type_name -> binlogdata.OnDDLAction
+ 159, // 62: tabletmanagerdata.UpdateVReplicationWorkflowRequest.state:type_name -> binlogdata.VReplicationWorkflowState
+ 147, // 63: tabletmanagerdata.UpdateVReplicationWorkflowResponse.result:type_name -> query.QueryResult
+ 159, // 64: tabletmanagerdata.UpdateVReplicationWorkflowsRequest.state:type_name -> binlogdata.VReplicationWorkflowState
+ 147, // 65: tabletmanagerdata.UpdateVReplicationWorkflowsResponse.result:type_name -> query.QueryResult
+ 134, // 66: tabletmanagerdata.CheckThrottlerResponse.metrics:type_name -> tabletmanagerdata.CheckThrottlerResponse.MetricsEntry
+ 1, // 67: tabletmanagerdata.CheckThrottlerResponse.response_code:type_name -> tabletmanagerdata.CheckThrottlerResponseCode
+ 136, // 68: tabletmanagerdata.GetThrottlerStatusResponse.aggregated_metrics:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry
+ 137, // 69: tabletmanagerdata.GetThrottlerStatusResponse.metric_thresholds:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricThresholdsEntry
+ 139, // 70: tabletmanagerdata.GetThrottlerStatusResponse.metrics_health:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry
+ 140, // 71: tabletmanagerdata.GetThrottlerStatusResponse.throttled_apps:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry
+ 141, // 72: tabletmanagerdata.GetThrottlerStatusResponse.app_checked_metrics:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.AppCheckedMetricsEntry
+ 143, // 73: tabletmanagerdata.GetThrottlerStatusResponse.recent_apps:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry
+ 156, // 74: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.bls:type_name -> binlogdata.BinlogSource
+ 155, // 75: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_updated:type_name -> vttime.Time
+ 155, // 76: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.transaction_timestamp:type_name -> vttime.Time
+ 159, // 77: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.state:type_name -> binlogdata.VReplicationWorkflowState
+ 155, // 78: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_heartbeat:type_name -> vttime.Time
+ 155, // 79: tabletmanagerdata.ReadVReplicationWorkflowResponse.Stream.time_throttled:type_name -> vttime.Time
+ 1, // 80: tabletmanagerdata.CheckThrottlerResponse.Metric.response_code:type_name -> tabletmanagerdata.CheckThrottlerResponseCode
+ 133, // 81: tabletmanagerdata.CheckThrottlerResponse.MetricsEntry.value:type_name -> tabletmanagerdata.CheckThrottlerResponse.Metric
+ 135, // 82: tabletmanagerdata.GetThrottlerStatusResponse.AggregatedMetricsEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricResult
+ 155, // 83: tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth.last_healthy_at:type_name -> vttime.Time
+ 138, // 84: tabletmanagerdata.GetThrottlerStatusResponse.MetricsHealthEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.MetricHealth
+ 161, // 85: tabletmanagerdata.GetThrottlerStatusResponse.ThrottledAppsEntry.value:type_name -> topodata.ThrottledAppRule
+ 155, // 86: tabletmanagerdata.GetThrottlerStatusResponse.RecentApp.checked_at:type_name -> vttime.Time
+ 1, // 87: tabletmanagerdata.GetThrottlerStatusResponse.RecentApp.response_code:type_name -> tabletmanagerdata.CheckThrottlerResponseCode
+ 142, // 88: tabletmanagerdata.GetThrottlerStatusResponse.RecentAppsEntry.value:type_name -> tabletmanagerdata.GetThrottlerStatusResponse.RecentApp
+ 89, // [89:89] is the sub-list for method output_type
+ 89, // [89:89] is the sub-list for method input_type
+ 89, // [89:89] is the sub-list for extension type_name
+ 89, // [89:89] is the sub-list for extension extendee
+ 0, // [0:89] is the sub-list for field type_name
}
func init() { file_tabletmanagerdata_proto_init() }
@@ -10241,7 +10376,7 @@ func file_tabletmanagerdata_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_tabletmanagerdata_proto_rawDesc,
- NumEnums: 1,
+ NumEnums: 2,
NumMessages: 142,
NumExtensions: 0,
NumServices: 0,
diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata_vtproto.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata_vtproto.pb.go
index d48882613d1..343e96b59b5 100644
--- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata_vtproto.pb.go
+++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata_vtproto.pb.go
@@ -2499,13 +2499,14 @@ func (m *CheckThrottlerResponse_Metric) CloneVT() *CheckThrottlerResponse_Metric
return (*CheckThrottlerResponse_Metric)(nil)
}
r := &CheckThrottlerResponse_Metric{
- Name: m.Name,
- StatusCode: m.StatusCode,
- Value: m.Value,
- Threshold: m.Threshold,
- Error: m.Error,
- Message: m.Message,
- Scope: m.Scope,
+ Name: m.Name,
+ StatusCode: m.StatusCode,
+ Value: m.Value,
+ Threshold: m.Threshold,
+ Error: m.Error,
+ Message: m.Message,
+ Scope: m.Scope,
+ ResponseCode: m.ResponseCode,
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
@@ -2529,6 +2530,9 @@ func (m *CheckThrottlerResponse) CloneVT() *CheckThrottlerResponse {
Error: m.Error,
Message: m.Message,
RecentlyChecked: m.RecentlyChecked,
+ AppName: m.AppName,
+ Summary: m.Summary,
+ ResponseCode: m.ResponseCode,
}
if rhs := m.Metrics; rhs != nil {
tmpContainer := make(map[string]*CheckThrottlerResponse_Metric, len(rhs))
@@ -2607,8 +2611,9 @@ func (m *GetThrottlerStatusResponse_RecentApp) CloneVT() *GetThrottlerStatusResp
return (*GetThrottlerStatusResponse_RecentApp)(nil)
}
r := &GetThrottlerStatusResponse_RecentApp{
- CheckedAt: m.CheckedAt.CloneVT(),
- StatusCode: m.StatusCode,
+ CheckedAt: m.CheckedAt.CloneVT(),
+ StatusCode: m.StatusCode,
+ ResponseCode: m.ResponseCode,
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
@@ -8755,6 +8760,11 @@ func (m *CheckThrottlerResponse_Metric) MarshalToSizedBufferVT(dAtA []byte) (int
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if m.ResponseCode != 0 {
+ i = encodeVarint(dAtA, i, uint64(m.ResponseCode))
+ i--
+ dAtA[i] = 0x40
+ }
if len(m.Scope) > 0 {
i -= len(m.Scope)
copy(dAtA[i:], m.Scope)
@@ -8833,6 +8843,25 @@ func (m *CheckThrottlerResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if m.ResponseCode != 0 {
+ i = encodeVarint(dAtA, i, uint64(m.ResponseCode))
+ i--
+ dAtA[i] = 0x50
+ }
+ if len(m.Summary) > 0 {
+ i -= len(m.Summary)
+ copy(dAtA[i:], m.Summary)
+ i = encodeVarint(dAtA, i, uint64(len(m.Summary)))
+ i--
+ dAtA[i] = 0x4a
+ }
+ if len(m.AppName) > 0 {
+ i -= len(m.AppName)
+ copy(dAtA[i:], m.AppName)
+ i = encodeVarint(dAtA, i, uint64(len(m.AppName)))
+ i--
+ dAtA[i] = 0x42
+ }
if len(m.Metrics) > 0 {
for k := range m.Metrics {
v := m.Metrics[k]
@@ -9056,6 +9085,11 @@ func (m *GetThrottlerStatusResponse_RecentApp) MarshalToSizedBufferVT(dAtA []byt
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if m.ResponseCode != 0 {
+ i = encodeVarint(dAtA, i, uint64(m.ResponseCode))
+ i--
+ dAtA[i] = 0x18
+ }
if m.StatusCode != 0 {
i = encodeVarint(dAtA, i, uint64(m.StatusCode))
i--
@@ -11523,6 +11557,9 @@ func (m *CheckThrottlerResponse_Metric) SizeVT() (n int) {
if l > 0 {
n += 1 + l + sov(uint64(l))
}
+ if m.ResponseCode != 0 {
+ n += 1 + sov(uint64(m.ResponseCode))
+ }
n += len(m.unknownFields)
return n
}
@@ -11566,6 +11603,17 @@ func (m *CheckThrottlerResponse) SizeVT() (n int) {
n += mapEntrySize + 1 + sov(uint64(mapEntrySize))
}
}
+ l = len(m.AppName)
+ if l > 0 {
+ n += 1 + l + sov(uint64(l))
+ }
+ l = len(m.Summary)
+ if l > 0 {
+ n += 1 + l + sov(uint64(l))
+ }
+ if m.ResponseCode != 0 {
+ n += 1 + sov(uint64(m.ResponseCode))
+ }
n += len(m.unknownFields)
return n
}
@@ -11627,6 +11675,9 @@ func (m *GetThrottlerStatusResponse_RecentApp) SizeVT() (n int) {
if m.StatusCode != 0 {
n += 1 + sov(uint64(m.StatusCode))
}
+ if m.ResponseCode != 0 {
+ n += 1 + sov(uint64(m.ResponseCode))
+ }
n += len(m.unknownFields)
return n
}
@@ -25289,6 +25340,25 @@ func (m *CheckThrottlerResponse_Metric) UnmarshalVT(dAtA []byte) error {
}
m.Scope = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
+ case 8:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ResponseCode", wireType)
+ }
+ m.ResponseCode = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.ResponseCode |= CheckThrottlerResponseCode(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
@@ -25594,6 +25664,89 @@ func (m *CheckThrottlerResponse) UnmarshalVT(dAtA []byte) error {
}
m.Metrics[mapkey] = mapvalue
iNdEx = postIndex
+ case 8:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLength
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLength
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.AppName = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 9:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Summary", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLength
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLength
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Summary = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 10:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ResponseCode", wireType)
+ }
+ m.ResponseCode = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.ResponseCode |= CheckThrottlerResponseCode(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
@@ -25951,6 +26104,25 @@ func (m *GetThrottlerStatusResponse_RecentApp) UnmarshalVT(dAtA []byte) error {
break
}
}
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ResponseCode", wireType)
+ }
+ m.ResponseCode = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.ResponseCode |= CheckThrottlerResponseCode(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
diff --git a/go/vt/proto/vtctldata/vtctldata.pb.go b/go/vt/proto/vtctldata/vtctldata.pb.go
index a79acd29dab..51a94298a40 100644
--- a/go/vt/proto/vtctldata/vtctldata.pb.go
+++ b/go/vt/proto/vtctldata/vtctldata.pb.go
@@ -9668,6 +9668,8 @@ type PlannedReparentShardRequest struct {
// acceptable for a tablet to be eligible for promotion when Vitess makes the choice of a new primary.
// A value of 0 indicates that Vitess shouldn't consider the replication lag at all.
TolerableReplicationLag *vttime.Duration `protobuf:"bytes,6,opt,name=tolerable_replication_lag,json=tolerableReplicationLag,proto3" json:"tolerable_replication_lag,omitempty"`
+ // AllowCrossCellPromotion allows cross cell promotion,
+ AllowCrossCellPromotion bool `protobuf:"varint,7,opt,name=allow_cross_cell_promotion,json=allowCrossCellPromotion,proto3" json:"allow_cross_cell_promotion,omitempty"`
}
func (x *PlannedReparentShardRequest) Reset() {
@@ -9744,6 +9746,13 @@ func (x *PlannedReparentShardRequest) GetTolerableReplicationLag() *vttime.Durat
return nil
}
+func (x *PlannedReparentShardRequest) GetAllowCrossCellPromotion() bool {
+ if x != nil {
+ return x.AllowCrossCellPromotion
+ }
+ return false
+}
+
type PlannedReparentShardResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -18159,7 +18168,7 @@ var file_vtctldata_proto_rawDesc = []byte{
0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74,
0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69,
0x61, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd7, 0x02, 0x0a, 0x1b, 0x50, 0x6c, 0x61,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x94, 0x03, 0x0a, 0x1b, 0x50, 0x6c, 0x61,
0x6e, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x72,
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73,
0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73,
@@ -18181,538 +18190,576 @@ var file_vtctldata_proto_rawDesc = []byte{
0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65,
0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x17, 0x74, 0x6f, 0x6c, 0x65, 0x72,
0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c,
- 0x61, 0x67, 0x22, 0xba, 0x01, 0x0a, 0x1c, 0x50, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x65,
- 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
- 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
- 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x40, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65,
- 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x64,
- 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
- 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69,
- 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22,
- 0x74, 0x0a, 0x1b, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
- 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65,
- 0x6c, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73,
- 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61,
- 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x50, 0x61,
- 0x72, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x1e, 0x0a, 0x1c, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, 0x62,
- 0x75, 0x69, 0x6c, 0x64, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x47, 0x72, 0x61, 0x70, 0x68,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x13, 0x52, 0x65, 0x66, 0x72,
- 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x66,
- 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x22, 0x64, 0x0a, 0x1a, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x66, 0x72,
- 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x5f, 0x70, 0x61,
- 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65,
- 0x66, 0x72, 0x65, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c,
- 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x52,
- 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x4f, 0x0a,
- 0x13, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61,
- 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70,
- 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61,
- 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x16,
- 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x6c, 0x6f, 0x61,
- 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74,
- 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x61, 0x69, 0x74, 0x50,
- 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75,
- 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
- 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
- 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
- 0x63, 0x79, 0x22, 0x46, 0x0a, 0x1c, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65,
- 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x76, 0x65,
- 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x18, 0x52,
- 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x61, 0x69,
- 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0c, 0x77, 0x61, 0x69, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27,
- 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72,
- 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
- 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75,
- 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f,
- 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x43, 0x0a, 0x19, 0x52, 0x65, 0x6c,
- 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c,
- 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5b,
- 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x52,
- 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x7f, 0x0a, 0x19, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4b, 0x65, 0x79,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x61, 0x67, 0x12, 0x3b, 0x0a, 0x1a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x63, 0x72, 0x6f, 0x73,
+ 0x73, 0x5f, 0x63, 0x65, 0x6c, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e,
+ 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x43, 0x72, 0x6f,
+ 0x73, 0x73, 0x43, 0x65, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x22,
+ 0xba, 0x01, 0x0a, 0x1c, 0x50, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x65, 0x70, 0x61, 0x72,
+ 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04,
- 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c,
- 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73,
- 0x69, 0x76, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72,
- 0x73, 0x69, 0x76, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4b, 0x65,
- 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x22, 0x9b, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x68, 0x61,
- 0x72, 0x64, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61,
- 0x72, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x12, 0x14, 0x0a, 0x05,
- 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72,
- 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18,
- 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65,
- 0x22, 0x19, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43,
- 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x15, 0x52,
- 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e,
- 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x74, 0x22, 0x7b, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a,
+ 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05,
+ 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61,
+ 0x72, 0x64, 0x12, 0x40, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x64, 0x5f, 0x70,
+ 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
+ 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c,
+ 0x69, 0x61, 0x73, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x64, 0x50, 0x72, 0x69,
+ 0x6d, 0x61, 0x72, 0x79, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x74, 0x0a, 0x1b,
+ 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x47,
+ 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73,
+ 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x23, 0x0a,
+ 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x50, 0x61, 0x72, 0x74, 0x69,
+ 0x61, 0x6c, 0x22, 0x1e, 0x0a, 0x1c, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x4b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x53, 0x63,
+ 0x68, 0x65, 0x6d, 0x61, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x22, 0x1d, 0x0a, 0x1b, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c,
+ 0x64, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4f, 0x0a, 0x13, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
+ 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x64,
+ 0x0a, 0x1a, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x79,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x14,
+ 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63,
+ 0x65, 0x6c, 0x6c, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69,
+ 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x10, 0x69, 0x73, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x66, 0x72, 0x65,
+ 0x73, 0x68, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x72, 0x65,
+ 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x15, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x65, 0x66, 0x72,
+ 0x65, 0x73, 0x68, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x4f, 0x0a, 0x13, 0x52, 0x65,
+ 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
+ 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x52,
+ 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x22, 0xa9, 0x01, 0x0a, 0x1b, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63,
+ 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
+ 0x23, 0x0a, 0x0d, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x61, 0x69, 0x74, 0x50, 0x6f, 0x73, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f,
+ 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69,
+ 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a,
+ 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22,
+ 0x46, 0x0a, 0x1c, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
+ 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xbc, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x6c, 0x6f,
+ 0x61, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x70,
+ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77,
+ 0x61, 0x69, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x69,
+ 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x69,
+ 0x6d, 0x61, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65,
+ 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75,
+ 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x43, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x6f, 0x61, 0x64,
+ 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x76,
+ 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5b, 0x0a, 0x13, 0x52,
+ 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14,
+ 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73,
+ 0x68, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x6d, 0x6f,
+ 0x76, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x7f, 0x0a, 0x19, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61,
- 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12,
- 0x2f, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
- 0x22, 0x8f, 0x04, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72,
- 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72,
- 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63,
- 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c,
- 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
- 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x6c, 0x0a, 0x1b, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70,
- 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32,
- 0x2c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x19, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72,
- 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x6b, 0x69, 0x70,
- 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x18, 0x08, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x43, 0x6f,
- 0x70, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x6e, 0x5f, 0x64, 0x64, 0x6c, 0x18, 0x09, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x05, 0x6f, 0x6e, 0x44, 0x64, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x6f,
- 0x70, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x18, 0x0a, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x41, 0x66, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x70,
- 0x79, 0x12, 0x30, 0x0a, 0x14, 0x64, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e,
- 0x64, 0x61, 0x72, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x12, 0x64, 0x65, 0x66, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x4b,
- 0x65, 0x79, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x72,
- 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x53, 0x74, 0x61,
- 0x72, 0x74, 0x22, 0x82, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72,
- 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x62, 0x61, 0x63,
- 0x6b, 0x75, 0x70, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
- 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x62, 0x61,
- 0x63, 0x6b, 0x75, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x74,
- 0x6f, 0x72, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0c, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x50, 0x6f, 0x73, 0x12, 0x17,
- 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x3e, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x74, 0x6f,
- 0x72, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18,
- 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54,
- 0x69, 0x6d, 0x65, 0x52, 0x12, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x54, 0x69,
- 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xad, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x73, 0x74,
- 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f,
- 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f,
- 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69,
- 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x12, 0x24, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x0e, 0x2e, 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
- 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x4d, 0x0a, 0x1b, 0x52, 0x65, 0x74, 0x72, 0x79,
- 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c,
+ 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x12, 0x14, 0x0a,
+ 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f,
+ 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76,
+ 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
+ 0x9b, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43,
+ 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f,
+ 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72,
+ 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12,
+ 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x22, 0x19, 0x0a,
+ 0x17, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x43, 0x65, 0x6c, 0x6c,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x0a, 0x15, 0x52, 0x65, 0x70, 0x61,
+ 0x72, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62,
+ 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x22, 0x7b, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x2f, 0x0a, 0x07,
+ 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+ 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41,
+ 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x8f, 0x04,
+ 0x0a, 0x14, 0x52, 0x65, 0x73, 0x68, 0x61, 0x72, 0x64, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
+ 0x6f, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x23,
+ 0x0a, 0x0d, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18,
+ 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61,
+ 0x72, 0x64, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x68,
+ 0x61, 0x72, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67,
+ 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c,
+ 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x37,
+ 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06,
+ 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x6c, 0x0a, 0x1b, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x66,
+ 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+ 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x19, 0x74, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65,
+ 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x73, 0x63,
+ 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x0e, 0x73, 0x6b, 0x69, 0x70, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x43, 0x6f, 0x70, 0x79, 0x12,
+ 0x15, 0x0a, 0x06, 0x6f, 0x6e, 0x5f, 0x64, 0x64, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x05, 0x6f, 0x6e, 0x44, 0x64, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x61,
+ 0x66, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x41, 0x66, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x30,
+ 0x0a, 0x14, 0x64, 0x65, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72,
+ 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x64, 0x65,
+ 0x66, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x73,
+ 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x0c,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x22,
+ 0x82, 0x02, 0x0a, 0x18, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x42,
+ 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2d, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70,
+ 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x74,
+ 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x75,
+ 0x70, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x5f, 0x74, 0x6f, 0x5f, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72,
+ 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x50, 0x6f, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x64,
+ 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72,
+ 0x79, 0x52, 0x75, 0x6e, 0x12, 0x3e, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f,
+ 0x74, 0x6f, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65,
+ 0x52, 0x12, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x54, 0x6f, 0x54, 0x69, 0x6d, 0x65, 0x73,
+ 0x74, 0x61, 0x6d, 0x70, 0x22, 0xad, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65,
+ 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69,
+ 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52,
+ 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x24,
+ 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
+ 0x6c, 0x6f, 0x67, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65,
+ 0x76, 0x65, 0x6e, 0x74, 0x22, 0x4d, 0x0a, 0x1b, 0x52, 0x65, 0x74, 0x72, 0x79, 0x53, 0x63, 0x68,
+ 0x65, 0x6d, 0x61, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
+ 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75,
+ 0x75, 0x69, 0x64, 0x22, 0xdd, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x74, 0x72, 0x79, 0x53, 0x63, 0x68,
+ 0x65, 0x6d, 0x61, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x16, 0x72, 0x6f, 0x77, 0x73, 0x5f, 0x61, 0x66, 0x66,
+ 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01,
+ 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x52, 0x65, 0x74, 0x72, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4d, 0x69, 0x67, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x6f,
+ 0x77, 0x73, 0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72,
+ 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x72, 0x6f, 0x77, 0x73, 0x41, 0x66, 0x66, 0x65,
+ 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x46, 0x0a, 0x18, 0x52,
+ 0x6f, 0x77, 0x73, 0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x53, 0x68, 0x61,
+ 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x15, 0x52, 0x75, 0x6e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68,
+ 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x75, 0x6e, 0x48, 0x65, 0x61,
+ 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x6d, 0x0a, 0x22, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44,
+ 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0xdd, 0x01, 0x0a, 0x1c, 0x52, 0x65, 0x74, 0x72, 0x79,
- 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x16, 0x72, 0x6f, 0x77, 0x73, 0x5f,
- 0x61, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x79, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4d,
- 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x2e, 0x52, 0x6f, 0x77, 0x73, 0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x53,
- 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x72, 0x6f, 0x77, 0x73, 0x41,
- 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x46,
- 0x0a, 0x18, 0x52, 0x6f, 0x77, 0x73, 0x41, 0x66, 0x66, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x79,
- 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
- 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x51, 0x0a, 0x15, 0x52, 0x75, 0x6e, 0x48, 0x65, 0x61,
- 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x18, 0x0a, 0x16, 0x52, 0x75, 0x6e,
- 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x6d, 0x0a, 0x22, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c,
- 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x10, 0x64, 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69,
- 0x63, 0x79, 0x22, 0x55, 0x0a, 0x23, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x44, 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63,
- 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6b, 0x65, 0x79,
+ 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79,
+ 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x64,
+ 0x75, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x22,
+ 0x55, 0x0a, 0x23, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x75,
+ 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x5e, 0x0a, 0x1e, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66,
+ 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03,
+ 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x51, 0x0a, 0x1f, 0x53, 0x65, 0x74, 0x4b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x66,
+ 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x6b, 0x65, 0x79,
0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f,
0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x5e, 0x0a, 0x1e, 0x53, 0x65, 0x74,
- 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
- 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b,
- 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b,
- 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08,
- 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x51, 0x0a, 0x1f, 0x53, 0x65, 0x74,
- 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
- 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x08,
- 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12,
- 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x72, 0x0a, 0x1f,
- 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x73, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72,
- 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67,
- 0x22, 0x49, 0x0a, 0x20, 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x73, 0x50, 0x72,
- 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53,
- 0x68, 0x61, 0x72, 0x64, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x8e, 0x02, 0x0a, 0x1c,
- 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x43, 0x6f,
- 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x22, 0x72, 0x0a, 0x1f, 0x53, 0x65, 0x74,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x73, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x53, 0x65,
+ 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x35,
- 0x0a, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x04,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64,
- 0x65, 0x6e, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73,
- 0x12, 0x32, 0x0a, 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x13, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72,
- 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x07,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x46, 0x0a, 0x1d,
- 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x43, 0x6f,
- 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a,
- 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74,
- 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x22, 0x6a, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41,
- 0x6c, 0x69, 0x61, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x22, 0x15, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x53, 0x68, 0x61, 0x72,
- 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15,
- 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74,
- 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69,
- 0x61, 0x73, 0x22, 0x1d, 0x0a, 0x1b, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x22, 0x62, 0x0a, 0x1a, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x22, 0x54, 0x0a, 0x1b, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65,
- 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53,
- 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45,
- 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x54, 0x0a, 0x20, 0x53,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x22, 0x49, 0x0a,
+ 0x20, 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x73, 0x50, 0x72, 0x69, 0x6d, 0x61,
+ 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72,
+ 0x64, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x8e, 0x02, 0x0a, 0x1c, 0x53, 0x65, 0x74,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72,
+ 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e,
+ 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79,
+ 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x6e, 0x69,
+ 0x65, 0x64, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x32, 0x0a,
+ 0x15, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x64, 0x69,
+ 0x73, 0x61, 0x62, 0x6c, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x46, 0x0a, 0x1d, 0x53, 0x65, 0x74,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72,
+ 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68,
+ 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x22, 0x6a, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+ 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41,
+ 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61,
+ 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x15, 0x0a,
+ 0x13, 0x53, 0x65, 0x74, 0x57, 0x72, 0x69, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
+ 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+ 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f,
+ 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f,
+ 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69,
+ 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22,
+ 0x1d, 0x0a, 0x1b, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x62,
+ 0x0a, 0x1a, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x46, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x12,
+ 0x0a, 0x04, 0x63, 0x65, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x65,
+ 0x6c, 0x6c, 0x22, 0x54, 0x0a, 0x1b, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x35, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x1f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72,
+ 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f,
+ 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x54, 0x0a, 0x20, 0x53, 0x68, 0x61, 0x72,
+ 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x73, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0xaa,
+ 0x03, 0x0a, 0x21, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53,
0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
- 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x22, 0xaa, 0x03, 0x0a, 0x21, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x18,
- 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74,
- 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x72, 0x65,
+ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x72, 0x65, 0x70, 0x6c, 0x69,
+ 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65, 0x73, 0x12, 0x5a,
+ 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53,
+ 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
+ 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
+ 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x1a, 0x5f, 0x0a, 0x18, 0x52, 0x65,
0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x65,
- 0x73, 0x12, 0x5a, 0x0a, 0x0a, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x18,
- 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74,
- 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74,
- 0x72, 0x79, 0x52, 0x09, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x1a, 0x5f, 0x0a,
- 0x18, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x70,
- 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x74, 0x61,
- 0x74, 0x75, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4e,
- 0x0a, 0x0e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
- 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62,
- 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8b,
- 0x01, 0x0a, 0x1d, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05,
- 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61,
- 0x72, 0x64, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69,
- 0x61, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52,
- 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x20, 0x0a, 0x1e,
+ 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4e, 0x0a, 0x0e, 0x54,
+ 0x61, 0x62, 0x6c, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+ 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+ 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,
+ 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8b, 0x01, 0x0a, 0x1d,
0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7c,
- 0x0a, 0x12, 0x53, 0x6c, 0x65, 0x65, 0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61,
- 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70,
- 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61,
- 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2c,
- 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x15, 0x0a, 0x13,
- 0x53, 0x6c, 0x65, 0x65, 0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0xf0, 0x01, 0x0a, 0x15, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68,
- 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
+ 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61,
0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12,
- 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69,
- 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73,
- 0x70, 0x61, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x2f, 0x0a,
- 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4b, 0x65, 0x79, 0x52,
- 0x61, 0x6e, 0x67, 0x65, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x16,
- 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x16, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x53, 0x68, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64,
- 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x5e, 0x0a, 0x18, 0x53, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x20, 0x0a, 0x1e, 0x53, 0x68, 0x61,
+ 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x6d,
+ 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x7c, 0x0a, 0x12, 0x53,
+ 0x6c, 0x65, 0x65, 0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61,
+ 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
+ 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0b,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2c, 0x0a, 0x08, 0x64,
+ 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e,
+ 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
+ 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x15, 0x0a, 0x13, 0x53, 0x6c, 0x65,
+ 0x65, 0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0xf0, 0x01, 0x0a, 0x15, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64,
+ 0x41, 0x64, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03,
+ 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x27,
+ 0x0a, 0x0f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
+ 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x2f, 0x0a, 0x09, 0x6b, 0x65,
+ 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e,
+ 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x61, 0x6e, 0x67,
+ 0x65, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x16, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61,
+ 0x72, 0x64, 0x41, 0x64, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a,
+ 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74,
+ 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x05, 0x73,
+ 0x68, 0x61, 0x72, 0x64, 0x22, 0x5e, 0x0a, 0x18, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68,
+ 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05,
+ 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61,
+ 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
+ 0x03, 0x75, 0x69, 0x64, 0x22, 0x42, 0x0a, 0x19, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x68,
+ 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53, 0x68, 0x61, 0x72,
+ 0x64, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x53, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x72,
+ 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c,
+ 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73,
+ 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x1a, 0x0a,
+ 0x18, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x16, 0x53, 0x74, 0x6f,
+ 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x61, 0x6c,
+ 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73,
+ 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x19, 0x0a,
+ 0x17, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x21, 0x54, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x52, 0x65, 0x70, 0x61,
+ 0x72, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a,
+ 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+ 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41,
+ 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x22, 0xc6, 0x01, 0x0a,
+ 0x22, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x6c,
+ 0x79, 0x52, 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
- 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
- 0x28, 0x05, 0x52, 0x03, 0x75, 0x69, 0x64, 0x22, 0x42, 0x0a, 0x19, 0x53, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x53,
- 0x68, 0x61, 0x72, 0x64, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x53, 0x0a, 0x17, 0x53,
- 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
- 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
- 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c,
- 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73,
- 0x22, 0x1a, 0x0a, 0x18, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x16,
- 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
- 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
- 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c,
- 0x69, 0x61, 0x73, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73,
- 0x22, 0x19, 0x0a, 0x17, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x52, 0x0a, 0x21, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x6c, 0x79, 0x52,
- 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x22,
- 0xc6, 0x01, 0x0a, 0x22, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e,
- 0x61, 0x6c, 0x6c, 0x79, 0x52, 0x65, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x5f,
- 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
- 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41,
- 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
- 0x12, 0x36, 0x0a, 0x0b, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0a, 0x6f, 0x6c,
- 0x64, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x5c, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61,
- 0x74, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x65, 0x6c, 0x6c, 0x5f, 0x69, 0x6e,
- 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x65,
- 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x5d, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x65, 0x6c, 0x6c, 0x5f, 0x69, 0x6e, 0x66,
- 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x65, 0x6c,
- 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x64, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
- 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
- 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x5f, 0x61, 0x6c,
- 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f,
- 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52,
- 0x0a, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x65, 0x0a, 0x18, 0x55,
- 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x63,
- 0x65, 0x6c, 0x6c, 0x73, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c,
- 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0a, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69,
- 0x61, 0x73, 0x22, 0x34, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e,
- 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x22, 0xfb, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c,
- 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
- 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02,
- 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61,
- 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
- 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x1a, 0x69, 0x0a, 0x16, 0x52,
+ 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x5f, 0x70, 0x72, 0x69,
+ 0x6d, 0x61, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70,
+ 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61,
+ 0x73, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x36, 0x0a,
+ 0x0b, 0x6f, 0x6c, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0a, 0x6f, 0x6c, 0x64, 0x50, 0x72,
+ 0x69, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x5c, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
+ 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x65, 0x6c, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x49,
+ 0x6e, 0x66, 0x6f, 0x22, 0x5d, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x6c,
+ 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x65, 0x6c, 0x6c, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x43, 0x65, 0x6c, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x63, 0x65, 0x6c, 0x6c, 0x49, 0x6e,
+ 0x66, 0x6f, 0x22, 0x64, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x65, 0x6c, 0x6c,
+ 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74,
+ 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x0a, 0x63, 0x65,
+ 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x65, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x63, 0x65, 0x6c, 0x6c,
+ 0x73, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
+ 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c,
+ 0x69, 0x61, 0x73, 0x52, 0x0a, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x22,
+ 0x34, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x73, 0x22, 0xfb, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
+ 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65,
+ 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73,
+ 0x75, 0x6c, 0x74, 0x73, 0x12, 0x62, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f,
+ 0x62, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28,
+ 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61,
+ 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
- 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, 0x0a,
- 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73,
- 0x22, 0xfc, 0x01, 0x0a, 0x18, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
- 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x61, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x37, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61,
- 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79,
- 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x75,
- 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63, 0x0a, 0x13, 0x52, 0x65,
- 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72,
- 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
- 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56,
- 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
- 0xd8, 0x01, 0x0a, 0x1d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65,
- 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x25, 0x0a,
- 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18,
- 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x61,
- 0x62, 0x6c, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f,
- 0x76, 0x69, 0x65, 0x77, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63,
- 0x6c, 0x75, 0x64, 0x65, 0x56, 0x69, 0x65, 0x77, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, 0x69,
- 0x70, 0x5f, 0x6e, 0x6f, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x6f, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72,
- 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x76, 0x73, 0x63,
- 0x68, 0x65, 0x6d, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c,
- 0x75, 0x64, 0x65, 0x56, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x88, 0x02, 0x0a, 0x1e, 0x56,
- 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a,
- 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x3d, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61,
- 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73,
- 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73,
- 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x52, 0x0e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64,
- 0x1a, 0x63, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61,
- 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c,
- 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61,
- 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x14, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
- 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61,
- 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12,
- 0x21, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x73, 0x22, 0x31, 0x0a, 0x15, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68,
- 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72,
- 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65,
- 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x3c, 0x0a, 0x1e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
- 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x22, 0x8a, 0x02, 0x0a, 0x1f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
- 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
- 0x73, 0x12, 0x68, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f,
- 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x76, 0x74,
- 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
- 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x11, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79,
+ 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x1a, 0x69, 0x0a, 0x16, 0x52, 0x65, 0x73, 0x75,
+ 0x6c, 0x74, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+ 0x02, 0x38, 0x01, 0x22, 0x58, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
+ 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x69,
+ 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x22, 0xfc, 0x01,
+ 0x0a, 0x18, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65,
+ 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73,
+ 0x75, 0x6c, 0x74, 0x73, 0x12, 0x61, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f,
+ 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37,
+ 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64,
+ 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
+ 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61,
+ 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
+ 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
+ 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
+ 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69,
+ 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd8, 0x01, 0x0a,
+ 0x1d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b,
+ 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
+ 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78,
+ 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x0d, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65,
+ 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x76, 0x69, 0x65,
+ 0x77, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
+ 0x65, 0x56, 0x69, 0x65, 0x77, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x6e,
+ 0x6f, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x4e, 0x6f, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x27,
+ 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x76, 0x73, 0x63, 0x68, 0x65, 0x6d,
+ 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65,
+ 0x56, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x22, 0x88, 0x02, 0x0a, 0x1e, 0x56, 0x61, 0x6c, 0x69,
+ 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65,
+ 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73,
+ 0x75, 0x6c, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f,
+ 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d,
+ 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64,
+ 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
+ 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
+ 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72,
+ 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63, 0x0a,
+ 0x13, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45,
+ 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74,
+ 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
+ 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x14, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68,
+ 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65,
+ 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x12, 0x21, 0x0a, 0x0c,
+ 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x0b, 0x70, 0x69, 0x6e, 0x67, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x73, 0x22,
+ 0x31, 0x0a, 0x15, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75,
+ 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c,
+ 0x74, 0x73, 0x22, 0x3c, 0x0a, 0x1e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x22, 0x8a, 0x02, 0x0a, 0x1f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x68,
+ 0x0a, 0x10, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61,
+ 0x72, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c,
+ 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68,
+ 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
+ 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x75,
+ 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+ 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+ 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c,
+ 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4f, 0x0a,
+ 0x1b, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x68, 0x61, 0x72,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72, 0x64, 0x22, 0x38,
+ 0x0a, 0x1c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+ 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18,
+ 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x98, 0x01, 0x0a, 0x16, 0x56, 0x61, 0x6c,
+ 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
+ 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78, 0x63, 0x6c, 0x75,
+ 0x64, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x0d, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x23,
+ 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x73, 0x18,
+ 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x56, 0x69,
+ 0x65, 0x77, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
+ 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
+ 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x60, 0x0a, 0x10, 0x72, 0x65, 0x73,
+ 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20,
+ 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42,
0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63, 0x0a, 0x13, 0x52,
@@ -18722,340 +18769,306 @@ var file_vtctldata_proto_rawDesc = []byte{
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
- 0x22, 0x4f, 0x0a, 0x1b, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73,
- 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73,
- 0x68, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x22, 0x38, 0x0a, 0x1c, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72,
- 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x98, 0x01, 0x0a, 0x16,
- 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x78,
- 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0d, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x76, 0x69, 0x65,
- 0x77, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
- 0x65, 0x56, 0x69, 0x65, 0x77, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64,
- 0x61, 0x74, 0x65, 0x56, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20,
- 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x60, 0x0a, 0x10,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x5f, 0x62, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x56, 0x53, 0x63, 0x68, 0x65,
- 0x6d, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c,
- 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e,
- 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x1a, 0x63,
- 0x0a, 0x13, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64,
- 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
- 0x02, 0x38, 0x01, 0x22, 0x88, 0x07, 0x0a, 0x12, 0x56, 0x44, 0x69, 0x66, 0x66, 0x43, 0x72, 0x65,
- 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f,
- 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f,
- 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
- 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75,
- 0x75, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x65,
- 0x6c, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x5f, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61,
- 0x72, 0x67, 0x65, 0x74, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0e, 0x32,
- 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70,
- 0x65, 0x73, 0x12, 0x6c, 0x0a, 0x1b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x6c,
- 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63,
- 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
- 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65,
- 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x19, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c,
- 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
- 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09,
- 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69,
- 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x55,
- 0x0a, 0x1e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65,
- 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e,
- 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x61, 0x69,
- 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x71,
- 0x75, 0x65, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x62, 0x75,
- 0x67, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x09, 0x6f, 0x6e, 0x6c, 0x79, 0x5f, 0x70,
- 0x5f, 0x6b, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x6e, 0x6c, 0x79, 0x50,
- 0x4b, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
- 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73,
- 0x12, 0x38, 0x0a, 0x19, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x6f,
- 0x77, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x18, 0x0e, 0x20,
- 0x01, 0x28, 0x03, 0x52, 0x15, 0x6d, 0x61, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x52, 0x6f, 0x77,
- 0x73, 0x54, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x61,
- 0x69, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x61, 0x69, 0x74, 0x12, 0x42,
- 0x0a, 0x14, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e,
- 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76,
- 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12,
- 0x77, 0x61, 0x69, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
- 0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79,
- 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x74, 0x72,
- 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x12, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x16, 0x6d,
- 0x61, 0x78, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65,
- 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6d, 0x61, 0x78,
- 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73,
- 0x12, 0x3c, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x64, 0x75, 0x72,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74,
- 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6d,
- 0x61, 0x78, 0x44, 0x69, 0x66, 0x66, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29,
- 0x0a, 0x13, 0x56, 0x44, 0x69, 0x66, 0x66, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x04, 0x55, 0x55, 0x49, 0x44, 0x22, 0x6b, 0x0a, 0x12, 0x56, 0x44, 0x69,
- 0x66, 0x66, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
- 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x74,
- 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73,
- 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x03, 0x61, 0x72, 0x67, 0x22, 0x15, 0x0a, 0x13, 0x56, 0x44, 0x69, 0x66, 0x66, 0x44,
- 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6d, 0x0a,
- 0x12, 0x56, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75,
- 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12,
- 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
- 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64,
- 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x15, 0x0a, 0x13,
- 0x56, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x22, 0x69, 0x0a, 0x10, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x77,
+ 0x22, 0x88, 0x07, 0x0a, 0x12, 0x56, 0x44, 0x69, 0x66, 0x66, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66,
0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6b, 0x65,
0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61,
- 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03,
- 0x61, 0x72, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x72, 0x67, 0x22, 0xd7,
- 0x01, 0x0a, 0x11, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x10, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x72,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31,
- 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x44, 0x69, 0x66, 0x66,
- 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62,
- 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
- 0x79, 0x52, 0x0f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x73, 0x1a, 0x64, 0x0a, 0x14, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
- 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05,
- 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e,
- 0x56, 0x44, 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x10, 0x56, 0x44, 0x69, 0x66,
- 0x66, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
+ 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04,
+ 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64,
+ 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x65, 0x6c, 0x6c, 0x73,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x65,
+ 0x6c, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x65,
+ 0x6c, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x43, 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74,
+ 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79,
+ 0x70, 0x65, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12,
+ 0x6c, 0x0a, 0x1b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07,
+ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2c, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e,
+ 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53,
+ 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
+ 0x63, 0x65, 0x52, 0x19, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74,
+ 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x16, 0x0a,
+ 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x55, 0x0a, 0x1e, 0x66,
+ 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20,
+ 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x65, 0x64, 0x52,
+ 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x61, 0x69, 0x74, 0x54, 0x69,
+ 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x71, 0x75, 0x65, 0x72,
+ 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x51, 0x75,
+ 0x65, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x09, 0x6f, 0x6e, 0x6c, 0x79, 0x5f, 0x70, 0x5f, 0x6b, 0x73,
+ 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x6e, 0x6c, 0x79, 0x50, 0x4b, 0x73, 0x12,
+ 0x2c, 0x0a, 0x12, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f,
+ 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x75, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x38, 0x0a,
+ 0x19, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x5f,
+ 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03,
+ 0x52, 0x15, 0x6d, 0x61, 0x78, 0x45, 0x78, 0x74, 0x72, 0x61, 0x52, 0x6f, 0x77, 0x73, 0x54, 0x6f,
+ 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x61, 0x69, 0x74, 0x18,
+ 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x77, 0x61, 0x69, 0x74, 0x12, 0x42, 0x0a, 0x14, 0x77,
+ 0x61, 0x69, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72,
+ 0x76, 0x61, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69,
+ 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x77, 0x61, 0x69,
+ 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x11, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x75, 0x74, 0x6f, 0x52, 0x65, 0x74, 0x72, 0x79, 0x12, 0x18,
+ 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x16, 0x6d, 0x61, 0x78, 0x5f,
+ 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, 0x72, 0x6f,
+ 0x77, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x70,
+ 0x6f, 0x72, 0x74, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x3c, 0x0a,
+ 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x44,
+ 0x69, 0x66, 0x66, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0a, 0x13, 0x56,
+ 0x44, 0x69, 0x66, 0x66, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x04, 0x55, 0x55, 0x49, 0x44, 0x22, 0x6b, 0x0a, 0x12, 0x56, 0x44, 0x69, 0x66, 0x66, 0x44,
+ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67,
0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x74,
- 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb2, 0x01, 0x0a, 0x15, 0x57,
- 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1b, 0x0a, 0x09,
- 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x08, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x12, 0x6b, 0x65, 0x65,
- 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x6b, 0x65, 0x65, 0x70, 0x52, 0x6f, 0x75, 0x74, 0x69,
- 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64,
- 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x22,
- 0xd1, 0x01, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65,
- 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75,
- 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d,
- 0x6d, 0x61, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18,
- 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74,
- 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x49,
- 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x55, 0x0a, 0x0a,
- 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70,
- 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61,
- 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c,
- 0x65, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65,
- 0x74, 0x65, 0x64, 0x22, 0x67, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
- 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
- 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03,
- 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x22, 0xe6, 0x07, 0x0a,
- 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x10, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28,
- 0x0b, 0x32, 0x35, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f,
+ 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+ 0x61, 0x72, 0x67, 0x22, 0x15, 0x0a, 0x13, 0x56, 0x44, 0x69, 0x66, 0x66, 0x44, 0x65, 0x6c, 0x65,
+ 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6d, 0x0a, 0x12, 0x56, 0x44,
+ 0x69, 0x66, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f,
+ 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x56, 0x44, 0x69,
+ 0x66, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x22, 0x69, 0x0a, 0x10, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x71,
+ 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+ 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x67,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x72, 0x67, 0x22, 0xd7, 0x01, 0x0a, 0x11,
+ 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x5c, 0x0a, 0x10, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x76, 0x74,
+ 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x68, 0x6f,
+ 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x1a,
+ 0x64, 0x0a, 0x14, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+ 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x56, 0x44, 0x69,
+ 0x66, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x10, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x74,
+ 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72,
+ 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
+ 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e,
+ 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12,
+ 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75,
+ 0x69, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x56, 0x44, 0x69, 0x66, 0x66, 0x53, 0x74, 0x6f, 0x70, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb2, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x0a,
+ 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x65,
+ 0x70, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6b, 0x65,
+ 0x65, 0x70, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x12, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x72,
+ 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x10, 0x6b, 0x65, 0x65, 0x70, 0x52, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x52,
+ 0x75, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x05,
+ 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x22, 0xd1, 0x01, 0x0a,
+ 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61,
+ 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72,
+ 0x79, 0x12, 0x46, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57,
+ 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f,
+ 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x55, 0x0a, 0x0a, 0x54, 0x61, 0x62,
+ 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
+ 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64,
+ 0x22, 0x67, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x22, 0xe6, 0x07, 0x0a, 0x16, 0x57, 0x6f,
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
- 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74,
- 0x61, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43,
- 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x58, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72,
- 0x64, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
- 0x33, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x10, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f,
+ 0x70, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35,
+ 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66,
+ 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70, 0x79,
+ 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x58, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x64, 0x5f, 0x73,
+ 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x76,
+ 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e,
+ 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72,
+ 0x79, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12,
+ 0x23, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65,
+ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x1a, 0xe8, 0x01, 0x0a, 0x0e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f,
+ 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f, 0x77, 0x73, 0x5f,
+ 0x63, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x72, 0x6f,
+ 0x77, 0x73, 0x43, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x77, 0x73,
+ 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x6f,
+ 0x77, 0x73, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f, 0x77, 0x73, 0x5f,
+ 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02,
+ 0x52, 0x0e, 0x72, 0x6f, 0x77, 0x73, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65,
+ 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x70, 0x69, 0x65, 0x64,
+ 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x43, 0x6f, 0x70,
+ 0x69, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x74, 0x6f, 0x74,
+ 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x54,
+ 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x65,
+ 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0f,
+ 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x1a,
+ 0xbc, 0x01, 0x0a, 0x10, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53,
+ 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
+ 0x52, 0x02, 0x69, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e,
+ 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62,
+ 0x6c, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x68,
+ 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
+ 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69,
+ 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e,
+ 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x1a, 0x5c,
+ 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x4c,
+ 0x0a, 0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x32, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
- 0x73, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x45,
- 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61,
- 0x6d, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x73, 0x74,
- 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x66, 0x66,
- 0x69, 0x63, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0xe8, 0x01, 0x0a, 0x0e, 0x54, 0x61, 0x62, 0x6c,
- 0x65, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x6f,
- 0x77, 0x73, 0x5f, 0x63, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
- 0x0a, 0x72, 0x6f, 0x77, 0x73, 0x43, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x72,
- 0x6f, 0x77, 0x73, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
- 0x09, 0x72, 0x6f, 0x77, 0x73, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x6f,
- 0x77, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x02, 0x52, 0x0e, 0x72, 0x6f, 0x77, 0x73, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
- 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x70,
- 0x69, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73,
- 0x43, 0x6f, 0x70, 0x69, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f,
- 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x62, 0x79, 0x74,
- 0x65, 0x73, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x62, 0x79, 0x74, 0x65, 0x73,
- 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
- 0x02, 0x52, 0x0f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61,
- 0x67, 0x65, 0x1a, 0xbc, 0x01, 0x0a, 0x10, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65,
- 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
- 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x5f, 0x73, 0x68, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73,
- 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73,
- 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
- 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a,
- 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66,
- 0x6f, 0x1a, 0x5c, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
- 0x73, 0x12, 0x4c, 0x0a, 0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03,
- 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57,
- 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73,
- 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61,
- 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x1a,
- 0x73, 0x0a, 0x13, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64,
+ 0x73, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x52, 0x07, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x1a, 0x73, 0x0a, 0x13,
+ 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x6e,
+ 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x6f, 0x70,
+ 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+ 0x01, 0x1a, 0x6f, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
+ 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x74,
- 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x43, 0x6f, 0x70, 0x79, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
- 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x6f, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x64, 0x53, 0x74, 0x72,
- 0x65, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x05, 0x76,
- 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x76, 0x74, 0x63,
- 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x68,
- 0x61, 0x72, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
- 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xef, 0x03, 0x0a, 0x1c, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
- 0x6f, 0x77, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x14,
- 0x0a, 0x05, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63,
- 0x65, 0x6c, 0x6c, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74,
- 0x79, 0x70, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70,
- 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65,
- 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x4f, 0x0a,
- 0x1b, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x5f, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x18, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x61, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x3c,
- 0x0a, 0x1a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65,
- 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01,
- 0x28, 0x08, 0x52, 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73,
- 0x65, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09,
- 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52,
- 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x69,
- 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74,
- 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74,
- 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75,
- 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12,
- 0x3e, 0x0a, 0x1b, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x5f, 0x74, 0x61,
- 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a,
- 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65,
- 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12,
- 0x16, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52,
- 0x06, 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x1d, 0x57, 0x6f, 0x72, 0x6b,
- 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69,
- 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d,
- 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d,
- 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x74, 0x61,
- 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x53,
- 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f,
- 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x72,
- 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x72, 0x79,
- 0x5f, 0x72, 0x75, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03,
- 0x28, 0x09, 0x52, 0x0d, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
- 0x73, 0x22, 0x90, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x55, 0x70,
- 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b,
- 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b,
- 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x34, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64,
- 0x61, 0x74, 0x61, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x22, 0xd1, 0x01, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
- 0x77, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
- 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x07, 0x64, 0x65, 0x74,
- 0x61, 0x69, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x74, 0x63,
- 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x55,
- 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61,
- 0x62, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c,
- 0x73, 0x1a, 0x55, 0x0a, 0x0a, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12,
- 0x2d, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x15, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x12, 0x18,
- 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
- 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d,
- 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x22, 0x51, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x75,
- 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x6d,
- 0x69, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x14, 0x2e, 0x76, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4d, 0x69, 0x72, 0x72,
- 0x6f, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x0b, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52,
- 0x75, 0x6c, 0x65, 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x1c, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
- 0x77, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x37, 0x0a,
- 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20,
- 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54,
- 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
- 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
- 0x22, 0x7f, 0x0a, 0x1d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4d, 0x69, 0x72, 0x72,
- 0x6f, 0x72, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
- 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x73,
- 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d,
- 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74,
- 0x65, 0x2a, 0x4a, 0x0a, 0x15, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55,
- 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x4f, 0x56, 0x45, 0x54, 0x41,
- 0x42, 0x4c, 0x45, 0x53, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45,
- 0x4c, 0x4f, 0x4f, 0x4b, 0x55, 0x50, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x02, 0x2a, 0x38, 0x0a,
- 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x08,
- 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x53, 0x43, 0x45,
- 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x53, 0x43, 0x45,
- 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x42, 0x28, 0x5a, 0x26, 0x76, 0x69, 0x74, 0x65, 0x73,
- 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76,
- 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74,
- 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x64,
+ 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
+ 0x38, 0x01, 0x22, 0xef, 0x03, 0x0a, 0x1c, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53,
+ 0x77, 0x69, 0x74, 0x63, 0x68, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75,
+ 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12,
+ 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x14, 0x0a, 0x05, 0x63,
+ 0x65, 0x6c, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x63, 0x65, 0x6c, 0x6c,
+ 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
+ 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61,
+ 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x4f, 0x0a, 0x1b, 0x6d, 0x61,
+ 0x78, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x61,
+ 0x67, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x18, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x4c, 0x61, 0x67, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x65,
+ 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x72, 0x65,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52,
+ 0x18, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x52, 0x65,
+ 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72,
+ 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x69,
+ 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
+ 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x76, 0x74, 0x74, 0x69, 0x6d,
+ 0x65, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65,
+ 0x6f, 0x75, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x09,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x3e, 0x0a, 0x1b,
+ 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28,
+ 0x08, 0x52, 0x19, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x54, 0x61, 0x72,
+ 0x67, 0x65, 0x74, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06,
+ 0x73, 0x68, 0x61, 0x72, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x68,
+ 0x61, 0x72, 0x64, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x1d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72,
+ 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
+ 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61,
+ 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
+ 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75,
+ 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x0d, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x90,
+ 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x72,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0x74, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x64, 0x61, 0x74, 0x61,
+ 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x52, 0x0d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x22, 0xd1, 0x01, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x55, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
+ 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73,
+ 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c,
+ 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64,
+ 0x61, 0x74, 0x61, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x55, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65,
+ 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x1a, 0x55,
+ 0x0a, 0x0a, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x06,
+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74,
+ 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x41, 0x6c,
+ 0x69, 0x61, 0x73, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63,
+ 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x68,
+ 0x61, 0x6e, 0x67, 0x65, 0x64, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x72, 0x72,
+ 0x6f, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x51,
+ 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x75, 0x6c, 0x65, 0x73,
+ 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x69, 0x72, 0x72,
+ 0x6f, 0x72, 0x5f, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
+ 0x2e, 0x76, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52,
+ 0x75, 0x6c, 0x65, 0x73, 0x52, 0x0b, 0x6d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x75, 0x6c, 0x65,
+ 0x73, 0x22, 0xa9, 0x01, 0x0a, 0x1c, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4d, 0x69,
+ 0x72, 0x72, 0x6f, 0x72, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65,
+ 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1a,
+ 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x37, 0x0a, 0x0c, 0x74, 0x61,
+ 0x62, 0x6c, 0x65, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e,
+ 0x32, 0x14, 0x2e, 0x74, 0x6f, 0x70, 0x6f, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61, 0x62, 0x6c,
+ 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x54, 0x79,
+ 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04,
+ 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x22, 0x7f, 0x0a,
+ 0x1d, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4d, 0x69, 0x72, 0x72, 0x6f, 0x72, 0x54,
+ 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18,
+ 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72,
+ 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
+ 0x74, 0x61, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x72,
+ 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2a, 0x4a,
+ 0x0a, 0x15, 0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f,
+ 0x4d, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x4f, 0x56, 0x45, 0x54, 0x41, 0x42, 0x4c, 0x45,
+ 0x53, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x4c, 0x4f, 0x4f,
+ 0x4b, 0x55, 0x50, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x02, 0x2a, 0x38, 0x0a, 0x0d, 0x51, 0x75,
+ 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x08, 0x0a, 0x04, 0x4e,
+ 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x41, 0x53, 0x43, 0x45, 0x4e, 0x44, 0x49,
+ 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x53, 0x43, 0x45, 0x4e, 0x44, 0x49,
+ 0x4e, 0x47, 0x10, 0x02, 0x42, 0x28, 0x5a, 0x26, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2e, 0x69,
+ 0x6f, 0x2f, 0x76, 0x69, 0x74, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x74, 0x2f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x74, 0x63, 0x74, 0x6c, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go b/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go
index 7e38623a907..9532622dc98 100644
--- a/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go
+++ b/go/vt/proto/vtctldata/vtctldata_vtproto.pb.go
@@ -3484,6 +3484,7 @@ func (m *PlannedReparentShardRequest) CloneVT() *PlannedReparentShardRequest {
AvoidPrimary: m.AvoidPrimary.CloneVT(),
WaitReplicasTimeout: m.WaitReplicasTimeout.CloneVT(),
TolerableReplicationLag: m.TolerableReplicationLag.CloneVT(),
+ AllowCrossCellPromotion: m.AllowCrossCellPromotion,
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
@@ -15087,6 +15088,16 @@ func (m *PlannedReparentShardRequest) MarshalToSizedBufferVT(dAtA []byte) (int,
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
+ if m.AllowCrossCellPromotion {
+ i--
+ if m.AllowCrossCellPromotion {
+ dAtA[i] = 1
+ } else {
+ dAtA[i] = 0
+ }
+ i--
+ dAtA[i] = 0x38
+ }
if m.TolerableReplicationLag != nil {
size, err := m.TolerableReplicationLag.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
@@ -24414,6 +24425,9 @@ func (m *PlannedReparentShardRequest) SizeVT() (n int) {
l = m.TolerableReplicationLag.SizeVT()
n += 1 + l + sov(uint64(l))
}
+ if m.AllowCrossCellPromotion {
+ n += 2
+ }
n += len(m.unknownFields)
return n
}
@@ -49626,6 +49640,26 @@ func (m *PlannedReparentShardRequest) UnmarshalVT(dAtA []byte) error {
return err
}
iNdEx = postIndex
+ case 7:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field AllowCrossCellPromotion", wireType)
+ }
+ var v int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflow
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ v |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ m.AllowCrossCellPromotion = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skip(dAtA[iNdEx:])
diff --git a/go/vt/schemadiff/capability.go b/go/vt/schemadiff/capability.go
index cde99ac18c3..1471599d390 100644
--- a/go/vt/schemadiff/capability.go
+++ b/go/vt/schemadiff/capability.go
@@ -61,24 +61,13 @@ func alterOptionCapableOfInstantDDL(alterOption sqlparser.AlterOption, createTab
}
}
- isGeneratedColumn := func(col *sqlparser.ColumnDefinition) (bool, sqlparser.ColumnStorage) {
- if col == nil {
- return false, 0
- }
- if col.Type.Options == nil {
- return false, 0
- }
- if col.Type.Options.As == nil {
- return false, 0
- }
- return true, col.Type.Options.Storage
- }
- colStringStrippedDown := func(col *sqlparser.ColumnDefinition, stripDefault bool, stripEnum bool) string {
+ colStringStrippedDown := func(col *sqlparser.ColumnDefinition, stripEnum bool) string {
strippedCol := sqlparser.Clone(col)
- if stripDefault {
- strippedCol.Type.Options.Default = nil
- strippedCol.Type.Options.DefaultLiteral = false
- }
+ // strip `default`
+ strippedCol.Type.Options.Default = nil
+ strippedCol.Type.Options.DefaultLiteral = false
+ // strip `visibility`
+ strippedCol.Type.Options.Invisible = nil
if stripEnum {
strippedCol.Type.EnumValues = nil
}
@@ -95,15 +84,53 @@ func alterOptionCapableOfInstantDDL(alterOption sqlparser.AlterOption, createTab
}
return true
}
+ changeModifyColumnCapableOfInstantDDL := func(col *sqlparser.ColumnDefinition, newCol *sqlparser.ColumnDefinition) (bool, error) {
+ // Check if only diff is change of default.
+ // We temporarily remove the DEFAULT expression (if any) from both
+ // table and ALTER statement, and compare the columns: if they're otherwise equal,
+ // then the only change can be an addition/change/removal of DEFAULT, which
+ // is instant-table.
+ tableColDefinition := colStringStrippedDown(col, false)
+ newColDefinition := colStringStrippedDown(newCol, false)
+ if tableColDefinition == newColDefinition {
+ return capableOf(capabilities.InstantChangeColumnDefaultFlavorCapability)
+ }
+ // Check if:
+ // 1. this an ENUM/SET
+ // 2. and the change is to append values to the end of the list
+ // 3. and the number of added values does not increase the storage size for the enum/set
+ // 4. while still not caring about a change in the default value
+ if len(col.Type.EnumValues) > 0 && len(newCol.Type.EnumValues) > 0 {
+ // both are enum or set
+ if !hasPrefix(newCol.Type.EnumValues, col.Type.EnumValues) {
+ return false, nil
+ }
+ // we know the new column definition is identical to, or extends, the old definition.
+ // Now validate storage:
+ if strings.EqualFold(col.Type.Type, "enum") {
+ if len(col.Type.EnumValues) <= 255 && len(newCol.Type.EnumValues) > 255 {
+ // this increases the SET storage size (1 byte for up to 8 values, 2 bytes beyond)
+ return false, nil
+ }
+ }
+ if strings.EqualFold(col.Type.Type, "set") {
+ if (len(col.Type.EnumValues)+7)/8 != (len(newCol.Type.EnumValues)+7)/8 {
+ // this increases the SET storage size (1 byte for up to 8 values, 2 bytes for 8-15, etc.)
+ return false, nil
+ }
+ }
+ // Now don't care about change of default:
+ tableColDefinition := colStringStrippedDown(col, true)
+ newColDefinition := colStringStrippedDown(newCol, true)
+ if tableColDefinition == newColDefinition {
+ return capableOf(capabilities.InstantExpandEnumCapability)
+ }
+ }
+ return false, nil
+ }
+
// Up to 8.0.26 we could only ADD COLUMN as last column
switch opt := alterOption.(type) {
- case *sqlparser.ChangeColumn:
- // We do not support INSTANT for renaming a column (ALTER TABLE ...CHANGE) because:
- // 1. We discourage column rename
- // 2. We do not produce CHANGE statements in declarative diff
- // 3. The success of the operation depends on whether the column is referenced by a foreign key
- // in another table. Which is a bit too much to compute here.
- return false, nil
case *sqlparser.AddColumns:
if tableHasFulltextIndex {
// not supported if the table has a FULLTEXT index
@@ -114,7 +141,7 @@ func alterOptionCapableOfInstantDDL(alterOption sqlparser.AlterOption, createTab
return false, nil
}
for _, column := range opt.Columns {
- if isGenerated, storage := isGeneratedColumn(column); isGenerated {
+ if isGenerated, storage := IsGeneratedColumn(column); isGenerated {
if storage == sqlparser.StoredStorage {
// Adding a generated "STORED" column is unsupported
return false, nil
@@ -149,7 +176,7 @@ func alterOptionCapableOfInstantDDL(alterOption sqlparser.AlterOption, createTab
// not supported if the column is part of an index
return false, nil
}
- if isGenerated, _ := isGeneratedColumn(col); isGenerated {
+ if isGenerated, _ := IsGeneratedColumn(col); isGenerated {
// supported by all 8.0 versions
// Note: according to the docs dropping a STORED generated column is not INSTANT-able,
// but in practice this is supported. This is why we don't test for STORED here, like
@@ -157,49 +184,30 @@ func alterOptionCapableOfInstantDDL(alterOption sqlparser.AlterOption, createTab
return capableOf(capabilities.InstantAddDropVirtualColumnFlavorCapability)
}
return capableOf(capabilities.InstantAddDropColumnFlavorCapability)
+ case *sqlparser.ChangeColumn:
+ // We do not support INSTANT for renaming a column (ALTER TABLE ...CHANGE) because:
+ // 1. We discourage column rename
+ // 2. We do not produce CHANGE statements in declarative diff
+ // 3. The success of the operation depends on whether the column is referenced by a foreign key
+ // in another table. Which is a bit too much to compute here.
+ if opt.OldColumn.Name.String() != opt.NewColDefinition.Name.String() {
+ return false, nil
+ }
+ if col := findColumn(opt.OldColumn.Name.String()); col != nil {
+ return changeModifyColumnCapableOfInstantDDL(col, opt.NewColDefinition)
+ }
+ return false, nil
case *sqlparser.ModifyColumn:
if col := findColumn(opt.NewColDefinition.Name.String()); col != nil {
- // Check if only diff is change of default.
- // We temporarily remove the DEFAULT expression (if any) from both
- // table and ALTER statement, and compare the columns: if they're otherwise equal,
- // then the only change can be an addition/change/removal of DEFAULT, which
- // is instant-table.
- tableColDefinition := colStringStrippedDown(col, true, false)
- newColDefinition := colStringStrippedDown(opt.NewColDefinition, true, false)
- if tableColDefinition == newColDefinition {
- return capableOf(capabilities.InstantChangeColumnDefaultFlavorCapability)
- }
- // Check if:
- // 1. this an ENUM/SET
- // 2. and the change is to append values to the end of the list
- // 3. and the number of added values does not increase the storage size for the enum/set
- // 4. while still not caring about a change in the default value
- if len(col.Type.EnumValues) > 0 && len(opt.NewColDefinition.Type.EnumValues) > 0 {
- // both are enum or set
- if !hasPrefix(opt.NewColDefinition.Type.EnumValues, col.Type.EnumValues) {
- return false, nil
- }
- // we know the new column definition is identical to, or extends, the old definition.
- // Now validate storage:
- if strings.EqualFold(col.Type.Type, "enum") {
- if len(col.Type.EnumValues) <= 255 && len(opt.NewColDefinition.Type.EnumValues) > 255 {
- // this increases the SET storage size (1 byte for up to 8 values, 2 bytes beyond)
- return false, nil
- }
- }
- if strings.EqualFold(col.Type.Type, "set") {
- if (len(col.Type.EnumValues)+7)/8 != (len(opt.NewColDefinition.Type.EnumValues)+7)/8 {
- // this increases the SET storage size (1 byte for up to 8 values, 2 bytes for 8-15, etc.)
- return false, nil
- }
- }
- // Now don't care about change of default:
- tableColDefinition := colStringStrippedDown(col, true, true)
- newColDefinition := colStringStrippedDown(opt.NewColDefinition, true, true)
- if tableColDefinition == newColDefinition {
- return capableOf(capabilities.InstantExpandEnumCapability)
- }
- }
+ return changeModifyColumnCapableOfInstantDDL(col, opt.NewColDefinition)
+ }
+ return false, nil
+ case *sqlparser.AlterColumn:
+ if opt.DropDefault || opt.DefaultLiteral || opt.DefaultVal != nil {
+ return capableOf(capabilities.InstantChangeColumnDefaultFlavorCapability)
+ }
+ if opt.Invisible != nil {
+ return capableOf(capabilities.InstantChangeColumnVisibilityCapability)
}
return false, nil
default:
diff --git a/go/vt/schemadiff/capability_test.go b/go/vt/schemadiff/capability_test.go
index ca3387bb1a7..b35afb7fe22 100644
--- a/go/vt/schemadiff/capability_test.go
+++ b/go/vt/schemadiff/capability_test.go
@@ -19,6 +19,7 @@ func TestAlterTableCapableOfInstantDDL(t *testing.T) {
capabilities.InstantAddDropVirtualColumnFlavorCapability,
capabilities.InstantAddDropColumnFlavorCapability,
capabilities.InstantChangeColumnDefaultFlavorCapability,
+ capabilities.InstantChangeColumnVisibilityCapability,
capabilities.InstantExpandEnumCapability:
return true, nil
}
@@ -272,6 +273,36 @@ func TestAlterTableCapableOfInstantDDL(t *testing.T) {
alter: "alter table t modify column c1 set('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i')",
expectCapableOfInstantDDL: false,
},
+ {
+ name: "make a column invisible",
+ create: "create table t1 (id int, i1 int)",
+ alter: "alter table t1 modify column i1 int invisible",
+ expectCapableOfInstantDDL: true,
+ },
+ {
+ name: "make a column visible",
+ create: "create table t1 (id int, i1 int)",
+ alter: "alter table t1 change column i1 i1 int visible",
+ expectCapableOfInstantDDL: true,
+ },
+ {
+ name: "make a column visible with rename",
+ create: "create table t1 (id int, i1 int)",
+ alter: "alter table t1 change column i1 i2 int visible",
+ expectCapableOfInstantDDL: false,
+ },
+ {
+ name: "make a column invisible via SET",
+ create: "create table t1 (id int, i1 int)",
+ alter: "alter table t1 alter column i1 set invisible",
+ expectCapableOfInstantDDL: true,
+ },
+ {
+ name: "drop column default",
+ create: "create table t1 (id int, i1 int)",
+ alter: "alter table t1 alter column i1 drop default",
+ expectCapableOfInstantDDL: true,
+ },
}
for _, tcase := range tcases {
t.Run(tcase.name, func(t *testing.T) {
diff --git a/go/vt/schemadiff/column.go b/go/vt/schemadiff/column.go
index 7e55192cb06..63181cef9cb 100644
--- a/go/vt/schemadiff/column.go
+++ b/go/vt/schemadiff/column.go
@@ -20,6 +20,7 @@ import (
"strings"
"vitess.io/vitess/go/mysql/collations"
+ "vitess.io/vitess/go/ptr"
"vitess.io/vitess/go/vt/sqlparser"
)
@@ -71,63 +72,100 @@ func NewModifyColumnDiffByDefinition(definition *sqlparser.ColumnDefinition) *Mo
}
type ColumnDefinitionEntity struct {
- columnDefinition *sqlparser.ColumnDefinition
+ ColumnDefinition *sqlparser.ColumnDefinition
+ inPK bool // Does this column appear in the primary key?
tableCharsetCollate *charsetCollate
Env *Environment
}
-func NewColumnDefinitionEntity(env *Environment, c *sqlparser.ColumnDefinition, tableCharsetCollate *charsetCollate) *ColumnDefinitionEntity {
+func NewColumnDefinitionEntity(env *Environment, c *sqlparser.ColumnDefinition, inPK bool, tableCharsetCollate *charsetCollate) *ColumnDefinitionEntity {
return &ColumnDefinitionEntity{
- columnDefinition: c,
+ ColumnDefinition: c,
+ inPK: inPK,
tableCharsetCollate: tableCharsetCollate,
Env: env,
}
}
+func (c *ColumnDefinitionEntity) Name() string {
+ return c.ColumnDefinition.Name.String()
+}
+
+func (c *ColumnDefinitionEntity) NameLowered() string {
+ return c.ColumnDefinition.Name.Lowered()
+}
+
func (c *ColumnDefinitionEntity) Clone() *ColumnDefinitionEntity {
clone := &ColumnDefinitionEntity{
- columnDefinition: sqlparser.Clone(c.columnDefinition),
+ ColumnDefinition: sqlparser.Clone(c.ColumnDefinition),
+ inPK: c.inPK,
tableCharsetCollate: c.tableCharsetCollate,
Env: c.Env,
}
return clone
}
+// SetExplicitDefaultAndNull sets:
+// - NOT NULL, if the columns is part of the PRIMARY KEY
+// - DEFAULT NULL, if the columns is NULLable and no DEFAULT was mentioned
+// Normally in schemadiff we work the opposite way: we strive to have the minimal equivalent representation
+// of a definition. But this function can be used (often in conjunction with Clone()) to enrich a column definition
+// so as to have explicit and authoritative view on any particular column.
+func (c *ColumnDefinitionEntity) SetExplicitDefaultAndNull() {
+ if c.inPK {
+ // Any column in the primary key is implicitly NOT NULL.
+ c.ColumnDefinition.Type.Options.Null = ptr.Of(false)
+ }
+ if c.ColumnDefinition.Type.Options.Null == nil || *c.ColumnDefinition.Type.Options.Null {
+ // Nullable column, let'se see if there's already a DEFAULT.
+ if c.ColumnDefinition.Type.Options.Default == nil {
+ // nope, let's add a DEFAULT NULL
+ c.ColumnDefinition.Type.Options.Default = &sqlparser.NullVal{}
+ }
+ }
+}
+
// SetExplicitCharsetCollate enriches this column definition with collation and charset. Those may be
// already present, or perhaps just one of them is present (in which case we use the one to populate the other),
// or both might be missing, in which case we use the table's charset/collation.
+// Normally in schemadiff we work the opposite way: we strive to have the minimal equivalent representation
+// of a definition. But this function can be used (often in conjunction with Clone()) to enrich a column definition
+// so as to have explicit and authoritative view on any particular column.
func (c *ColumnDefinitionEntity) SetExplicitCharsetCollate() error {
if !c.IsTextual() {
return nil
}
// We will now denormalize the columns charset & collate as needed (if empty, populate from table.)
// Normalizing _this_ column definition:
- if c.columnDefinition.Type.Charset.Name != "" && c.columnDefinition.Type.Options.Collate == "" {
+ if c.ColumnDefinition.Type.Charset.Name != "" && c.ColumnDefinition.Type.Options.Collate == "" {
// Charset defined without collation. Assign the default collation for that charset.
- collation := c.Env.CollationEnv().DefaultCollationForCharset(c.columnDefinition.Type.Charset.Name)
+ collation := c.Env.CollationEnv().DefaultCollationForCharset(c.ColumnDefinition.Type.Charset.Name)
if collation == collations.Unknown {
- return &UnknownColumnCharsetCollationError{Column: c.columnDefinition.Name.String(), Charset: c.tableCharsetCollate.charset}
+ return &UnknownColumnCharsetCollationError{Column: c.ColumnDefinition.Name.String(), Charset: c.tableCharsetCollate.charset}
}
- c.columnDefinition.Type.Options.Collate = c.Env.CollationEnv().LookupName(collation)
+ c.ColumnDefinition.Type.Options.Collate = c.Env.CollationEnv().LookupName(collation)
}
- if c.columnDefinition.Type.Charset.Name == "" && c.columnDefinition.Type.Options.Collate != "" {
+ if c.ColumnDefinition.Type.Charset.Name == "" && c.ColumnDefinition.Type.Options.Collate != "" {
// Column has explicit collation but no charset. We can infer the charset from the collation.
- collationID := c.Env.CollationEnv().LookupByName(c.columnDefinition.Type.Options.Collate)
+ collationID := c.Env.CollationEnv().LookupByName(c.ColumnDefinition.Type.Options.Collate)
charset := c.Env.CollationEnv().LookupCharsetName(collationID)
if charset == "" {
- return &UnknownColumnCollationCharsetError{Column: c.columnDefinition.Name.String(), Collation: c.columnDefinition.Type.Options.Collate}
+ return &UnknownColumnCollationCharsetError{Column: c.ColumnDefinition.Name.String(), Collation: c.ColumnDefinition.Type.Options.Collate}
}
- c.columnDefinition.Type.Charset.Name = charset
+ c.ColumnDefinition.Type.Charset.Name = charset
}
- if c.columnDefinition.Type.Charset.Name == "" {
+ if c.ColumnDefinition.Type.Charset.Name == "" {
// Still nothing? Assign the table's charset/collation.
- c.columnDefinition.Type.Charset.Name = c.tableCharsetCollate.charset
- if c.columnDefinition.Type.Options.Collate = c.tableCharsetCollate.collate; c.columnDefinition.Type.Options.Collate == "" {
+ c.ColumnDefinition.Type.Charset.Name = c.tableCharsetCollate.charset
+ if c.ColumnDefinition.Type.Options.Collate == "" {
+ c.ColumnDefinition.Type.Options.Collate = c.tableCharsetCollate.collate
+ }
+ if c.ColumnDefinition.Type.Options.Collate = c.tableCharsetCollate.collate; c.ColumnDefinition.Type.Options.Collate == "" {
collation := c.Env.CollationEnv().DefaultCollationForCharset(c.tableCharsetCollate.charset)
if collation == collations.Unknown {
- return &UnknownColumnCharsetCollationError{Column: c.columnDefinition.Name.String(), Charset: c.tableCharsetCollate.charset}
+ return &UnknownColumnCharsetCollationError{Column: c.ColumnDefinition.Name.String(), Charset: c.tableCharsetCollate.charset}
}
- c.columnDefinition.Type.Options.Collate = c.Env.CollationEnv().LookupName(collation)
+ c.ColumnDefinition.Type.Options.Collate = c.Env.CollationEnv().LookupName(collation)
}
}
return nil
@@ -168,7 +206,7 @@ func (c *ColumnDefinitionEntity) ColumnDiff(
}
}
- if sqlparser.Equals.RefOfColumnDefinition(cClone.columnDefinition, otherClone.columnDefinition) {
+ if sqlparser.Equals.RefOfColumnDefinition(cClone.ColumnDefinition, otherClone.ColumnDefinition) {
return nil, nil
}
@@ -181,19 +219,228 @@ func (c *ColumnDefinitionEntity) ColumnDiff(
}
switch hints.EnumReorderStrategy {
case EnumReorderStrategyReject:
- otherEnumValuesMap := getEnumValuesMap(otherClone.columnDefinition.Type.EnumValues)
- for ordinal, enumValue := range cClone.columnDefinition.Type.EnumValues {
+ otherEnumValuesMap := getEnumValuesMap(otherClone.ColumnDefinition.Type.EnumValues)
+ for ordinal, enumValue := range cClone.ColumnDefinition.Type.EnumValues {
if otherOrdinal, ok := otherEnumValuesMap[enumValue]; ok {
if ordinal != otherOrdinal {
- return nil, &EnumValueOrdinalChangedError{Table: tableName, Column: cClone.columnDefinition.Name.String(), Value: enumValue, Ordinal: ordinal, NewOrdinal: otherOrdinal}
+ return nil, &EnumValueOrdinalChangedError{Table: tableName, Column: cClone.ColumnDefinition.Name.String(), Value: enumValue, Ordinal: ordinal, NewOrdinal: otherOrdinal}
}
}
}
}
- return NewModifyColumnDiffByDefinition(other.columnDefinition), nil
+ return NewModifyColumnDiffByDefinition(other.ColumnDefinition), nil
+}
+
+// Type returns the column's type
+func (c *ColumnDefinitionEntity) Type() string {
+ return c.ColumnDefinition.Type.Type
}
// IsTextual returns true when this column is of textual type, and is capable of having a character set property
func (c *ColumnDefinitionEntity) IsTextual() bool {
- return charsetTypes[strings.ToLower(c.columnDefinition.Type.Type)]
+ return charsetTypes[strings.ToLower(c.Type())]
+}
+
+// IsGenerated returns true when this column is generated, and indicates the storage type (virtual/stored)
+func IsGeneratedColumn(col *sqlparser.ColumnDefinition) (bool, sqlparser.ColumnStorage) {
+ if col == nil {
+ return false, 0
+ }
+ if col.Type.Options == nil {
+ return false, 0
+ }
+ if col.Type.Options.As == nil {
+ return false, 0
+ }
+ return true, col.Type.Options.Storage
+}
+
+// IsGenerated returns true when this column is generated, and indicates the storage type (virtual/stored)
+func (c *ColumnDefinitionEntity) IsGenerated() bool {
+ isGenerated, _ := IsGeneratedColumn(c.ColumnDefinition)
+ return isGenerated
+}
+
+// IsNullable returns true when this column is NULLable
+func (c *ColumnDefinitionEntity) IsNullable() bool {
+ if c.inPK {
+ return false
+ }
+ return c.ColumnDefinition.Type.Options.Null == nil || *c.ColumnDefinition.Type.Options.Null
+}
+
+// IsDefaultNull returns true when this column has DEFAULT NULL
+func (c *ColumnDefinitionEntity) IsDefaultNull() bool {
+ if !c.IsNullable() {
+ return false
+ }
+ _, ok := c.ColumnDefinition.Type.Options.Default.(*sqlparser.NullVal)
+ return ok
+}
+
+// IsDefaultNull returns true when this column has DEFAULT NULL
+func (c *ColumnDefinitionEntity) HasDefault() bool {
+ if c.ColumnDefinition.Type.Options.Default == nil {
+ return false
+ }
+ if c.IsDefaultNull() {
+ return true
+ }
+ return true
+}
+
+// IsAutoIncrement returns true when this column is AUTO_INCREMENT
+func (c *ColumnDefinitionEntity) IsAutoIncrement() bool {
+ return c.ColumnDefinition.Type.Options.Autoincrement
+}
+
+// IsUnsigned returns true when this column is UNSIGNED
+func (c *ColumnDefinitionEntity) IsUnsigned() bool {
+ return c.ColumnDefinition.Type.Unsigned
+}
+
+// IsNumeric returns true when this column is a numeric type
+func (c *ColumnDefinitionEntity) IsIntegralType() bool {
+ return IsIntegralType(c.Type())
+}
+
+// IsFloatingPointType returns true when this column is a floating point type
+func (c *ColumnDefinitionEntity) IsFloatingPointType() bool {
+ return IsFloatingPointType(c.Type())
+}
+
+// IsDecimalType returns true when this column is a decimal type
+func (c *ColumnDefinitionEntity) IsDecimalType() bool {
+ return IsDecimalType(c.Type())
+}
+
+// HasBlobTypeStorage returns true when this column is a text/blob type
+func (c *ColumnDefinitionEntity) HasBlobTypeStorage() bool {
+ return BlobTypeStorage(c.Type()) != 0
+}
+
+// Charset returns the column's charset
+func (c *ColumnDefinitionEntity) Charset() string {
+ return c.ColumnDefinition.Type.Charset.Name
+}
+
+// Collate returns the column's collation
+func (c *ColumnDefinitionEntity) Collate() string {
+ return c.ColumnDefinition.Type.Options.Collate
+}
+
+func (c *ColumnDefinitionEntity) EnumValues() []string {
+ return c.ColumnDefinition.Type.EnumValues
+}
+
+func (c *ColumnDefinitionEntity) HasEnumValues() bool {
+ return len(c.EnumValues()) > 0
+}
+
+// EnumValuesOrdinals returns a map of enum values to their ordinals
+func (c *ColumnDefinitionEntity) EnumValuesOrdinals() map[string]int {
+ m := make(map[string]int, len(c.ColumnDefinition.Type.EnumValues))
+ for i, enumValue := range c.ColumnDefinition.Type.EnumValues {
+ m[enumValue] = i + 1
+ }
+ return m
+}
+
+// EnumOrdinalValues returns a map of enum ordinals to their values
+func (c *ColumnDefinitionEntity) EnumOrdinalValues() map[int]string {
+ m := make(map[int]string, len(c.ColumnDefinition.Type.EnumValues))
+ for i, enumValue := range c.ColumnDefinition.Type.EnumValues {
+ // SET and ENUM values are 1 indexed.
+ m[i+1] = enumValue
+ }
+ return m
+}
+
+// Length returns the type length (e.g. 17 for VARCHAR(17), 10 for DECIMAL(10,2), 6 for TIMESTAMP(6), etc.)
+func (c *ColumnDefinitionEntity) Length() int {
+ if c.ColumnDefinition.Type.Length == nil {
+ return 0
+ }
+ return *c.ColumnDefinition.Type.Length
+}
+
+// Scale returns the type scale (e.g. 2 for DECIMAL(10,2))
+func (c *ColumnDefinitionEntity) Scale() int {
+ if c.ColumnDefinition.Type.Scale == nil {
+ return 0
+ }
+ return *c.ColumnDefinition.Type.Scale
+}
+
+// ColumnDefinitionEntityList is a formalized list of ColumnDefinitionEntity, with some
+// utility functions.
+type ColumnDefinitionEntityList struct {
+ Entities []*ColumnDefinitionEntity
+ byName map[string]*ColumnDefinitionEntity
+}
+
+func NewColumnDefinitionEntityList(entities []*ColumnDefinitionEntity) *ColumnDefinitionEntityList {
+ list := &ColumnDefinitionEntityList{
+ Entities: entities,
+ byName: make(map[string]*ColumnDefinitionEntity),
+ }
+ for _, entity := range entities {
+ list.byName[entity.Name()] = entity
+ list.byName[entity.NameLowered()] = entity
+ }
+ return list
+}
+
+func (l *ColumnDefinitionEntityList) Len() int {
+ return len(l.Entities)
+}
+
+// Names returns the names of all the columns in this list
+func (l *ColumnDefinitionEntityList) Names() []string {
+ names := make([]string, len(l.Entities))
+ for i, entity := range l.Entities {
+ names[i] = entity.Name()
+ }
+ return names
+}
+
+// GetColumn returns the column with the given name, or nil if not found
+func (l *ColumnDefinitionEntityList) GetColumn(name string) *ColumnDefinitionEntity {
+ return l.byName[name]
+}
+
+// Contains returns true when this list contains all the entities from the other list
+func (l *ColumnDefinitionEntityList) Contains(other *ColumnDefinitionEntityList) bool {
+ for _, entity := range other.Entities {
+ if l.GetColumn(entity.NameLowered()) == nil {
+ return false
+ }
+ }
+ return true
+}
+
+// Union returns a new ColumnDefinitionEntityList with all the entities from this list and the other list
+func (l *ColumnDefinitionEntityList) Union(other *ColumnDefinitionEntityList) *ColumnDefinitionEntityList {
+ entities := append(l.Entities, other.Entities...)
+ return NewColumnDefinitionEntityList(entities)
+}
+
+// Clone creates a copy of this list, with copies of the entities
+func (l *ColumnDefinitionEntityList) Clone() *ColumnDefinitionEntityList {
+ entities := make([]*ColumnDefinitionEntity, len(l.Entities))
+ for i, entity := range l.Entities {
+ entities[i] = entity.Clone()
+ }
+ return NewColumnDefinitionEntityList(entities)
+}
+
+// Filter returns a new subset ColumnDefinitionEntityList with only the entities that pass the filter
+func (l *ColumnDefinitionEntityList) Filter(include func(entity *ColumnDefinitionEntity) bool) *ColumnDefinitionEntityList {
+ var entities []*ColumnDefinitionEntity
+ for _, entity := range l.Entities {
+ if include(entity) {
+ entities = append(entities, entity)
+ }
+ }
+ return NewColumnDefinitionEntityList(entities)
}
diff --git a/go/vt/schemadiff/column_test.go b/go/vt/schemadiff/column_test.go
new file mode 100644
index 00000000000..f1b8f9e4f75
--- /dev/null
+++ b/go/vt/schemadiff/column_test.go
@@ -0,0 +1,497 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 schemadiff
+
+import (
+ "fmt"
+ "testing"
+
+ "golang.org/x/exp/maps"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestColumnFunctions(t *testing.T) {
+ table := `
+ create table t (
+ id int,
+ col1 int,
+ col2 int not null,
+ col3 int default null,
+ col4 int default 1,
+ COL5 int default 1,
+ ts1 timestamp,
+ ts2 timestamp(3) null,
+ ts3 timestamp(6) not null,
+ primary key (id)
+ )`
+ env := NewTestEnv()
+ createTableEntity, err := NewCreateTableEntityFromSQL(env, table)
+ require.NoError(t, err)
+ m := createTableEntity.ColumnDefinitionEntitiesMap()
+ for _, col := range m {
+ col.SetExplicitDefaultAndNull()
+ err := col.SetExplicitCharsetCollate()
+ require.NoError(t, err)
+ }
+
+ t.Run("nullable", func(t *testing.T) {
+ assert.False(t, m["id"].IsNullable())
+ assert.True(t, m["col1"].IsNullable())
+ assert.False(t, m["col2"].IsNullable())
+ assert.True(t, m["col3"].IsNullable())
+ assert.True(t, m["col4"].IsNullable())
+ assert.True(t, m["col5"].IsNullable())
+ assert.True(t, m["ts1"].IsNullable())
+ assert.True(t, m["ts2"].IsNullable())
+ assert.False(t, m["ts3"].IsNullable())
+ })
+ t.Run("default null", func(t *testing.T) {
+ assert.False(t, m["id"].IsDefaultNull())
+ assert.True(t, m["col1"].IsDefaultNull())
+ assert.False(t, m["col2"].IsDefaultNull())
+ assert.True(t, m["col3"].IsDefaultNull())
+ assert.False(t, m["col4"].IsDefaultNull())
+ assert.False(t, m["col5"].IsDefaultNull())
+ assert.True(t, m["ts1"].IsDefaultNull())
+ assert.True(t, m["ts2"].IsDefaultNull())
+ assert.False(t, m["ts3"].IsDefaultNull())
+ })
+ t.Run("has default", func(t *testing.T) {
+ assert.False(t, m["id"].HasDefault())
+ assert.True(t, m["col1"].HasDefault())
+ assert.False(t, m["col2"].HasDefault())
+ assert.True(t, m["col3"].HasDefault())
+ assert.True(t, m["col4"].HasDefault())
+ assert.True(t, m["col5"].HasDefault())
+ assert.True(t, m["ts1"].HasDefault())
+ assert.True(t, m["ts2"].HasDefault())
+ assert.False(t, m["ts3"].HasDefault())
+ })
+}
+
+func TestExpands(t *testing.T) {
+ tcases := []struct {
+ source string
+ target string
+ expands bool
+ msg string
+ }{
+ {
+ source: "int",
+ target: "int",
+ },
+ {
+ source: "int",
+ target: "smallint",
+ },
+ {
+ source: "int",
+ target: "smallint unsigned",
+ },
+ {
+ source: "int unsigned",
+ target: "tinyint",
+ expands: true,
+ msg: "source is unsigned, target is signed",
+ },
+ {
+ source: "int unsigned",
+ target: "tinyint signed",
+ expands: true,
+ msg: "source is unsigned, target is signed",
+ },
+ {
+ source: "int",
+ target: "tinyint",
+ },
+ {
+ source: "int",
+ target: "bigint",
+ expands: true,
+ msg: "increased integer range",
+ },
+ {
+ source: "int",
+ target: "bigint unsigned",
+ expands: true,
+ msg: "increased integer range",
+ },
+ {
+ source: "int",
+ target: "int unsigned",
+ expands: true,
+ msg: "target unsigned value exceeds source unsigned value",
+ },
+ {
+ source: "int unsigned",
+ target: "int",
+ expands: true,
+ msg: "source is unsigned, target is signed",
+ },
+ {
+ source: "int",
+ target: "int default null",
+ },
+ {
+ source: "int default null",
+ target: "int",
+ },
+ {
+ source: "int",
+ target: "int not null",
+ },
+ {
+ source: "int not null",
+ target: "int",
+ expands: true,
+ msg: "target is NULL-able, source is not",
+ },
+ {
+ source: "int not null",
+ target: "int default null",
+ expands: true,
+ msg: "target is NULL-able, source is not",
+ },
+ {
+ source: "float",
+ target: "int",
+ },
+ {
+ source: "int",
+ target: "float",
+ expands: true,
+ msg: "target is floating point, source is not",
+ },
+ {
+ source: "float",
+ target: "double",
+ expands: true,
+ msg: "increased floating point range",
+ },
+ {
+ source: "decimal(5,2)",
+ target: "float",
+ expands: true,
+ msg: "target is floating point, source is not",
+ },
+ {
+ source: "int",
+ target: "decimal",
+ expands: true,
+ msg: "target is decimal, source is not",
+ },
+ {
+ source: "int",
+ target: "decimal(5,2)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "int",
+ target: "decimal(5,0)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "decimal(5,2)", // 123.45
+ target: "decimal(3,2)", // 1.23
+ },
+ {
+ source: "decimal(5,2)", // 123.45
+ target: "decimal(4,1)", // 123.4
+ },
+ {
+ source: "decimal(5,2)", // 123.45
+ target: "decimal(5,1)", // 1234.5
+ expands: true,
+ msg: "increased decimal range",
+ },
+ {
+ source: "char(7)",
+ target: "char(7)",
+ },
+ {
+ source: "char(7)",
+ target: "varchar(7)",
+ },
+ {
+ source: "char(7)",
+ target: "varchar(5)",
+ },
+ {
+ source: "char(5)",
+ target: "varchar(7)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "varchar(5)",
+ target: "char(7)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "tinytext",
+ target: "tinytext",
+ },
+ {
+ source: "tinytext",
+ target: "tinyblob",
+ },
+ {
+ source: "mediumtext",
+ target: "tinytext",
+ },
+ {
+ source: "mediumblob",
+ target: "tinytext",
+ },
+ {
+ source: "tinytext",
+ target: "text",
+ expands: true,
+ msg: "increased blob range",
+ },
+ {
+ source: "tinytext",
+ target: "mediumblob",
+ expands: true,
+ msg: "increased blob range",
+ },
+ {
+ source: "timestamp",
+ target: "timestamp",
+ },
+ {
+ source: "timestamp",
+ target: "time",
+ },
+ {
+ source: "datetime",
+ target: "timestamp",
+ },
+ {
+ source: "datetime",
+ target: "date",
+ },
+ {
+ source: "time",
+ target: "timestamp",
+ expands: true,
+ msg: "target is expanded data type of source",
+ },
+ {
+ source: "timestamp",
+ target: "datetime",
+ expands: true,
+ msg: "target is expanded data type of source",
+ },
+ {
+ source: "date",
+ target: "datetime",
+ expands: true,
+ msg: "target is expanded data type of source",
+ },
+ {
+ source: "timestamp",
+ target: "timestamp(3)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "timestamp",
+ target: "timestamp(6)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "timestamp(3)",
+ target: "timestamp(6)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "timestamp(6)",
+ target: "timestamp(3)",
+ },
+ {
+ source: "timestamp(6)",
+ target: "timestamp",
+ },
+ {
+ source: "timestamp",
+ target: "time(3)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "datetime",
+ target: "time(3)",
+ expands: true,
+ msg: "increased length",
+ },
+ {
+ source: "enum('a','b')",
+ target: "enum('a','b')",
+ },
+ {
+ source: "enum('a','b')",
+ target: "enum('a')",
+ },
+ {
+ source: "enum('a','b')",
+ target: "enum('b')",
+ expands: true,
+ msg: "target enum/set expands or reorders source enum/set",
+ },
+ {
+ source: "enum('a','b')",
+ target: "enum('a','b','c')",
+ expands: true,
+ msg: "target enum/set expands or reorders source enum/set",
+ },
+ {
+ source: "enum('a','b')",
+ target: "enum('a','x')",
+ expands: true,
+ msg: "target enum/set expands or reorders source enum/set",
+ },
+ {
+ source: "set('a','b')",
+ target: "set('a','b')",
+ },
+ {
+ source: "set('a','b')",
+ target: "set('a','b','c')",
+ expands: true,
+ msg: "target enum/set expands or reorders source enum/set",
+ },
+ }
+ env := NewTestEnv()
+ for _, tcase := range tcases {
+ t.Run(tcase.source+" -> "+tcase.target, func(t *testing.T) {
+ fromCreateTableSQL := fmt.Sprintf("create table t (col %s)", tcase.source)
+ from, err := NewCreateTableEntityFromSQL(env, fromCreateTableSQL)
+ require.NoError(t, err)
+
+ toCreateTableSQL := fmt.Sprintf("create table t (col %s)", tcase.target)
+ to, err := NewCreateTableEntityFromSQL(env, toCreateTableSQL)
+ require.NoError(t, err)
+
+ require.Len(t, from.ColumnDefinitionEntities(), 1)
+ fromCol := from.ColumnDefinitionEntities()[0]
+ require.Len(t, to.ColumnDefinitionEntities(), 1)
+ toCol := to.ColumnDefinitionEntities()[0]
+
+ expands, message := ColumnChangeExpandsDataRange(fromCol, toCol)
+ assert.Equal(t, tcase.expands, expands, message)
+ if expands {
+ require.NotEmpty(t, tcase.msg, message)
+ }
+ assert.Contains(t, message, tcase.msg)
+ })
+ }
+}
+
+func TestColumnDefinitionEntityList(t *testing.T) {
+ table := `
+ create table t (
+ id int,
+ col1 int,
+ Col2 int not null,
+ primary key (id)
+ )`
+ env := NewTestEnv()
+ createTableEntity, err := NewCreateTableEntityFromSQL(env, table)
+ require.NoError(t, err)
+ entities := createTableEntity.ColumnDefinitionEntities()
+ require.NotEmpty(t, entities)
+ list := NewColumnDefinitionEntityList(entities)
+ assert.NotNil(t, list.GetColumn("id"))
+ assert.NotNil(t, list.GetColumn("col1"))
+ assert.NotNil(t, list.GetColumn("Col2"))
+ assert.NotNil(t, list.GetColumn("col2")) // we also allow lower case
+ assert.Nil(t, list.GetColumn("COL2"))
+ assert.Nil(t, list.GetColumn("ID"))
+ assert.Nil(t, list.GetColumn("Col1"))
+ assert.Nil(t, list.GetColumn("col3"))
+}
+
+func TestColumnDefinitionEntityListSubset(t *testing.T) {
+ table1 := `
+ create table t (
+ ID int,
+ col1 int,
+ Col2 int not null,
+ primary key (id)
+ )`
+ table2 := `
+ create table t (
+ id int,
+ Col1 int,
+ primary key (id)
+ )`
+ env := NewTestEnv()
+ createTableEntity1, err := NewCreateTableEntityFromSQL(env, table1)
+ require.NoError(t, err)
+ entities1 := createTableEntity1.ColumnDefinitionEntities()
+ require.NotEmpty(t, entities1)
+ list1 := NewColumnDefinitionEntityList(entities1)
+
+ createTableEntity2, err := NewCreateTableEntityFromSQL(env, table2)
+ require.NoError(t, err)
+ entities2 := createTableEntity2.ColumnDefinitionEntities()
+ require.NotEmpty(t, entities2)
+ list2 := NewColumnDefinitionEntityList(entities2)
+
+ assert.True(t, list1.Contains(list2))
+ assert.False(t, list2.Contains(list1))
+}
+
+func TestColumnDefinitionEntity(t *testing.T) {
+ table1 := `
+ create table t (
+ it int,
+ e enum('a','b','c'),
+ primary key (id)
+ )`
+ env := NewTestEnv()
+ createTableEntity1, err := NewCreateTableEntityFromSQL(env, table1)
+ require.NoError(t, err)
+ entities1 := createTableEntity1.ColumnDefinitionEntities()
+ require.NotEmpty(t, entities1)
+ list1 := NewColumnDefinitionEntityList(entities1)
+
+ t.Run("enum", func(t *testing.T) {
+ enumCol := list1.GetColumn("e")
+ require.NotNil(t, enumCol)
+ assert.Equal(t, []string{"'a'", "'b'", "'c'"}, enumCol.EnumValues())
+
+ {
+ ordinalsMap := enumCol.EnumValuesOrdinals()
+ assert.ElementsMatch(t, []int{1, 2, 3}, maps.Values(ordinalsMap))
+ assert.ElementsMatch(t, []string{"'a'", "'b'", "'c'"}, maps.Keys(ordinalsMap))
+ }
+ {
+ valuesMap := enumCol.EnumOrdinalValues()
+ assert.ElementsMatch(t, []int{1, 2, 3}, maps.Keys(valuesMap))
+ assert.ElementsMatch(t, []string{"'a'", "'b'", "'c'"}, maps.Values(valuesMap))
+ }
+ })
+}
diff --git a/go/vt/schemadiff/key.go b/go/vt/schemadiff/key.go
new file mode 100644
index 00000000000..865073a5a98
--- /dev/null
+++ b/go/vt/schemadiff/key.go
@@ -0,0 +1,162 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 schemadiff
+
+import (
+ "vitess.io/vitess/go/vt/sqlparser"
+)
+
+// IndexDefinitionEntity represents an index definition in a CREATE TABLE statement,
+// and includes the list of columns that are part of the index.
+type IndexDefinitionEntity struct {
+ IndexDefinition *sqlparser.IndexDefinition
+ ColumnList *ColumnDefinitionEntityList
+ Env *Environment
+}
+
+func NewIndexDefinitionEntity(env *Environment, indexDefinition *sqlparser.IndexDefinition, columnDefinitionEntitiesList *ColumnDefinitionEntityList) *IndexDefinitionEntity {
+ return &IndexDefinitionEntity{
+ IndexDefinition: indexDefinition,
+ ColumnList: columnDefinitionEntitiesList,
+ Env: env,
+ }
+}
+
+func (i *IndexDefinitionEntity) Name() string {
+ return i.IndexDefinition.Info.Name.String()
+}
+
+func (i *IndexDefinitionEntity) NameLowered() string {
+ return i.IndexDefinition.Info.Name.Lowered()
+}
+
+// Clone returns a copy of this list, with copies of all the entities.
+func (i *IndexDefinitionEntity) Clone() *IndexDefinitionEntity {
+ clone := &IndexDefinitionEntity{
+ IndexDefinition: sqlparser.Clone(i.IndexDefinition),
+ ColumnList: i.ColumnList.Clone(),
+ Env: i.Env,
+ }
+ return clone
+}
+
+func (i *IndexDefinitionEntity) Len() int {
+ return len(i.IndexDefinition.Columns)
+}
+
+// IsPrimary returns true if the index is a primary key.
+func (i *IndexDefinitionEntity) IsPrimary() bool {
+ return i.IndexDefinition.Info.Type == sqlparser.IndexTypePrimary
+}
+
+// IsUnique returns true if the index is a unique key.
+func (i *IndexDefinitionEntity) IsUnique() bool {
+ return i.IndexDefinition.Info.IsUnique()
+}
+
+// HasNullable returns true if any of the columns in the index are nullable.
+func (i *IndexDefinitionEntity) HasNullable() bool {
+ for _, col := range i.ColumnList.Entities {
+ if col.IsNullable() {
+ return true
+ }
+ }
+ return false
+}
+
+// HasFloat returns true if any of the columns in the index are floating point types.
+func (i *IndexDefinitionEntity) HasFloat() bool {
+ for _, col := range i.ColumnList.Entities {
+ if col.IsFloatingPointType() {
+ return true
+ }
+ }
+ return false
+}
+
+// HasColumnPrefix returns true if any of the columns in the index have a length prefix.
+func (i *IndexDefinitionEntity) HasColumnPrefix() bool {
+ for _, col := range i.IndexDefinition.Columns {
+ if col.Length != nil {
+ return true
+ }
+ }
+ return false
+}
+
+// ColumnNames returns the names of the columns in the index.
+func (i *IndexDefinitionEntity) ColumnNames() []string {
+ names := make([]string, 0, len(i.IndexDefinition.Columns))
+ for _, col := range i.IndexDefinition.Columns {
+ names = append(names, col.Column.String())
+ }
+ return names
+}
+
+// ContainsColumns returns true if the index contains all the columns in the given list.
+func (i *IndexDefinitionEntity) ContainsColumns(columns *ColumnDefinitionEntityList) bool {
+ return i.ColumnList.Contains(columns)
+}
+
+// CoveredByColumns returns true if the index is covered by the given list of columns.
+func (i *IndexDefinitionEntity) CoveredByColumns(columns *ColumnDefinitionEntityList) bool {
+ return columns.Contains(i.ColumnList)
+}
+
+// IndexDefinitionEntityList is a formalized list of IndexDefinitionEntity objects with a few
+// utility methods.
+type IndexDefinitionEntityList struct {
+ Entities []*IndexDefinitionEntity
+}
+
+func NewIndexDefinitionEntityList(entities []*IndexDefinitionEntity) *IndexDefinitionEntityList {
+ return &IndexDefinitionEntityList{
+ Entities: entities,
+ }
+}
+
+func (l *IndexDefinitionEntityList) Len() int {
+ return len(l.Entities)
+}
+
+// Names returns the names of the indexes in the list.
+func (l *IndexDefinitionEntityList) Names() []string {
+ names := make([]string, len(l.Entities))
+ for i, entity := range l.Entities {
+ names[i] = entity.Name()
+ }
+ return names
+}
+
+// SubsetCoveredByColumns returns a new list of indexes that are covered by the given list of columns.
+func (l *IndexDefinitionEntityList) SubsetCoveredByColumns(columns *ColumnDefinitionEntityList) *IndexDefinitionEntityList {
+ var subset []*IndexDefinitionEntity
+ for _, entity := range l.Entities {
+ if entity.CoveredByColumns(columns) {
+ subset = append(subset, entity)
+ }
+ }
+ return NewIndexDefinitionEntityList(subset)
+}
+
+// First returns the first index in the list, or nil if the list is empty.
+func (l *IndexDefinitionEntityList) First() *IndexDefinitionEntity {
+ if len(l.Entities) == 0 {
+ return nil
+ }
+ return l.Entities[0]
+}
diff --git a/go/vt/schemadiff/key_test.go b/go/vt/schemadiff/key_test.go
new file mode 100644
index 00000000000..f11d5589ab3
--- /dev/null
+++ b/go/vt/schemadiff/key_test.go
@@ -0,0 +1,185 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 schemadiff
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestIndexDefinitionEntityMap(t *testing.T) {
+ table := `
+ create table t (
+ id int,
+ col1 int,
+ Col2 int not null,
+ col3 int not null default 3,
+ f float not null,
+ v varchar(32),
+ primary key (id),
+ unique key ukid (id),
+ unique key uk1 (col1),
+ unique key uk2 (Col2),
+ unique key uk3 (col3),
+ key k1 (col1),
+ key k2 (Col2),
+ key k3 (col3),
+ key kf (f),
+ key kf2 (f, Col2),
+ key kv (v),
+ key kv1 (v, col1),
+ key kv2 (v(10), Col2),
+ unique key uk12 (col1, Col2),
+ unique key uk21 (col2, Col1),
+ unique key uk23 (col2, col3),
+ unique key ukid3 (id, col3)
+ )`
+ tcases := []struct {
+ key string
+ unique bool
+ columns []string
+ nullable bool
+ float bool
+ prefix bool
+ }{
+ {
+ key: "primary",
+ unique: true,
+ columns: []string{"id"},
+ nullable: false,
+ },
+ {
+ key: "ukid",
+ unique: true,
+ columns: []string{"id"},
+ nullable: false,
+ },
+ {
+ key: "uk1",
+ unique: true,
+ columns: []string{"col1"},
+ nullable: true,
+ },
+ {
+ key: "uk2",
+ unique: true,
+ columns: []string{"Col2"},
+ nullable: false,
+ },
+ {
+ key: "uk3",
+ unique: true,
+ columns: []string{"col3"},
+ nullable: false,
+ },
+ {
+ key: "k1",
+ unique: false,
+ columns: []string{"col1"},
+ nullable: true,
+ },
+ {
+ key: "k2",
+ unique: false,
+ columns: []string{"Col2"},
+ nullable: false,
+ },
+ {
+ key: "k3",
+ unique: false,
+ columns: []string{"col3"},
+ nullable: false,
+ },
+ {
+ key: "kf",
+ unique: false,
+ columns: []string{"f"},
+ nullable: false,
+ float: true,
+ },
+ {
+ key: "kf2",
+ unique: false,
+ columns: []string{"f", "Col2"},
+ nullable: false,
+ float: true,
+ },
+ {
+ key: "kv",
+ unique: false,
+ columns: []string{"v"},
+ nullable: true,
+ },
+ {
+ key: "kv1",
+ unique: false,
+ columns: []string{"v", "col1"},
+ nullable: true,
+ },
+ {
+ key: "kv2",
+ unique: false,
+ columns: []string{"v", "Col2"},
+ nullable: true,
+ prefix: true,
+ },
+ {
+ key: "uk12",
+ unique: true,
+ columns: []string{"col1", "Col2"},
+ nullable: true,
+ },
+ {
+ key: "uk21",
+ unique: true,
+ columns: []string{"col2", "Col1"},
+ nullable: true,
+ },
+ {
+ key: "uk23",
+ unique: true,
+ columns: []string{"col2", "col3"},
+ nullable: false,
+ },
+ {
+ key: "ukid3",
+ unique: true,
+ columns: []string{"id", "col3"},
+ nullable: false,
+ },
+ }
+ env := NewTestEnv()
+ createTableEntity, err := NewCreateTableEntityFromSQL(env, table)
+ require.NoError(t, err)
+ err = createTableEntity.validate()
+ require.NoError(t, err)
+ m := createTableEntity.IndexDefinitionEntitiesMap()
+ require.NotEmpty(t, m)
+ for _, tcase := range tcases {
+ t.Run(tcase.key, func(t *testing.T) {
+ key := m[tcase.key]
+ require.NotNil(t, key)
+ assert.Equal(t, tcase.unique, key.IsUnique())
+ assert.Equal(t, tcase.columns, key.ColumnNames())
+ assert.Equal(t, tcase.nullable, key.HasNullable())
+ assert.Equal(t, tcase.float, key.HasFloat())
+ assert.Equal(t, tcase.prefix, key.HasColumnPrefix())
+ })
+ }
+}
diff --git a/go/vt/schemadiff/mysql.go b/go/vt/schemadiff/mysql.go
index 624897e2e43..65adcc1b7a1 100644
--- a/go/vt/schemadiff/mysql.go
+++ b/go/vt/schemadiff/mysql.go
@@ -21,20 +21,26 @@ var engineCasing = map[string]string{
"MYISAM": "MyISAM",
}
-var integralTypes = map[string]bool{
- "tinyint": true,
- "smallint": true,
- "mediumint": true,
- "int": true,
- "bigint": true,
+// integralTypes maps known integer types to their byte storage size
+var integralTypes = map[string]int{
+ "tinyint": 1,
+ "smallint": 2,
+ "mediumint": 3,
+ "int": 4,
+ "bigint": 8,
}
-var floatTypes = map[string]bool{
- "float": true,
- "float4": true,
- "float8": true,
- "double": true,
- "real": true,
+var floatTypes = map[string]int{
+ "float": 4,
+ "float4": 4,
+ "float8": 8,
+ "double": 8,
+ "real": 8,
+}
+
+var decimalTypes = map[string]bool{
+ "decimal": true,
+ "numeric": true,
}
var charsetTypes = map[string]bool{
@@ -48,6 +54,56 @@ var charsetTypes = map[string]bool{
"set": true,
}
+var blobStorageExponent = map[string]int{
+ "tinyblob": 8,
+ "tinytext": 8,
+ "blob": 16,
+ "text": 16,
+ "mediumblob": 24,
+ "mediumtext": 24,
+ "longblob": 32,
+ "longtext": 32,
+}
+
+func IsFloatingPointType(columnType string) bool {
+ _, ok := floatTypes[columnType]
+ return ok
+}
+
+func FloatingPointTypeStorage(columnType string) int {
+ return floatTypes[columnType]
+}
+
func IsIntegralType(columnType string) bool {
+ _, ok := integralTypes[columnType]
+ return ok
+}
+
+func IntegralTypeStorage(columnType string) int {
return integralTypes[columnType]
}
+
+func IsDecimalType(columnType string) bool {
+ return decimalTypes[columnType]
+}
+
+func BlobTypeStorage(columnType string) int {
+ return blobStorageExponent[columnType]
+}
+
+// expandedDataTypes maps some known and difficult-to-compute by INFORMATION_SCHEMA data types which expand other data types.
+// For example, in "date:datetime", datetime expands date because it has more precision. In "timestamp:date" date expands timestamp
+// because it can contain years not covered by timestamp.
+var expandedDataTypes = map[string]bool{
+ "time:datetime": true,
+ "date:datetime": true,
+ "timestamp:datetime": true,
+ "time:timestamp": true,
+ "date:timestamp": true,
+ "timestamp:date": true,
+}
+
+func IsExpandingDataType(sourceType string, targetType string) bool {
+ _, ok := expandedDataTypes[sourceType+":"+targetType]
+ return ok
+}
diff --git a/go/vt/schemadiff/onlineddl.go b/go/vt/schemadiff/onlineddl.go
new file mode 100644
index 00000000000..66908e502f5
--- /dev/null
+++ b/go/vt/schemadiff/onlineddl.go
@@ -0,0 +1,590 @@
+/*
+Copyright 2022 The Vitess Authors.
+
+Licensed 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 schemadiff
+
+import (
+ "fmt"
+ "math"
+ "sort"
+ "strings"
+
+ "vitess.io/vitess/go/vt/sqlparser"
+)
+
+// ColumnChangeExpandsDataRange sees if target column has any value set/range that is impossible in source column.
+func ColumnChangeExpandsDataRange(source *ColumnDefinitionEntity, target *ColumnDefinitionEntity) (bool, string) {
+ if target.IsNullable() && !source.IsNullable() {
+ return true, "target is NULL-able, source is not"
+ }
+ if target.Length() > source.Length() {
+ return true, "increased length"
+ }
+ if target.Scale() > source.Scale() {
+ return true, "increased scale"
+ }
+ if source.IsUnsigned() && !target.IsUnsigned() {
+ return true, "source is unsigned, target is signed"
+ }
+ if IntegralTypeStorage(target.Type()) > IntegralTypeStorage(source.Type()) && IntegralTypeStorage(source.Type()) != 0 {
+ return true, "increased integer range"
+ }
+ if IntegralTypeStorage(source.Type()) <= IntegralTypeStorage(target.Type()) &&
+ !source.IsUnsigned() && target.IsUnsigned() {
+ // e.g. INT SIGNED => INT UNSIGNED, INT SIGNED => BIGINT UNSIGNED
+ return true, "target unsigned value exceeds source unsigned value"
+ }
+ if FloatingPointTypeStorage(target.Type()) > FloatingPointTypeStorage(source.Type()) && FloatingPointTypeStorage(source.Type()) != 0 {
+ return true, "increased floating point range"
+ }
+ if target.IsFloatingPointType() && !source.IsFloatingPointType() {
+ return true, "target is floating point, source is not"
+ }
+ if target.IsDecimalType() && !source.IsDecimalType() {
+ return true, "target is decimal, source is not"
+ }
+ if target.IsDecimalType() && source.IsDecimalType() {
+ if target.Length()-target.Scale() > source.Length()-source.Scale() {
+ return true, "increased decimal range"
+ }
+ }
+ if IsExpandingDataType(source.Type(), target.Type()) {
+ return true, "target is expanded data type of source"
+ }
+ if BlobTypeStorage(target.Type()) > BlobTypeStorage(source.Type()) && BlobTypeStorage(source.Type()) != 0 {
+ return true, "increased blob range"
+ }
+ if source.Charset() != target.Charset() {
+ if target.Charset() == "utf8mb4" {
+ return true, "expand character set to utf8mb4"
+ }
+ if strings.HasPrefix(target.Charset(), "utf8") && !strings.HasPrefix(source.Charset(), "utf8") {
+ // not utf to utf
+ return true, "expand character set to utf8"
+ }
+ }
+ for _, colType := range []string{"enum", "set"} {
+ // enums and sets have very similar properties, and are practically identical in our analysis
+ if source.Type() == colType {
+ // this is an enum or a set
+ if target.Type() != colType {
+ return true, "conversion from enum/set to non-enum/set adds potential values"
+ }
+ // target is an enum or a set. See if all values on target exist in source
+ sourceEnumTokensMap := source.EnumOrdinalValues()
+ targetEnumTokensMap := target.EnumOrdinalValues()
+ for k, v := range targetEnumTokensMap {
+ if sourceEnumTokensMap[k] != v {
+ return true, "target enum/set expands or reorders source enum/set"
+ }
+ }
+ }
+ }
+ return false, ""
+}
+
+// IsValidIterationKey returns true if the key is eligible for Online DDL iteration.
+func IsValidIterationKey(key *IndexDefinitionEntity) bool {
+ if key == nil {
+ return false
+ }
+ if !key.IsUnique() {
+ return false
+ }
+ if key.HasFloat() {
+ return false
+ }
+ if key.HasColumnPrefix() {
+ return false
+ }
+ if key.HasNullable() {
+ return false
+ }
+ return true
+}
+
+// PrioritizedUniqueKeys returns all unique keys on given table, ordered from "best" to "worst",
+// for Online DDL purposes. The list of keys includes some that are not eligible for Online DDL
+// iteration.
+func PrioritizedUniqueKeys(createTableEntity *CreateTableEntity) *IndexDefinitionEntityList {
+ uniqueKeys := []*IndexDefinitionEntity{}
+ for _, key := range createTableEntity.IndexDefinitionEntities() {
+ if !key.IsUnique() {
+ continue
+ }
+ uniqueKeys = append(uniqueKeys, key)
+ }
+ sort.SliceStable(uniqueKeys, func(i, j int) bool {
+ if uniqueKeys[i].IsPrimary() {
+ // PRIMARY is always first
+ return true
+ }
+ if uniqueKeys[j].IsPrimary() {
+ // PRIMARY is always first
+ return false
+ }
+ if !uniqueKeys[i].HasNullable() && uniqueKeys[j].HasNullable() {
+ // Non NULLable comes first
+ return true
+ }
+ if uniqueKeys[i].HasNullable() && !uniqueKeys[j].HasNullable() {
+ // NULLable come last
+ return false
+ }
+ if !uniqueKeys[i].HasColumnPrefix() && uniqueKeys[j].HasColumnPrefix() {
+ // Non prefix comes first
+ return true
+ }
+ if uniqueKeys[i].HasColumnPrefix() && !uniqueKeys[j].HasColumnPrefix() {
+ // Prefix comes last
+ return false
+ }
+ iFirstColEntity := uniqueKeys[i].ColumnList.Entities[0]
+ jFirstColEntity := uniqueKeys[j].ColumnList.Entities[0]
+ if iFirstColEntity.IsIntegralType() && !jFirstColEntity.IsIntegralType() {
+ // Prioritize integers
+ return true
+ }
+ if !iFirstColEntity.IsIntegralType() && jFirstColEntity.IsIntegralType() {
+ // Prioritize integers
+ return false
+ }
+ if !iFirstColEntity.HasBlobTypeStorage() && jFirstColEntity.HasBlobTypeStorage() {
+ return true
+ }
+ if iFirstColEntity.HasBlobTypeStorage() && !jFirstColEntity.HasBlobTypeStorage() {
+ return false
+ }
+ if !iFirstColEntity.IsTextual() && jFirstColEntity.IsTextual() {
+ return true
+ }
+ if iFirstColEntity.IsTextual() && !jFirstColEntity.IsTextual() {
+ return false
+ }
+ if storageDiff := IntegralTypeStorage(iFirstColEntity.Type()) - IntegralTypeStorage(jFirstColEntity.Type()); storageDiff != 0 {
+ return storageDiff < 0
+ }
+ if lenDiff := len(uniqueKeys[i].ColumnList.Entities) - len(uniqueKeys[j].ColumnList.Entities); lenDiff != 0 {
+ return lenDiff < 0
+ }
+ return false
+ })
+ return NewIndexDefinitionEntityList(uniqueKeys)
+}
+
+// RemovedForeignKeyNames returns the names of removed foreign keys, ignoring mere name changes
+func RemovedForeignKeyNames(source *CreateTableEntity, target *CreateTableEntity) (names []string, err error) {
+ if source == nil || target == nil {
+ return nil, nil
+ }
+ diffHints := DiffHints{
+ ConstraintNamesStrategy: ConstraintNamesIgnoreAll,
+ }
+ diff, err := source.Diff(target, &diffHints)
+ if err != nil {
+ return nil, err
+ }
+ names = []string{}
+ validateWalk := func(node sqlparser.SQLNode) (kontinue bool, err error) {
+ switch node := node.(type) {
+ case *sqlparser.DropKey:
+ if node.Type == sqlparser.ForeignKeyType {
+ names = append(names, node.Name.String())
+ }
+ }
+ return true, nil
+ }
+ _ = sqlparser.Walk(validateWalk, diff.Statement()) // We never return an error
+ return names, nil
+}
+
+// AlterTableAnalysis contains useful Online DDL information about an AlterTable statement
+type AlterTableAnalysis struct {
+ ColumnRenameMap map[string]string
+ DroppedColumnsMap map[string]bool
+ IsRenameTable bool
+ IsAutoIncrementChangeRequested bool
+}
+
+// AnalyzeAlter looks for specific changes in the AlterTable statement, that are relevant
+// to OnlineDDL/VReplication
+func OnlineDDLAlterTableAnalysis(alterTable *sqlparser.AlterTable) *AlterTableAnalysis {
+ analysis := &AlterTableAnalysis{
+ ColumnRenameMap: make(map[string]string),
+ DroppedColumnsMap: make(map[string]bool),
+ }
+ if alterTable == nil {
+ return analysis
+ }
+ for _, opt := range alterTable.AlterOptions {
+ switch opt := opt.(type) {
+ case *sqlparser.RenameTableName:
+ analysis.IsRenameTable = true
+ case *sqlparser.DropColumn:
+ analysis.DroppedColumnsMap[opt.Name.Name.String()] = true
+ case *sqlparser.ChangeColumn:
+ if opt.OldColumn != nil && opt.NewColDefinition != nil {
+ oldName := opt.OldColumn.Name.String()
+ newName := opt.NewColDefinition.Name.String()
+ analysis.ColumnRenameMap[oldName] = newName
+ }
+ case sqlparser.TableOptions:
+ for _, tableOption := range opt {
+ if strings.ToUpper(tableOption.Name) == "AUTO_INCREMENT" {
+ analysis.IsAutoIncrementChangeRequested = true
+ }
+ }
+ }
+ }
+ return analysis
+}
+
+// GetExpandedColumnNames is given source and target shared columns, and returns the list of columns whose data type is expanded.
+// An expanded data type is one where the target can have a value which the source does not. Examples:
+// - any NOT NULL to NULLable (a NULL in the target cannot appear on source)
+// - INT -> BIGINT (obvious)
+// - BIGINT UNSIGNED -> INT SIGNED (negative values)
+// - TIMESTAMP -> TIMESTAMP(3)
+// etc.
+func GetExpandedColumns(
+ sourceColumns *ColumnDefinitionEntityList,
+ targetColumns *ColumnDefinitionEntityList,
+) (
+ expandedColumns *ColumnDefinitionEntityList,
+ expandedDescriptions map[string]string,
+ err error,
+) {
+ if len(sourceColumns.Entities) != len(targetColumns.Entities) {
+ return nil, nil, fmt.Errorf("source and target columns must be of same length")
+ }
+
+ expandedEntities := []*ColumnDefinitionEntity{}
+ expandedDescriptions = map[string]string{}
+ for i := range sourceColumns.Entities {
+ // source and target columns assumed to be mapped 1:1, same length
+ sourceColumn := sourceColumns.Entities[i]
+ targetColumn := targetColumns.Entities[i]
+
+ if isExpanded, description := ColumnChangeExpandsDataRange(sourceColumn, targetColumn); isExpanded {
+ expandedEntities = append(expandedEntities, sourceColumn)
+ expandedDescriptions[sourceColumn.Name()] = description
+ }
+ }
+ return NewColumnDefinitionEntityList(expandedEntities), expandedDescriptions, nil
+}
+
+// AnalyzeSharedColumns returns the intersection of two lists of columns in same order as the first list
+func AnalyzeSharedColumns(
+ sourceColumns, targetColumns *ColumnDefinitionEntityList,
+ alterTableAnalysis *AlterTableAnalysis,
+) (
+ sourceSharedColumns *ColumnDefinitionEntityList,
+ targetSharedColumns *ColumnDefinitionEntityList,
+ droppedSourceNonGeneratedColumns *ColumnDefinitionEntityList,
+ sharedColumnsMap map[string]string,
+) {
+ sharedColumnsMap = map[string]string{}
+ sourceShared := []*ColumnDefinitionEntity{}
+ targetShared := []*ColumnDefinitionEntity{}
+ droppedNonGenerated := []*ColumnDefinitionEntity{}
+
+ for _, sourceColumn := range sourceColumns.Entities {
+ if sourceColumn.IsGenerated() {
+ continue
+ }
+ isDroppedFromSource := false
+ // Note to a future engineer: you may be tempted to remove this loop based on the
+ // assumption that the later `targetColumn := targetColumns.GetColumn(expectedTargetName)`
+ // check is sufficient. It is not. It is possible that a columns was explicitly dropped
+ // and added (`DROP COLUMN c, ADD COLUMN c INT`) in the same ALTER TABLE statement.
+ // Without checking the ALTER TABLE statement, we would be fooled to believe that column
+ // `c` is unchanged in the target, when in fact it was dropped and re-added.
+ for droppedColumn := range alterTableAnalysis.DroppedColumnsMap {
+ if strings.EqualFold(sourceColumn.Name(), droppedColumn) {
+ isDroppedFromSource = true
+ break
+ }
+ }
+ if isDroppedFromSource {
+ droppedNonGenerated = append(droppedNonGenerated, sourceColumn)
+ // Column was dropped, hence cannot be a shared column
+ continue
+ }
+ expectedTargetName := sourceColumn.NameLowered()
+ if mappedName := alterTableAnalysis.ColumnRenameMap[sourceColumn.Name()]; mappedName != "" {
+ expectedTargetName = mappedName
+ }
+ targetColumn := targetColumns.GetColumn(expectedTargetName)
+ if targetColumn == nil {
+ // Column not found in target
+ droppedNonGenerated = append(droppedNonGenerated, sourceColumn)
+ continue
+ }
+ if targetColumn.IsGenerated() {
+ // virtual/generated columns are silently skipped.
+ continue
+ }
+ // OK, the column is shared (possibly renamed) between source and target.
+ sharedColumnsMap[sourceColumn.Name()] = targetColumn.Name()
+ sourceShared = append(sourceShared, sourceColumn)
+ targetShared = append(targetShared, targetColumn)
+ }
+ return NewColumnDefinitionEntityList(sourceShared),
+ NewColumnDefinitionEntityList(targetShared),
+ NewColumnDefinitionEntityList(droppedNonGenerated),
+ sharedColumnsMap
+}
+
+// KeyAtLeastConstrainedAs returns 'true' when sourceUniqueKey is at least as constrained as targetUniqueKey.
+// "More constrained" means the uniqueness constraint is "stronger". Thus, if sourceUniqueKey is as-or-more constrained than targetUniqueKey, then
+// rows valid under sourceUniqueKey must also be valid in targetUniqueKey. The opposite is not necessarily so: rows that are valid in targetUniqueKey
+// may cause a unique key violation under sourceUniqueKey
+func KeyAtLeastConstrainedAs(
+ sourceUniqueKey *IndexDefinitionEntity,
+ targetUniqueKey *IndexDefinitionEntity,
+ columnRenameMap map[string]string,
+) bool {
+ if !sourceUniqueKey.IsUnique() {
+ return false
+ }
+ if !targetUniqueKey.IsUnique() {
+ return true
+ }
+ sourceKeyLengths := map[string]int{}
+ for _, col := range sourceUniqueKey.IndexDefinition.Columns {
+ if col.Length == nil {
+ sourceKeyLengths[col.Column.Lowered()] = math.MaxInt64
+ } else {
+ sourceKeyLengths[col.Column.Lowered()] = *col.Length
+ }
+ }
+ targetKeyLengths := map[string]int{}
+ for _, col := range targetUniqueKey.IndexDefinition.Columns {
+ if col.Length == nil {
+ targetKeyLengths[col.Column.Lowered()] = math.MaxInt64
+ } else {
+ targetKeyLengths[col.Column.Lowered()] = *col.Length
+ }
+ }
+ // source is more constrained than target if every column in source is also in target, order is immaterial
+ for _, sourceCol := range sourceUniqueKey.ColumnList.Entities {
+ mappedColName, ok := columnRenameMap[sourceCol.Name()]
+ if !ok {
+ mappedColName = sourceCol.NameLowered()
+ }
+ targetCol := targetUniqueKey.ColumnList.GetColumn(mappedColName)
+ if targetCol == nil {
+ // source can't be more constrained if it covers *more* columns
+ return false
+ }
+ // We now know that sourceCol maps to targetCol
+ if sourceKeyLengths[sourceCol.NameLowered()] > targetKeyLengths[targetCol.NameLowered()] {
+ // source column covers a larger prefix than target column. It is therefore less constrained.
+ return false
+ }
+ }
+ return true
+}
+
+// IntroducedUniqueConstraints returns the unique key constraints added in target.
+// This does not necessarily mean that the unique key itself is new,
+// rather that there's a new, stricter constraint on a set of columns, that didn't exist before. Example:
+//
+// before:
+// unique key my_key (c1, c2, c3)
+// after:
+// unique key `other_key`(c1, c2)
+// Synopsis: the constraint on (c1, c2) is new; and `other_key` in target table is considered a new key
+//
+// Order of columns is immaterial to uniqueness of column combination.
+func IntroducedUniqueConstraints(sourceUniqueKeys *IndexDefinitionEntityList, targetUniqueKeys *IndexDefinitionEntityList, columnRenameMap map[string]string) *IndexDefinitionEntityList {
+ introducedUniqueConstraints := []*IndexDefinitionEntity{}
+ for _, targetUniqueKey := range targetUniqueKeys.Entities {
+ foundSourceKeyAtLeastAsConstrained := func() bool {
+ for _, sourceUniqueKey := range sourceUniqueKeys.Entities {
+ if KeyAtLeastConstrainedAs(sourceUniqueKey, targetUniqueKey, columnRenameMap) {
+ // target key does not add a new constraint
+ return true
+ }
+ }
+ return false
+ }
+ if !foundSourceKeyAtLeastAsConstrained() {
+ introducedUniqueConstraints = append(introducedUniqueConstraints, targetUniqueKey)
+ }
+ }
+ return NewIndexDefinitionEntityList(introducedUniqueConstraints)
+}
+
+// RemovedUniqueConstraints returns the list of unique key constraints _removed_ going from source to target.
+func RemovedUniqueConstraints(sourceUniqueKeys *IndexDefinitionEntityList, targetUniqueKeys *IndexDefinitionEntityList, columnRenameMap map[string]string) *IndexDefinitionEntityList {
+ reverseColumnRenameMap := map[string]string{}
+ for k, v := range columnRenameMap {
+ reverseColumnRenameMap[v] = k
+ }
+ return IntroducedUniqueConstraints(targetUniqueKeys, sourceUniqueKeys, reverseColumnRenameMap)
+}
+
+// IterationKeysByColumns returns the Online DDL compliant unique keys from given list,
+// whose columns are all covered by the given column list.
+func IterationKeysByColumns(keys *IndexDefinitionEntityList, columns *ColumnDefinitionEntityList) *IndexDefinitionEntityList {
+ subset := []*IndexDefinitionEntity{}
+ for _, key := range keys.SubsetCoveredByColumns(columns).Entities {
+ if IsValidIterationKey(key) {
+ subset = append(subset, key)
+ }
+ }
+ return NewIndexDefinitionEntityList(subset)
+}
+
+// MappedColumnNames
+func MappedColumnNames(columnsList *ColumnDefinitionEntityList, columnNamesMap map[string]string) []string {
+ names := columnsList.Names()
+ for i := range names {
+ if mappedName, ok := columnNamesMap[names[i]]; ok {
+ names[i] = mappedName
+ }
+ }
+ return names
+}
+
+// AlterTableAnalysis contains useful Online DDL information about an AlterTable statement
+type MigrationTablesAnalysis struct {
+ SourceSharedColumns *ColumnDefinitionEntityList
+ TargetSharedColumns *ColumnDefinitionEntityList
+ DroppedNoDefaultColumns *ColumnDefinitionEntityList
+ ExpandedColumns *ColumnDefinitionEntityList
+ SharedColumnsMap map[string]string
+ ChosenSourceUniqueKey *IndexDefinitionEntity
+ ChosenTargetUniqueKey *IndexDefinitionEntity
+ AddedUniqueKeys *IndexDefinitionEntityList
+ RemovedUniqueKeys *IndexDefinitionEntityList
+ RemovedForeignKeyNames []string
+ IntToEnumMap map[string]bool
+ SourceAutoIncrement uint64
+ RevertibleNotes []string
+}
+
+func OnlineDDLMigrationTablesAnalysis(
+ sourceCreateTableEntity *CreateTableEntity,
+ targetCreateTableEntity *CreateTableEntity,
+ alterTableAnalysis *AlterTableAnalysis,
+) (analysis *MigrationTablesAnalysis, err error) {
+ analysis = &MigrationTablesAnalysis{
+ IntToEnumMap: make(map[string]bool),
+ RevertibleNotes: []string{},
+ }
+ // columns:
+ generatedColumns := func(columns *ColumnDefinitionEntityList) *ColumnDefinitionEntityList {
+ return columns.Filter(func(col *ColumnDefinitionEntity) bool {
+ return col.IsGenerated()
+ })
+ }
+ noDefaultColumns := func(columns *ColumnDefinitionEntityList) *ColumnDefinitionEntityList {
+ return columns.Filter(func(col *ColumnDefinitionEntity) bool {
+ return !col.HasDefault()
+ })
+ }
+ sourceColumns := sourceCreateTableEntity.ColumnDefinitionEntitiesList()
+ targetColumns := targetCreateTableEntity.ColumnDefinitionEntitiesList()
+
+ var droppedSourceNonGeneratedColumns *ColumnDefinitionEntityList
+ analysis.SourceSharedColumns, analysis.TargetSharedColumns, droppedSourceNonGeneratedColumns, analysis.SharedColumnsMap = AnalyzeSharedColumns(sourceColumns, targetColumns, alterTableAnalysis)
+
+ // unique keys
+ sourceUniqueKeys := PrioritizedUniqueKeys(sourceCreateTableEntity)
+ if sourceUniqueKeys.Len() == 0 {
+ return nil, fmt.Errorf("found no possible unique key on `%s`", sourceCreateTableEntity.Name())
+ }
+
+ targetUniqueKeys := PrioritizedUniqueKeys(targetCreateTableEntity)
+ if targetUniqueKeys.Len() == 0 {
+ return nil, fmt.Errorf("found no possible unique key on `%s`", targetCreateTableEntity.Name())
+ }
+ // VReplication supports completely different unique keys on source and target, covering
+ // some/completely different columns. The condition is that the key on source
+ // must use columns which all exist on target table.
+ eligibleSourceColumnsForUniqueKey := analysis.SourceSharedColumns.Union(generatedColumns(sourceColumns))
+ analysis.ChosenSourceUniqueKey = IterationKeysByColumns(sourceUniqueKeys, eligibleSourceColumnsForUniqueKey).First()
+ if analysis.ChosenSourceUniqueKey == nil {
+ return nil, fmt.Errorf("found no possible unique key on `%s` whose columns are in target table `%s`", sourceCreateTableEntity.Name(), targetCreateTableEntity.Name())
+ }
+
+ eligibleTargetColumnsForUniqueKey := analysis.TargetSharedColumns.Union(generatedColumns(targetColumns))
+ analysis.ChosenTargetUniqueKey = IterationKeysByColumns(targetUniqueKeys, eligibleTargetColumnsForUniqueKey).First()
+ if analysis.ChosenTargetUniqueKey == nil {
+ return nil, fmt.Errorf("found no possible unique key on `%s` whose columns are in source table `%s`", targetCreateTableEntity.Name(), sourceCreateTableEntity.Name())
+ }
+
+ analysis.AddedUniqueKeys = IntroducedUniqueConstraints(sourceUniqueKeys, targetUniqueKeys, alterTableAnalysis.ColumnRenameMap)
+ analysis.RemovedUniqueKeys = RemovedUniqueConstraints(sourceUniqueKeys, targetUniqueKeys, alterTableAnalysis.ColumnRenameMap)
+ analysis.RemovedForeignKeyNames, err = RemovedForeignKeyNames(sourceCreateTableEntity, targetCreateTableEntity)
+ if err != nil {
+ return nil, err
+ }
+
+ formalizeColumns := func(columnsLists ...*ColumnDefinitionEntityList) error {
+ for _, colList := range columnsLists {
+ for _, col := range colList.Entities {
+ col.SetExplicitDefaultAndNull()
+ if err := col.SetExplicitCharsetCollate(); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+
+ if err := formalizeColumns(analysis.SourceSharedColumns, analysis.TargetSharedColumns, droppedSourceNonGeneratedColumns); err != nil {
+ return nil, err
+ }
+
+ for i := range analysis.SourceSharedColumns.Entities {
+ sourceColumn := analysis.SourceSharedColumns.Entities[i]
+ mappedColumn := analysis.TargetSharedColumns.Entities[i]
+
+ if sourceColumn.IsIntegralType() && mappedColumn.Type() == "enum" {
+ analysis.IntToEnumMap[sourceColumn.Name()] = true
+ }
+ }
+
+ analysis.DroppedNoDefaultColumns = noDefaultColumns(droppedSourceNonGeneratedColumns)
+ var expandedDescriptions map[string]string
+ analysis.ExpandedColumns, expandedDescriptions, err = GetExpandedColumns(analysis.SourceSharedColumns, analysis.TargetSharedColumns)
+ if err != nil {
+ return nil, err
+ }
+
+ analysis.SourceAutoIncrement, err = sourceCreateTableEntity.AutoIncrementValue()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, uk := range analysis.RemovedUniqueKeys.Names() {
+ analysis.RevertibleNotes = append(analysis.RevertibleNotes, fmt.Sprintf("unique constraint removed: %s", uk))
+ }
+ for _, name := range analysis.DroppedNoDefaultColumns.Names() {
+ analysis.RevertibleNotes = append(analysis.RevertibleNotes, fmt.Sprintf("column %s dropped, and had no default value", name))
+ }
+ for _, name := range analysis.ExpandedColumns.Names() {
+ analysis.RevertibleNotes = append(analysis.RevertibleNotes, fmt.Sprintf("column %s: %s", name, expandedDescriptions[name]))
+ }
+ for _, name := range analysis.RemovedForeignKeyNames {
+ analysis.RevertibleNotes = append(analysis.RevertibleNotes, fmt.Sprintf("foreign key %s dropped", name))
+ }
+
+ return analysis, nil
+}
diff --git a/go/vt/schemadiff/onlineddl_test.go b/go/vt/schemadiff/onlineddl_test.go
new file mode 100644
index 00000000000..bd08bedfe8a
--- /dev/null
+++ b/go/vt/schemadiff/onlineddl_test.go
@@ -0,0 +1,960 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 schemadiff
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "vitess.io/vitess/go/vt/sqlparser"
+)
+
+func TestPrioritizedUniqueKeys(t *testing.T) {
+ table := `
+ create table t (
+ idsha varchar(64),
+ col1 int,
+ col2 int not null,
+ col3 bigint not null default 3,
+ col4 smallint not null,
+ f float not null,
+ v varchar(32) not null,
+ primary key (idsha),
+ unique key ukidsha (idsha),
+ unique key uk1 (col1),
+ unique key uk2 (col2),
+ unique key uk3 (col3),
+ key k1 (col1),
+ key kf (f),
+ key k1f (col1, f),
+ key kv (v),
+ unique key ukv (v),
+ unique key ukvprefix (v(10)),
+ unique key uk2vprefix (col2, v(10)),
+ unique key uk1f (col1, f),
+ unique key uk41 (col4, col1),
+ unique key uk42 (col4, col2)
+ )`
+ env := NewTestEnv()
+ createTableEntity, err := NewCreateTableEntityFromSQL(env, table)
+ require.NoError(t, err)
+ err = createTableEntity.validate()
+ require.NoError(t, err)
+
+ keys := PrioritizedUniqueKeys(createTableEntity)
+ require.NotEmpty(t, keys)
+ names := make([]string, 0, len(keys.Entities))
+ for _, key := range keys.Entities {
+ names = append(names, key.Name())
+ }
+ expect := []string{
+ "PRIMARY",
+ "uk42",
+ "uk2",
+ "uk3",
+ "ukidsha",
+ "ukv",
+ "uk2vprefix",
+ "ukvprefix",
+ "uk41",
+ "uk1",
+ "uk1f",
+ }
+ assert.Equal(t, expect, names)
+}
+
+func TestRemovedForeignKeyNames(t *testing.T) {
+ env := NewTestEnv()
+
+ tcases := []struct {
+ before string
+ after string
+ names []string
+ }{
+ {
+ before: "create table t (id int primary key)",
+ after: "create table t (id2 int primary key, i int)",
+ },
+ {
+ before: "create table t (id int primary key)",
+ after: "create table t2 (id2 int primary key, i int)",
+ },
+ {
+ before: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
+ after: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
+ },
+ {
+ before: "create table t (id int primary key, i int, constraint f1 foreign key (i) references parent (id) on delete cascade)",
+ after: "create table t (id int primary key, i int, constraint f2 foreign key (i) references parent (id) on delete cascade)",
+ },
+ {
+ before: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
+ after: "create table t (id int primary key, i int)",
+ names: []string{"f"},
+ },
+ {
+ before: "create table t (id int primary key, i int, i2 int, constraint f1 foreign key (i) references parent (id) on delete cascade, constraint fi2 foreign key (i2) references parent (id) on delete cascade)",
+ after: "create table t (id int primary key, i int, i2 int, constraint f2 foreign key (i) references parent (id) on delete cascade)",
+ names: []string{"fi2"},
+ },
+ {
+ before: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))",
+ after: "create table t2 (id int primary key, i int)",
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run(tcase.before, func(t *testing.T) {
+ before, err := NewCreateTableEntityFromSQL(env, tcase.before)
+ require.NoError(t, err)
+ err = before.validate()
+ require.NoError(t, err)
+
+ after, err := NewCreateTableEntityFromSQL(env, tcase.after)
+ require.NoError(t, err)
+ err = after.validate()
+ require.NoError(t, err)
+
+ names, err := RemovedForeignKeyNames(before, after)
+ assert.NoError(t, err)
+ if tcase.names == nil {
+ tcase.names = []string{}
+ }
+ assert.Equal(t, tcase.names, names)
+ })
+ }
+}
+
+func TestGetAlterTableAnalysis(t *testing.T) {
+ tcases := []struct {
+ alter string
+ renames map[string]string
+ drops map[string]bool
+ isrename bool
+ autoinc bool
+ }{
+ {
+ alter: "alter table t add column t int, engine=innodb",
+ },
+ {
+ alter: "alter table t add column t int, change ts ts timestamp, engine=innodb",
+ renames: map[string]string{"ts": "ts"},
+ },
+ {
+ alter: "alter table t AUTO_INCREMENT=7",
+ autoinc: true,
+ },
+ {
+ alter: "alter table t add column t int, change ts ts timestamp, auto_increment=7 engine=innodb",
+ renames: map[string]string{"ts": "ts"},
+ autoinc: true,
+ },
+ {
+ alter: "alter table t add column t int, change ts ts timestamp, CHANGE f `f` float, engine=innodb",
+ renames: map[string]string{"ts": "ts", "f": "f"},
+ },
+ {
+ alter: `alter table t add column b bigint, change f fl float, change i count int, engine=innodb`,
+ renames: map[string]string{"f": "fl", "i": "count"},
+ },
+ {
+ alter: "alter table t add column b bigint, change column `f` fl float, change `i` `count` int, engine=innodb",
+ renames: map[string]string{"f": "fl", "i": "count"},
+ },
+ {
+ alter: "alter table t add column b bigint, change column `f` fl float, change `i` `count` int, change ts ts timestamp, engine=innodb",
+ renames: map[string]string{"f": "fl", "i": "count", "ts": "ts"},
+ },
+ {
+ alter: "alter table t drop column b",
+ drops: map[string]bool{"b": true},
+ },
+ {
+ alter: "alter table t drop column b, drop key c_idx, drop column `d`",
+ drops: map[string]bool{"b": true, "d": true},
+ },
+ {
+ alter: "alter table t drop column b, drop key c_idx, drop column `d`, drop `e`, drop primary key, drop foreign key fk_1",
+ drops: map[string]bool{"b": true, "d": true, "e": true},
+ },
+ {
+ alter: "alter table t rename as something_else",
+ isrename: true,
+ },
+ {
+ alter: "alter table t drop column b, rename as something_else",
+ isrename: true,
+ drops: map[string]bool{"b": true},
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run(tcase.alter, func(t *testing.T) {
+ if tcase.renames == nil {
+ tcase.renames = make(map[string]string)
+ }
+ if tcase.drops == nil {
+ tcase.drops = make(map[string]bool)
+ }
+ stmt, err := sqlparser.NewTestParser().ParseStrictDDL(tcase.alter)
+ require.NoError(t, err)
+ alter, ok := stmt.(*sqlparser.AlterTable)
+ require.True(t, ok)
+
+ analysis := OnlineDDLAlterTableAnalysis(alter)
+ require.NotNil(t, analysis)
+ assert.Equal(t, tcase.isrename, analysis.IsRenameTable)
+ assert.Equal(t, tcase.autoinc, analysis.IsAutoIncrementChangeRequested)
+ assert.Equal(t, tcase.renames, analysis.ColumnRenameMap)
+ assert.Equal(t, tcase.drops, analysis.DroppedColumnsMap)
+ })
+ }
+}
+
+func TestAnalyzeSharedColumns(t *testing.T) {
+ sourceTable := `
+ create table t (
+ id int,
+ cint int,
+ cgen1 int generated always as (cint + 1) stored,
+ cgen2 int generated always as (cint + 2) stored,
+ cchar char(1),
+ cremoved int not null default 7,
+ cnullable int,
+ cnodefault int not null,
+ extra1 int,
+ primary key (id)
+ )
+ `
+ targetTable := `
+ create table t (
+ id int,
+ cint int,
+ cgen1 int generated always as (cint + 1) stored,
+ cchar_alternate char(1),
+ cnullable int,
+ cnodefault int not null,
+ extra2 int,
+ primary key (id)
+ )
+ `
+ tcases := []struct {
+ name string
+ sourceTable string
+ targetTable string
+ renameMap map[string]string
+ expectSourceSharedColNames []string
+ expectTargetSharedColNames []string
+ expectDroppedSourceNonGeneratedColNames []string
+ expectSharedColumnsMap map[string]string
+ }{
+ {
+ name: "rename map empty",
+ renameMap: map[string]string{},
+ expectSourceSharedColNames: []string{"id", "cint", "cnullable", "cnodefault"},
+ expectTargetSharedColNames: []string{"id", "cint", "cnullable", "cnodefault"},
+ expectDroppedSourceNonGeneratedColNames: []string{"cchar", "cremoved", "extra1"},
+ expectSharedColumnsMap: map[string]string{"id": "id", "cint": "cint", "cnullable": "cnullable", "cnodefault": "cnodefault"},
+ },
+ {
+ name: "renamed column",
+ renameMap: map[string]string{"cchar": "cchar_alternate"},
+ expectSourceSharedColNames: []string{"id", "cint", "cchar", "cnullable", "cnodefault"},
+ expectTargetSharedColNames: []string{"id", "cint", "cchar_alternate", "cnullable", "cnodefault"},
+ expectDroppedSourceNonGeneratedColNames: []string{"cremoved", "extra1"},
+ expectSharedColumnsMap: map[string]string{"id": "id", "cint": "cint", "cchar": "cchar_alternate", "cnullable": "cnullable", "cnodefault": "cnodefault"},
+ },
+ }
+
+ env := NewTestEnv()
+ alterTableAnalysis := OnlineDDLAlterTableAnalysis(nil) // empty
+ for _, tcase := range tcases {
+ t.Run(tcase.name, func(t *testing.T) {
+ if tcase.sourceTable == "" {
+ tcase.sourceTable = sourceTable
+ }
+ if tcase.targetTable == "" {
+ tcase.targetTable = targetTable
+ }
+ if tcase.renameMap != nil {
+ alterTableAnalysis.ColumnRenameMap = tcase.renameMap
+ }
+
+ sourceEntity, err := NewCreateTableEntityFromSQL(env, tcase.sourceTable)
+ require.NoError(t, err)
+ err = sourceEntity.validate()
+ require.NoError(t, err)
+
+ targetEntity, err := NewCreateTableEntityFromSQL(env, tcase.targetTable)
+ require.NoError(t, err)
+ err = targetEntity.validate()
+ require.NoError(t, err)
+
+ sourceSharedCols, targetSharedCols, droppedNonGeneratedCols, sharedColumnsMap := AnalyzeSharedColumns(
+ sourceEntity.ColumnDefinitionEntitiesList(),
+ targetEntity.ColumnDefinitionEntitiesList(),
+ alterTableAnalysis,
+ )
+ assert.Equal(t, tcase.expectSourceSharedColNames, sourceSharedCols.Names())
+ assert.Equal(t, tcase.expectTargetSharedColNames, targetSharedCols.Names())
+ assert.Equal(t, tcase.expectDroppedSourceNonGeneratedColNames, droppedNonGeneratedCols.Names())
+ assert.Equal(t, tcase.expectSharedColumnsMap, sharedColumnsMap)
+ })
+ }
+}
+
+func TestKeyAtLeastConstrainedAs(t *testing.T) {
+ env := NewTestEnv()
+ sourceTable := `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ c9 int,
+ v varchar(32),
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk2 (c2),
+ unique key uk3 (c3),
+ unique key uk9 (c9),
+ unique key uk12 (c1, c2),
+ unique key uk13 (c1, c3),
+ unique key uk23 (c2, c3),
+ unique key uk123 (c1, c2, c3),
+ unique key uk21 (c2, c1),
+ unique key ukv (v),
+ unique key ukv3 (v(3)),
+ unique key ukv5 (v(5)),
+ unique key uk2v5 (c2, v(5))
+ )`
+ targetTable := `
+ create table target_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3_renamed int,
+ v varchar(32),
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk2 (c2),
+ unique key uk3 (c3_renamed),
+ unique key uk12 (c1, c2),
+ unique key uk13 (c1, c3_renamed),
+ unique key uk23 (c2, c3_renamed),
+ unique key uk123 (c1, c2, c3_renamed),
+ unique key uk21 (c2, c1),
+ unique key ukv (v),
+ unique key ukv3 (v(3)),
+ unique key ukv5 (v(5)),
+ unique key uk2v5 (c2, v(5))
+ )`
+ renameMap := map[string]string{
+ "c3": "c3_renamed",
+ }
+ tcases := []struct {
+ sourceKey string
+ targetKey string
+ renameMap map[string]string
+ expect bool
+ }{
+ {
+ sourceKey: "uk1",
+ targetKey: "uk1",
+ expect: true,
+ },
+ {
+ sourceKey: "uk2",
+ targetKey: "uk2",
+ expect: true,
+ },
+ {
+ sourceKey: "uk3",
+ targetKey: "uk3",
+ expect: false, // c3 is renamed
+ },
+ {
+ sourceKey: "uk2",
+ targetKey: "uk1",
+ expect: false,
+ },
+ {
+ sourceKey: "uk12",
+ targetKey: "uk1",
+ expect: false,
+ },
+ {
+ sourceKey: "uk1",
+ targetKey: "uk12",
+ expect: true,
+ },
+ {
+ sourceKey: "uk1",
+ targetKey: "uk21",
+ expect: true,
+ },
+ {
+ sourceKey: "uk12",
+ targetKey: "uk21",
+ expect: true,
+ },
+ {
+ sourceKey: "uk123",
+ targetKey: "uk21",
+ expect: false,
+ },
+ {
+ sourceKey: "uk123",
+ targetKey: "uk123",
+ expect: false, // c3 is renamed
+ },
+ {
+ sourceKey: "uk1",
+ targetKey: "uk123",
+ expect: true, // c3 is renamed but not referenced
+ },
+ {
+ sourceKey: "uk21",
+ targetKey: "uk123",
+ expect: true, // c3 is renamed but not referenced
+ },
+ {
+ sourceKey: "uk9",
+ targetKey: "uk123",
+ expect: false, // c9 not in target
+ },
+ {
+ sourceKey: "uk3",
+ targetKey: "uk3",
+ renameMap: renameMap,
+ expect: true,
+ },
+ {
+ sourceKey: "uk123",
+ targetKey: "uk123",
+ renameMap: renameMap,
+ expect: true,
+ },
+ {
+ sourceKey: "uk3",
+ targetKey: "uk123",
+ renameMap: renameMap,
+ expect: true,
+ },
+ {
+ sourceKey: "ukv",
+ targetKey: "ukv",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv3",
+ targetKey: "ukv3",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv",
+ targetKey: "ukv3",
+ expect: false,
+ },
+ {
+ sourceKey: "ukv5",
+ targetKey: "ukv3",
+ expect: false,
+ },
+ {
+ sourceKey: "ukv3",
+ targetKey: "ukv5",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv3",
+ targetKey: "ukv",
+ expect: true,
+ },
+ {
+ sourceKey: "uk2",
+ targetKey: "uk2v5",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv5",
+ targetKey: "uk2v5",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv3",
+ targetKey: "uk2v5",
+ expect: true,
+ },
+ {
+ sourceKey: "ukv",
+ targetKey: "uk2v5",
+ expect: false,
+ },
+ {
+ sourceKey: "uk2v5",
+ targetKey: "ukv5",
+ expect: false,
+ },
+ }
+
+ sourceEntity, err := NewCreateTableEntityFromSQL(env, sourceTable)
+ require.NoError(t, err)
+ err = sourceEntity.validate()
+ require.NoError(t, err)
+ sourceKeys := sourceEntity.IndexDefinitionEntitiesMap()
+
+ targetEntity, err := NewCreateTableEntityFromSQL(env, targetTable)
+ require.NoError(t, err)
+ err = targetEntity.validate()
+ require.NoError(t, err)
+ targetKeys := targetEntity.IndexDefinitionEntitiesMap()
+
+ for _, tcase := range tcases {
+ t.Run(tcase.sourceKey+"/"+tcase.targetKey, func(t *testing.T) {
+ if tcase.renameMap == nil {
+ tcase.renameMap = make(map[string]string)
+ }
+ sourceKey := sourceKeys[tcase.sourceKey]
+ require.NotNil(t, sourceKey)
+
+ targetKey := targetKeys[tcase.targetKey]
+ require.NotNil(t, targetKey)
+
+ result := KeyAtLeastConstrainedAs(sourceKey, targetKey, tcase.renameMap)
+ assert.Equal(t, tcase.expect, result)
+ })
+ }
+}
+
+func TestIntroducedUniqueConstraints(t *testing.T) {
+ env := NewTestEnv()
+ tcases := []struct {
+ sourceTable string
+ targetTable string
+ expectIntroduced []string
+ expectRemoved []string
+ }{
+ {
+ sourceTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk2 (c2),
+ unique key uk31 (c3, c1),
+ key k1 (c1)
+ )`,
+ targetTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk3 (c3),
+ unique key uk31_alias (c3, c1),
+ key k2 (c2)
+ )`,
+ expectIntroduced: []string{"uk3"},
+ expectRemoved: []string{"uk2"},
+ },
+ {
+ sourceTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk2 (c2),
+ unique key uk31 (c3, c1),
+ key k1 (c1)
+ )`,
+ targetTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk3 (c3),
+ key k2 (c2)
+ )`,
+ expectIntroduced: []string{"uk3"}, // uk31 (c3, c1) not considered removed because the new "uk3" is even more constrained
+ expectRemoved: []string{"uk2"},
+ },
+ {
+ sourceTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ v varchar(128),
+ primary key (id),
+ unique key uk12 (c1, c2),
+ unique key ukv5 (v(5)),
+ key k1 (c1)
+ )`,
+ targetTable: `
+ create table source_table (
+ id int,
+ c1 int,
+ c2 int,
+ c3 int,
+ v varchar(128),
+ primary key (id),
+ unique key uk1v2 (c1, v(2)),
+ unique key uk1v7 (c1, v(7)),
+ unique key ukv3 (v(3)),
+ key k2 (c2)
+ )`,
+ expectIntroduced: []string{"uk1v2", "ukv3"},
+ expectRemoved: []string{"uk12"},
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run("", func(t *testing.T) {
+ sourceEntity, err := NewCreateTableEntityFromSQL(env, tcase.sourceTable)
+ require.NoError(t, err)
+ err = sourceEntity.validate()
+ require.NoError(t, err)
+ sourceUniqueKeys := PrioritizedUniqueKeys(sourceEntity)
+
+ targetEntity, err := NewCreateTableEntityFromSQL(env, tcase.targetTable)
+ require.NoError(t, err)
+ err = targetEntity.validate()
+ require.NoError(t, err)
+ targetUniqueKeys := PrioritizedUniqueKeys(targetEntity)
+
+ introduced := IntroducedUniqueConstraints(sourceUniqueKeys, targetUniqueKeys, nil)
+ assert.Equal(t, tcase.expectIntroduced, introduced.Names())
+ })
+ }
+}
+
+func TestUniqueKeysCoveredByColumns(t *testing.T) {
+ env := NewTestEnv()
+ table := `
+ create table t (
+ id int,
+ c1 int not null,
+ c2 int not null,
+ c3 int not null,
+ c9 int,
+ v varchar(32) not null,
+ primary key (id),
+ unique key uk1 (c1),
+ unique key uk3 (c3),
+ unique key uk9 (c9),
+ key k3 (c3),
+ unique key uk12 (c1, c2),
+ unique key uk13 (c1, c3),
+ unique key uk23 (c2, c3),
+ unique key uk123 (c1, c2, c3),
+ unique key uk21 (c2, c1),
+ unique key ukv (v),
+ unique key ukv3 (v(3)),
+ unique key uk2v5 (c2, v(5)),
+ unique key uk3v (c3, v)
+ )
+ `
+ tcases := []struct {
+ columns []string
+ expect []string
+ }{
+ {
+ columns: []string{"id"},
+ expect: []string{"PRIMARY"},
+ },
+ {
+ columns: []string{"c1"},
+ expect: []string{"uk1"},
+ },
+ {
+ columns: []string{"id", "c1"},
+ expect: []string{"PRIMARY", "uk1"},
+ },
+ {
+ columns: []string{"c1", "id"},
+ expect: []string{"PRIMARY", "uk1"},
+ },
+ {
+ columns: []string{"c9"},
+ expect: []string{}, // nullable column
+ },
+ {
+ columns: []string{"v"},
+ expect: []string{"ukv"},
+ },
+ {
+ columns: []string{"v", "c9"},
+ expect: []string{"ukv"},
+ },
+ {
+ columns: []string{"v", "c2"},
+ expect: []string{"ukv"},
+ },
+ {
+ columns: []string{"v", "c2", "c3"},
+ expect: []string{"uk3", "uk23", "uk3v", "ukv"},
+ },
+ {
+ columns: []string{"id", "c1", "c2", "c3", "v"},
+ expect: []string{"PRIMARY", "uk1", "uk3", "uk12", "uk13", "uk23", "uk21", "uk3v", "uk123", "ukv"},
+ },
+ }
+
+ entity, err := NewCreateTableEntityFromSQL(env, table)
+ require.NoError(t, err)
+ err = entity.validate()
+ require.NoError(t, err)
+ tableColumns := entity.ColumnDefinitionEntitiesList()
+ tableKeys := PrioritizedUniqueKeys(entity)
+ assert.Equal(t, []string{
+ "PRIMARY",
+ "uk1",
+ "uk3",
+ "uk12",
+ "uk13",
+ "uk23",
+ "uk21",
+ "uk3v",
+ "uk123",
+ "ukv",
+ "uk2v5",
+ "ukv3",
+ "uk9",
+ }, tableKeys.Names())
+
+ for _, tcase := range tcases {
+ t.Run(strings.Join(tcase.columns, ","), func(t *testing.T) {
+ columns := []*ColumnDefinitionEntity{}
+ for _, tcaseCol := range tcase.columns {
+ col := tableColumns.GetColumn(tcaseCol)
+ require.NotNil(t, col)
+ columns = append(columns, col)
+ }
+ columnsList := NewColumnDefinitionEntityList(columns)
+
+ covered := IterationKeysByColumns(tableKeys, columnsList)
+ assert.Equal(t, tcase.expect, covered.Names())
+ })
+ }
+}
+
+func TestRevertible(t *testing.T) {
+
+ type revertibleTestCase struct {
+ name string
+ fromSchema string
+ toSchema string
+ // expectProblems bool
+ removedForeignKeyNames string
+ removedUniqueKeyNames string
+ droppedNoDefaultColumnNames string
+ expandedColumnNames string
+ }
+
+ var testCases = []revertibleTestCase{
+ {
+ name: "identical schemas",
+ fromSchema: `id int primary key, i1 int not null default 0`,
+ toSchema: `id int primary key, i2 int not null default 0`,
+ },
+ {
+ name: "different schemas, nothing to note",
+ fromSchema: `id int primary key, i1 int not null default 0, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i1 int not null default 0, i2 int not null default 0, unique key i1_uidx(i1)`,
+ },
+ {
+ name: "removed non-nullable unique key",
+ fromSchema: `id int primary key, i1 int not null default 0, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i2 int not null default 0`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "removed nullable unique key",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i2 int default null`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "expanding unique key removes unique constraint",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1, id)`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "expanding unique key prefix removes unique constraint",
+ fromSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(20))`,
+ toSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(21))`,
+ removedUniqueKeyNames: `v_uidx`,
+ },
+ {
+ name: "reducing unique key does not remove unique constraint",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1, id)`,
+ toSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ removedUniqueKeyNames: ``,
+ },
+ {
+ name: "reducing unique key does not remove unique constraint",
+ fromSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(21))`,
+ toSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(20))`,
+ },
+ {
+ name: "removed foreign key",
+ fromSchema: "id int primary key, i int, constraint some_fk_1 foreign key (i) references parent (id) on delete cascade",
+ toSchema: "id int primary key, i int",
+ removedForeignKeyNames: "some_fk_1",
+ },
+
+ {
+ name: "renamed foreign key",
+ fromSchema: "id int primary key, i int, constraint f1 foreign key (i) references parent (id) on delete cascade",
+ toSchema: "id int primary key, i int, constraint f2 foreign key (i) references parent (id) on delete cascade",
+ },
+ {
+ name: "remove column without default",
+ fromSchema: `id int primary key, i1 int not null, i2 int not null default 0, i3 int default null`,
+ toSchema: `id int primary key, i4 int not null default 0`,
+ droppedNoDefaultColumnNames: `i1`,
+ },
+ {
+ name: "expanded: nullable",
+ fromSchema: `id int primary key, i1 int not null, i2 int default null`,
+ toSchema: `id int primary key, i1 int default null, i2 int not null`,
+ expandedColumnNames: `i1`,
+ },
+ {
+ name: "expanded: longer text",
+ fromSchema: `id int primary key, i1 int default null, v1 varchar(40) not null, v2 varchar(5), v3 varchar(3)`,
+ toSchema: `id int primary key, i1 int not null, v1 varchar(100) not null, v2 char(3), v3 char(5)`,
+ expandedColumnNames: `v1,v3`,
+ },
+ {
+ name: "expanded: int numeric precision and scale",
+ fromSchema: `id int primary key, i1 int, i2 tinyint, i3 mediumint, i4 bigint`,
+ toSchema: `id int primary key, i1 int, i2 mediumint, i3 int, i4 tinyint`,
+ expandedColumnNames: `i2,i3`,
+ },
+ {
+ name: "expanded: floating point",
+ fromSchema: `id int primary key, i1 int, n2 bigint, n3 bigint, n4 float, n5 double`,
+ toSchema: `id int primary key, i1 int, n2 float, n3 double, n4 double, n5 float`,
+ expandedColumnNames: `n2,n3,n4`,
+ },
+ {
+ name: "expanded: decimal numeric precision and scale",
+ fromSchema: `id int primary key, i1 int, d1 decimal(10,2), d2 decimal (10,2), d3 decimal (10,2)`,
+ toSchema: `id int primary key, i1 int, d1 decimal(11,2), d2 decimal (9,1), d3 decimal (10,3)`,
+ expandedColumnNames: `d1,d3`,
+ },
+ {
+ name: "expanded: signed, unsigned",
+ fromSchema: `id int primary key, i1 bigint signed, i2 int unsigned, i3 bigint unsigned`,
+ toSchema: `id int primary key, i1 int signed, i2 int signed, i3 int signed`,
+ expandedColumnNames: `i2,i3`,
+ },
+ {
+ name: "expanded: signed, unsigned: range",
+ fromSchema: `id int primary key, i1 int signed, i2 bigint signed, i3 int signed`,
+ toSchema: `id int primary key, i1 int unsigned, i2 int unsigned, i3 bigint unsigned`,
+ expandedColumnNames: `i1,i3`,
+ },
+ {
+ name: "expanded: datetime precision",
+ fromSchema: `id int primary key, dt1 datetime, ts1 timestamp, ti1 time, dt2 datetime(3), dt3 datetime(6), ts2 timestamp(3)`,
+ toSchema: `id int primary key, dt1 datetime(3), ts1 timestamp(6), ti1 time(3), dt2 datetime(6), dt3 datetime(3), ts2 timestamp`,
+ expandedColumnNames: `dt1,ts1,ti1,dt2`,
+ },
+ {
+ name: "expanded: strange data type changes",
+ fromSchema: `id int primary key, dt1 datetime, ts1 timestamp, i1 int, d1 date, e1 enum('a', 'b')`,
+ toSchema: `id int primary key, dt1 char(32), ts1 varchar(32), i1 tinytext, d1 char(2), e1 varchar(2)`,
+ expandedColumnNames: `dt1,ts1,i1,d1,e1`,
+ },
+ {
+ name: "expanded: temporal types",
+ fromSchema: `id int primary key, t1 time, t2 timestamp, t3 date, t4 datetime, t5 time, t6 date`,
+ toSchema: `id int primary key, t1 datetime, t2 datetime, t3 timestamp, t4 timestamp, t5 timestamp, t6 datetime`,
+ expandedColumnNames: `t1,t2,t3,t5,t6`,
+ },
+ {
+ name: "expanded: character sets",
+ fromSchema: `id int primary key, c1 char(3) charset utf8, c2 char(3) charset utf8mb4, c3 char(3) charset ascii, c4 char(3) charset utf8mb4, c5 char(3) charset utf8, c6 char(3) charset latin1`,
+ toSchema: `id int primary key, c1 char(3) charset utf8mb4, c2 char(3) charset utf8, c3 char(3) charset utf8, c4 char(3) charset ascii, c5 char(3) charset utf8, c6 char(3) charset utf8mb4`,
+ expandedColumnNames: `c1,c3,c6`,
+ },
+ {
+ name: "expanded: enum",
+ fromSchema: `id int primary key, e1 enum('a', 'b'), e2 enum('a', 'b'), e3 enum('a', 'b'), e4 enum('a', 'b'), e5 enum('a', 'b'), e6 enum('a', 'b'), e7 enum('a', 'b'), e8 enum('a', 'b')`,
+ toSchema: `id int primary key, e1 enum('a', 'b'), e2 enum('a'), e3 enum('a', 'b', 'c'), e4 enum('a', 'x'), e5 enum('a', 'x', 'b'), e6 enum('b'), e7 varchar(1), e8 tinyint`,
+ expandedColumnNames: `e3,e4,e5,e6,e7,e8`,
+ },
+ {
+ name: "expanded: set",
+ fromSchema: `id int primary key, e1 set('a', 'b'), e2 set('a', 'b'), e3 set('a', 'b'), e4 set('a', 'b'), e5 set('a', 'b'), e6 set('a', 'b'), e7 set('a', 'b'), e8 set('a', 'b')`,
+ toSchema: `id int primary key, e1 set('a', 'b'), e2 set('a'), e3 set('a', 'b', 'c'), e4 set('a', 'x'), e5 set('a', 'x', 'b'), e6 set('b'), e7 varchar(1), e8 tinyint`,
+ expandedColumnNames: `e3,e4,e5,e6,e7,e8`,
+ },
+ }
+
+ var (
+ createTableWrapper = `CREATE TABLE t (%s)`
+ )
+
+ env := NewTestEnv()
+ diffHints := &DiffHints{}
+ for _, tcase := range testCases {
+ t.Run(tcase.name, func(t *testing.T) {
+ tcase.fromSchema = fmt.Sprintf(createTableWrapper, tcase.fromSchema)
+ sourceTableEntity, err := NewCreateTableEntityFromSQL(env, tcase.fromSchema)
+ require.NoError(t, err)
+
+ tcase.toSchema = fmt.Sprintf(createTableWrapper, tcase.toSchema)
+ targetTableEntity, err := NewCreateTableEntityFromSQL(env, tcase.toSchema)
+ require.NoError(t, err)
+
+ diff, err := sourceTableEntity.TableDiff(targetTableEntity, diffHints)
+ require.NoError(t, err)
+ alterTableAnalysis := OnlineDDLAlterTableAnalysis(diff.AlterTable())
+
+ analysis, err := OnlineDDLMigrationTablesAnalysis(sourceTableEntity, targetTableEntity, alterTableAnalysis)
+ require.NoError(t, err)
+
+ toStringSlice := func(s string) []string {
+ if s == "" {
+ return []string{}
+ }
+ return strings.Split(s, ",")
+ }
+ assert.Equal(t, toStringSlice(tcase.removedForeignKeyNames), analysis.RemovedForeignKeyNames)
+ assert.Equal(t, toStringSlice(tcase.removedUniqueKeyNames), analysis.RemovedUniqueKeys.Names())
+ assert.Equal(t, toStringSlice(tcase.droppedNoDefaultColumnNames), analysis.DroppedNoDefaultColumns.Names())
+ assert.Equal(t, toStringSlice(tcase.expandedColumnNames), analysis.ExpandedColumns.Names())
+ })
+ }
+}
diff --git a/go/vt/schemadiff/schema_diff_test.go b/go/vt/schemadiff/schema_diff_test.go
index 10ad260100b..8088cc896ed 100644
--- a/go/vt/schemadiff/schema_diff_test.go
+++ b/go/vt/schemadiff/schema_diff_test.go
@@ -1321,7 +1321,6 @@ func TestSchemaDiff(t *testing.T) {
instantCapability := schemaDiff.InstantDDLCapability()
assert.Equal(t, tc.instantCapability, instantCapability, "for instant capability")
})
-
}
}
diff --git a/go/vt/schemadiff/table.go b/go/vt/schemadiff/table.go
index 5629210b6c1..c326b2763b3 100644
--- a/go/vt/schemadiff/table.go
+++ b/go/vt/schemadiff/table.go
@@ -445,6 +445,18 @@ type CreateTableEntity struct {
Env *Environment
}
+func NewCreateTableEntityFromSQL(env *Environment, sql string) (*CreateTableEntity, error) {
+ stmt, err := env.Parser().ParseStrictDDL(sql)
+ if err != nil {
+ return nil, err
+ }
+ createTable, ok := stmt.(*sqlparser.CreateTable)
+ if !ok {
+ return nil, ErrExpectedCreateTable
+ }
+ return NewCreateTableEntity(env, createTable)
+}
+
func NewCreateTableEntity(env *Environment, c *sqlparser.CreateTable) (*CreateTableEntity, error) {
if !c.IsFullyParsed() {
return nil, &NotFullyParsedError{Entity: c.Table.Name.String(), Statement: sqlparser.CanonicalString(c)}
@@ -454,15 +466,64 @@ func NewCreateTableEntity(env *Environment, c *sqlparser.CreateTable) (*CreateTa
return entity, nil
}
+// ColumnDefinitionEntities returns the list of column entities for the table.
func (c *CreateTableEntity) ColumnDefinitionEntities() []*ColumnDefinitionEntity {
cc := getTableCharsetCollate(c.Env, &c.CreateTable.TableSpec.Options)
+ pkColumnsMaps := c.primaryKeyColumnsMap()
entities := make([]*ColumnDefinitionEntity, len(c.CreateTable.TableSpec.Columns))
for i := range c.CreateTable.TableSpec.Columns {
- entities[i] = NewColumnDefinitionEntity(c.Env, c.CreateTable.TableSpec.Columns[i], cc)
+ col := c.CreateTable.TableSpec.Columns[i]
+ _, inPK := pkColumnsMaps[col.Name.Lowered()]
+ entities[i] = NewColumnDefinitionEntity(c.Env, col, inPK, cc)
}
return entities
}
+// ColumnDefinitionEntities returns the list of column entities for the table.
+func (c *CreateTableEntity) ColumnDefinitionEntitiesList() *ColumnDefinitionEntityList {
+ return NewColumnDefinitionEntityList(c.ColumnDefinitionEntities())
+}
+
+// ColumnDefinitionEntities returns column entities mapped by their lower cased name
+func (c *CreateTableEntity) ColumnDefinitionEntitiesMap() map[string]*ColumnDefinitionEntity {
+ entities := c.ColumnDefinitionEntities()
+ m := make(map[string]*ColumnDefinitionEntity, len(entities))
+ for _, entity := range entities {
+ m[entity.NameLowered()] = entity
+ }
+ return m
+}
+
+// IndexDefinitionEntities returns the list of index entities for the table.
+func (c *CreateTableEntity) IndexDefinitionEntities() []*IndexDefinitionEntity {
+ colMap := c.ColumnDefinitionEntitiesMap()
+ keys := c.CreateTable.TableSpec.Indexes
+ entities := make([]*IndexDefinitionEntity, len(keys))
+ for i, key := range keys {
+ colEntities := make([]*ColumnDefinitionEntity, len(key.Columns))
+ for i, keyCol := range key.Columns {
+ colEntities[i] = colMap[keyCol.Column.Lowered()]
+ }
+ entities[i] = NewIndexDefinitionEntity(c.Env, key, NewColumnDefinitionEntityList(colEntities))
+ }
+ return entities
+}
+
+// IndexDefinitionEntityList returns the list of index entities for the table.
+func (c *CreateTableEntity) IndexDefinitionEntitiesList() *IndexDefinitionEntityList {
+ return NewIndexDefinitionEntityList(c.IndexDefinitionEntities())
+}
+
+// IndexDefinitionEntitiesMap returns index entities mapped by their lower cased name.
+func (c *CreateTableEntity) IndexDefinitionEntitiesMap() map[string]*IndexDefinitionEntity {
+ entities := c.IndexDefinitionEntities()
+ m := make(map[string]*IndexDefinitionEntity, len(entities))
+ for _, entity := range entities {
+ m[entity.NameLowered()] = entity
+ }
+ return m
+}
+
// normalize cleans up the table definition:
// - setting names to all keys
// - table option case (upper/lower/special)
@@ -1740,8 +1801,8 @@ func (c *CreateTableEntity) diffColumns(alterTable *sqlparser.AlterTable,
t2ColName := t2Col.Name.Lowered()
// we know that column exists in both tables
t1Col := t1ColumnsMap[t2ColName]
- t1ColEntity := NewColumnDefinitionEntity(c.Env, t1Col.col, t1cc)
- t2ColEntity := NewColumnDefinitionEntity(c.Env, t2Col, t2cc)
+ t1ColEntity := NewColumnDefinitionEntity(c.Env, t1Col.col, false, t1cc)
+ t2ColEntity := NewColumnDefinitionEntity(c.Env, t2Col, false, t2cc)
// check diff between before/after columns:
modifyColumnDiff, err := t1ColEntity.ColumnDiff(c.Env, c.Name(), t2ColEntity, hints)
@@ -1892,6 +1953,15 @@ func (c *CreateTableEntity) primaryKeyColumns() []*sqlparser.IndexColumn {
return nil
}
+func (c *CreateTableEntity) primaryKeyColumnsMap() map[string]*sqlparser.IndexColumn {
+ columns := c.primaryKeyColumns()
+ m := make(map[string]*sqlparser.IndexColumn, len(columns))
+ for _, col := range columns {
+ m[col.Column.Lowered()] = col
+ }
+ return m
+}
+
// Create implements Entity interface
func (c *CreateTableEntity) Create() EntityDiff {
if c == nil {
@@ -2648,3 +2718,18 @@ func (c *CreateTableEntity) identicalOtherThanName(other *CreateTableEntity) boo
return sqlparser.Equals.RefOfTableSpec(c.TableSpec, other.TableSpec) &&
sqlparser.Equals.RefOfParsedComments(c.Comments, other.Comments)
}
+
+// AutoIncrementValue returns the value of the AUTO_INCREMENT option, or zero if not exists.
+func (c *CreateTableEntity) AutoIncrementValue() (autoIncrement uint64, err error) {
+ for _, option := range c.CreateTable.TableSpec.Options {
+ if strings.ToUpper(option.Name) == "AUTO_INCREMENT" {
+ autoIncrement, err := strconv.ParseUint(option.Value.Val, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ return autoIncrement, nil
+ }
+ }
+ // Auto increment not found
+ return 0, nil
+}
diff --git a/go/vt/schemadiff/table_test.go b/go/vt/schemadiff/table_test.go
index 1168f53f3b6..389e55f447c 100644
--- a/go/vt/schemadiff/table_test.go
+++ b/go/vt/schemadiff/table_test.go
@@ -2781,9 +2781,10 @@ func TestValidate(t *testing.T) {
func TestNormalize(t *testing.T) {
tt := []struct {
- name string
- from string
- to string
+ name string
+ from string
+ to string
+ autoinc uint64
}{
{
name: "basic table",
@@ -2795,6 +2796,17 @@ func TestNormalize(t *testing.T) {
from: "create table t (id int primary key, i int)",
to: "CREATE TABLE `t` (\n\t`id` int,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)",
},
+ {
+ name: "basic table, auto increment",
+ from: "create table t (id int auto_increment primary key, i int)",
+ to: "CREATE TABLE `t` (\n\t`id` int AUTO_INCREMENT,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n)",
+ },
+ {
+ name: "basic table, auto increment val",
+ from: "create table t (id int auto_increment primary key, i int) auto_increment = 123",
+ to: "CREATE TABLE `t` (\n\t`id` int AUTO_INCREMENT,\n\t`i` int,\n\tPRIMARY KEY (`id`)\n) AUTO_INCREMENT 123",
+ autoinc: 123,
+ },
{
name: "removes default null",
from: "create table t (id int, i int default null, primary key (id))",
@@ -3067,6 +3079,10 @@ func TestNormalize(t *testing.T) {
from, err := NewCreateTableEntity(env, fromCreateTable)
require.NoError(t, err)
assert.Equal(t, ts.to, sqlparser.CanonicalString(from))
+
+ autoinc, err := from.AutoIncrementValue()
+ require.NoError(t, err)
+ assert.EqualValues(t, ts.autoinc, autoinc)
})
}
}
diff --git a/go/vt/schemadiff/view.go b/go/vt/schemadiff/view.go
index d2dc4dfb76f..8783f1803bb 100644
--- a/go/vt/schemadiff/view.go
+++ b/go/vt/schemadiff/view.go
@@ -310,6 +310,18 @@ func NewCreateViewEntity(env *Environment, c *sqlparser.CreateView) (*CreateView
return entity, nil
}
+func NewCreateViewEntityFromSQL(env *Environment, sql string) (*CreateViewEntity, error) {
+ stmt, err := env.Parser().ParseStrictDDL(sql)
+ if err != nil {
+ return nil, err
+ }
+ createView, ok := stmt.(*sqlparser.CreateView)
+ if !ok {
+ return nil, ErrExpectedCreateTable
+ }
+ return NewCreateViewEntity(env, createView)
+}
+
func (c *CreateViewEntity) normalize() {
// Drop the default algorithm
if strings.EqualFold(c.CreateView.Algorithm, "undefined") {
diff --git a/go/vt/schemadiff/view_test.go b/go/vt/schemadiff/view_test.go
index d1a26c3cdaa..d020649b17e 100644
--- a/go/vt/schemadiff/view_test.go
+++ b/go/vt/schemadiff/view_test.go
@@ -150,19 +150,16 @@ func TestCreateViewDiff(t *testing.T) {
for _, ts := range tt {
t.Run(ts.name, func(t *testing.T) {
fromStmt, err := env.Parser().ParseStrictDDL(ts.from)
- assert.NoError(t, err)
+ require.NoError(t, err)
fromCreateView, ok := fromStmt.(*sqlparser.CreateView)
assert.True(t, ok)
- toStmt, err := env.Parser().ParseStrictDDL(ts.to)
- assert.NoError(t, err)
- toCreateView, ok := toStmt.(*sqlparser.CreateView)
- assert.True(t, ok)
-
c, err := NewCreateViewEntity(env, fromCreateView)
require.NoError(t, err)
- other, err := NewCreateViewEntity(env, toCreateView)
+ // Test from SQL:
+ other, err := NewCreateViewEntityFromSQL(env, ts.to)
require.NoError(t, err)
+
alter, err := c.Diff(other, hints)
switch {
case ts.isError:
diff --git a/go/vt/sidecardb/schema/onlineddl/schema_migrations.sql b/go/vt/sidecardb/schema/onlineddl/schema_migrations.sql
index 2926ec76f28..82d0c221f0e 100644
--- a/go/vt/sidecardb/schema/onlineddl/schema_migrations.sql
+++ b/go/vt/sidecardb/schema/onlineddl/schema_migrations.sql
@@ -63,6 +63,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations
`special_plan` text NOT NULL,
`last_throttled_timestamp` timestamp NULL DEFAULT NULL,
`component_throttled` tinytext NOT NULL,
+ `reason_throttled` text NOT NULL,
`cancelled_timestamp` timestamp NULL DEFAULT NULL,
`postpone_launch` tinyint unsigned NOT NULL DEFAULT '0',
`stage` text NOT NULL,
diff --git a/go/vt/sidecardb/schema/vreplication/vreplication.sql b/go/vt/sidecardb/schema/vreplication/vreplication.sql
index 8d2ec41d1a6..293997056fd 100644
--- a/go/vt/sidecardb/schema/vreplication/vreplication.sql
+++ b/go/vt/sidecardb/schema/vreplication/vreplication.sql
@@ -36,6 +36,7 @@ CREATE TABLE IF NOT EXISTS vreplication
`workflow_type` int NOT NULL DEFAULT '0',
`time_throttled` bigint NOT NULL DEFAULT '0',
`component_throttled` varchar(255) NOT NULL DEFAULT '',
+ `reason_throttled` varchar(1000) NOT NULL DEFAULT '',
`workflow_sub_type` int NOT NULL DEFAULT '0',
`defer_secondary_keys` tinyint(1) NOT NULL DEFAULT '0',
/*
diff --git a/go/vt/sqlparser/ast_rewriting.go b/go/vt/sqlparser/ast_rewriting.go
index 64de1f9d920..ef46b124875 100644
--- a/go/vt/sqlparser/ast_rewriting.go
+++ b/go/vt/sqlparser/ast_rewriting.go
@@ -301,10 +301,12 @@ func (er *astRewriter) rewriteVariable(cursor *Cursor, node *Variable) {
if v, isSet := cursor.Parent().(*SetExpr); isSet && v.Var == node {
return
}
+ // no rewriting for global scope variable.
+ // this should be returned from the underlying database.
switch node.Scope {
case VariableScope:
er.udvRewrite(cursor, node)
- case GlobalScope, SessionScope, NextTxScope:
+ case SessionScope, NextTxScope:
er.sysVarRewrite(cursor, node)
}
}
diff --git a/go/vt/sysvars/sysvars.go b/go/vt/sysvars/sysvars.go
index c8037563ca1..297ed956bf8 100644
--- a/go/vt/sysvars/sysvars.go
+++ b/go/vt/sysvars/sysvars.go
@@ -191,6 +191,7 @@ var (
{Name: ForeignKeyChecks, IsBoolean: true, SupportSetVar: true},
{Name: "group_concat_max_len", SupportSetVar: true},
{Name: "information_schema_stats_expiry"},
+ {Name: "innodb_lock_wait_timeout"},
{Name: "max_heap_table_size", SupportSetVar: true},
{Name: "max_seeks_for_key", SupportSetVar: true},
{Name: "max_tmp_tables"},
@@ -246,7 +247,6 @@ var (
{Name: "collation_server"},
{Name: "completion_type"},
{Name: "div_precision_increment", SupportSetVar: true},
- {Name: "innodb_lock_wait_timeout"},
{Name: "interactive_timeout"},
{Name: "lc_time_names"},
{Name: "lock_wait_timeout", SupportSetVar: true},
diff --git a/go/vt/vtctl/grpcvtctldserver/server.go b/go/vt/vtctl/grpcvtctldserver/server.go
index 0ab76e6b523..d036cb0e8dd 100644
--- a/go/vt/vtctl/grpcvtctldserver/server.go
+++ b/go/vt/vtctl/grpcvtctldserver/server.go
@@ -2976,10 +2976,11 @@ func (s *VtctldServer) PlannedReparentShard(ctx context.Context, req *vtctldatap
req.Keyspace,
req.Shard,
reparentutil.PlannedReparentOptions{
- AvoidPrimaryAlias: req.AvoidPrimary,
- NewPrimaryAlias: req.NewPrimary,
- WaitReplicasTimeout: waitReplicasTimeout,
- TolerableReplLag: tolerableReplLag,
+ AvoidPrimaryAlias: req.AvoidPrimary,
+ NewPrimaryAlias: req.NewPrimary,
+ WaitReplicasTimeout: waitReplicasTimeout,
+ TolerableReplLag: tolerableReplLag,
+ AllowCrossCellPromotion: req.AllowCrossCellPromotion,
},
)
diff --git a/go/vt/vtctl/reparent.go b/go/vt/vtctl/reparent.go
index 4498228d9c7..192d19ed7ee 100644
--- a/go/vt/vtctl/reparent.go
+++ b/go/vt/vtctl/reparent.go
@@ -119,6 +119,7 @@ func commandPlannedReparentShard(ctx context.Context, wr *wrangler.Wrangler, sub
keyspaceShard := subFlags.String("keyspace_shard", "", "keyspace/shard of the shard that needs to be reparented")
newPrimary := subFlags.String("new_primary", "", "alias of a tablet that should be the new primary")
avoidTablet := subFlags.String("avoid_tablet", "", "alias of a tablet that should not be the primary, i.e. reparent to any other tablet if this one is the primary")
+ allowCrossCellPromotion := subFlags.Bool("allow-cross-cell-promotion", false, "allow cross cell promotions")
if err := subFlags.Parse(args); err != nil {
return err
@@ -153,10 +154,11 @@ func commandPlannedReparentShard(ctx context.Context, wr *wrangler.Wrangler, sub
}
return wr.PlannedReparentShard(ctx, keyspace, shard, reparentutil.PlannedReparentOptions{
- NewPrimaryAlias: newPrimaryAlias,
- AvoidPrimaryAlias: avoidTabletAlias,
- WaitReplicasTimeout: *waitReplicasTimeout,
- TolerableReplLag: *tolerableReplicationLag,
+ NewPrimaryAlias: newPrimaryAlias,
+ AvoidPrimaryAlias: avoidTabletAlias,
+ WaitReplicasTimeout: *waitReplicasTimeout,
+ TolerableReplLag: *tolerableReplicationLag,
+ AllowCrossCellPromotion: *allowCrossCellPromotion,
})
}
diff --git a/go/vt/vtctl/reparentutil/planned_reparenter.go b/go/vt/vtctl/reparentutil/planned_reparenter.go
index e09761ea982..0852583bec9 100644
--- a/go/vt/vtctl/reparentutil/planned_reparenter.go
+++ b/go/vt/vtctl/reparentutil/planned_reparenter.go
@@ -59,10 +59,11 @@ type PlannedReparenter struct {
// operations. Options are passed by value, so it is safe for callers to mutate
// resue options structs for multiple calls.
type PlannedReparentOptions struct {
- NewPrimaryAlias *topodatapb.TabletAlias
- AvoidPrimaryAlias *topodatapb.TabletAlias
- WaitReplicasTimeout time.Duration
- TolerableReplLag time.Duration
+ NewPrimaryAlias *topodatapb.TabletAlias
+ AvoidPrimaryAlias *topodatapb.TabletAlias
+ WaitReplicasTimeout time.Duration
+ TolerableReplLag time.Duration
+ AllowCrossCellPromotion bool
// Private options managed internally. We use value-passing semantics to
// set these options inside a PlannedReparent without leaking these details
@@ -181,7 +182,7 @@ func (pr *PlannedReparenter) preflightChecks(
}
event.DispatchUpdate(ev, "electing a primary candidate")
- opts.NewPrimaryAlias, err = ElectNewPrimary(ctx, pr.tmc, &ev.ShardInfo, tabletMap, innodbBufferPoolData, opts.NewPrimaryAlias, opts.AvoidPrimaryAlias, opts.WaitReplicasTimeout, opts.TolerableReplLag, opts.durability, pr.logger)
+ opts.NewPrimaryAlias, err = ElectNewPrimary(ctx, pr.tmc, &ev.ShardInfo, tabletMap, innodbBufferPoolData, opts, pr.logger)
if err != nil {
return true, err
}
diff --git a/go/vt/vtctl/reparentutil/util.go b/go/vt/vtctl/reparentutil/util.go
index ea7a9f7262c..fd701f8c69b 100644
--- a/go/vt/vtctl/reparentutil/util.go
+++ b/go/vt/vtctl/reparentutil/util.go
@@ -69,11 +69,7 @@ func ElectNewPrimary(
shardInfo *topo.ShardInfo,
tabletMap map[string]*topo.TabletInfo,
innodbBufferPoolData map[string]int,
- newPrimaryAlias *topodatapb.TabletAlias,
- avoidPrimaryAlias *topodatapb.TabletAlias,
- waitReplicasTimeout time.Duration,
- tolerableReplLag time.Duration,
- durability Durabler,
+ opts *PlannedReparentOptions,
// (TODO:@ajm188) it's a little gross we need to pass this, maybe embed in the context?
logger logutil.Logger,
) (*topodatapb.TabletAlias, error) {
@@ -98,16 +94,16 @@ func ElectNewPrimary(
reasonsToInvalidate := strings.Builder{}
for _, tablet := range tabletMap {
switch {
- case newPrimaryAlias != nil:
+ case opts.NewPrimaryAlias != nil:
// If newPrimaryAlias is provided, then that is the only valid tablet, even if it is not of type replica or in a different cell.
- if !topoproto.TabletAliasEqual(tablet.Alias, newPrimaryAlias) {
+ if !topoproto.TabletAliasEqual(tablet.Alias, opts.NewPrimaryAlias) {
reasonsToInvalidate.WriteString(fmt.Sprintf("\n%v does not match the new primary alias provided", topoproto.TabletAliasString(tablet.Alias)))
continue
}
- case primaryCell != "" && tablet.Alias.Cell != primaryCell:
+ case !opts.AllowCrossCellPromotion && primaryCell != "" && tablet.Alias.Cell != primaryCell:
reasonsToInvalidate.WriteString(fmt.Sprintf("\n%v is not in the same cell as the previous primary", topoproto.TabletAliasString(tablet.Alias)))
continue
- case avoidPrimaryAlias != nil && topoproto.TabletAliasEqual(tablet.Alias, avoidPrimaryAlias):
+ case opts.AvoidPrimaryAlias != nil && topoproto.TabletAliasEqual(tablet.Alias, opts.AvoidPrimaryAlias):
reasonsToInvalidate.WriteString(fmt.Sprintf("\n%v matches the primary alias to avoid", topoproto.TabletAliasString(tablet.Alias)))
continue
case tablet.Tablet.Type != topodatapb.TabletType_REPLICA:
@@ -122,7 +118,7 @@ func ElectNewPrimary(
// then we don't need to find the position of the said tablet for sorting.
// We can just return the tablet quickly.
// This check isn't required, but it saves us an RPC call that is otherwise unnecessary.
- if len(candidates) == 1 && tolerableReplLag == 0 {
+ if len(candidates) == 1 && opts.TolerableReplLag == 0 {
return candidates[0].Alias, nil
}
@@ -130,10 +126,10 @@ func ElectNewPrimary(
tb := tablet
errorGroup.Go(func() error {
// find and store the positions for the tablet
- pos, replLag, err := findPositionAndLagForTablet(groupCtx, tb, logger, tmc, waitReplicasTimeout)
+ pos, replLag, err := findPositionAndLagForTablet(groupCtx, tb, logger, tmc, opts.WaitReplicasTimeout)
mu.Lock()
defer mu.Unlock()
- if err == nil && (tolerableReplLag == 0 || tolerableReplLag >= replLag) {
+ if err == nil && (opts.TolerableReplLag == 0 || opts.TolerableReplLag >= replLag) {
validTablets = append(validTablets, tb)
tabletPositions = append(tabletPositions, pos)
innodbBufferPool = append(innodbBufferPool, innodbBufferPoolData[topoproto.TabletAliasString(tb.Alias)])
@@ -155,7 +151,7 @@ func ElectNewPrimary(
}
// sort the tablets for finding the best primary
- err = sortTabletsForReparent(validTablets, tabletPositions, innodbBufferPool, durability)
+ err = sortTabletsForReparent(validTablets, tabletPositions, innodbBufferPool, opts.durability)
if err != nil {
return nil, err
}
diff --git a/go/vt/vtctl/reparentutil/util_test.go b/go/vt/vtctl/reparentutil/util_test.go
index d42ae76f337..f4e9092fc3f 100644
--- a/go/vt/vtctl/reparentutil/util_test.go
+++ b/go/vt/vtctl/reparentutil/util_test.go
@@ -67,16 +67,17 @@ func TestElectNewPrimary(t *testing.T) {
ctx := context.Background()
logger := logutil.NewMemoryLogger()
tests := []struct {
- name string
- tmc *chooseNewPrimaryTestTMClient
- shardInfo *topo.ShardInfo
- tabletMap map[string]*topo.TabletInfo
- innodbBufferPoolData map[string]int
- newPrimaryAlias *topodatapb.TabletAlias
- avoidPrimaryAlias *topodatapb.TabletAlias
- tolerableReplLag time.Duration
- expected *topodatapb.TabletAlias
- errContains []string
+ name string
+ tmc *chooseNewPrimaryTestTMClient
+ shardInfo *topo.ShardInfo
+ tabletMap map[string]*topo.TabletInfo
+ innodbBufferPoolData map[string]int
+ newPrimaryAlias *topodatapb.TabletAlias
+ avoidPrimaryAlias *topodatapb.TabletAlias
+ tolerableReplLag time.Duration
+ allowCrossCellPromotion bool
+ expected *topodatapb.TabletAlias
+ errContains []string
}{
{
name: "found a replica",
@@ -716,6 +717,64 @@ func TestElectNewPrimary(t *testing.T) {
`zone1-0000000102 is not in the same cell as the previous primary`,
},
},
+ {
+ name: "no replicas in primary cell but cross cell allowed",
+ tmc: &chooseNewPrimaryTestTMClient{
+ // zone1-101 is behind zone1-102
+ replicationStatuses: map[string]*replicationdatapb.Status{
+ "zone1-0000000101": {
+ Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1",
+ },
+ "zone1-0000000102": {
+ Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5",
+ },
+ },
+ },
+ allowCrossCellPromotion: true,
+ shardInfo: topo.NewShardInfo("testkeyspace", "-", &topodatapb.Shard{
+ PrimaryAlias: &topodatapb.TabletAlias{
+ Cell: "zone2",
+ Uid: 200,
+ },
+ }, nil),
+ tabletMap: map[string]*topo.TabletInfo{
+ "primary": {
+ Tablet: &topodatapb.Tablet{
+ Alias: &topodatapb.TabletAlias{
+ Cell: "zone2",
+ Uid: 200,
+ },
+ Type: topodatapb.TabletType_PRIMARY,
+ },
+ },
+ "replica1": {
+ Tablet: &topodatapb.Tablet{
+ Alias: &topodatapb.TabletAlias{
+ Cell: "zone1",
+ Uid: 101,
+ },
+ Type: topodatapb.TabletType_REPLICA,
+ },
+ },
+ "replica2": {
+ Tablet: &topodatapb.Tablet{
+ Alias: &topodatapb.TabletAlias{
+ Cell: "zone1",
+ Uid: 102,
+ },
+ Type: topodatapb.TabletType_REPLICA,
+ },
+ },
+ },
+ avoidPrimaryAlias: &topodatapb.TabletAlias{
+ Cell: "zone1",
+ Uid: 0,
+ },
+ expected: &topodatapb.TabletAlias{
+ Cell: "zone1",
+ Uid: 102,
+ },
+ },
{
name: "only available tablet is AvoidPrimary",
tmc: &chooseNewPrimaryTestTMClient{
@@ -794,7 +853,15 @@ zone1-0000000100 is not a replica`,
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
- actual, err := ElectNewPrimary(ctx, tt.tmc, tt.shardInfo, tt.tabletMap, tt.innodbBufferPoolData, tt.newPrimaryAlias, tt.avoidPrimaryAlias, time.Millisecond*50, tt.tolerableReplLag, durability, logger)
+ options := &PlannedReparentOptions{
+ NewPrimaryAlias: tt.newPrimaryAlias,
+ AvoidPrimaryAlias: tt.avoidPrimaryAlias,
+ TolerableReplLag: tt.tolerableReplLag,
+ durability: durability,
+ AllowCrossCellPromotion: tt.allowCrossCellPromotion,
+ WaitReplicasTimeout: time.Millisecond * 50,
+ }
+ actual, err := ElectNewPrimary(ctx, tt.tmc, tt.shardInfo, tt.tabletMap, tt.innodbBufferPoolData, options, logger)
if len(tt.errContains) > 0 {
for _, errC := range tt.errContains {
assert.ErrorContains(t, err, errC)
diff --git a/go/vt/vtctl/workflow/framework_test.go b/go/vt/vtctl/workflow/framework_test.go
index e2ccde0a0e7..56feeee0860 100644
--- a/go/vt/vtctl/workflow/framework_test.go
+++ b/go/vt/vtctl/workflow/framework_test.go
@@ -66,6 +66,7 @@ type testKeyspace struct {
type queryResult struct {
query string
result *querypb.QueryResult
+ err error
}
func TestMain(m *testing.M) {
@@ -389,7 +390,7 @@ func (tmc *testTMClient) VReplicationExec(ctx context.Context, tablet *topodatap
return nil, fmt.Errorf("tablet %v:\nunexpected query\n%s\nwant:\n%s", tablet, query, qrs[0].query)
}
tmc.vrQueries[int(tablet.Alias.Uid)] = qrs[1:]
- return qrs[0].result, nil
+ return qrs[0].result, qrs[0].err
}
func (tmc *testTMClient) ExecuteFetchAsDba(ctx context.Context, tablet *topodatapb.Tablet, usePool bool, req *tabletmanagerdatapb.ExecuteFetchAsDbaRequest) (*querypb.QueryResult, error) {
diff --git a/go/vt/vtctl/workflow/server.go b/go/vt/vtctl/workflow/server.go
index 5b6c3f05343..3601ed2d1a1 100644
--- a/go/vt/vtctl/workflow/server.go
+++ b/go/vt/vtctl/workflow/server.go
@@ -35,7 +35,6 @@ import (
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
- "vitess.io/vitess/go/mysql/sqlerror"
"vitess.io/vitess/go/protoutil"
"vitess.io/vitess/go/sets"
"vitess.io/vitess/go/sqlescape"
@@ -2548,7 +2547,7 @@ func (s *Server) optimizeCopyStateTable(tablet *topodatapb.Tablet) {
Query: []byte(sqlOptimizeTable),
MaxRows: uint64(100), // always produces 1+rows with notes and status
}); err != nil {
- if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num == sqlerror.ERNoSuchTable { // the table may not exist
+ if IsTableDidNotExistError(err) {
return
}
log.Warningf("Failed to optimize the copy_state table on %q: %v", tablet.Alias.String(), err)
diff --git a/go/vt/vtctl/workflow/server_test.go b/go/vt/vtctl/workflow/server_test.go
index c67d45bb9e6..542361a1571 100644
--- a/go/vt/vtctl/workflow/server_test.go
+++ b/go/vt/vtctl/workflow/server_test.go
@@ -213,15 +213,34 @@ func TestWorkflowDelete(t *testing.T) {
defer cancel()
workflowName := "wf1"
- tableName := "t1"
+ table1Name := "t1"
+ table2Name := "t1_2"
+ table3Name := "t1_3"
+ tableTemplate := "CREATE TABLE %s (id BIGINT, name VARCHAR(64), PRIMARY KEY (id))"
sourceKeyspaceName := "sourceks"
targetKeyspaceName := "targetks"
schema := map[string]*tabletmanagerdatapb.SchemaDefinition{
- "t1": {
+ table1Name: {
TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
{
- Name: tableName,
- Schema: fmt.Sprintf("CREATE TABLE %s (id BIGINT, name VARCHAR(64), PRIMARY KEY (id))", tableName),
+ Name: table1Name,
+ Schema: fmt.Sprintf(tableTemplate, table1Name),
+ },
+ },
+ },
+ table2Name: {
+ TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
+ {
+ Name: table2Name,
+ Schema: fmt.Sprintf(tableTemplate, table2Name),
+ },
+ },
+ },
+ table3Name: {
+ TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
+ {
+ Name: table3Name,
+ Schema: fmt.Sprintf(tableTemplate, table3Name),
},
},
},
@@ -239,7 +258,7 @@ func TestWorkflowDelete(t *testing.T) {
postFunc func(t *testing.T, env *testEnv)
}{
{
- name: "basic",
+ name: "missing table",
sourceKeyspace: &testKeyspace{
KeyspaceName: sourceKeyspaceName,
ShardNames: []string{"0"},
@@ -261,7 +280,21 @@ func TestWorkflowDelete(t *testing.T) {
},
expectedTargetQueries: []*queryResult{
{
- query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, tableName),
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table1Name),
+ result: &querypb.QueryResult{},
+ },
+ {
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table2Name),
+ result: &querypb.QueryResult{},
+ // We don't care that the cell and tablet info is off in the error message, only that
+ // it contains the expected SQL error we'd encounter when attempting to drop a table
+ // that doesn't exist. That will then cause this error to be non-fatal and the workflow
+ // delete work will continue.
+ err: fmt.Errorf("rpc error: code = Unknown desc = TabletManager.ExecuteFetchAsDba on cell-01: rpc error: code = Unknown desc = Unknown table 'vt_%s.%s' (errno 1051) (sqlstate 42S02) during query: drop table `vt_%s`.`%s`",
+ targetKeyspaceName, table2Name, targetKeyspaceName, table2Name),
+ },
+ {
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table3Name),
result: &querypb.QueryResult{},
},
},
@@ -281,7 +314,7 @@ func TestWorkflowDelete(t *testing.T) {
},
},
{
- name: "basic with existing denied table entries",
+ name: "missing denied table entries",
sourceKeyspace: &testKeyspace{
KeyspaceName: sourceKeyspaceName,
ShardNames: []string{"0"},
@@ -298,7 +331,9 @@ func TestWorkflowDelete(t *testing.T) {
defer targetUnlock(&err)
for _, shard := range env.targetKeyspace.ShardNames {
_, err := env.ts.UpdateShardFields(lockCtx, targetKeyspaceName, shard, func(si *topo.ShardInfo) error {
- err := si.UpdateDeniedTables(lockCtx, topodatapb.TabletType_PRIMARY, nil, false, []string{tableName, "t2", "t3"})
+ // So t1_2 and t1_3 do not exist in the denied table list when we go
+ // to remove t1, t1_2, and t1_3.
+ err := si.UpdateDeniedTables(lockCtx, topodatapb.TabletType_PRIMARY, nil, false, []string{table1Name, "t2", "t3"})
return err
})
require.NoError(t, err)
@@ -317,7 +352,15 @@ func TestWorkflowDelete(t *testing.T) {
},
expectedTargetQueries: []*queryResult{
{
- query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, tableName),
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table1Name),
+ result: &querypb.QueryResult{},
+ },
+ {
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table2Name),
+ result: &querypb.QueryResult{},
+ },
+ {
+ query: fmt.Sprintf("drop table `vt_%s`.`%s`", targetKeyspaceName, table3Name),
result: &querypb.QueryResult{},
},
},
diff --git a/go/vt/vtctl/workflow/traffic_switcher.go b/go/vt/vtctl/workflow/traffic_switcher.go
index c9d9952ef8f..bcc42d13ce9 100644
--- a/go/vt/vtctl/workflow/traffic_switcher.go
+++ b/go/vt/vtctl/workflow/traffic_switcher.go
@@ -30,7 +30,6 @@ import (
"golang.org/x/sync/errgroup"
"vitess.io/vitess/go/json2"
- "vitess.io/vitess/go/mysql/sqlerror"
"vitess.io/vitess/go/sqlescape"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/binlog/binlogplayer"
@@ -548,12 +547,12 @@ func (ts *trafficSwitcher) removeSourceTables(ctx context.Context, removalType T
DisableForeignKeyChecks: true,
})
if err != nil {
- if mysqlErr, ok := err.(*sqlerror.SQLError); ok && mysqlErr.Num == sqlerror.ERNoSuchTable {
+ if IsTableDidNotExistError(err) {
ts.Logger().Warningf("%s: Table %s did not exist when attempting to remove it", topoproto.TabletAliasString(source.GetPrimary().GetAlias()), tableName)
- return nil
+ } else {
+ ts.Logger().Errorf("%s: Error removing table %s: %v", topoproto.TabletAliasString(source.GetPrimary().GetAlias()), tableName, err)
+ return err
}
- ts.Logger().Errorf("%s: Error removing table %s: %v", topoproto.TabletAliasString(source.GetPrimary().GetAlias()), tableName, err)
- return err
}
ts.Logger().Infof("%s: Removed table %s.%s\n", topoproto.TabletAliasString(source.GetPrimary().GetAlias()), source.GetPrimary().DbName(), tableName)
@@ -1179,13 +1178,13 @@ func (ts *trafficSwitcher) removeTargetTables(ctx context.Context) error {
})
log.Infof("Removed target table with result: %+v", res)
if err != nil {
- if mysqlErr, ok := err.(*sqlerror.SQLError); ok && mysqlErr.Num == sqlerror.ERNoSuchTable {
+ if IsTableDidNotExistError(err) {
// The table was already gone, so we can ignore the error.
ts.Logger().Warningf("%s: Table %s did not exist when attempting to remove it", topoproto.TabletAliasString(target.GetPrimary().GetAlias()), tableName)
- return nil
+ } else {
+ ts.Logger().Errorf("%s: Error removing table %s: %v", topoproto.TabletAliasString(target.GetPrimary().GetAlias()), tableName, err)
+ return err
}
- ts.Logger().Errorf("%s: Error removing table %s: %v", topoproto.TabletAliasString(target.GetPrimary().GetAlias()), tableName, err)
- return err
}
ts.Logger().Infof("%s: Removed table %s.%s\n",
topoproto.TabletAliasString(target.GetPrimary().GetAlias()), target.GetPrimary().DbName(), tableName)
diff --git a/go/vt/vtctl/workflow/utils.go b/go/vt/vtctl/workflow/utils.go
index d4e8d7b4ec0..9cedf01733e 100644
--- a/go/vt/vtctl/workflow/utils.go
+++ b/go/vt/vtctl/workflow/utils.go
@@ -28,12 +28,9 @@ import (
"strings"
"sync"
- querypb "vitess.io/vitess/go/vt/proto/query"
-
- "vitess.io/vitess/go/vt/vtgate/vindexes"
-
"google.golang.org/protobuf/encoding/prototext"
+ "vitess.io/vitess/go/mysql/sqlerror"
"vitess.io/vitess/go/sets"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/concurrency"
@@ -46,9 +43,11 @@ import (
"vitess.io/vitess/go/vt/topo/topoproto"
"vitess.io/vitess/go/vt/topotools"
"vitess.io/vitess/go/vt/vterrors"
+ "vitess.io/vitess/go/vt/vtgate/vindexes"
"vitess.io/vitess/go/vt/vttablet/tmclient"
binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
+ querypb "vitess.io/vitess/go/vt/proto/query"
tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
vtctldatapb "vitess.io/vitess/go/vt/proto/vtctldata"
@@ -949,3 +948,14 @@ func getTabletTypeSuffix(tabletType topodatapb.TabletType) string {
}
return ""
}
+
+// IsTableDidNotExistError will convert the given error to an sqlerror.SQLError and if
+// the error code is ERNoSuchTable or ERBadTable, it will return true. This is helpful
+// when e.g. processing a gRPC error which will be a status.Error that needs to be
+// converted to an sqlerror.SQLError before we can examine the error code.
+func IsTableDidNotExistError(err error) bool {
+ if sqlErr, ok := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError); ok {
+ return sqlErr.Num == sqlerror.ERNoSuchTable || sqlErr.Num == sqlerror.ERBadTable
+ }
+ return false
+}
diff --git a/go/vt/vterrors/code.go b/go/vt/vterrors/code.go
index d485c930b77..83a87503265 100644
--- a/go/vt/vterrors/code.go
+++ b/go/vt/vterrors/code.go
@@ -96,8 +96,10 @@ var (
VT09022 = errorWithoutState("VT09022", vtrpcpb.Code_FAILED_PRECONDITION, "Destination does not have exactly one shard: %v", "Cannot send query to multiple shards.")
VT09023 = errorWithoutState("VT09023", vtrpcpb.Code_FAILED_PRECONDITION, "could not map %v to a keyspace id", "Unable to determine the shard for the given row.")
VT09024 = errorWithoutState("VT09024", vtrpcpb.Code_FAILED_PRECONDITION, "could not map %v to a unique keyspace id: %v", "Unable to determine the shard for the given row.")
+ VT09025 = errorWithoutState("VT09025", vtrpcpb.Code_FAILED_PRECONDITION, "atomic transaction error: %v", "Error in atomic transactions")
VT10001 = errorWithoutState("VT10001", vtrpcpb.Code_ABORTED, "foreign key constraints are not allowed", "Foreign key constraints are not allowed, see https://vitess.io/blog/2021-06-15-online-ddl-why-no-fk/.")
+ VT10002 = errorWithoutState("VT10002", vtrpcpb.Code_ABORTED, "atomic distributed transaction not allowed: %s", "The distributed transaction cannot be committed. A rollback decision is taken.")
VT12001 = errorWithoutState("VT12001", vtrpcpb.Code_UNIMPLEMENTED, "unsupported: %s", "This statement is unsupported by Vitess. Please rewrite your query to use supported syntax.")
VT12002 = errorWithoutState("VT12002", vtrpcpb.Code_UNIMPLEMENTED, "unsupported: cross-shard foreign keys", "Vitess does not support cross shard foreign keys.")
@@ -182,6 +184,7 @@ var (
VT09023,
VT09024,
VT10001,
+ VT10002,
VT12001,
VT12002,
VT13001,
diff --git a/go/vt/vtgate/debug_2pc.go b/go/vt/vtgate/debug_2pc.go
index f31f1413007..dc052df33d6 100644
--- a/go/vt/vtgate/debug_2pc.go
+++ b/go/vt/vtgate/debug_2pc.go
@@ -18,4 +18,52 @@ limitations under the License.
package vtgate
+import (
+ "context"
+
+ "vitess.io/vitess/go/vt/callerid"
+ "vitess.io/vitess/go/vt/log"
+ querypb "vitess.io/vitess/go/vt/proto/query"
+ vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
+ "vitess.io/vitess/go/vt/vterrors"
+)
+
const DebugTwoPc = true
+
+// checkTestFailure is used to simulate failures in 2PC flow for testing when DebugTwoPc is true.
+func checkTestFailure(ctx context.Context, expectCaller string, target *querypb.Target) error {
+ callerID := callerid.EffectiveCallerIDFromContext(ctx)
+ if callerID == nil || callerID.GetPrincipal() != expectCaller {
+ return nil
+ }
+ switch callerID.Principal {
+ case "TRCreated_FailNow":
+ log.Errorf("Fail After TR created")
+ // no commit decision is made. Transaction should be a rolled back.
+ return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After TR created")
+ case "RMPrepare_-40_FailNow":
+ if target.Shard != "-40" {
+ return nil
+ }
+ log.Errorf("Fail During RM prepare")
+ // no commit decision is made. Transaction should be a rolled back.
+ return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail During RM prepare")
+ case "RMPrepared_FailNow":
+ log.Errorf("Fail After RM prepared")
+ // no commit decision is made. Transaction should be a rolled back.
+ return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After RM prepared")
+ case "MMCommitted_FailNow":
+ log.Errorf("Fail After MM commit")
+ // commit decision is made. Transaction should be committed.
+ return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After MM commit")
+ case "RMCommit_-40_FailNow":
+ if target.Shard != "-40" {
+ return nil
+ }
+ log.Errorf("Fail During RM commit")
+ // commit decision is made. Transaction should be a committed.
+ return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail During RM commit")
+ default:
+ return nil
+ }
+}
diff --git a/go/vt/vtgate/engine/fake_vcursor_test.go b/go/vt/vtgate/engine/fake_vcursor_test.go
index adc425c0632..653bcf64576 100644
--- a/go/vt/vtgate/engine/fake_vcursor_test.go
+++ b/go/vt/vtgate/engine/fake_vcursor_test.go
@@ -342,7 +342,7 @@ func (t *noopVCursor) ExceedsMaxMemoryRows(numRows int) bool {
}
func (t *noopVCursor) GetKeyspace() string {
- return ""
+ return "test_ks"
}
func (t *noopVCursor) RecordWarning(warning *querypb.QueryWarning) {
diff --git a/go/vt/vtgate/engine/transaction_status.go b/go/vt/vtgate/engine/transaction_status.go
index a087db08256..61cc72c08d9 100644
--- a/go/vt/vtgate/engine/transaction_status.go
+++ b/go/vt/vtgate/engine/transaction_status.go
@@ -84,7 +84,7 @@ func (t *TransactionStatus) TryExecute(ctx context.Context, vcursor VCursor, bin
if wantfields {
res.Fields = t.getFields()
}
- if transactionState != nil {
+ if transactionState != nil && transactionState.Dtid != "" {
var participantString []string
for _, participant := range transactionState.Participants {
participantString = append(participantString, fmt.Sprintf("%s:%s", participant.Keyspace, participant.Shard))
diff --git a/go/vt/vtgate/engine/vindex_func.go b/go/vt/vtgate/engine/vindex_func.go
index ecd83baeaad..13507631716 100644
--- a/go/vt/vtgate/engine/vindex_func.go
+++ b/go/vt/vtgate/engine/vindex_func.go
@@ -153,6 +153,9 @@ func (vf *VindexFunc) mapVindex(ctx context.Context, vcursor VCursor, bindVars m
case key.DestinationKeyspaceID:
if len(d) > 0 {
if vcursor != nil {
+ if vcursor.GetKeyspace() == "" {
+ return nil, vterrors.VT09005()
+ }
resolvedShards, _, err := vcursor.ResolveDestinations(ctx, vcursor.GetKeyspace(), nil, []key.Destination{d})
if err != nil {
return nil, err
diff --git a/go/vt/vtgate/evalengine/cached_size.go b/go/vt/vtgate/evalengine/cached_size.go
index 6f447f0d1c1..c1ed1f9475c 100644
--- a/go/vt/vtgate/evalengine/cached_size.go
+++ b/go/vt/vtgate/evalengine/cached_size.go
@@ -1397,6 +1397,30 @@ func (cached *builtinPad) CachedSize(alloc bool) int64 {
size += cached.CallExpr.CachedSize(false)
return size
}
+func (cached *builtinPeriodAdd) CachedSize(alloc bool) int64 {
+ if cached == nil {
+ return int64(0)
+ }
+ size := int64(0)
+ if alloc {
+ size += int64(48)
+ }
+ // field CallExpr vitess.io/vitess/go/vt/vtgate/evalengine.CallExpr
+ size += cached.CallExpr.CachedSize(false)
+ return size
+}
+func (cached *builtinPeriodDiff) CachedSize(alloc bool) int64 {
+ if cached == nil {
+ return int64(0)
+ }
+ size := int64(0)
+ if alloc {
+ size += int64(48)
+ }
+ // field CallExpr vitess.io/vitess/go/vt/vtgate/evalengine.CallExpr
+ size += cached.CallExpr.CachedSize(false)
+ return size
+}
func (cached *builtinPi) CachedSize(alloc bool) int64 {
if cached == nil {
return int64(0)
diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go
index 0cac66d9e5e..dfb1a30bffc 100644
--- a/go/vt/vtgate/evalengine/compiler_asm.go
+++ b/go/vt/vtgate/evalengine/compiler_asm.go
@@ -4299,6 +4299,46 @@ func (asm *assembler) Fn_YEARWEEK() {
}, "FN YEARWEEK DATE(SP-1)")
}
+func (asm *assembler) Fn_PERIOD_ADD() {
+ asm.adjustStack(-1)
+ asm.emit(func(env *ExpressionEnv) int {
+ if env.vm.stack[env.vm.sp-2] == nil {
+ env.vm.sp--
+ return 1
+ }
+ period := env.vm.stack[env.vm.sp-2].(*evalInt64).i
+ months := env.vm.stack[env.vm.sp-1].(*evalInt64).i
+ res, err := periodAdd(period, months)
+ if err != nil {
+ env.vm.err = err
+ return 0
+ }
+ env.vm.stack[env.vm.sp-2] = res
+ env.vm.sp--
+ return 1
+ }, "FN PERIOD_ADD INT64(SP-2) INT64(SP-1)")
+}
+
+func (asm *assembler) Fn_PERIOD_DIFF() {
+ asm.adjustStack(-1)
+ asm.emit(func(env *ExpressionEnv) int {
+ if env.vm.stack[env.vm.sp-2] == nil {
+ env.vm.sp--
+ return 1
+ }
+ period1 := env.vm.stack[env.vm.sp-2].(*evalInt64).i
+ period2 := env.vm.stack[env.vm.sp-1].(*evalInt64).i
+ res, err := periodDiff(period1, period2)
+ if err != nil {
+ env.vm.err = err
+ return 0
+ }
+ env.vm.stack[env.vm.sp-2] = res
+ env.vm.sp--
+ return 1
+ }, "FN PERIOD_DIFF INT64(SP-2) INT64(SP-1)")
+}
+
func (asm *assembler) Interval(l int) {
asm.adjustStack(-l)
asm.emit(func(env *ExpressionEnv) int {
diff --git a/go/vt/vtgate/evalengine/fn_time.go b/go/vt/vtgate/evalengine/fn_time.go
index 8d920e9e135..2d5e12f518d 100644
--- a/go/vt/vtgate/evalengine/fn_time.go
+++ b/go/vt/vtgate/evalengine/fn_time.go
@@ -26,6 +26,9 @@ import (
"vitess.io/vitess/go/mysql/datetime"
"vitess.io/vitess/go/mysql/decimal"
"vitess.io/vitess/go/sqltypes"
+ "vitess.io/vitess/go/vt/vterrors"
+
+ vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)
var SystemTime = time.Now
@@ -174,6 +177,14 @@ type (
CallExpr
}
+ builtinPeriodAdd struct {
+ CallExpr
+ }
+
+ builtinPeriodDiff struct {
+ CallExpr
+ }
+
builtinDateMath struct {
CallExpr
sub bool
@@ -214,6 +225,8 @@ var _ IR = (*builtinWeekDay)(nil)
var _ IR = (*builtinWeekOfYear)(nil)
var _ IR = (*builtinYear)(nil)
var _ IR = (*builtinYearWeek)(nil)
+var _ IR = (*builtinPeriodAdd)(nil)
+var _ IR = (*builtinPeriodDiff)(nil)
func (call *builtinNow) eval(env *ExpressionEnv) (eval, error) {
now := env.time(call.utc)
@@ -1964,6 +1977,105 @@ func (call *builtinYearWeek) compile(c *compiler) (ctype, error) {
return ctype{Type: sqltypes.Int64, Col: collationNumeric, Flag: arg.Flag | flagNullable}, nil
}
+func periodAdd(period, months int64) (*evalInt64, error) {
+ if !datetime.ValidatePeriod(period) {
+ return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongArguments, "Incorrect arguments to period_add")
+ }
+ return newEvalInt64(datetime.MonthsToPeriod(datetime.PeriodToMonths(period) + months)), nil
+}
+
+func (b *builtinPeriodAdd) eval(env *ExpressionEnv) (eval, error) {
+ p, m, err := b.arg2(env)
+ if err != nil {
+ return nil, err
+ }
+ if p == nil || m == nil {
+ return nil, nil
+ }
+ period := evalToInt64(p)
+ months := evalToInt64(m)
+ return periodAdd(period.i, months.i)
+}
+
+func (call *builtinPeriodAdd) compile(c *compiler) (ctype, error) {
+ period, err := call.Arguments[0].compile(c)
+ if err != nil {
+ return ctype{}, err
+ }
+ months, err := call.Arguments[1].compile(c)
+ if err != nil {
+ return ctype{}, err
+ }
+
+ skip := c.compileNullCheck2(period, months)
+
+ switch period.Type {
+ case sqltypes.Int64:
+ default:
+ c.asm.Convert_xi(2)
+ }
+
+ switch months.Type {
+ case sqltypes.Int64:
+ default:
+ c.asm.Convert_xi(1)
+ }
+
+ c.asm.Fn_PERIOD_ADD()
+ c.asm.jumpDestination(skip)
+ return ctype{Type: sqltypes.Int64, Flag: period.Flag | months.Flag | flagNullable}, nil
+}
+
+func periodDiff(period1, period2 int64) (*evalInt64, error) {
+ if !datetime.ValidatePeriod(period1) || !datetime.ValidatePeriod(period2) {
+ return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.WrongArguments, "Incorrect arguments to period_diff")
+ }
+ res := datetime.PeriodToMonths(period1) - datetime.PeriodToMonths(period2)
+ return newEvalInt64(res), nil
+}
+
+func (b *builtinPeriodDiff) eval(env *ExpressionEnv) (eval, error) {
+ p1, p2, err := b.arg2(env)
+ if err != nil {
+ return nil, err
+ }
+ if p1 == nil || p2 == nil {
+ return nil, nil
+ }
+ period1 := evalToInt64(p1)
+ period2 := evalToInt64(p2)
+ return periodDiff(period1.i, period2.i)
+}
+
+func (call *builtinPeriodDiff) compile(c *compiler) (ctype, error) {
+ period1, err := call.Arguments[0].compile(c)
+ if err != nil {
+ return ctype{}, err
+ }
+ period2, err := call.Arguments[1].compile(c)
+ if err != nil {
+ return ctype{}, err
+ }
+
+ skip := c.compileNullCheck2(period1, period2)
+
+ switch period1.Type {
+ case sqltypes.Int64:
+ default:
+ c.asm.Convert_xi(2)
+ }
+
+ switch period2.Type {
+ case sqltypes.Int64:
+ default:
+ c.asm.Convert_xi(1)
+ }
+
+ c.asm.Fn_PERIOD_DIFF()
+ c.asm.jumpDestination(skip)
+ return ctype{Type: sqltypes.Int64, Flag: period1.Flag | period2.Flag | flagNullable}, nil
+}
+
func evalToInterval(itv eval, unit datetime.IntervalType, negate bool) *datetime.Interval {
switch itv := itv.(type) {
case *evalBytes:
diff --git a/go/vt/vtgate/evalengine/testcases/cases.go b/go/vt/vtgate/evalengine/testcases/cases.go
index 003eb45c0a3..ed1c5ed1f76 100644
--- a/go/vt/vtgate/evalengine/testcases/cases.go
+++ b/go/vt/vtgate/evalengine/testcases/cases.go
@@ -155,6 +155,8 @@ var Cases = []TestCase{
{Run: FnWeekOfYear},
{Run: FnYear},
{Run: FnYearWeek},
+ {Run: FnPeriodAdd},
+ {Run: FnPeriodDiff},
{Run: FnInetAton},
{Run: FnInetNtoa},
{Run: FnInet6Aton},
@@ -2223,6 +2225,48 @@ func FnYearWeek(yield Query) {
}
}
+func FnPeriodAdd(yield Query) {
+ for _, p := range inputBitwise {
+ for _, m := range inputBitwise {
+ yield(fmt.Sprintf("PERIOD_ADD(%s, %s)", p, m), nil)
+ }
+ }
+ for _, p := range inputPeriods {
+ for _, m := range inputBitwise {
+ yield(fmt.Sprintf("PERIOD_ADD(%s, %s)", p, m), nil)
+ }
+ }
+
+ mysqlDocSamples := []string{
+ `PERIOD_ADD(200801,2)`,
+ }
+
+ for _, q := range mysqlDocSamples {
+ yield(q, nil)
+ }
+}
+
+func FnPeriodDiff(yield Query) {
+ for _, p1 := range inputBitwise {
+ for _, p2 := range inputBitwise {
+ yield(fmt.Sprintf("PERIOD_DIFF(%s, %s)", p1, p2), nil)
+ }
+ }
+ for _, p1 := range inputPeriods {
+ for _, p2 := range inputPeriods {
+ yield(fmt.Sprintf("PERIOD_DIFF(%s, %s)", p1, p2), nil)
+ }
+ }
+
+ mysqlDocSamples := []string{
+ `PERIOD_DIFF(200802,200703)`,
+ }
+
+ for _, q := range mysqlDocSamples {
+ yield(q, nil)
+ }
+}
+
func FnInetAton(yield Query) {
for _, d := range ipInputs {
yield(fmt.Sprintf("INET_ATON(%s)", d), nil)
diff --git a/go/vt/vtgate/evalengine/testcases/inputs.go b/go/vt/vtgate/evalengine/testcases/inputs.go
index eb94235d9b4..ac23281fd54 100644
--- a/go/vt/vtgate/evalengine/testcases/inputs.go
+++ b/go/vt/vtgate/evalengine/testcases/inputs.go
@@ -59,6 +59,11 @@ var inputBitwise = []string{
"64", "'64'", "_binary '64'", "X'40'", "_binary X'40'",
}
+var inputPeriods = []string{
+ "110192", "'119812'", "2703", "7111", "200103", "200309", "0309", "-110102", "0",
+ "'032'", "223", "'-119812'", "-2703", "99999999999999999999999911", "'-0309'",
+}
+
var radianInputs = []string{
"0",
"1",
diff --git a/go/vt/vtgate/evalengine/translate_builtin.go b/go/vt/vtgate/evalengine/translate_builtin.go
index d4c6bcdae5a..476ee32483b 100644
--- a/go/vt/vtgate/evalengine/translate_builtin.go
+++ b/go/vt/vtgate/evalengine/translate_builtin.go
@@ -528,6 +528,20 @@ func (ast *astCompiler) translateFuncExpr(fn *sqlparser.FuncExpr) (IR, error) {
default:
return nil, argError(method)
}
+ case "period_add":
+ switch len(args) {
+ case 2:
+ return &builtinPeriodAdd{CallExpr: call}, nil
+ default:
+ return nil, argError(method)
+ }
+ case "period_diff":
+ switch len(args) {
+ case 2:
+ return &builtinPeriodDiff{CallExpr: call}, nil
+ default:
+ return nil, argError(method)
+ }
case "inet_aton":
if len(args) != 1 {
return nil, argError(method)
diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go
index bd24907af9b..6e3bcdd3eda 100644
--- a/go/vt/vtgate/executor_select_test.go
+++ b/go/vt/vtgate/executor_select_test.go
@@ -427,6 +427,19 @@ func TestSetSystemVariablesWithReservedConnection(t *testing.T) {
sbc1.Queries = nil
}
+func TestSelectVindexFunc(t *testing.T) {
+ executor, _, _, _, _ := createExecutorEnv(t)
+
+ query := "select * from hash_index where id = 1"
+ session := NewAutocommitSession(&vtgatepb.Session{})
+ _, err := executor.Execute(context.Background(), nil, "TestSelectVindexFunc", session, query, nil)
+ require.ErrorContains(t, err, "VT09005: no database selected")
+
+ session.TargetString = KsTestSharded
+ _, err = executor.Execute(context.Background(), nil, "TestSelectVindexFunc", session, query, nil)
+ require.NoError(t, err)
+}
+
func TestCreateTableValidTimestamp(t *testing.T) {
executor, sbc1, _, _, _ := createExecutorEnv(t)
executor.normalize = true
@@ -4335,3 +4348,50 @@ func TestStreamJoinQuery(t *testing.T) {
utils.MustMatch(t, wantResult.Rows[idx], result.Rows[idx], "mismatched on: ", strconv.Itoa(idx))
}
}
+
+// TestSysVarGlobalAndSession tests that global and session variables are set correctly.
+// It also tests that setting a global variable does not affect the session variable and vice versa.
+// Also, test what happens on running select @@global and select @@session for a system variable.
+func TestSysVarGlobalAndSession(t *testing.T) {
+ executor, sbc1, _, _, _ := createExecutorEnv(t)
+ executor.normalize = true
+ session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, SystemVariables: map[string]string{}})
+
+ sbc1.SetResults([]*sqltypes.Result{
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("innodb_lock_wait_timeout", "uint64"), "20"),
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("innodb_lock_wait_timeout", "uint64"), "20"),
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("1", "int64")),
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("new", "uint64"), "40"),
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("reserve_execute", "uint64")),
+ sqltypes.MakeTestResult(sqltypes.MakeTestFields("@@global.innodb_lock_wait_timeout", "uint64"), "20"),
+ })
+ qr, err := executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "select @@innodb_lock_wait_timeout", nil)
+ require.NoError(t, err)
+ require.Equal(t, `[[UINT64(20)]]`, fmt.Sprintf("%v", qr.Rows))
+
+ qr, err = executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "select @@global.innodb_lock_wait_timeout", nil)
+ require.NoError(t, err)
+ require.Equal(t, `[[UINT64(20)]]`, fmt.Sprintf("%v", qr.Rows))
+
+ _, err = executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "set @@global.innodb_lock_wait_timeout = 120", nil)
+ require.NoError(t, err)
+ require.Empty(t, session.SystemVariables["innodb_lock_wait_timeout"])
+
+ _, err = executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "set @@innodb_lock_wait_timeout = 40", nil)
+ require.NoError(t, err)
+ require.EqualValues(t, "40", session.SystemVariables["innodb_lock_wait_timeout"])
+
+ qr, err = executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "select @@innodb_lock_wait_timeout", nil)
+ require.NoError(t, err)
+ require.Equal(t, `[[INT64(40)]]`, fmt.Sprintf("%v", qr.Rows))
+
+ qr, err = executor.Execute(context.Background(), nil, "TestSetStmt", session,
+ "select @@global.innodb_lock_wait_timeout", nil)
+ require.NoError(t, err)
+ require.Equal(t, `[[UINT64(20)]]`, fmt.Sprintf("%v", qr.Rows))
+}
diff --git a/go/vt/vtgate/executor_set_test.go b/go/vt/vtgate/executor_set_test.go
index 5e66899db44..2792c957edd 100644
--- a/go/vt/vtgate/executor_set_test.go
+++ b/go/vt/vtgate/executor_set_test.go
@@ -364,6 +364,13 @@ func TestExecutorSetOp(t *testing.T) {
in: "set tx_isolation = 'read-committed'",
sysVars: map[string]string{"tx_isolation": "'read-committed'"},
result: returnResult("tx_isolation", "varchar", "read-committed"),
+ }, {
+ in: "set @@innodb_lock_wait_timeout=120",
+ sysVars: map[string]string{"innodb_lock_wait_timeout": "120"},
+ result: returnResult("innodb_lock_wait_timeout", "int64", "120"),
+ }, {
+ in: "set @@global.innodb_lock_wait_timeout=120",
+ result: returnResult("innodb_lock_wait_timeout", "int64", "120"),
}}
for _, tcase := range testcases {
t.Run(tcase.in, func(t *testing.T) {
diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go
index cce717674d6..b8e2b996780 100644
--- a/go/vt/vtgate/executor_test.go
+++ b/go/vt/vtgate/executor_test.go
@@ -1105,6 +1105,15 @@ func TestExecutorShowTargeted(t *testing.T) {
}
}
+func TestExecutorShowFromSystemSchema(t *testing.T) {
+ executor, _, _, _, ctx := createExecutorEnv(t)
+
+ session := NewSafeSession(&vtgatepb.Session{TargetString: "mysql"})
+
+ _, err := executor.Execute(ctx, nil, "TestExecutorShowFromSystemSchema", session, "show tables", nil)
+ require.NoError(t, err)
+}
+
func TestExecutorUse(t *testing.T) {
executor, _, _, _, ctx := createExecutorEnv(t)
diff --git a/go/vt/vtgate/planbuilder/operators/apply_join.go b/go/vt/vtgate/planbuilder/operators/apply_join.go
index cd8f7b94dd5..ef36f6a6765 100644
--- a/go/vt/vtgate/planbuilder/operators/apply_join.go
+++ b/go/vt/vtgate/planbuilder/operators/apply_join.go
@@ -37,8 +37,6 @@ type (
// JoinType is permitted to store only 3 of the possible values
// NormalJoinType, StraightJoinType and LeftJoinType.
JoinType sqlparser.JoinType
- // LeftJoin will be true in the case of an outer join
- LeftJoin bool
// JoinColumns keeps track of what AST expression is represented in the Columns array
JoinColumns *applyJoinColumns
@@ -295,7 +293,7 @@ func (aj *ApplyJoin) AddWSColumn(ctx *plancontext.PlanningContext, offset int, u
func (aj *ApplyJoin) planOffsets(ctx *plancontext.PlanningContext) Operator {
if len(aj.Columns) > 0 {
// we've already done offset planning
- return aj
+ return nil
}
for _, col := range aj.JoinColumns.columns {
// Read the type description for applyJoinColumn to understand the following code
@@ -344,6 +342,10 @@ func (aj *ApplyJoin) ShortDescription() string {
}
firstPart := fmt.Sprintf("on %s columns: %s", fn(aj.JoinPredicates), fn(aj.JoinColumns))
+ if aj.JoinType == sqlparser.LeftJoinType {
+ firstPart = "LEFT JOIN " + firstPart
+ }
+
if len(aj.ExtraLHSVars) == 0 {
return firstPart
}
diff --git a/go/vt/vtgate/planbuilder/operators/dml_with_input.go b/go/vt/vtgate/planbuilder/operators/dml_with_input.go
index 09859b90bac..3843e2f3fa8 100644
--- a/go/vt/vtgate/planbuilder/operators/dml_with_input.go
+++ b/go/vt/vtgate/planbuilder/operators/dml_with_input.go
@@ -114,7 +114,7 @@ func (d *DMLWithInput) planOffsets(ctx *plancontext.PlanningContext) Operator {
}
}
d.BvList = bvList
- return d
+ return nil
}
var _ Operator = (*DMLWithInput)(nil)
diff --git a/go/vt/vtgate/planbuilder/operators/hash_join.go b/go/vt/vtgate/planbuilder/operators/hash_join.go
index 1928f4dda9e..23d0d061e21 100644
--- a/go/vt/vtgate/planbuilder/operators/hash_join.go
+++ b/go/vt/vtgate/planbuilder/operators/hash_join.go
@@ -326,20 +326,9 @@ func (hj *HashJoin) addColumn(ctx *plancontext.PlanningContext, in sqlparser.Exp
inOffset = op.AddColumn(ctx, false, false, aeWrap(expr))
}
- // we turn the
+ // we have to turn the incoming offset to an outgoing offset of the columns this operator is exposing
internalOffset := offsetter(inOffset)
-
- // ok, we have an offset from the input operator. Let's check if we already have it
- // in our list of incoming columns
-
- for idx, offset := range hj.ColumnOffsets {
- if internalOffset == offset {
- return idx
- }
- }
-
hj.ColumnOffsets = append(hj.ColumnOffsets, internalOffset)
-
return len(hj.ColumnOffsets) - 1
}
@@ -434,17 +423,7 @@ func (hj *HashJoin) addSingleSidedColumn(
// we have to turn the incoming offset to an outgoing offset of the columns this operator is exposing
internalOffset := offsetter(inOffset)
-
- // ok, we have an offset from the input operator. Let's check if we already have it
- // in our list of incoming columns
- for idx, offset := range hj.ColumnOffsets {
- if internalOffset == offset {
- return idx
- }
- }
-
hj.ColumnOffsets = append(hj.ColumnOffsets, internalOffset)
-
return len(hj.ColumnOffsets) - 1
}
diff --git a/go/vt/vtgate/planbuilder/operators/join_merging.go b/go/vt/vtgate/planbuilder/operators/join_merging.go
index 8bba8ba57d9..6f2af8b5ff9 100644
--- a/go/vt/vtgate/planbuilder/operators/join_merging.go
+++ b/go/vt/vtgate/planbuilder/operators/join_merging.go
@@ -22,6 +22,7 @@ import (
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
+ "vitess.io/vitess/go/vt/vtgate/vindexes"
)
// mergeJoinInputs checks whether two operators can be merged into a single one.
@@ -34,9 +35,9 @@ func mergeJoinInputs(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinPr
}
switch {
+ // We clone the right hand side and try and push all the join predicates that are solved entirely by that side.
+ // If a dual is on the left side, and it is a left join (all right joins are changed to left joins), then we can only merge if the right side is a single sharded routing.
case a == dual:
- // We clone the right hand side and try and push all the join predicates that are solved entirely by that side.
- // If a dual is on the left side and it is a left join (all right joins are changed to left joins), then we can only merge if the right side is a single sharded routing.
rhsClone := Clone(rhs).(*Route)
for _, predicate := range joinPredicates {
if ctx.SemTable.DirectDeps(predicate).IsSolvedBy(TableID(rhsClone)) {
@@ -47,10 +48,16 @@ func mergeJoinInputs(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinPr
return nil
}
return m.merge(ctx, lhsRoute, rhsClone, rhsClone.Routing)
+
+ // If a dual is on the right side.
case b == dual:
- // If a dual is on the right side.
return m.merge(ctx, lhsRoute, rhsRoute, routingA)
+ // As both are reference route. We need to merge the alternates as well.
+ case a == anyShard && b == anyShard && sameKeyspace:
+ newrouting := mergeAnyShardRoutings(ctx, routingA.(*AnyShardRouting), routingB.(*AnyShardRouting), joinPredicates, m.joinType)
+ return m.merge(ctx, lhsRoute, rhsRoute, newrouting)
+
// an unsharded/reference route can be merged with anything going to that keyspace
case a == anyShard && sameKeyspace:
return m.merge(ctx, lhsRoute, rhsRoute, routingB)
@@ -69,13 +76,33 @@ func mergeJoinInputs(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinPr
// sharded routing is complex, so we handle it in a separate method
case a == sharded && b == sharded:
- return tryMergeJoinShardedRouting(ctx, lhsRoute, rhsRoute, m, joinPredicates)
+ return tryMergeShardedRouting(ctx, lhsRoute, rhsRoute, m, joinPredicates)
default:
return nil
}
}
+func mergeAnyShardRoutings(ctx *plancontext.PlanningContext, a, b *AnyShardRouting, joinPredicates []sqlparser.Expr, joinType sqlparser.JoinType) *AnyShardRouting {
+ alternates := make(map[*vindexes.Keyspace]*Route)
+ for ak, av := range a.Alternates {
+ for bk, bv := range b.Alternates {
+ // only same keyspace alternates can be merged.
+ if ak != bk {
+ continue
+ }
+ op, _ := mergeOrJoin(ctx, av, bv, joinPredicates, joinType)
+ if r, ok := op.(*Route); ok {
+ alternates[ak] = r
+ }
+ }
+ }
+ return &AnyShardRouting{
+ keyspace: a.keyspace,
+ Alternates: alternates,
+ }
+}
+
func prepareInputRoutes(lhs Operator, rhs Operator) (*Route, *Route, Routing, Routing, routingType, routingType, bool) {
lhsRoute, rhsRoute := operatorsToRoutes(lhs, rhs)
if lhsRoute == nil || rhsRoute == nil {
diff --git a/go/vt/vtgate/planbuilder/operators/joins.go b/go/vt/vtgate/planbuilder/operators/joins.go
index 86cdf06fe7e..fb740fd1920 100644
--- a/go/vt/vtgate/planbuilder/operators/joins.go
+++ b/go/vt/vtgate/planbuilder/operators/joins.go
@@ -17,7 +17,10 @@ limitations under the License.
package operators
import (
+ "fmt"
+
"vitess.io/vitess/go/vt/sqlparser"
+ "vitess.io/vitess/go/vt/vterrors"
"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
"vitess.io/vitess/go/vt/vtgate/semantics"
)
@@ -86,7 +89,7 @@ func AddPredicate(
return join
}
- return nil
+ panic(vterrors.VT13001(fmt.Sprintf("pushed wrong predicate to the join: %s", sqlparser.String(expr))))
}
// we are looking for predicates like `tbl.col = <>` or `<> = tbl.col`,
diff --git a/go/vt/vtgate/planbuilder/operators/offset_planning.go b/go/vt/vtgate/planbuilder/operators/offset_planning.go
index 7a9cedccb89..e8301c18823 100644
--- a/go/vt/vtgate/planbuilder/operators/offset_planning.go
+++ b/go/vt/vtgate/planbuilder/operators/offset_planning.go
@@ -38,7 +38,6 @@ func planOffsets(ctx *plancontext.PlanningContext, root Operator) Operator {
panic(vterrors.VT13001(fmt.Sprintf("should not see %T here", in)))
case offsettable:
newOp := op.planOffsets(ctx)
-
if newOp == nil {
newOp = op
}
@@ -47,7 +46,13 @@ func planOffsets(ctx *plancontext.PlanningContext, root Operator) Operator {
fmt.Println("Planned offsets for:")
fmt.Println(ToTree(newOp))
}
- return newOp, nil
+
+ if newOp == op {
+ return newOp, nil
+ } else {
+ // We got a new operator from plan offsets. We should return that something has changed.
+ return newOp, Rewrote("planning offsets introduced a new operator")
+ }
}
return in, NoRewrite
}
diff --git a/go/vt/vtgate/planbuilder/operators/route_planning.go b/go/vt/vtgate/planbuilder/operators/route_planning.go
index 47405e3b935..22db69f287b 100644
--- a/go/vt/vtgate/planbuilder/operators/route_planning.go
+++ b/go/vt/vtgate/planbuilder/operators/route_planning.go
@@ -305,13 +305,18 @@ func mergeOrJoin(ctx *plancontext.PlanningContext, lhs, rhs Operator, joinPredic
}
join := NewApplyJoin(ctx, Clone(rhs), Clone(lhs), nil, joinType)
- newOp := pushJoinPredicates(ctx, joinPredicates, join)
- return newOp, Rewrote("logical join to applyJoin, switching side because LIMIT")
+ for _, pred := range joinPredicates {
+ join.AddJoinPredicate(ctx, pred)
+ }
+ return join, Rewrote("logical join to applyJoin, switching side because LIMIT")
}
join := NewApplyJoin(ctx, Clone(lhs), Clone(rhs), nil, joinType)
- newOp := pushJoinPredicates(ctx, joinPredicates, join)
- return newOp, Rewrote("logical join to applyJoin ")
+ for _, pred := range joinPredicates {
+ join.AddJoinPredicate(ctx, pred)
+ }
+
+ return join, Rewrote("logical join to applyJoin ")
}
func operatorsToRoutes(a, b Operator) (*Route, *Route) {
@@ -530,15 +535,3 @@ func hexEqual(a, b *sqlparser.Literal) bool {
}
return false
}
-
-func pushJoinPredicates(ctx *plancontext.PlanningContext, exprs []sqlparser.Expr, op *ApplyJoin) Operator {
- if len(exprs) == 0 {
- return op
- }
-
- for _, expr := range exprs {
- AddPredicate(ctx, op, expr, true, newFilterSinglePredicate)
- }
-
- return op
-}
diff --git a/go/vt/vtgate/planbuilder/operators/sharded_routing.go b/go/vt/vtgate/planbuilder/operators/sharded_routing.go
index 1319b76f040..066cb47d9a9 100644
--- a/go/vt/vtgate/planbuilder/operators/sharded_routing.go
+++ b/go/vt/vtgate/planbuilder/operators/sharded_routing.go
@@ -23,7 +23,6 @@ import (
"vitess.io/vitess/go/mysql/collations"
"vitess.io/vitess/go/slice"
"vitess.io/vitess/go/vt/sqlparser"
- "vitess.io/vitess/go/vt/vterrors"
"vitess.io/vitess/go/vt/vtgate/engine"
"vitess.io/vitess/go/vt/vtgate/evalengine"
"vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext"
@@ -634,13 +633,15 @@ func (tr *ShardedRouting) extraInfo() string {
)
}
-func tryMergeJoinShardedRouting(
+func tryMergeShardedRouting(
ctx *plancontext.PlanningContext,
routeA, routeB *Route,
m merger,
joinPredicates []sqlparser.Expr,
) *Route {
- sameKeyspace := routeA.Routing.Keyspace() == routeB.Routing.Keyspace()
+ if routeA.Routing.Keyspace() != routeB.Routing.Keyspace() {
+ return nil
+ }
tblA := routeA.Routing.(*ShardedRouting)
tblB := routeB.Routing.(*ShardedRouting)
@@ -669,10 +670,6 @@ func tryMergeJoinShardedRouting(
return nil
}
- if !sameKeyspace {
- panic(vterrors.VT12001("cross-shard correlated subquery"))
- }
-
canMerge := canMergeOnFilters(ctx, routeA, routeB, joinPredicates)
if !canMerge {
return nil
diff --git a/go/vt/vtgate/planbuilder/operators/subquery_planning.go b/go/vt/vtgate/planbuilder/operators/subquery_planning.go
index aef54bd8c41..0893afbeead 100644
--- a/go/vt/vtgate/planbuilder/operators/subquery_planning.go
+++ b/go/vt/vtgate/planbuilder/operators/subquery_planning.go
@@ -758,7 +758,7 @@ func mergeSubqueryInputs(ctx *plancontext.PlanningContext, in, out Operator, joi
// sharded routing is complex, so we handle it in a separate method
case inner == sharded && outer == sharded:
- return tryMergeJoinShardedRouting(ctx, inRoute, outRoute, m, joinPredicates)
+ return tryMergeShardedRouting(ctx, inRoute, outRoute, m, joinPredicates)
default:
return nil
diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
index eca27d81213..628a959af1d 100644
--- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
+++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json
@@ -6663,55 +6663,70 @@
"OrderBy": "(4|6) ASC, (5|7) ASC",
"Inputs": [
{
- "OperatorType": "Join",
- "Variant": "HashLeftJoin",
- "Collation": "binary",
- "ComparisonType": "INT16",
- "JoinColumnIndexes": "-1,1,-2,2,-3,3",
- "Predicate": "`user`.col = ue.col",
- "TableName": "`user`_user_extra",
+ "OperatorType": "Projection",
+ "Expressions": [
+ "count(*) as count(*)",
+ "count(*) as count(*)",
+ "`user`.col as col",
+ "ue.col as col",
+ "`user`.foo as foo",
+ "ue.bar as bar",
+ "weight_string(`user`.foo) as weight_string(`user`.foo)",
+ "weight_string(ue.bar) as weight_string(ue.bar)"
+ ],
"Inputs": [
{
- "OperatorType": "Route",
- "Variant": "Scatter",
- "Keyspace": {
- "Name": "user",
- "Sharded": true
- },
- "FieldQuery": "select count(*), `user`.col, `user`.foo from `user` where 1 != 1 group by `user`.col, `user`.foo",
- "Query": "select count(*), `user`.col, `user`.foo from `user` group by `user`.col, `user`.foo",
- "Table": "`user`"
- },
- {
- "OperatorType": "Aggregate",
- "Variant": "Ordered",
- "Aggregates": "count_star(0)",
- "GroupBy": "1, (2|3)",
- "ResultColumns": 3,
+ "OperatorType": "Join",
+ "Variant": "HashLeftJoin",
+ "Collation": "binary",
+ "ComparisonType": "INT16",
+ "JoinColumnIndexes": "-1,1,-2,2,-3,3,-3,3",
+ "Predicate": "`user`.col = ue.col",
+ "TableName": "`user`_user_extra",
"Inputs": [
{
- "OperatorType": "SimpleProjection",
- "Columns": "2,0,1,3",
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select count(*), `user`.col, `user`.foo from `user` where 1 != 1 group by `user`.col, `user`.foo",
+ "Query": "select count(*), `user`.col, `user`.foo from `user` group by `user`.col, `user`.foo",
+ "Table": "`user`"
+ },
+ {
+ "OperatorType": "Aggregate",
+ "Variant": "Ordered",
+ "Aggregates": "count_star(0)",
+ "GroupBy": "1, (2|3)",
+ "ResultColumns": 3,
"Inputs": [
{
- "OperatorType": "Sort",
- "Variant": "Memory",
- "OrderBy": "0 ASC, (1|3) ASC",
+ "OperatorType": "SimpleProjection",
+ "Columns": "2,0,1,3",
"Inputs": [
{
- "OperatorType": "Limit",
- "Count": "10",
+ "OperatorType": "Sort",
+ "Variant": "Memory",
+ "OrderBy": "0 ASC, (1|3) ASC",
"Inputs": [
{
- "OperatorType": "Route",
- "Variant": "Scatter",
- "Keyspace": {
- "Name": "user",
- "Sharded": true
- },
- "FieldQuery": "select ue.col, ue.bar, 1, weight_string(ue.bar) from (select col, bar from user_extra where 1 != 1) as ue where 1 != 1",
- "Query": "select ue.col, ue.bar, 1, weight_string(ue.bar) from (select col, bar from user_extra) as ue limit 10",
- "Table": "user_extra"
+ "OperatorType": "Limit",
+ "Count": "10",
+ "Inputs": [
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select ue.col, ue.bar, 1, weight_string(ue.bar) from (select col, bar from user_extra where 1 != 1) as ue where 1 != 1",
+ "Query": "select ue.col, ue.bar, 1, weight_string(ue.bar) from (select col, bar from user_extra) as ue limit 10",
+ "Table": "user_extra"
+ }
+ ]
}
]
}
diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.json b/go/vt/vtgate/planbuilder/testdata/from_cases.json
index 50b56b428ec..ca94f4ee866 100644
--- a/go/vt/vtgate/planbuilder/testdata/from_cases.json
+++ b/go/vt/vtgate/planbuilder/testdata/from_cases.json
@@ -720,6 +720,119 @@
]
}
},
+ {
+ "comment": "Complex query that has hash left join underneath a memory sort and ordered aggregation",
+ "query": "select 1 from user join user_extra on user.id = user_extra.user_id join music on music.intcol = user_extra.col left join (select user_metadata.col, count(*) as count from user_metadata group by user_metadata.col) um on um.col = user_extra.col where user.id IN (103) group by user_extra.col, music.intcol",
+ "plan": {
+ "QueryType": "SELECT",
+ "Original": "select 1 from user join user_extra on user.id = user_extra.user_id join music on music.intcol = user_extra.col left join (select user_metadata.col, count(*) as count from user_metadata group by user_metadata.col) um on um.col = user_extra.col where user.id IN (103) group by user_extra.col, music.intcol",
+ "Instructions": {
+ "OperatorType": "Aggregate",
+ "Variant": "Ordered",
+ "Aggregates": "any_value(0) AS 1",
+ "GroupBy": "1, 4",
+ "ResultColumns": 1,
+ "Inputs": [
+ {
+ "OperatorType": "Sort",
+ "Variant": "Memory",
+ "OrderBy": "1 ASC, 4 ASC",
+ "Inputs": [
+ {
+ "OperatorType": "Join",
+ "Variant": "HashLeftJoin",
+ "Collation": "binary",
+ "ComparisonType": "FLOAT64",
+ "JoinColumnIndexes": "-1,-2,1,-2,-4,-1",
+ "Predicate": "user_extra.col = um.col",
+ "TableName": "music_`user`, user_extra_user_metadata",
+ "Inputs": [
+ {
+ "OperatorType": "Join",
+ "Variant": "Join",
+ "JoinColumnIndexes": "L:0,R:0,R:0,L:1",
+ "JoinVars": {
+ "music_intcol": 1
+ },
+ "TableName": "music_`user`, user_extra",
+ "Inputs": [
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select 1, music.intcol from music where 1 != 1 group by music.intcol",
+ "Query": "select 1, music.intcol from music group by music.intcol",
+ "Table": "music"
+ },
+ {
+ "OperatorType": "Route",
+ "Variant": "EqualUnique",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select user_extra.col, user_extra.col from `user`, user_extra where 1 != 1 group by user_extra.col",
+ "Query": "select user_extra.col, user_extra.col from `user`, user_extra where `user`.id in (103) and user_extra.col = :music_intcol /* INT16 */ and `user`.id = user_extra.user_id group by user_extra.col",
+ "Table": "`user`, user_extra",
+ "Values": [
+ "103"
+ ],
+ "Vindex": "user_index"
+ }
+ ]
+ },
+ {
+ "OperatorType": "Aggregate",
+ "Variant": "Ordered",
+ "GroupBy": "(0|1)",
+ "ResultColumns": 1,
+ "Inputs": [
+ {
+ "OperatorType": "SimpleProjection",
+ "Columns": "0,2",
+ "Inputs": [
+ {
+ "OperatorType": "Aggregate",
+ "Variant": "Ordered",
+ "Aggregates": "sum_count_star(1) AS count",
+ "GroupBy": "(0|2)",
+ "ResultColumns": 3,
+ "Inputs": [
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select user_metadata.col, count(*) as `count`, weight_string(user_metadata.col) from user_metadata where 1 != 1 group by user_metadata.col, weight_string(user_metadata.col)",
+ "OrderBy": "(0|2) ASC",
+ "Query": "select user_metadata.col, count(*) as `count`, weight_string(user_metadata.col) from user_metadata group by user_metadata.col, weight_string(user_metadata.col) order by user_metadata.col asc",
+ "Table": "user_metadata"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "TablesUsed": [
+ "user.music",
+ "user.user",
+ "user.user_extra",
+ "user.user_metadata"
+ ]
+ }
+ },
{
"comment": "Straight-join (ignores the straight_join hint)",
"query": "select m1.col from unsharded as m1 straight_join unsharded as m2",
@@ -784,6 +897,59 @@
]
}
},
+ {
+ "comment": "Outer join with join predicates that only depend on the inner side",
+ "query": "select 1 from user left join user_extra on user.foo = 42 and user.bar = user_extra.bar",
+ "plan": {
+ "QueryType": "SELECT",
+ "Original": "select 1 from user left join user_extra on user.foo = 42 and user.bar = user_extra.bar",
+ "Instructions": {
+ "OperatorType": "Projection",
+ "Expressions": [
+ "1 as 1"
+ ],
+ "Inputs": [
+ {
+ "OperatorType": "Join",
+ "Variant": "LeftJoin",
+ "JoinVars": {
+ "user_bar": 1,
+ "user_foo": 0
+ },
+ "TableName": "`user`_user_extra",
+ "Inputs": [
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select `user`.foo, `user`.bar from `user` where 1 != 1",
+ "Query": "select `user`.foo, `user`.bar from `user`",
+ "Table": "`user`"
+ },
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select 1 from user_extra where 1 != 1",
+ "Query": "select 1 from user_extra where user_extra.bar = :user_bar and :user_foo = 42",
+ "Table": "user_extra"
+ }
+ ]
+ }
+ ]
+ },
+ "TablesUsed": [
+ "user.user",
+ "user.user_extra"
+ ]
+ }
+ },
{
"comment": "Parenthesized, single chunk",
"query": "select user.col from user join (unsharded as m1 join unsharded as m2)",
@@ -4566,6 +4732,55 @@
]
}
},
+ {
+ "comment": "Cross keyspace join",
+ "query": "select 1 from user join t1 on user.id = t1.id",
+ "plan": {
+ "QueryType": "SELECT",
+ "Original": "select 1 from user join t1 on user.id = t1.id",
+ "Instructions": {
+ "OperatorType": "Join",
+ "Variant": "Join",
+ "JoinColumnIndexes": "L:0",
+ "JoinVars": {
+ "t1_id": 1
+ },
+ "TableName": "t1_`user`",
+ "Inputs": [
+ {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "zlookup_unique",
+ "Sharded": true
+ },
+ "FieldQuery": "select 1, t1.id from t1 where 1 != 1",
+ "Query": "select 1, t1.id from t1",
+ "Table": "t1"
+ },
+ {
+ "OperatorType": "Route",
+ "Variant": "EqualUnique",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select 1 from `user` where 1 != 1",
+ "Query": "select 1 from `user` where `user`.id = :t1_id",
+ "Table": "`user`",
+ "Values": [
+ ":t1_id"
+ ],
+ "Vindex": "user_index"
+ }
+ ]
+ },
+ "TablesUsed": [
+ "user.user",
+ "zlookup_unique.t1"
+ ]
+ }
+ },
{
"comment": "Select everything from a derived table having a cross-shard join",
"query": "select * from (select u.foo * ue.bar from user u join user_extra ue) as dt",
diff --git a/go/vt/vtgate/planbuilder/testdata/reference_cases.json b/go/vt/vtgate/planbuilder/testdata/reference_cases.json
index a89fa103923..6aa01355934 100644
--- a/go/vt/vtgate/planbuilder/testdata/reference_cases.json
+++ b/go/vt/vtgate/planbuilder/testdata/reference_cases.json
@@ -746,5 +746,30 @@
"user.user"
]
}
+ },
+ {
+ "comment": "two sharded and two unsharded reference table join - all should be merged into one route",
+ "query": "select 1 from user u join user_extra ue on u.id = ue.user_id join main.source_of_ref sr on sr.foo = ue.foo join main.rerouted_ref rr on rr.bar = sr.bar",
+ "plan": {
+ "QueryType": "SELECT",
+ "Original": "select 1 from user u join user_extra ue on u.id = ue.user_id join main.source_of_ref sr on sr.foo = ue.foo join main.rerouted_ref rr on rr.bar = sr.bar",
+ "Instructions": {
+ "OperatorType": "Route",
+ "Variant": "Scatter",
+ "Keyspace": {
+ "Name": "user",
+ "Sharded": true
+ },
+ "FieldQuery": "select 1 from `user` as u, user_extra as ue, ref_with_source as sr, ref as rr where 1 != 1",
+ "Query": "select 1 from `user` as u, user_extra as ue, ref_with_source as sr, ref as rr where rr.bar = sr.bar and u.id = ue.user_id and sr.foo = ue.foo",
+ "Table": "`user`, ref, ref_with_source, user_extra"
+ },
+ "TablesUsed": [
+ "user.ref",
+ "user.ref_with_source",
+ "user.user",
+ "user.user_extra"
+ ]
+ }
}
]
diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.json b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.json
index e1618d91efb..0e230b3e44d 100644
--- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.json
+++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.json
@@ -294,6 +294,11 @@
"query": "select 1 from music union (select id from user union all select name from unsharded)",
"plan": "VT12001: unsupported: nesting of UNIONs on the right-hand side"
},
+ {
+ "comment": "Cross keyspace query with subquery",
+ "query": "select 1 from user where id = (select id from t1 where user.foo = t1.bar)",
+ "plan": "VT12001: unsupported: correlated subquery is only supported for EXISTS"
+ },
{
"comment": "multi-shard union",
"query": "select 1 from music union (select id from user union select name from unsharded)",
diff --git a/go/vt/vtgate/planbuilder/testdata/vschemas/schema.json b/go/vt/vtgate/planbuilder/testdata/vschemas/schema.json
index a8fe91e5d49..4fe275f2398 100644
--- a/go/vt/vtgate/planbuilder/testdata/vschemas/schema.json
+++ b/go/vt/vtgate/planbuilder/testdata/vschemas/schema.json
@@ -282,6 +282,12 @@
"column": "id",
"name": "music_user_map"
}
+ ],
+ "columns": [
+ {
+ "name": "intcol",
+ "type": "INT16"
+ }
]
},
"authoritative": {
diff --git a/go/vt/vtgate/production.go b/go/vt/vtgate/production.go
index 83e0cbdddf5..d3b0ff4fe7e 100644
--- a/go/vt/vtgate/production.go
+++ b/go/vt/vtgate/production.go
@@ -18,6 +18,12 @@ limitations under the License.
package vtgate
+import (
+ "context"
+
+ querypb "vitess.io/vitess/go/vt/proto/query"
+)
+
// This file defines debug constants that are always false.
// This file is used for building production code.
// We use go build directives to include a file that defines the constant to true
@@ -26,3 +32,7 @@ package vtgate
// production performance.
const DebugTwoPc = false
+
+func checkTestFailure(_ context.Context, _ string, _ *querypb.Target) error {
+ return nil
+}
diff --git a/go/vt/vtgate/tx_conn.go b/go/vt/vtgate/tx_conn.go
index 56d45799175..e388740ee6a 100644
--- a/go/vt/vtgate/tx_conn.go
+++ b/go/vt/vtgate/tx_conn.go
@@ -22,10 +22,7 @@ import (
"strings"
"sync"
- "github.com/pkg/errors"
-
"vitess.io/vitess/go/mysql/sqlerror"
- "vitess.io/vitess/go/vt/callerid"
"vitess.io/vitess/go/vt/concurrency"
"vitess.io/vitess/go/vt/dtids"
"vitess.io/vitess/go/vt/log"
@@ -62,6 +59,16 @@ var txAccessModeToEOTxAccessMode = map[sqlparser.TxAccessMode]querypb.ExecuteOpt
sqlparser.ReadOnly: querypb.ExecuteOptions_READ_ONLY,
}
+type commitPhase int
+
+const (
+ Commit2pcCreateTransaction commitPhase = iota
+ Commit2pcPrepare
+ Commit2pcStartCommit
+ Commit2pcPrepareCommit
+ Commit2pcConclude
+)
+
// Begin begins a new transaction. If one is already in progress, it commits it
// and starts a new one.
func (txc *TxConn) Begin(ctx context.Context, session *SafeSession, txAccessModes []sqlparser.TxAccessMode) error {
@@ -179,7 +186,7 @@ func (txc *TxConn) commitNormal(ctx context.Context, session *SafeSession) error
}
// commit2PC will not used the pinned tablets - to make sure we use the current source, we need to use the gateway's queryservice
-func (txc *TxConn) commit2PC(ctx context.Context, session *SafeSession) error {
+func (txc *TxConn) commit2PC(ctx context.Context, session *SafeSession) (err error) {
if len(session.PreSessions) != 0 || len(session.PostSessions) != 0 {
_ = txc.Rollback(ctx, session)
return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "pre or post actions not allowed for 2PC commits")
@@ -190,114 +197,118 @@ func (txc *TxConn) commit2PC(ctx context.Context, session *SafeSession) error {
return txc.commitNormal(ctx, session)
}
- participants := make([]*querypb.Target, 0, len(session.ShardSessions)-1)
- for _, s := range session.ShardSessions[1:] {
- participants = append(participants, s.Target)
- }
mmShard := session.ShardSessions[0]
+ rmShards := session.ShardSessions[1:]
dtid := dtids.New(mmShard)
- err := txc.tabletGateway.CreateTransaction(ctx, mmShard.Target, dtid, participants)
- if err != nil {
- // Normal rollback is safe because nothing was prepared yet.
- _ = txc.Rollback(ctx, session)
+ participants := make([]*querypb.Target, len(rmShards))
+ for i, s := range rmShards {
+ participants[i] = s.Target
+ }
+
+ var txPhase commitPhase
+ defer func() {
+ if err == nil {
+ return
+ }
+ txc.errActionAndLogWarn(ctx, session, txPhase, dtid, mmShard, rmShards)
+ }()
+
+ txPhase = Commit2pcCreateTransaction
+ if err = txc.tabletGateway.CreateTransaction(ctx, mmShard.Target, dtid, participants); err != nil {
return err
}
- if DebugTwoPc {
- // Test code to simulate a failure after RM prepare
- if failNow, err := checkTestFailure(callerid.EffectiveCallerIDFromContext(ctx), "TRCreated_FailNow", nil); failNow {
- return errors.Wrapf(err, "%v", dtid)
+ if DebugTwoPc { // Test code to simulate a failure after RM prepare
+ if terr := checkTestFailure(ctx, "TRCreated_FailNow", nil); terr != nil {
+ return terr
}
}
- err = txc.runSessions(ctx, session.ShardSessions[1:], session.logging, func(ctx context.Context, s *vtgatepb.Session_ShardSession, logging *executeLogger) error {
- if DebugTwoPc {
- // Test code to simulate a failure during RM prepare
- if failNow, err := checkTestFailure(callerid.EffectiveCallerIDFromContext(ctx), "RMPrepare_-40_FailNow", s.Target); failNow {
- return err
+ txPhase = Commit2pcPrepare
+ prepareAction := func(ctx context.Context, s *vtgatepb.Session_ShardSession, logging *executeLogger) error {
+ if DebugTwoPc { // Test code to simulate a failure during RM prepare
+ if terr := checkTestFailure(ctx, "RMPrepare_-40_FailNow", s.Target); terr != nil {
+ return terr
}
}
return txc.tabletGateway.Prepare(ctx, s.Target, s.TransactionId, dtid)
- })
- if err != nil {
- // TODO(sougou): Perform a more fine-grained cleanup
- // including unprepared transactions.
- if resumeErr := txc.rollbackTx(ctx, dtid, mmShard, session.ShardSessions[1:], session.logging); resumeErr != nil {
- log.Warningf("Rollback failed after Prepare failure: %v", resumeErr)
- }
- // Return the original error even if the previous operation fails.
+ }
+ if err = txc.runSessions(ctx, rmShards, session.logging, prepareAction); err != nil {
return err
}
- if DebugTwoPc {
- // Test code to simulate a failure after RM prepare
- if failNow, err := checkTestFailure(callerid.EffectiveCallerIDFromContext(ctx), "RMPrepared_FailNow", nil); failNow {
- return err
+ if DebugTwoPc { // Test code to simulate a failure after RM prepare
+ if terr := checkTestFailure(ctx, "RMPrepared_FailNow", nil); terr != nil {
+ return terr
}
}
+ txPhase = Commit2pcStartCommit
err = txc.tabletGateway.StartCommit(ctx, mmShard.Target, mmShard.TransactionId, dtid)
if err != nil {
return err
}
- if DebugTwoPc {
- // Test code to simulate a failure after MM commit
- if failNow, err := checkTestFailure(callerid.EffectiveCallerIDFromContext(ctx), "MMCommitted_FailNow", nil); failNow {
- return err
+ if DebugTwoPc { // Test code to simulate a failure after MM commit
+ if terr := checkTestFailure(ctx, "MMCommitted_FailNow", nil); terr != nil {
+ return terr
}
}
- err = txc.runSessions(ctx, session.ShardSessions[1:], session.logging, func(ctx context.Context, s *vtgatepb.Session_ShardSession, logging *executeLogger) error {
- if DebugTwoPc {
- // Test code to simulate a failure during RM prepare
- if failNow, err := checkTestFailure(callerid.EffectiveCallerIDFromContext(ctx), "RMCommit_-40_FailNow", s.Target); failNow {
- return err
+ txPhase = Commit2pcPrepareCommit
+ prepareCommitAction := func(ctx context.Context, s *vtgatepb.Session_ShardSession, logging *executeLogger) error {
+ if DebugTwoPc { // Test code to simulate a failure during RM prepare
+ if terr := checkTestFailure(ctx, "RMCommit_-40_FailNow", s.Target); terr != nil {
+ return terr
}
}
return txc.tabletGateway.CommitPrepared(ctx, s.Target, dtid)
- })
- if err != nil {
+ }
+ if err = txc.runSessions(ctx, rmShards, session.logging, prepareCommitAction); err != nil {
return err
}
- return txc.tabletGateway.ConcludeTransaction(ctx, mmShard.Target, dtid)
+ // At this point, application can continue forward.
+ // The transaction is already committed.
+ // This step is to clean up the transaction metadata.
+ txPhase = Commit2pcConclude
+ _ = txc.tabletGateway.ConcludeTransaction(ctx, mmShard.Target, dtid)
+ return nil
}
-func checkTestFailure(callerID *vtrpcpb.CallerID, expectCaller string, target *querypb.Target) (bool, error) {
- if callerID == nil || callerID.GetPrincipal() != expectCaller {
- return false, nil
- }
- switch callerID.Principal {
- case "TRCreated_FailNow":
- log.Errorf("Fail After TR created")
- // no commit decision is made. Transaction should be a rolled back.
- return true, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After TR created")
- case "RMPrepare_-40_FailNow":
- if target.Shard != "-40" {
- return false, nil
+func (txc *TxConn) errActionAndLogWarn(ctx context.Context, session *SafeSession, txPhase commitPhase, dtid string, mmShard *vtgatepb.Session_ShardSession, rmShards []*vtgatepb.Session_ShardSession) {
+ switch txPhase {
+ case Commit2pcCreateTransaction:
+ // Normal rollback is safe because nothing was prepared yet.
+ if rollbackErr := txc.Rollback(ctx, session); rollbackErr != nil {
+ log.Warningf("Rollback failed after Create Transaction failure: %v", rollbackErr)
}
- log.Errorf("Fail During RM prepare")
- // no commit decision is made. Transaction should be a rolled back.
- return true, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail During RM prepare")
- case "RMPrepared_FailNow":
- log.Errorf("Fail After RM prepared")
- // no commit decision is made. Transaction should be a rolled back.
- return true, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After RM prepared")
- case "MMCommitted_FailNow":
- log.Errorf("Fail After MM commit")
- // commit decision is made. Transaction should be committed.
- return true, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail After MM commit")
- case "RMCommit_-40_FailNow":
- if target.Shard != "-40" {
- return false, nil
+ case Commit2pcPrepare:
+ // Rollback the prepared and unprepared transactions.
+ if resumeErr := txc.rollbackTx(ctx, dtid, mmShard, rmShards, session.logging); resumeErr != nil {
+ log.Warningf("Rollback failed after Prepare failure: %v", resumeErr)
}
- log.Errorf("Fail During RM commit")
- // commit decision is made. Transaction should be a committed.
- return true, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Fail During RM commit")
- default:
- return false, nil
}
+ session.RecordWarning(&querypb.QueryWarning{
+ Code: uint32(sqlerror.ERInAtomicRecovery),
+ Message: createWarningMessage(dtid, txPhase)})
+}
+
+func createWarningMessage(dtid string, txPhase commitPhase) string {
+ warningMsg := fmt.Sprintf("%s distributed transaction ID failed during", dtid)
+ switch txPhase {
+ case Commit2pcCreateTransaction:
+ warningMsg += " transaction record creation; rollback attempted; conclude on recovery"
+ case Commit2pcPrepare:
+ warningMsg += " transaction prepare phase; prepare transaction rollback attempted; conclude on recovery"
+ case Commit2pcStartCommit:
+ warningMsg += " metadata manager commit; transaction will be committed/rollbacked based on the state on recovery"
+ case Commit2pcPrepareCommit:
+ warningMsg += " resource manager commit; transaction will be committed on recovery"
+ case Commit2pcConclude:
+ warningMsg += " transaction conclusion"
+ }
+ return warningMsg
}
// Rollback rolls back the current transaction. There are no retries on this operation.
@@ -447,44 +458,52 @@ func (txc *TxConn) resolveTx(ctx context.Context, target *querypb.Target, transa
case querypb.TransactionState_PREPARE:
// If state is PREPARE, make a decision to rollback and
// fallthrough to the rollback workflow.
- if err := txc.tabletGateway.SetRollback(ctx, target, transaction.Dtid, mmShard.TransactionId); err != nil {
+ if err = txc.tabletGateway.SetRollback(ctx, target, transaction.Dtid, mmShard.TransactionId); err != nil {
return err
}
fallthrough
case querypb.TransactionState_ROLLBACK:
- if err := txc.resumeRollback(ctx, target, transaction); err != nil {
+ if err = txc.resumeRollback(ctx, target, transaction); err != nil {
return err
}
case querypb.TransactionState_COMMIT:
- if err := txc.resumeCommit(ctx, target, transaction); err != nil {
+ if err = txc.resumeCommit(ctx, target, transaction); err != nil {
return err
}
default:
// Should never happen.
- return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "invalid state: %v", transaction.State)
+ return vterrors.VT13001(fmt.Sprintf("invalid state: %v", transaction.State))
}
return nil
}
// rollbackTx rollbacks the specified distributed transaction.
+// Rollbacks happens on the metadata manager and all participants irrespective of the failure.
func (txc *TxConn) rollbackTx(ctx context.Context, dtid string, mmShard *vtgatepb.Session_ShardSession, participants []*vtgatepb.Session_ShardSession, logging *executeLogger) error {
- qs, err := txc.queryService(ctx, mmShard.TabletAlias)
- if err != nil {
- return err
+ var errs []error
+ if mmErr := txc.rollbackMM(ctx, dtid, mmShard); mmErr != nil {
+ errs = append(errs, mmErr)
}
- if err := qs.SetRollback(ctx, mmShard.Target, dtid, mmShard.TransactionId); err != nil {
- return err
- }
- err = txc.runSessions(ctx, participants, logging, func(ctx context.Context, session *vtgatepb.Session_ShardSession, logger *executeLogger) error {
+ if rmErr := txc.runSessions(ctx, participants, logging, func(ctx context.Context, session *vtgatepb.Session_ShardSession, logger *executeLogger) error {
return txc.tabletGateway.RollbackPrepared(ctx, session.Target, dtid, session.TransactionId)
- })
- if err != nil {
+ }); rmErr != nil {
+ errs = append(errs, rmErr)
+ }
+ if err := vterrors.Aggregate(errs); err != nil {
return err
}
return txc.tabletGateway.ConcludeTransaction(ctx, mmShard.Target, dtid)
}
+func (txc *TxConn) rollbackMM(ctx context.Context, dtid string, mmShard *vtgatepb.Session_ShardSession) error {
+ qs, err := txc.queryService(ctx, mmShard.TabletAlias)
+ if err != nil {
+ return err
+ }
+ return qs.SetRollback(ctx, mmShard.Target, dtid, mmShard.TransactionId)
+}
+
func (txc *TxConn) resumeRollback(ctx context.Context, target *querypb.Target, transaction *querypb.TransactionMetadata) error {
err := txc.runTargets(transaction.Participants, func(t *querypb.Target) error {
return txc.tabletGateway.RollbackPrepared(ctx, t, transaction.Dtid, 0)
diff --git a/go/vt/vtgate/tx_conn_test.go b/go/vt/vtgate/tx_conn_test.go
index 74329153936..ed977b75051 100644
--- a/go/vt/vtgate/tx_conn_test.go
+++ b/go/vt/vtgate/tx_conn_test.go
@@ -1090,9 +1090,7 @@ func TestTxConnCommit2PCConcludeTransactionFail(t *testing.T) {
sbc0.MustFailConcludeTransaction = 1
session.TransactionMode = vtgatepb.TransactionMode_TWOPC
err := sc.txConn.Commit(ctx, session)
- want := "error: err"
- require.Error(t, err)
- assert.Contains(t, err.Error(), want, "Commit")
+ require.NoError(t, err) // ConcludeTransaction is best-effort as it does not impact the outcome.
assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Load(), "sbc0.CreateTransactionCount")
assert.EqualValues(t, 1, sbc1.PrepareCount.Load(), "sbc1.PrepareCount")
assert.EqualValues(t, 1, sbc0.StartCommitCount.Load(), "sbc0.StartCommitCount")
diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go
index ae9c073e123..ee000abed8f 100644
--- a/go/vt/vtgate/vcursor_impl.go
+++ b/go/vt/vtgate/vcursor_impl.go
@@ -819,7 +819,7 @@ func commentedShardQueries(shardQueries []*querypb.BoundQuery, marginComments sq
// TargetDestination implements the ContextVSchema interface
func (vc *vcursorImpl) TargetDestination(qualifier string) (key.Destination, *vindexes.Keyspace, topodatapb.TabletType, error) {
- keyspaceName := vc.keyspace
+ keyspaceName := vc.getActualKeyspace()
if vc.destination == nil && qualifier != "" {
keyspaceName = qualifier
}
diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go
index 1aa75907e88..0d43d52d7f4 100644
--- a/go/vt/vttablet/onlineddl/executor.go
+++ b/go/vt/vttablet/onlineddl/executor.go
@@ -616,7 +616,7 @@ func (e *Executor) getCreateTableStatement(ctx context.Context, tableName string
}
createTable, ok := stmt.(*sqlparser.CreateTable)
if !ok {
- return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "expected CREATE TABLE. Got %v", sqlparser.CanonicalString(stmt))
+ return nil, schemadiff.ErrExpectedCreateTable
}
return createTable, nil
}
@@ -1518,7 +1518,10 @@ func (e *Executor) initVreplicationOriginalMigration(ctx context.Context, online
return v, err
}
- v = NewVRepl(e.env.Environment(), onlineDDL.UUID, e.keyspace, e.shard, e.dbName, onlineDDL.Table, vreplTableName, originalCreateTable, vreplCreateTable, alterTable, onlineDDL.StrategySetting().IsAnalyzeTableFlag())
+ v, err = NewVRepl(e.env.Environment(), onlineDDL.UUID, e.keyspace, e.shard, e.dbName, originalCreateTable, vreplCreateTable, alterTable, onlineDDL.StrategySetting().IsAnalyzeTableFlag())
+ if err != nil {
+ return v, err
+ }
return v, nil
}
@@ -1526,7 +1529,7 @@ func (e *Executor) initVreplicationOriginalMigration(ctx context.Context, online
// This function is called after both source and target tables have been analyzed, so there's more information
// about the two, and about the transition between the two.
func (e *Executor) postInitVreplicationOriginalMigration(ctx context.Context, onlineDDL *schema.OnlineDDL, v *VRepl, conn *dbconnpool.DBConnection) (err error) {
- if v.sourceAutoIncrement > 0 && !v.parser.IsAutoIncrementDefined() {
+ if v.analysis.SourceAutoIncrement > 0 && !v.alterTableAnalysis.IsAutoIncrementChangeRequested {
restoreSQLModeFunc, err := e.initMigrationSQLMode(ctx, onlineDDL, conn)
defer restoreSQLModeFunc()
if err != nil {
@@ -1534,9 +1537,9 @@ func (e *Executor) postInitVreplicationOriginalMigration(ctx context.Context, on
}
// Apply ALTER TABLE AUTO_INCREMENT=?
- parsed := sqlparser.BuildParsedQuery(sqlAlterTableAutoIncrement, v.targetTable, ":auto_increment")
+ parsed := sqlparser.BuildParsedQuery(sqlAlterTableAutoIncrement, v.targetTableName(), ":auto_increment")
bindVars := map[string]*querypb.BindVariable{
- "auto_increment": sqltypes.Uint64BindVariable(v.sourceAutoIncrement),
+ "auto_increment": sqltypes.Uint64BindVariable(v.analysis.SourceAutoIncrement),
}
bound, err := parsed.GenerateQuery(bindVars, nil)
if err != nil {
@@ -1572,7 +1575,18 @@ func (e *Executor) initVreplicationRevertMigration(ctx context.Context, onlineDD
if err := e.updateArtifacts(ctx, onlineDDL.UUID, vreplTableName); err != nil {
return v, err
}
- v = NewVRepl(e.env.Environment(), onlineDDL.UUID, e.keyspace, e.shard, e.dbName, onlineDDL.Table, vreplTableName, nil, nil, nil, false)
+ originalCreateTable, err := e.getCreateTableStatement(ctx, onlineDDL.Table)
+ if err != nil {
+ return v, err
+ }
+ vreplCreateTable, err := e.getCreateTableStatement(ctx, vreplTableName)
+ if err != nil {
+ return v, err
+ }
+ v, err = NewVRepl(e.env.Environment(), onlineDDL.UUID, e.keyspace, e.shard, e.dbName, originalCreateTable, vreplCreateTable, nil, false)
+ if err != nil {
+ return v, err
+ }
v.pos = revertStream.pos
return v, nil
}
@@ -1614,19 +1628,15 @@ func (e *Executor) ExecuteWithVReplication(ctx context.Context, onlineDDL *schem
if err := e.updateMigrationTableRows(ctx, onlineDDL.UUID, v.tableRows); err != nil {
return err
}
- removedUniqueKeyNames := []string{}
- for _, uniqueKey := range v.removedUniqueKeys {
- removedUniqueKeyNames = append(removedUniqueKeyNames, uniqueKey.Name)
- }
if err := e.updateSchemaAnalysis(ctx, onlineDDL.UUID,
- len(v.addedUniqueKeys),
- len(v.removedUniqueKeys),
- strings.Join(sqlescape.EscapeIDs(removedUniqueKeyNames), ","),
- strings.Join(sqlescape.EscapeIDs(v.removedForeignKeyNames), ","),
- strings.Join(sqlescape.EscapeIDs(v.droppedNoDefaultColumnNames), ","),
- strings.Join(sqlescape.EscapeIDs(v.expandedColumnNames), ","),
- v.revertibleNotes,
+ v.analysis.AddedUniqueKeys.Len(),
+ v.analysis.RemovedUniqueKeys.Len(),
+ strings.Join(sqlescape.EscapeIDs(v.analysis.RemovedUniqueKeys.Names()), ","),
+ strings.Join(sqlescape.EscapeIDs(v.analysis.RemovedForeignKeyNames), ","),
+ strings.Join(sqlescape.EscapeIDs(v.analysis.DroppedNoDefaultColumns.Names()), ","),
+ strings.Join(sqlescape.EscapeIDs(v.analysis.ExpandedColumns.Names()), ","),
+ v.analysis.RevertibleNotes,
); err != nil {
return err
}
@@ -1654,7 +1664,7 @@ func (e *Executor) ExecuteWithVReplication(ctx context.Context, onlineDDL *schem
}
// create vreplication entry
- insertVReplicationQuery, err := v.generateInsertStatement(ctx)
+ insertVReplicationQuery, err := v.generateInsertStatement()
if err != nil {
return err
}
@@ -1671,7 +1681,7 @@ func (e *Executor) ExecuteWithVReplication(ctx context.Context, onlineDDL *schem
}
}
// start stream!
- startVReplicationQuery, err := v.generateStartStatement(ctx)
+ startVReplicationQuery, err := v.generateStartStatement()
if err != nil {
return err
}
@@ -2967,7 +2977,7 @@ func (e *Executor) analyzeDropDDLActionMigration(ctx context.Context, onlineDDL
// Write analysis:
}
if err := e.updateSchemaAnalysis(ctx, onlineDDL.UUID,
- 0, 0, "", strings.Join(sqlescape.EscapeIDs(removedForeignKeyNames), ","), "", "", "",
+ 0, 0, "", strings.Join(sqlescape.EscapeIDs(removedForeignKeyNames), ","), "", "", nil,
); err != nil {
return err
}
@@ -3640,6 +3650,7 @@ func (e *Executor) readVReplStream(ctx context.Context, uuid string, okIfMissing
timeHeartbeat: row.AsInt64("time_heartbeat", 0),
timeThrottled: row.AsInt64("time_throttled", 0),
componentThrottled: row.AsString("component_throttled", ""),
+ reasonThrottled: row.AsString("reason_throttled", ""),
transactionTimestamp: row.AsInt64("transaction_timestamp", 0),
state: binlogdatapb.VReplicationWorkflowState(binlogdatapb.VReplicationWorkflowState_value[row.AsString("state", "")]),
message: row.AsString("message", ""),
@@ -3872,7 +3883,7 @@ func (e *Executor) reviewRunningMigrations(ctx context.Context) (countRunnning i
_ = e.updateMigrationETASecondsByProgress(ctx, uuid)
if s.timeThrottled != 0 {
// Avoid creating a 0000-00-00 00:00:00 timestamp
- _ = e.updateMigrationLastThrottled(ctx, uuid, time.Unix(s.timeThrottled, 0), s.componentThrottled)
+ _ = e.updateMigrationLastThrottled(ctx, uuid, time.Unix(s.timeThrottled, 0), s.componentThrottled, s.reasonThrottled)
}
if onlineDDL.StrategySetting().IsInOrderCompletion() {
// We will fail an in-order migration if there's _prior_ migrations within the same migration-context
@@ -4491,7 +4502,8 @@ func (e *Executor) updateSchemaAnalysis(ctx context.Context, uuid string,
addedUniqueKeys, removedUniqueKeys int, removedUniqueKeyNames string,
removedForeignKeyNames string,
droppedNoDefaultColumnNames string, expandedColumnNames string,
- revertibleNotes string) error {
+ revertibleNotes []string) error {
+ notes := strings.Join(revertibleNotes, "\n")
query, err := sqlparser.ParseAndBind(sqlUpdateSchemaAnalysis,
sqltypes.Int64BindVariable(int64(addedUniqueKeys)),
sqltypes.Int64BindVariable(int64(removedUniqueKeys)),
@@ -4499,7 +4511,7 @@ func (e *Executor) updateSchemaAnalysis(ctx context.Context, uuid string,
sqltypes.StringBindVariable(removedForeignKeyNames),
sqltypes.StringBindVariable(droppedNoDefaultColumnNames),
sqltypes.StringBindVariable(expandedColumnNames),
- sqltypes.StringBindVariable(revertibleNotes),
+ sqltypes.StringBindVariable(notes),
sqltypes.StringBindVariable(uuid),
)
if err != nil {
@@ -4575,10 +4587,17 @@ func (e *Executor) updateMigrationETASecondsByProgress(ctx context.Context, uuid
return err
}
-func (e *Executor) updateMigrationLastThrottled(ctx context.Context, uuid string, lastThrottledTime time.Time, throttledCompnent string) error {
+func (e *Executor) updateMigrationLastThrottled(
+ ctx context.Context,
+ uuid string,
+ lastThrottledTime time.Time,
+ throttledCompnent string,
+ reasonThrottled string,
+) error {
query, err := sqlparser.ParseAndBind(sqlUpdateLastThrottled,
sqltypes.StringBindVariable(lastThrottledTime.Format(sqltypes.TimestampFormat)),
sqltypes.StringBindVariable(throttledCompnent),
+ sqltypes.StringBindVariable(reasonThrottled),
sqltypes.StringBindVariable(uuid),
)
if err != nil {
diff --git a/go/vt/vttablet/onlineddl/schema.go b/go/vt/vttablet/onlineddl/schema.go
index 7ff1cd220d6..28e32e7dab4 100644
--- a/go/vt/vttablet/onlineddl/schema.go
+++ b/go/vt/vttablet/onlineddl/schema.go
@@ -249,7 +249,7 @@ const (
migration_uuid=%a
`
sqlUpdateLastThrottled = `UPDATE _vt.schema_migrations
- SET last_throttled_timestamp=%a, component_throttled=%a
+ SET last_throttled_timestamp=%a, component_throttled=%a, reason_throttled=%a
WHERE
migration_uuid=%a
`
@@ -435,6 +435,7 @@ const (
last_throttled_timestamp,
cancelled_timestamp,
component_throttled,
+ reason_throttled,
postpone_launch,
postpone_completion,
is_immediate_operation,
@@ -460,16 +461,6 @@ const (
AND ACTION_TIMING='AFTER'
AND LEFT(TRIGGER_NAME, 7)='pt_osc_'
`
- sqlSelectColumnTypes = `
- select
- *,
- COLUMN_DEFAULT IS NULL AS is_default_null
- from
- information_schema.columns
- where
- table_schema=%a
- and table_name=%a
- `
selSelectCountFKParentConstraints = `
SELECT
COUNT(*) as num_fk_constraints
@@ -486,75 +477,10 @@ const (
TABLE_SCHEMA=%a AND TABLE_NAME=%a
AND REFERENCED_TABLE_NAME IS NOT NULL
`
- sqlSelectUniqueKeys = `
- SELECT
- COLUMNS.TABLE_SCHEMA as table_schema,
- COLUMNS.TABLE_NAME as table_name,
- COLUMNS.COLUMN_NAME as column_name,
- UNIQUES.INDEX_NAME as index_name,
- UNIQUES.COLUMN_NAMES as column_names,
- UNIQUES.COUNT_COLUMN_IN_INDEX as count_column_in_index,
- COLUMNS.DATA_TYPE as data_type,
- COLUMNS.CHARACTER_SET_NAME as character_set_name,
- LOCATE('auto_increment', EXTRA) > 0 as is_auto_increment,
- (DATA_TYPE='float' OR DATA_TYPE='double') AS is_float,
- has_subpart,
- has_nullable
- FROM INFORMATION_SCHEMA.COLUMNS INNER JOIN (
- SELECT
- TABLE_SCHEMA,
- TABLE_NAME,
- INDEX_NAME,
- COUNT(*) AS COUNT_COLUMN_IN_INDEX,
- GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX ASC) AS COLUMN_NAMES,
- SUBSTRING_INDEX(GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX ASC), ',', 1) AS FIRST_COLUMN_NAME,
- SUM(SUB_PART IS NOT NULL) > 0 AS has_subpart,
- SUM(NULLABLE='YES') > 0 AS has_nullable
- FROM INFORMATION_SCHEMA.STATISTICS
- WHERE
- NON_UNIQUE=0
- AND TABLE_SCHEMA=%a
- AND TABLE_NAME=%a
- GROUP BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME
- ) AS UNIQUES
- ON (
- COLUMNS.COLUMN_NAME = UNIQUES.FIRST_COLUMN_NAME
- )
- WHERE
- COLUMNS.TABLE_SCHEMA=%a
- AND COLUMNS.TABLE_NAME=%a
- ORDER BY
- COLUMNS.TABLE_SCHEMA, COLUMNS.TABLE_NAME,
- CASE UNIQUES.INDEX_NAME
- WHEN 'PRIMARY' THEN 0
- ELSE 1
- END,
- CASE has_nullable
- WHEN 0 THEN 0
- ELSE 1
- END,
- CASE has_subpart
- WHEN 0 THEN 0
- ELSE 1
- END,
- CASE IFNULL(CHARACTER_SET_NAME, '')
- WHEN '' THEN 0
- ELSE 1
- END,
- CASE DATA_TYPE
- WHEN 'tinyint' THEN 0
- WHEN 'smallint' THEN 1
- WHEN 'int' THEN 2
- WHEN 'bigint' THEN 3
- ELSE 100
- END,
- COUNT_COLUMN_IN_INDEX
- `
sqlDropTrigger = "DROP TRIGGER IF EXISTS `%a`.`%a`"
sqlShowTablesLike = "SHOW TABLES LIKE '%a'"
sqlDropTable = "DROP TABLE `%a`"
sqlDropTableIfExists = "DROP TABLE IF EXISTS `%a`"
- sqlShowColumnsFrom = "SHOW COLUMNS FROM `%a`"
sqlShowTableStatus = "SHOW TABLE STATUS LIKE '%a'"
sqlAnalyzeTable = "ANALYZE NO_WRITE_TO_BINLOG TABLE `%a`"
sqlShowCreateTable = "SHOW CREATE TABLE `%a`"
@@ -562,23 +488,14 @@ const (
sqlShowVariablesLikeFastAnalyzeTable = "show global variables like 'fast_analyze_table'"
sqlEnableFastAnalyzeTable = "set @@fast_analyze_table = 1"
sqlDisableFastAnalyzeTable = "set @@fast_analyze_table = 0"
- sqlGetAutoIncrement = `
- SELECT
- AUTO_INCREMENT
- FROM INFORMATION_SCHEMA.TABLES
- WHERE
- TABLES.TABLE_SCHEMA=%a
- AND TABLES.TABLE_NAME=%a
- AND AUTO_INCREMENT IS NOT NULL
- `
- sqlAlterTableAutoIncrement = "ALTER TABLE `%s` AUTO_INCREMENT=%a"
- sqlAlterTableExchangePartition = "ALTER TABLE `%a` EXCHANGE PARTITION `%a` WITH TABLE `%a`"
- sqlAlterTableRemovePartitioning = "ALTER TABLE `%a` REMOVE PARTITIONING"
- sqlAlterTableDropPartition = "ALTER TABLE `%a` DROP PARTITION `%a`"
- sqlStartVReplStream = "UPDATE _vt.vreplication set state='Running' where db_name=%a and workflow=%a"
- sqlStopVReplStream = "UPDATE _vt.vreplication set state='Stopped' where db_name=%a and workflow=%a"
- sqlDeleteVReplStream = "DELETE FROM _vt.vreplication where db_name=%a and workflow=%a"
- sqlReadVReplStream = `SELECT
+ sqlAlterTableAutoIncrement = "ALTER TABLE `%s` AUTO_INCREMENT=%a"
+ sqlAlterTableExchangePartition = "ALTER TABLE `%a` EXCHANGE PARTITION `%a` WITH TABLE `%a`"
+ sqlAlterTableRemovePartitioning = "ALTER TABLE `%a` REMOVE PARTITIONING"
+ sqlAlterTableDropPartition = "ALTER TABLE `%a` DROP PARTITION `%a`"
+ sqlStartVReplStream = "UPDATE _vt.vreplication set state='Running' where db_name=%a and workflow=%a"
+ sqlStopVReplStream = "UPDATE _vt.vreplication set state='Stopped' where db_name=%a and workflow=%a"
+ sqlDeleteVReplStream = "DELETE FROM _vt.vreplication where db_name=%a and workflow=%a"
+ sqlReadVReplStream = `SELECT
id,
workflow,
source,
@@ -588,6 +505,7 @@ const (
time_heartbeat,
time_throttled,
component_throttled,
+ reason_throttled,
state,
message,
rows_copied
diff --git a/go/vt/vttablet/onlineddl/vrepl.go b/go/vt/vttablet/onlineddl/vrepl.go
index cde2f276563..14c52d352bf 100644
--- a/go/vt/vttablet/onlineddl/vrepl.go
+++ b/go/vt/vttablet/onlineddl/vrepl.go
@@ -38,11 +38,10 @@ import (
"vitess.io/vitess/go/textutil"
"vitess.io/vitess/go/vt/dbconnpool"
"vitess.io/vitess/go/vt/log"
- "vitess.io/vitess/go/vt/schema"
+ "vitess.io/vitess/go/vt/schemadiff"
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vtenv"
"vitess.io/vitess/go/vt/vterrors"
- "vitess.io/vitess/go/vt/vttablet/onlineddl/vrepl"
"vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication"
binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
@@ -59,6 +58,7 @@ type VReplStream struct {
timeHeartbeat int64
timeThrottled int64
componentThrottled string
+ reasonThrottled string
transactionTimestamp int64
state binlogdatapb.VReplicationWorkflowState
message string
@@ -98,43 +98,23 @@ func (v *VReplStream) hasError() (isTerminal bool, vreplError error) {
// VRepl is an online DDL helper for VReplication based migrations (ddl_strategy="online")
type VRepl struct {
- workflow string
- keyspace string
- shard string
- dbName string
- sourceTable string
- targetTable string
- pos string
- alterQuery *sqlparser.AlterTable
- tableRows int64
-
- originalCreateTable *sqlparser.CreateTable
- vreplCreateTable *sqlparser.CreateTable
+ workflow string
+ keyspace string
+ shard string
+ dbName string
+ pos string
+ tableRows int64
- analyzeTable bool
-
- sourceSharedColumns *vrepl.ColumnList
- targetSharedColumns *vrepl.ColumnList
- droppedSourceNonGeneratedColumns *vrepl.ColumnList
- droppedNoDefaultColumnNames []string
- expandedColumnNames []string
- sharedColumnsMap map[string]string
- sourceAutoIncrement uint64
+ sourceCreateTableEntity *schemadiff.CreateTableEntity
+ targetCreateTableEntity *schemadiff.CreateTableEntity
+ analysis *schemadiff.MigrationTablesAnalysis
- chosenSourceUniqueKey *vrepl.UniqueKey
- chosenTargetUniqueKey *vrepl.UniqueKey
-
- addedUniqueKeys []*vrepl.UniqueKey
- removedUniqueKeys []*vrepl.UniqueKey
- removedForeignKeyNames []string
+ analyzeTable bool
- revertibleNotes string
- filterQuery string
- enumToTextMap map[string]string
- intToEnumMap map[string]bool
- bls *binlogdatapb.BinlogSource
+ filterQuery string
+ bls *binlogdatapb.BinlogSource
- parser *vrepl.AlterTableParser
+ alterTableAnalysis *schemadiff.AlterTableAnalysis
convertCharset map[string](*binlogdatapb.CharsetConversion)
@@ -148,110 +128,40 @@ func NewVRepl(
keyspace string,
shard string,
dbName string,
- sourceTable string,
- targetTable string,
- originalCreateTable *sqlparser.CreateTable,
- vreplCreateTable *sqlparser.CreateTable,
+ sourceCreateTable *sqlparser.CreateTable,
+ targetCreateTable *sqlparser.CreateTable,
alterQuery *sqlparser.AlterTable,
analyzeTable bool,
-) *VRepl {
- return &VRepl{
- env: env,
- workflow: workflow,
- keyspace: keyspace,
- shard: shard,
- dbName: dbName,
- sourceTable: sourceTable,
- targetTable: targetTable,
- originalCreateTable: originalCreateTable,
- vreplCreateTable: vreplCreateTable,
- alterQuery: alterQuery,
- analyzeTable: analyzeTable,
- parser: vrepl.NewAlterTableParser(),
- enumToTextMap: map[string]string{},
- intToEnumMap: map[string]bool{},
- convertCharset: map[string](*binlogdatapb.CharsetConversion){},
- }
-}
-
-// readAutoIncrement reads the AUTO_INCREMENT value, if any, for a give ntable
-func (v *VRepl) readAutoIncrement(ctx context.Context, conn *dbconnpool.DBConnection, tableName string) (autoIncrement uint64, err error) {
- query, err := sqlparser.ParseAndBind(sqlGetAutoIncrement,
- sqltypes.StringBindVariable(v.dbName),
- sqltypes.StringBindVariable(tableName),
- )
+) (*VRepl, error) {
+ v := &VRepl{
+ env: env,
+ workflow: workflow,
+ keyspace: keyspace,
+ shard: shard,
+ dbName: dbName,
+ alterTableAnalysis: schemadiff.OnlineDDLAlterTableAnalysis(alterQuery),
+ analyzeTable: analyzeTable,
+ convertCharset: map[string](*binlogdatapb.CharsetConversion){},
+ }
+ senv := schemadiff.NewEnv(v.env, v.env.CollationEnv().DefaultConnectionCharset())
+ var err error
+ v.sourceCreateTableEntity, err = schemadiff.NewCreateTableEntity(senv, sourceCreateTable)
if err != nil {
- return 0, err
+ return nil, err
}
-
- rs, err := conn.ExecuteFetch(query, -1, true)
+ v.targetCreateTableEntity, err = schemadiff.NewCreateTableEntity(senv, targetCreateTable)
if err != nil {
- return 0, err
- }
- for _, row := range rs.Named().Rows {
- autoIncrement = row.AsUint64("AUTO_INCREMENT", 0)
+ return nil, err
}
-
- return autoIncrement, nil
+ return v, nil
}
-// readTableColumns reads column list from given table
-func (v *VRepl) readTableColumns(ctx context.Context, conn *dbconnpool.DBConnection, tableName string) (columns *vrepl.ColumnList, virtualColumns *vrepl.ColumnList, pkColumns *vrepl.ColumnList, err error) {
- parsed := sqlparser.BuildParsedQuery(sqlShowColumnsFrom, tableName)
- rs, err := conn.ExecuteFetch(parsed.Query, -1, true)
- if err != nil {
- return nil, nil, nil, err
- }
- columnNames := []string{}
- virtualColumnNames := []string{}
- pkColumnNames := []string{}
- for _, row := range rs.Named().Rows {
- columnName := row.AsString("Field", "")
- columnNames = append(columnNames, columnName)
-
- extra := row.AsString("Extra", "")
- if strings.Contains(extra, "STORED GENERATED") || strings.Contains(extra, "VIRTUAL GENERATED") {
- virtualColumnNames = append(virtualColumnNames, columnName)
- }
-
- key := row.AsString("Key", "")
- if key == "PRI" {
- pkColumnNames = append(pkColumnNames, columnName)
- }
- }
- if len(columnNames) == 0 {
- return nil, nil, nil, fmt.Errorf("Found 0 columns on `%s`", tableName)
- }
- return vrepl.NewColumnList(columnNames), vrepl.NewColumnList(virtualColumnNames), vrepl.NewColumnList(pkColumnNames), nil
+func (v *VRepl) sourceTableName() string {
+ return v.sourceCreateTableEntity.Name()
}
-// readTableUniqueKeys reads all unique keys from a given table, by order of usefulness/performance: PRIMARY first, integers are better, non-null are better
-func (v *VRepl) readTableUniqueKeys(ctx context.Context, conn *dbconnpool.DBConnection, tableName string) (uniqueKeys []*vrepl.UniqueKey, err error) {
- query, err := sqlparser.ParseAndBind(sqlSelectUniqueKeys,
- sqltypes.StringBindVariable(v.dbName),
- sqltypes.StringBindVariable(tableName),
- sqltypes.StringBindVariable(v.dbName),
- sqltypes.StringBindVariable(tableName),
- )
- if err != nil {
- return nil, err
- }
- rs, err := conn.ExecuteFetch(query, -1, true)
- if err != nil {
- return nil, err
- }
- for _, row := range rs.Named().Rows {
- uniqueKey := &vrepl.UniqueKey{
- Name: row.AsString("index_name", ""),
- Columns: *vrepl.ParseColumnList(row.AsString("column_names", "")),
- HasNullable: row.AsBool("has_nullable", false),
- HasSubpart: row.AsBool("has_subpart", false),
- HasFloat: row.AsBool("is_float", false),
- IsAutoIncrement: row.AsBool("is_auto_increment", false),
- }
- uniqueKeys = append(uniqueKeys, uniqueKey)
- }
- return uniqueKeys, nil
+func (v *VRepl) targetTableName() string {
+ return v.targetCreateTableEntity.Name()
}
// isFastAnalyzeTableSupported checks if the underlying MySQL server supports 'fast_analyze_table',
@@ -306,255 +216,64 @@ func (v *VRepl) readTableStatus(ctx context.Context, conn *dbconnpool.DBConnecti
return tableRows, err
}
-// applyColumnTypes
-func (v *VRepl) applyColumnTypes(ctx context.Context, conn *dbconnpool.DBConnection, tableName string, columnsLists ...*vrepl.ColumnList) error {
- query, err := sqlparser.ParseAndBind(sqlSelectColumnTypes,
- sqltypes.StringBindVariable(v.dbName),
- sqltypes.StringBindVariable(tableName),
- )
- if err != nil {
- return err
- }
- rs, err := conn.ExecuteFetch(query, -1, true)
- if err != nil {
- return err
- }
- for _, row := range rs.Named().Rows {
- columnName := row["COLUMN_NAME"].ToString()
- columnType := row["COLUMN_TYPE"].ToString()
- columnOctetLength := row.AsUint64("CHARACTER_OCTET_LENGTH", 0)
-
- for _, columnsList := range columnsLists {
- column := columnsList.GetColumn(columnName)
- if column == nil {
- continue
- }
-
- column.DataType = row.AsString("DATA_TYPE", "") // a more canonical form of column_type
- column.IsNullable = (row.AsString("IS_NULLABLE", "") == "YES")
- column.IsDefaultNull = row.AsBool("is_default_null", false)
-
- column.CharacterMaximumLength = row.AsInt64("CHARACTER_MAXIMUM_LENGTH", 0)
- column.NumericPrecision = row.AsInt64("NUMERIC_PRECISION", 0)
- column.NumericScale = row.AsInt64("NUMERIC_SCALE", 0)
- column.DateTimePrecision = row.AsInt64("DATETIME_PRECISION", -1)
-
- column.Type = vrepl.UnknownColumnType
- if strings.Contains(columnType, "unsigned") {
- column.IsUnsigned = true
- }
- if strings.Contains(columnType, "mediumint") {
- column.SetTypeIfUnknown(vrepl.MediumIntColumnType)
- }
- if strings.Contains(columnType, "timestamp") {
- column.SetTypeIfUnknown(vrepl.TimestampColumnType)
- }
- if strings.Contains(columnType, "datetime") {
- column.SetTypeIfUnknown(vrepl.DateTimeColumnType)
- }
- if strings.Contains(columnType, "json") {
- column.SetTypeIfUnknown(vrepl.JSONColumnType)
- }
- if strings.Contains(columnType, "float") {
- column.SetTypeIfUnknown(vrepl.FloatColumnType)
- }
- if strings.Contains(columnType, "double") {
- column.SetTypeIfUnknown(vrepl.DoubleColumnType)
- }
- if strings.HasPrefix(columnType, "enum") {
- column.SetTypeIfUnknown(vrepl.EnumColumnType)
- column.EnumValues = schema.ParseEnumValues(columnType)
- }
- if strings.HasPrefix(columnType, "set(") {
- column.SetTypeIfUnknown(vrepl.SetColumnType)
- column.EnumValues = schema.ParseSetValues(columnType)
- }
- if strings.HasPrefix(columnType, "binary") {
- column.SetTypeIfUnknown(vrepl.BinaryColumnType)
- column.BinaryOctetLength = columnOctetLength
- }
- if charset := row.AsString("CHARACTER_SET_NAME", ""); charset != "" {
- column.Charset = charset
- }
- if collation := row.AsString("COLLATION_NAME", ""); collation != "" {
- column.SetTypeIfUnknown(vrepl.StringColumnType)
- column.Collation = collation
+// formalizeColumns
+func formalizeColumns(columnsLists ...*schemadiff.ColumnDefinitionEntityList) error {
+ for _, colList := range columnsLists {
+ for _, col := range colList.Entities {
+ col.SetExplicitDefaultAndNull()
+ if err := col.SetExplicitCharsetCollate(); err != nil {
+ return err
}
}
}
return nil
}
-func (v *VRepl) analyzeAlter(ctx context.Context) error {
- if v.alterQuery == nil {
- // Happens for REVERT
- return nil
- }
- v.parser.AnalyzeAlter(v.alterQuery)
- if v.parser.IsRenameTable() {
- return fmt.Errorf("Renaming the table is not supported in ALTER TABLE: %s", sqlparser.CanonicalString(v.alterQuery))
+func (v *VRepl) analyzeAlter() error {
+ if v.alterTableAnalysis.IsRenameTable {
+ return fmt.Errorf("renaming the table is not supported in ALTER TABLE")
}
return nil
}
-func (v *VRepl) analyzeTables(ctx context.Context, conn *dbconnpool.DBConnection) (err error) {
- if v.analyzeTable {
- if err := v.executeAnalyzeTable(ctx, conn, v.sourceTable); err != nil {
- return err
- }
- }
- v.tableRows, err = v.readTableStatus(ctx, conn, v.sourceTable)
+func (v *VRepl) analyzeTables() (err error) {
+ analysis, err := schemadiff.OnlineDDLMigrationTablesAnalysis(v.sourceCreateTableEntity, v.targetCreateTableEntity, v.alterTableAnalysis)
if err != nil {
return err
}
- // columns:
- sourceColumns, sourceVirtualColumns, sourcePKColumns, err := v.readTableColumns(ctx, conn, v.sourceTable)
- if err != nil {
- return err
- }
- targetColumns, targetVirtualColumns, targetPKColumns, err := v.readTableColumns(ctx, conn, v.targetTable)
- if err != nil {
- return err
- }
- v.sourceSharedColumns, v.targetSharedColumns, v.droppedSourceNonGeneratedColumns, v.sharedColumnsMap = vrepl.GetSharedColumns(sourceColumns, targetColumns, sourceVirtualColumns, targetVirtualColumns, v.parser)
+ v.analysis = analysis
- // unique keys
- sourceUniqueKeys, err := v.readTableUniqueKeys(ctx, conn, v.sourceTable)
- if err != nil {
- return err
- }
- if len(sourceUniqueKeys) == 0 {
- return fmt.Errorf("Found no possible unique key on `%s`", v.sourceTable)
- }
- targetUniqueKeys, err := v.readTableUniqueKeys(ctx, conn, v.targetTable)
- if err != nil {
- return err
- }
- if len(targetUniqueKeys) == 0 {
- return fmt.Errorf("Found no possible unique key on `%s`", v.targetTable)
- }
- v.chosenSourceUniqueKey, v.chosenTargetUniqueKey = vrepl.GetSharedUniqueKeys(sourceUniqueKeys, targetUniqueKeys, v.parser.ColumnRenameMap())
- if v.chosenSourceUniqueKey == nil {
- // VReplication supports completely different unique keys on source and target, covering
- // some/completely different columns. The condition is that the key on source
- // must use columns which all exist on target table.
- v.chosenSourceUniqueKey = vrepl.GetUniqueKeyCoveredByColumns(sourceUniqueKeys, v.sourceSharedColumns)
- if v.chosenSourceUniqueKey == nil {
- // Still no luck.
- return fmt.Errorf("Found no possible unique key on `%s` whose columns are in target table `%s`", v.sourceTable, v.targetTable)
- }
- }
- if v.chosenTargetUniqueKey == nil {
- // VReplication supports completely different unique keys on source and target, covering
- // some/completely different columns. The condition is that the key on target
- // must use columns which all exist on source table.
- v.chosenTargetUniqueKey = vrepl.GetUniqueKeyCoveredByColumns(targetUniqueKeys, v.targetSharedColumns)
- if v.chosenTargetUniqueKey == nil {
- // Still no luck.
- return fmt.Errorf("Found no possible unique key on `%s` whose columns are in source table `%s`", v.targetTable, v.sourceTable)
- }
- }
- if v.chosenSourceUniqueKey == nil || v.chosenTargetUniqueKey == nil {
- return fmt.Errorf("Found no shared, not nullable, unique keys between `%s` and `%s`", v.sourceTable, v.targetTable)
- }
- v.addedUniqueKeys = vrepl.AddedUniqueKeys(sourceUniqueKeys, targetUniqueKeys, v.parser.ColumnRenameMap())
- v.removedUniqueKeys = vrepl.RemovedUniqueKeys(sourceUniqueKeys, targetUniqueKeys, v.parser.ColumnRenameMap())
- v.removedForeignKeyNames, err = vrepl.RemovedForeignKeyNames(v.env, v.originalCreateTable, v.vreplCreateTable)
- if err != nil {
- return err
- }
-
- // chosen source & target unique keys have exact columns in same order
- sharedPKColumns := &v.chosenSourceUniqueKey.Columns
-
- if err := v.applyColumnTypes(ctx, conn, v.sourceTable, sourceColumns, sourceVirtualColumns, sourcePKColumns, v.sourceSharedColumns, sharedPKColumns, v.droppedSourceNonGeneratedColumns); err != nil {
- return err
- }
- if err := v.applyColumnTypes(ctx, conn, v.targetTable, targetColumns, targetVirtualColumns, targetPKColumns, v.targetSharedColumns); err != nil {
- return err
- }
-
- for _, sourcePKColumn := range sharedPKColumns.Columns() {
- mappedColumn := v.targetSharedColumns.GetColumn(sourcePKColumn.Name)
- if sourcePKColumn.Type == vrepl.EnumColumnType && mappedColumn.Type == vrepl.EnumColumnType {
- // An ENUM as part of PRIMARY KEY. We must convert it to text because OMG that's complicated.
- // There's a scenario where a query may modify the enum value (and it's bad practice, seeing
- // that it's part of the PK, but it's still valid), and in that case we must have the string value
- // to be able to DELETE the old row
- v.targetSharedColumns.SetEnumToTextConversion(mappedColumn.Name, sourcePKColumn.EnumValues)
- v.enumToTextMap[sourcePKColumn.Name] = sourcePKColumn.EnumValues
- }
- }
-
- for i := range v.sourceSharedColumns.Columns() {
- sourceColumn := v.sourceSharedColumns.Columns()[i]
- mappedColumn := v.targetSharedColumns.Columns()[i]
- if sourceColumn.Type == vrepl.EnumColumnType {
- switch {
- // Either this is an ENUM column that stays an ENUM, or it is converted to a textual type.
- // We take note of the enum values, and make it available in vreplication's Filter.Rule.ConvertEnumToText.
- // This, in turn, will be used by vplayer (in TablePlan) like so:
- // - In the binary log, enum values are integers.
- // - Upon seeing this map, PlanBuilder will convert said int to the enum's logical string value.
- // - And will apply the value as a string (`StringBindVariable`) in the query.
- // What this allows is for enum values to have different ordering in the before/after table schema,
- // so that for example you could modify an enum column:
- // - from `('red', 'green', 'blue')` to `('red', 'blue')`
- // - from `('red', 'green', 'blue')` to `('blue', 'red', 'green')`
- case mappedColumn.Type == vrepl.EnumColumnType:
- v.enumToTextMap[sourceColumn.Name] = sourceColumn.EnumValues
- case mappedColumn.Charset != "":
- v.enumToTextMap[sourceColumn.Name] = sourceColumn.EnumValues
- v.targetSharedColumns.SetEnumToTextConversion(mappedColumn.Name, sourceColumn.EnumValues)
- }
- }
+ return nil
+}
- if sourceColumn.IsIntegralType() && mappedColumn.Type == vrepl.EnumColumnType {
- v.intToEnumMap[sourceColumn.Name] = true
+// analyzeTableStatus reads information from SHOW TABLE STATUS
+func (v *VRepl) analyzeTableStatus(ctx context.Context, conn *dbconnpool.DBConnection) (err error) {
+ if v.analyzeTable {
+ if err := v.executeAnalyzeTable(ctx, conn, v.sourceTableName()); err != nil {
+ return err
}
}
-
- v.droppedNoDefaultColumnNames = vrepl.GetNoDefaultColumnNames(v.droppedSourceNonGeneratedColumns)
- var expandedDescriptions map[string]string
- v.expandedColumnNames, expandedDescriptions = vrepl.GetExpandedColumnNames(v.sourceSharedColumns, v.targetSharedColumns)
-
- v.sourceAutoIncrement, err = v.readAutoIncrement(ctx, conn, v.sourceTable)
-
- notes := []string{}
- for _, uk := range v.removedUniqueKeys {
- notes = append(notes, fmt.Sprintf("unique constraint removed: %s", uk.Name))
- }
- for _, name := range v.droppedNoDefaultColumnNames {
- notes = append(notes, fmt.Sprintf("column %s dropped, and had no default value", name))
- }
- for _, name := range v.expandedColumnNames {
- notes = append(notes, fmt.Sprintf("column %s: %s", name, expandedDescriptions[name]))
- }
- for _, name := range v.removedForeignKeyNames {
- notes = append(notes, fmt.Sprintf("foreign key %s dropped", name))
- }
- v.revertibleNotes = strings.Join(notes, "\n")
+ v.tableRows, err = v.readTableStatus(ctx, conn, v.sourceTableName())
if err != nil {
return err
}
-
return nil
}
// generateFilterQuery creates a SELECT query used by vreplication as a filter. It SELECTs all
// non-generated columns between source & target tables, and takes care of column renames.
-func (v *VRepl) generateFilterQuery(ctx context.Context) error {
- if v.sourceSharedColumns.Len() == 0 {
- return fmt.Errorf("Empty column list")
+func (v *VRepl) generateFilterQuery() error {
+ if v.analysis.SourceSharedColumns.Len() == 0 {
+ return fmt.Errorf("empty column list")
}
var sb strings.Builder
sb.WriteString("select ")
- for i, sourceCol := range v.sourceSharedColumns.Columns() {
- name := sourceCol.Name
- targetName := v.sharedColumnsMap[name]
+ for i, sourceCol := range v.analysis.SourceSharedColumns.Entities {
+ name := sourceCol.Name()
+ targetName := v.analysis.SharedColumnsMap[name]
- targetCol := v.targetSharedColumns.GetColumn(targetName)
+ targetCol := v.analysis.TargetSharedColumns.GetColumn(targetName)
if targetCol == nil {
return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "Cannot find target column %s", targetName)
}
@@ -563,35 +282,36 @@ func (v *VRepl) generateFilterQuery(ctx context.Context) error {
sb.WriteString(", ")
}
switch {
- case sourceCol.EnumToTextConversion:
+ case sourceCol.HasEnumValues():
+ // Source is `enum` or `set`. We always take the textual represenation rather than the numeric one.
sb.WriteString(fmt.Sprintf("CONCAT(%s)", escapeName(name)))
- case v.intToEnumMap[name]:
+ case v.analysis.IntToEnumMap[name]:
sb.WriteString(fmt.Sprintf("CONCAT(%s)", escapeName(name)))
- case sourceCol.Type == vrepl.JSONColumnType:
+ case sourceCol.Type() == "json":
sb.WriteString(fmt.Sprintf("convert(%s using utf8mb4)", escapeName(name)))
- case sourceCol.Type == vrepl.StringColumnType:
+ case sourceCol.IsTextual():
// Check source and target charset/encoding. If needed, create
// a binlogdatapb.CharsetConversion entry (later written to vreplication)
- fromCollation := v.env.CollationEnv().DefaultCollationForCharset(sourceCol.Charset)
+ fromCollation := v.env.CollationEnv().DefaultCollationForCharset(sourceCol.Charset())
if fromCollation == collations.Unknown {
- return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Character set %s not supported for column %s", sourceCol.Charset, sourceCol.Name)
+ return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Character set %s not supported for column %s", sourceCol.Charset(), sourceCol.Name())
}
- toCollation := v.env.CollationEnv().DefaultCollationForCharset(targetCol.Charset)
+ toCollation := v.env.CollationEnv().DefaultCollationForCharset(targetCol.Charset())
// Let's see if target col is at all textual
- if targetCol.Type == vrepl.StringColumnType && toCollation == collations.Unknown {
- return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Character set %s not supported for column %s", targetCol.Charset, targetCol.Name)
+ if targetCol.IsTextual() && toCollation == collations.Unknown {
+ return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Character set %s not supported for column %s", targetCol.Charset(), targetCol.Name())
}
- if trivialCharset(fromCollation) && trivialCharset(toCollation) && targetCol.Type != vrepl.JSONColumnType {
+ if trivialCharset(fromCollation) && trivialCharset(toCollation) && targetCol.Type() != "json" {
sb.WriteString(escapeName(name))
} else {
v.convertCharset[targetName] = &binlogdatapb.CharsetConversion{
- FromCharset: sourceCol.Charset,
- ToCharset: targetCol.Charset,
+ FromCharset: sourceCol.Charset(),
+ ToCharset: targetCol.Charset(),
}
sb.WriteString(fmt.Sprintf("convert(%s using utf8mb4)", escapeName(name)))
}
- case targetCol.Type == vrepl.JSONColumnType && sourceCol.Type != vrepl.JSONColumnType:
+ case targetCol.Type() == "json" && sourceCol.Type() != "json":
// Convert any type to JSON: encode the type as utf8mb4 text
sb.WriteString(fmt.Sprintf("convert(%s using utf8mb4)", escapeName(name)))
default:
@@ -601,7 +321,7 @@ func (v *VRepl) generateFilterQuery(ctx context.Context) error {
sb.WriteString(escapeName(targetName))
}
sb.WriteString(" from ")
- sb.WriteString(escapeName(v.sourceTable))
+ sb.WriteString(escapeName(v.sourceTableName()))
v.filterQuery = sb.String()
return nil
@@ -623,25 +343,22 @@ func (v *VRepl) analyzeBinlogSource(ctx context.Context) {
StopAfterCopy: false,
}
- encodeColumns := func(columns *vrepl.ColumnList) string {
- return textutil.EscapeJoin(columns.Names(), ",")
+ encodeColumns := func(names []string) string {
+ return textutil.EscapeJoin(names, ",")
}
rule := &binlogdatapb.Rule{
- Match: v.targetTable,
+ Match: v.targetTableName(),
Filter: v.filterQuery,
- SourceUniqueKeyColumns: encodeColumns(&v.chosenSourceUniqueKey.Columns),
- TargetUniqueKeyColumns: encodeColumns(&v.chosenTargetUniqueKey.Columns),
- SourceUniqueKeyTargetColumns: encodeColumns(v.chosenSourceUniqueKey.Columns.MappedNamesColumnList(v.sharedColumnsMap)),
- ForceUniqueKey: url.QueryEscape(v.chosenSourceUniqueKey.Name),
+ SourceUniqueKeyColumns: encodeColumns(v.analysis.ChosenSourceUniqueKey.ColumnList.Names()),
+ TargetUniqueKeyColumns: encodeColumns(v.analysis.ChosenTargetUniqueKey.ColumnList.Names()),
+ SourceUniqueKeyTargetColumns: encodeColumns(schemadiff.MappedColumnNames(v.analysis.ChosenSourceUniqueKey.ColumnList, v.analysis.SharedColumnsMap)),
+ ForceUniqueKey: url.QueryEscape(v.analysis.ChosenSourceUniqueKey.Name()),
}
if len(v.convertCharset) > 0 {
rule.ConvertCharset = v.convertCharset
}
- if len(v.enumToTextMap) > 0 {
- rule.ConvertEnumToText = v.enumToTextMap
- }
- if len(v.intToEnumMap) > 0 {
- rule.ConvertIntToEnum = v.intToEnumMap
+ if len(v.analysis.IntToEnumMap) > 0 {
+ rule.ConvertIntToEnum = v.analysis.IntToEnumMap
}
bls.Filter.Rules = append(bls.Filter.Rules, rule)
@@ -649,13 +366,16 @@ func (v *VRepl) analyzeBinlogSource(ctx context.Context) {
}
func (v *VRepl) analyze(ctx context.Context, conn *dbconnpool.DBConnection) error {
- if err := v.analyzeAlter(ctx); err != nil {
+ if err := v.analyzeAlter(); err != nil {
+ return err
+ }
+ if err := v.analyzeTables(); err != nil {
return err
}
- if err := v.analyzeTables(ctx, conn); err != nil {
+ if err := v.generateFilterQuery(); err != nil {
return err
}
- if err := v.generateFilterQuery(ctx); err != nil {
+ if err := v.analyzeTableStatus(ctx, conn); err != nil {
return err
}
v.analyzeBinlogSource(ctx)
@@ -663,7 +383,7 @@ func (v *VRepl) analyze(ctx context.Context, conn *dbconnpool.DBConnection) erro
}
// generateInsertStatement generates the INSERT INTO _vt.replication statement that creates the vreplication workflow
-func (v *VRepl) generateInsertStatement(ctx context.Context) (string, error) {
+func (v *VRepl) generateInsertStatement() (string, error) {
ig := vreplication.NewInsertGenerator(binlogdatapb.VReplicationWorkflowState_Stopped, v.dbName)
ig.AddRow(v.workflow, v.bls, v.pos, "", "in_order:REPLICA,PRIMARY",
binlogdatapb.VReplicationWorkflowType_OnlineDDL, binlogdatapb.VReplicationWorkflowSubType_None, false)
@@ -672,7 +392,7 @@ func (v *VRepl) generateInsertStatement(ctx context.Context) (string, error) {
}
// generateStartStatement Generates the statement to start VReplication running on the workflow
-func (v *VRepl) generateStartStatement(ctx context.Context) (string, error) {
+func (v *VRepl) generateStartStatement() (string, error) {
return sqlparser.ParseAndBind(sqlStartVReplStream,
sqltypes.StringBindVariable(v.dbName),
sqltypes.StringBindVariable(v.workflow),
diff --git a/go/vt/vttablet/onlineddl/vrepl/columns.go b/go/vt/vttablet/onlineddl/vrepl/columns.go
deleted file mode 100644
index f2bb8f6d3f2..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/columns.go
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "fmt"
- "strings"
-
- "vitess.io/vitess/go/vt/schema"
-)
-
-// expandedDataTypes maps some known and difficult-to-compute by INFORMATION_SCHEMA data types which expand other data types.
-// For example, in "date:datetime", datetime expands date because it has more precision. In "timestamp:date" date expands timestamp
-// because it can contain years not covered by timestamp.
-var expandedDataTypes = map[string]bool{
- "time:datetime": true,
- "date:datetime": true,
- "timestamp:datetime": true,
- "time:timestamp": true,
- "date:timestamp": true,
- "timestamp:date": true,
-}
-
-// GetSharedColumns returns the intersection of two lists of columns in same order as the first list
-func GetSharedColumns(
- sourceColumns, targetColumns *ColumnList,
- sourceVirtualColumns, targetVirtualColumns *ColumnList,
- parser *AlterTableParser,
-) (
- sourceSharedColumns *ColumnList,
- targetSharedColumns *ColumnList,
- droppedSourceNonGeneratedColumns *ColumnList,
- sharedColumnsMap map[string]string,
-) {
- sharedColumnNames := []string{}
- droppedSourceNonGeneratedColumnsNames := []string{}
- for _, sourceColumn := range sourceColumns.Names() {
- isSharedColumn := false
- isVirtualColumnOnSource := false
- for _, targetColumn := range targetColumns.Names() {
- if strings.EqualFold(sourceColumn, targetColumn) {
- // both tables have this column. Good start.
- isSharedColumn = true
- break
- }
- if strings.EqualFold(parser.columnRenameMap[sourceColumn], targetColumn) {
- // column in source is renamed in target
- isSharedColumn = true
- break
- }
- }
- for droppedColumn := range parser.DroppedColumnsMap() {
- if strings.EqualFold(sourceColumn, droppedColumn) {
- isSharedColumn = false
- break
- }
- }
- for _, virtualColumn := range sourceVirtualColumns.Names() {
- // virtual/generated columns on source are silently skipped
- if strings.EqualFold(sourceColumn, virtualColumn) {
- isSharedColumn = false
- isVirtualColumnOnSource = true
- }
- }
- for _, virtualColumn := range targetVirtualColumns.Names() {
- // virtual/generated columns on target are silently skipped
- if strings.EqualFold(sourceColumn, virtualColumn) {
- isSharedColumn = false
- }
- }
- if isSharedColumn {
- sharedColumnNames = append(sharedColumnNames, sourceColumn)
- } else if !isVirtualColumnOnSource {
- droppedSourceNonGeneratedColumnsNames = append(droppedSourceNonGeneratedColumnsNames, sourceColumn)
- }
- }
- sharedColumnsMap = map[string]string{}
- for _, columnName := range sharedColumnNames {
- if mapped, ok := parser.columnRenameMap[columnName]; ok {
- sharedColumnsMap[columnName] = mapped
- } else {
- sharedColumnsMap[columnName] = columnName
- }
- }
- mappedSharedColumnNames := []string{}
- for _, columnName := range sharedColumnNames {
- mappedSharedColumnNames = append(mappedSharedColumnNames, sharedColumnsMap[columnName])
- }
- return NewColumnList(sharedColumnNames), NewColumnList(mappedSharedColumnNames), NewColumnList(droppedSourceNonGeneratedColumnsNames), sharedColumnsMap
-}
-
-// isExpandedColumn sees if target column has any value set/range that is impossible in source column. See GetExpandedColumns comment for examples
-func isExpandedColumn(sourceColumn *Column, targetColumn *Column) (bool, string) {
- if targetColumn.IsNullable && !sourceColumn.IsNullable {
- return true, "target is NULL-able, source is not"
- }
- if targetColumn.CharacterMaximumLength > sourceColumn.CharacterMaximumLength {
- return true, "increased CHARACTER_MAXIMUM_LENGTH"
- }
- if targetColumn.NumericPrecision > sourceColumn.NumericPrecision {
- return true, "increased NUMERIC_PRECISION"
- }
- if targetColumn.NumericScale > sourceColumn.NumericScale {
- return true, "increased NUMERIC_SCALE"
- }
- if targetColumn.DateTimePrecision > sourceColumn.DateTimePrecision {
- return true, "increased DATETIME_PRECISION"
- }
- if sourceColumn.IsNumeric() && targetColumn.IsNumeric() {
- if sourceColumn.IsUnsigned && !targetColumn.IsUnsigned {
- return true, "source is unsigned, target is signed"
- }
- if sourceColumn.NumericPrecision <= targetColumn.NumericPrecision && !sourceColumn.IsUnsigned && targetColumn.IsUnsigned {
- // e.g. INT SIGNED => INT UNSIGNED, INT SIGNED => BIGINT UNSIGNED
- return true, "target unsigned value exceeds source unsigned value"
- }
- if targetColumn.IsFloatingPoint() && !sourceColumn.IsFloatingPoint() {
- return true, "target is floating point, source is not"
- }
- }
- if expandedDataTypes[fmt.Sprintf("%s:%s", sourceColumn.DataType, targetColumn.DataType)] {
- return true, "target is expanded data type of source"
- }
- if sourceColumn.Charset != targetColumn.Charset {
- if targetColumn.Charset == "utf8mb4" {
- return true, "expand character set to utf8mb4"
- }
- if strings.HasPrefix(targetColumn.Charset, "utf8") && !strings.HasPrefix(sourceColumn.Charset, "utf8") {
- // not utf to utf
- return true, "expand character set to utf8"
- }
- }
- for _, colType := range []ColumnType{EnumColumnType, SetColumnType} {
- // enums and sets have very similar properties, and are practically identical in our analysis
- if sourceColumn.Type == colType {
- // this is an enum or a set
- if targetColumn.Type != colType {
- return true, "conversion from enum/set to non-enum/set adds potential values"
- }
- // target is an enum or a set. See if all values on target exist in source
- sourceEnumTokensMap := schema.ParseEnumOrSetTokensMap(sourceColumn.EnumValues)
- targetEnumTokensMap := schema.ParseEnumOrSetTokensMap(targetColumn.EnumValues)
- for k, v := range targetEnumTokensMap {
- if sourceEnumTokensMap[k] != v {
- return true, "target enum/set expands source enum/set"
- }
- }
- }
- }
- return false, ""
-}
-
-// GetExpandedColumnNames is given source and target shared columns, and returns the list of columns whose data type is expanded.
-// An expanded data type is one where the target can have a value which the source does not. Examples:
-// - any NOT NULL to NULLable (a NULL in the target cannot appear on source)
-// - INT -> BIGINT (obvious)
-// - BIGINT UNSIGNED -> INT SIGNED (negative values)
-// - TIMESTAMP -> TIMESTAMP(3)
-// etc.
-func GetExpandedColumnNames(
- sourceSharedColumns *ColumnList,
- targetSharedColumns *ColumnList,
-) (
- expandedColumnNames []string,
- expandedDescriptions map[string]string,
-) {
- expandedDescriptions = map[string]string{}
- for i := range sourceSharedColumns.Columns() {
- // source and target columns assumed to be mapped 1:1, same length
- sourceColumn := sourceSharedColumns.Columns()[i]
- targetColumn := targetSharedColumns.Columns()[i]
-
- if isExpanded, description := isExpandedColumn(&sourceColumn, &targetColumn); isExpanded {
- expandedColumnNames = append(expandedColumnNames, sourceColumn.Name)
- expandedDescriptions[sourceColumn.Name] = description
- }
- }
- return expandedColumnNames, expandedDescriptions
-}
-
-// GetNoDefaultColumnNames returns names of columns which have no default value, out of given list of columns
-func GetNoDefaultColumnNames(columns *ColumnList) (names []string) {
- names = []string{}
- for _, col := range columns.Columns() {
- if !col.HasDefault() {
- names = append(names, col.Name)
- }
- }
- return names
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/columns_test.go b/go/vt/vttablet/onlineddl/vrepl/columns_test.go
deleted file mode 100644
index 32efd104cc1..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/columns_test.go
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-var (
- columnsA = &ColumnList{
- columns: []Column{
- {
- Name: "id",
- },
- {
- Name: "cint",
- },
- {
- Name: "cgen1",
- },
- {
- Name: "cgen2",
- },
- {
- Name: "cchar",
- },
- {
- Name: "cremoved",
- },
- {
- Name: "cnullable",
- IsNullable: true,
- },
- {
- Name: "cnodefault",
- IsNullable: false,
- IsDefaultNull: true,
- },
- },
- Ordinals: ColumnsMap{},
- }
- columnsB = &ColumnList{
- columns: []Column{
- {
- Name: "id",
- },
- {
- Name: "cint",
- },
- {
- Name: "cgen1",
- },
- {
- Name: "cchar_alternate",
- },
- {
- Name: "cnullable",
- IsNullable: true,
- },
- {
- Name: "cnodefault",
- IsNullable: false,
- IsDefaultNull: true,
- },
- },
- Ordinals: ColumnsMap{},
- }
- columnsVirtual = ParseColumnList("cgen1,cgen2")
-)
-
-func TestGetSharedColumns(t *testing.T) {
- tt := []struct {
- name string
- sourceCols *ColumnList
- targetCols *ColumnList
- renameMap map[string]string
- expectSourceSharedColNames []string
- expectTargetSharedColNames []string
- expectDroppedSourceNonGeneratedColNames []string
- }{
- {
- name: "rename map empty",
- sourceCols: columnsA,
- targetCols: columnsB,
- renameMap: map[string]string{},
- expectSourceSharedColNames: []string{"id", "cint", "cnullable", "cnodefault"},
- expectTargetSharedColNames: []string{"id", "cint", "cnullable", "cnodefault"},
- expectDroppedSourceNonGeneratedColNames: []string{"cchar", "cremoved"},
- },
- {
- name: "renamed column",
- sourceCols: columnsA,
- targetCols: columnsB,
- renameMap: map[string]string{"cchar": "cchar_alternate"},
- expectSourceSharedColNames: []string{"id", "cint", "cchar", "cnullable", "cnodefault"},
- expectTargetSharedColNames: []string{"id", "cint", "cchar_alternate", "cnullable", "cnodefault"},
- expectDroppedSourceNonGeneratedColNames: []string{"cremoved"},
- },
- }
-
- parser := NewAlterTableParser()
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- parser.columnRenameMap = tc.renameMap
- sourceSharedCols, targetSharedCols, droppedNonGeneratedCols, _ := GetSharedColumns(
- tc.sourceCols, tc.targetCols,
- columnsVirtual, columnsVirtual,
- parser,
- )
- assert.Equal(t, tc.expectSourceSharedColNames, sourceSharedCols.Names())
- assert.Equal(t, tc.expectTargetSharedColNames, targetSharedCols.Names())
- assert.Equal(t, tc.expectDroppedSourceNonGeneratedColNames, droppedNonGeneratedCols.Names())
- })
- }
-}
-
-func TestGetExpandedColumnNames(t *testing.T) {
- var (
- columnsA = &ColumnList{
- columns: []Column{
- {
- Name: "c1",
- IsNullable: true,
- },
- {
- Name: "c2",
- IsNullable: true,
- },
- {
- Name: "c3",
- IsNullable: false,
- },
- },
- Ordinals: ColumnsMap{},
- }
- columnsB = &ColumnList{
- columns: []Column{
- {
- Name: "c1",
- IsNullable: true,
- },
- {
- Name: "c2",
- IsNullable: false,
- },
- {
- Name: "c3",
- IsNullable: true,
- },
- },
- Ordinals: ColumnsMap{},
- }
- )
- tcases := []struct {
- name string
- sourceCol Column
- targetCol Column
- expanded bool
- }{
- {
- "both nullable",
- Column{
- IsNullable: true,
- },
- Column{
- IsNullable: true,
- },
- false,
- },
- {
- "nullable to non nullable",
- Column{
- IsNullable: true,
- },
- Column{
- IsNullable: false,
- },
- false,
- },
- {
- "non nullable to nullable",
- Column{
- IsNullable: false,
- },
- Column{
- IsNullable: true,
- },
- true,
- },
- {
- "signed to unsigned",
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 4,
- IsUnsigned: false,
- },
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 4,
- IsUnsigned: true,
- },
- true,
- },
- {
- "unsigned to signed",
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 4,
- IsUnsigned: true,
- },
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 4,
- IsUnsigned: false,
- },
- true,
- },
- {
- "signed to smaller unsigned",
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 8,
- IsUnsigned: false,
- },
- Column{
- Type: IntegerColumnType,
- NumericPrecision: 4,
- IsUnsigned: true,
- },
- false,
- },
- {
- "same char length",
- Column{
- CharacterMaximumLength: 20,
- },
- Column{
- CharacterMaximumLength: 20,
- },
- false,
- },
- {
- "reduced char length",
- Column{
- CharacterMaximumLength: 20,
- },
- Column{
- CharacterMaximumLength: 19,
- },
- false,
- },
- {
- "increased char length",
- Column{
- CharacterMaximumLength: 20,
- },
- Column{
- CharacterMaximumLength: 21,
- },
- true,
- },
- {
- "expand temporal",
- Column{
- DataType: "time",
- },
- Column{
- DataType: "timestamp",
- },
- true,
- },
- {
- "expand temporal",
- Column{
- DataType: "date",
- },
- Column{
- DataType: "timestamp",
- },
- true,
- },
- {
- "expand temporal",
- Column{
- DataType: "date",
- },
- Column{
- DataType: "datetime",
- },
- true,
- },
- {
- "non expand temporal",
- Column{
- DataType: "datetime",
- },
- Column{
- DataType: "timestamp",
- },
- false,
- },
- {
- "expand temporal",
- Column{
- DataType: "timestamp",
- },
- Column{
- DataType: "datetime",
- },
- true,
- },
- {
- "expand enum",
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','b'",
- },
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','x'",
- },
- true,
- },
- {
- "expand enum",
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','b'",
- },
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','b','c'",
- },
- true,
- },
- {
- "reduce enum",
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','b','c'",
- },
- Column{
- Type: EnumColumnType,
- EnumValues: "'a','b'",
- },
- false,
- },
- }
-
- expectedExpandedColumnNames := []string{"c3"}
- expandedColumnNames, _ := GetExpandedColumnNames(columnsA, columnsB)
- assert.Equal(t, expectedExpandedColumnNames, expandedColumnNames)
-
- for _, tcase := range tcases {
- t.Run(tcase.name, func(t *testing.T) {
- expanded, _ := isExpandedColumn(&tcase.sourceCol, &tcase.targetCol)
- assert.Equal(t, tcase.expanded, expanded)
- })
- }
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/foreign_key.go b/go/vt/vttablet/onlineddl/vrepl/foreign_key.go
deleted file mode 100644
index 006beb7345c..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/foreign_key.go
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "vitess.io/vitess/go/vt/schemadiff"
- "vitess.io/vitess/go/vt/sqlparser"
- "vitess.io/vitess/go/vt/vtenv"
-)
-
-// RemovedForeignKeyNames returns the names of removed foreign keys, ignoring mere name changes
-func RemovedForeignKeyNames(
- venv *vtenv.Environment,
- originalCreateTable *sqlparser.CreateTable,
- vreplCreateTable *sqlparser.CreateTable,
-) (names []string, err error) {
- if originalCreateTable == nil || vreplCreateTable == nil {
- return nil, nil
- }
- env := schemadiff.NewEnv(venv, venv.CollationEnv().DefaultConnectionCharset())
- diffHints := schemadiff.DiffHints{
- ConstraintNamesStrategy: schemadiff.ConstraintNamesIgnoreAll,
- }
- diff, err := schemadiff.DiffTables(env, originalCreateTable, vreplCreateTable, &diffHints)
- if err != nil {
- return nil, err
- }
-
- validateWalk := func(node sqlparser.SQLNode) (kontinue bool, err error) {
- switch node := node.(type) {
- case *sqlparser.DropKey:
- if node.Type == sqlparser.ForeignKeyType {
- names = append(names, node.Name.String())
- }
- }
- return true, nil
- }
- _ = sqlparser.Walk(validateWalk, diff.Statement()) // We never return an error
- return names, nil
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/foreign_key_test.go b/go/vt/vttablet/onlineddl/vrepl/foreign_key_test.go
deleted file mode 100644
index 66775092dcb..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/foreign_key_test.go
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "vitess.io/vitess/go/vt/sqlparser"
- "vitess.io/vitess/go/vt/vtenv"
-)
-
-func TestRemovedForeignKeyNames(t *testing.T) {
-
- tcases := []struct {
- before string
- after string
- names []string
- }{
- {
- before: "create table t (id int primary key)",
- after: "create table t (id2 int primary key, i int)",
- },
- {
- before: "create table t (id int primary key)",
- after: "create table t2 (id2 int primary key, i int)",
- },
- {
- before: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
- after: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
- },
- {
- before: "create table t (id int primary key, i int, constraint f1 foreign key (i) references parent (id) on delete cascade)",
- after: "create table t (id int primary key, i int, constraint f2 foreign key (i) references parent (id) on delete cascade)",
- },
- {
- before: "create table t (id int primary key, i int, constraint f foreign key (i) references parent (id) on delete cascade)",
- after: "create table t (id int primary key, i int)",
- names: []string{"f"},
- },
- {
- before: "create table t (id int primary key, i int, i2 int, constraint f1 foreign key (i) references parent (id) on delete cascade, constraint fi2 foreign key (i2) references parent (id) on delete cascade)",
- after: "create table t (id int primary key, i int, i2 int, constraint f2 foreign key (i) references parent (id) on delete cascade)",
- names: []string{"fi2"},
- },
- {
- before: "create table t1 (id int primary key, i int, constraint `check1` CHECK ((`i` < 5)))",
- after: "create table t2 (id int primary key, i int)",
- },
- }
- for _, tcase := range tcases {
- t.Run(tcase.before, func(t *testing.T) {
- env := vtenv.NewTestEnv()
- beforeStmt, err := env.Parser().ParseStrictDDL(tcase.before)
- require.NoError(t, err)
- beforeCreateTable, ok := beforeStmt.(*sqlparser.CreateTable)
- require.True(t, ok)
- require.NotNil(t, beforeCreateTable)
-
- afterStmt, err := env.Parser().ParseStrictDDL(tcase.after)
- require.NoError(t, err)
- afterCreateTable, ok := afterStmt.(*sqlparser.CreateTable)
- require.True(t, ok)
- require.NotNil(t, afterCreateTable)
-
- names, err := RemovedForeignKeyNames(env, beforeCreateTable, afterCreateTable)
- assert.NoError(t, err)
- assert.Equal(t, tcase.names, names)
- })
- }
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/parser.go b/go/vt/vttablet/onlineddl/vrepl/parser.go
deleted file mode 100644
index f76f8735016..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/parser.go
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "strings"
-
- "vitess.io/vitess/go/vt/sqlparser"
-)
-
-// AlterTableParser is a parser tool for ALTER TABLE statements
-// This is imported from gh-ost. In the future, we should replace that with Vitess parsing.
-type AlterTableParser struct {
- columnRenameMap map[string]string
- droppedColumns map[string]bool
- isRenameTable bool
- isAutoIncrementDefined bool
-}
-
-// NewAlterTableParser creates a new parser
-func NewAlterTableParser() *AlterTableParser {
- return &AlterTableParser{
- columnRenameMap: make(map[string]string),
- droppedColumns: make(map[string]bool),
- }
-}
-
-// NewParserFromAlterStatement creates a new parser with a ALTER TABLE statement
-func NewParserFromAlterStatement(alterTable *sqlparser.AlterTable) *AlterTableParser {
- parser := NewAlterTableParser()
- parser.AnalyzeAlter(alterTable)
- return parser
-}
-
-// AnalyzeAlter looks for specific changes in the AlterTable statement, that are relevant
-// to OnlineDDL/VReplication
-func (p *AlterTableParser) AnalyzeAlter(alterTable *sqlparser.AlterTable) {
- for _, opt := range alterTable.AlterOptions {
- switch opt := opt.(type) {
- case *sqlparser.RenameTableName:
- p.isRenameTable = true
- case *sqlparser.DropColumn:
- p.droppedColumns[opt.Name.Name.String()] = true
- case *sqlparser.ChangeColumn:
- if opt.OldColumn != nil && opt.NewColDefinition != nil {
- oldName := opt.OldColumn.Name.String()
- newName := opt.NewColDefinition.Name.String()
- p.columnRenameMap[oldName] = newName
- }
- case sqlparser.TableOptions:
- for _, tableOption := range opt {
- if strings.ToUpper(tableOption.Name) == "AUTO_INCREMENT" {
- p.isAutoIncrementDefined = true
- }
- }
- }
- }
-}
-
-// GetNonTrivialRenames gets a list of renamed column
-func (p *AlterTableParser) GetNonTrivialRenames() map[string]string {
- result := make(map[string]string)
- for column, renamed := range p.columnRenameMap {
- if column != renamed {
- result[column] = renamed
- }
- }
- return result
-}
-
-// HasNonTrivialRenames is true when columns have been renamed
-func (p *AlterTableParser) HasNonTrivialRenames() bool {
- return len(p.GetNonTrivialRenames()) > 0
-}
-
-// DroppedColumnsMap returns list of dropped columns
-func (p *AlterTableParser) DroppedColumnsMap() map[string]bool {
- return p.droppedColumns
-}
-
-// IsRenameTable returns true when the ALTER TABLE statement includes renaming the table
-func (p *AlterTableParser) IsRenameTable() bool {
- return p.isRenameTable
-}
-
-// IsAutoIncrementDefined returns true when alter options include an explicit AUTO_INCREMENT value
-func (p *AlterTableParser) IsAutoIncrementDefined() bool {
- return p.isAutoIncrementDefined
-}
-
-// ColumnRenameMap returns the renamed column mapping
-func (p *AlterTableParser) ColumnRenameMap() map[string]string {
- return p.columnRenameMap
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/parser_test.go b/go/vt/vttablet/onlineddl/vrepl/parser_test.go
deleted file mode 100644
index 93e2ef25a15..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/parser_test.go
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "vitess.io/vitess/go/vt/sqlparser"
-)
-
-func alterTableStatement(t *testing.T, sql string) *sqlparser.AlterTable {
- stmt, err := sqlparser.NewTestParser().ParseStrictDDL(sql)
- require.NoError(t, err)
- alter, ok := stmt.(*sqlparser.AlterTable)
- require.True(t, ok)
- return alter
-}
-
-func TestParseAlterStatement(t *testing.T) {
- statement := "alter table t add column t int, engine=innodb"
- alterStatement := alterTableStatement(t, statement)
- parser := NewAlterTableParser()
- parser.AnalyzeAlter(alterStatement)
- assert.False(t, parser.HasNonTrivialRenames())
- assert.False(t, parser.IsAutoIncrementDefined())
-}
-
-func TestParseAlterStatementTrivialRename(t *testing.T) {
- statement := "alter table t add column t int, change ts ts timestamp, engine=innodb"
- alterStatement := alterTableStatement(t, statement)
- parser := NewAlterTableParser()
- parser.AnalyzeAlter(alterStatement)
- assert.False(t, parser.HasNonTrivialRenames())
- assert.False(t, parser.IsAutoIncrementDefined())
- assert.Equal(t, len(parser.columnRenameMap), 1)
- assert.Equal(t, parser.columnRenameMap["ts"], "ts")
-}
-
-func TestParseAlterStatementWithAutoIncrement(t *testing.T) {
-
- statements := []string{
- "auto_increment=7",
- "auto_increment = 7",
- "AUTO_INCREMENT = 71",
- "AUTO_INCREMENT 23",
- "AUTO_INCREMENT 23",
- "add column t int, change ts ts timestamp, auto_increment=7 engine=innodb",
- "add column t int, change ts ts timestamp, auto_increment =7 engine=innodb",
- "add column t int, change ts ts timestamp, AUTO_INCREMENT = 7 engine=innodb",
- "add column t int, change ts ts timestamp, engine=innodb auto_increment=73425",
- "add column t int, change ts ts timestamp, engine=innodb, auto_increment=73425",
- "add column t int, change ts ts timestamp, engine=innodb, auto_increment 73425",
- "add column t int, change ts ts timestamp, engine innodb, auto_increment 73425",
- "add column t int, change ts ts timestamp, engine innodb auto_increment 73425",
- }
- for _, statement := range statements {
- parser := NewAlterTableParser()
- statement := "alter table t " + statement
- alterStatement := alterTableStatement(t, statement)
- parser.AnalyzeAlter(alterStatement)
- assert.True(t, parser.IsAutoIncrementDefined())
- }
-}
-
-func TestParseAlterStatementTrivialRenames(t *testing.T) {
- statement := "alter table t add column t int, change ts ts timestamp, CHANGE f `f` float, engine=innodb"
- alterStatement := alterTableStatement(t, statement)
- parser := NewAlterTableParser()
- parser.AnalyzeAlter(alterStatement)
- assert.False(t, parser.HasNonTrivialRenames())
- assert.False(t, parser.IsAutoIncrementDefined())
- assert.Equal(t, len(parser.columnRenameMap), 2)
- assert.Equal(t, parser.columnRenameMap["ts"], "ts")
- assert.Equal(t, parser.columnRenameMap["f"], "f")
-}
-
-func TestParseAlterStatementNonTrivial(t *testing.T) {
- statements := []string{
- `add column b bigint, change f fl float, change i count int, engine=innodb`,
- "add column b bigint, change column `f` fl float, change `i` `count` int, engine=innodb",
- "add column b bigint, change column `f` fl float, change `i` `count` int, change ts ts timestamp, engine=innodb",
- `change
- f fl float,
- CHANGE COLUMN i
- count int, engine=innodb`,
- }
-
- for _, statement := range statements {
- statement := "alter table t " + statement
- alterStatement := alterTableStatement(t, statement)
- parser := NewAlterTableParser()
- parser.AnalyzeAlter(alterStatement)
- assert.False(t, parser.IsAutoIncrementDefined())
- renames := parser.GetNonTrivialRenames()
- assert.Equal(t, len(renames), 2)
- assert.Equal(t, renames["i"], "count")
- assert.Equal(t, renames["f"], "fl")
- }
-}
-
-func TestParseAlterStatementDroppedColumns(t *testing.T) {
-
- {
- parser := NewAlterTableParser()
- statement := "alter table t drop column b"
- alterStatement := alterTableStatement(t, statement)
- parser.AnalyzeAlter(alterStatement)
- assert.Equal(t, len(parser.droppedColumns), 1)
- assert.True(t, parser.droppedColumns["b"])
- }
- {
- parser := NewAlterTableParser()
- statement := "alter table t drop column b, drop key c_idx, drop column `d`"
- alterStatement := alterTableStatement(t, statement)
- parser.AnalyzeAlter(alterStatement)
- assert.Equal(t, len(parser.droppedColumns), 2)
- assert.True(t, parser.droppedColumns["b"])
- assert.True(t, parser.droppedColumns["d"])
- }
- {
- parser := NewAlterTableParser()
- statement := "alter table t drop column b, drop key c_idx, drop column `d`, drop `e`, drop primary key, drop foreign key fk_1"
- alterStatement := alterTableStatement(t, statement)
- parser.AnalyzeAlter(alterStatement)
- assert.Equal(t, len(parser.droppedColumns), 3)
- assert.True(t, parser.droppedColumns["b"])
- assert.True(t, parser.droppedColumns["d"])
- assert.True(t, parser.droppedColumns["e"])
- }
-}
-
-func TestParseAlterStatementRenameTable(t *testing.T) {
- tt := []struct {
- alter string
- isRename bool
- }{
- {
- alter: "alter table t drop column b",
- },
- {
- alter: "alter table t rename as something_else",
- isRename: true,
- },
- {
- alter: "alter table t rename to something_else",
- isRename: true,
- },
- {
- alter: "alter table t drop column b, rename as something_else",
- isRename: true,
- },
- {
- alter: "alter table t engine=innodb, rename as something_else",
- isRename: true,
- },
- {
- alter: "alter table t rename as something_else, engine=innodb",
- isRename: true,
- },
- }
- for _, tc := range tt {
- t.Run(tc.alter, func(t *testing.T) {
- parser := NewAlterTableParser()
- alterStatement := alterTableStatement(t, tc.alter)
- parser.AnalyzeAlter(alterStatement)
- assert.Equal(t, tc.isRename, parser.isRenameTable)
- })
- }
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/types.go b/go/vt/vttablet/onlineddl/vrepl/types.go
deleted file mode 100644
index 0ca834ffdf0..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/types.go
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- Original copyright by GitHub as follows. Additions by the Vitess authors as follows.
-*/
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "fmt"
- "reflect"
- "strings"
-
- "vitess.io/vitess/go/vt/schemadiff"
-)
-
-// ColumnType indicated some MySQL data types
-type ColumnType int
-
-const (
- UnknownColumnType ColumnType = iota
- TimestampColumnType
- DateTimeColumnType
- EnumColumnType
- SetColumnType
- MediumIntColumnType
- JSONColumnType
- FloatColumnType
- DoubleColumnType
- BinaryColumnType
- StringColumnType
- IntegerColumnType
-)
-
-// Column represents a table column
-type Column struct {
- Name string
- IsUnsigned bool
- Charset string
- Collation string
- Type ColumnType
- EnumValues string
- EnumToTextConversion bool
- DataType string // from COLUMN_TYPE column
-
- IsNullable bool
- IsDefaultNull bool
-
- CharacterMaximumLength int64
- NumericPrecision int64
- NumericScale int64
- DateTimePrecision int64
-
- // add Octet length for binary type, fix bytes with suffix "00" get clipped in mysql binlog.
- // https://github.com/github/gh-ost/issues/909
- BinaryOctetLength uint64
-}
-
-// SetTypeIfUnknown will set a new column type only if the current type is unknown, otherwise silently skip
-func (c *Column) SetTypeIfUnknown(t ColumnType) {
- if c.Type == UnknownColumnType {
- c.Type = t
- }
-}
-
-// HasDefault returns true if the column at all has a default value (possibly NULL)
-func (c *Column) HasDefault() bool {
- if c.IsDefaultNull && !c.IsNullable {
- // based on INFORMATION_SCHEMA.COLUMNS, this is the indicator for a 'NOT NULL' column with no default value.
- return false
- }
- return true
-}
-
-// IsNumeric returns true if the column is of a numeric type
-func (c *Column) IsNumeric() bool {
- return c.NumericPrecision > 0
-}
-
-// IsIntegralType returns true if the column is some form of an integer
-func (c *Column) IsIntegralType() bool {
- return schemadiff.IsIntegralType(c.DataType)
-}
-
-// IsFloatingPoint returns true if the column is of a floating point numeric type
-func (c *Column) IsFloatingPoint() bool {
- return c.Type == FloatColumnType || c.Type == DoubleColumnType
-}
-
-// IsFloatingPoint returns true if the column is of a temporal type
-func (c *Column) IsTemporal() bool {
- return c.DateTimePrecision >= 0
-}
-
-// NewColumns creates a new column array from non empty names
-func NewColumns(names []string) []Column {
- result := []Column{}
- for _, name := range names {
- if name == "" {
- continue
- }
- result = append(result, Column{Name: name})
- }
- return result
-}
-
-// ParseColumns creates a new column array fby parsing comma delimited names list
-func ParseColumns(names string) []Column {
- namesArray := strings.Split(names, ",")
- return NewColumns(namesArray)
-}
-
-// ColumnsMap maps a column name onto its ordinal position
-type ColumnsMap map[string]int
-
-// NewEmptyColumnsMap creates an empty map
-func NewEmptyColumnsMap() ColumnsMap {
- columnsMap := make(map[string]int)
- return ColumnsMap(columnsMap)
-}
-
-// NewColumnsMap creates a column map based on ordered list of columns
-func NewColumnsMap(orderedColumns []Column) ColumnsMap {
- columnsMap := NewEmptyColumnsMap()
- for i, column := range orderedColumns {
- columnsMap[column.Name] = i
- }
- return columnsMap
-}
-
-// ColumnList makes for a named list of columns
-type ColumnList struct {
- columns []Column
- Ordinals ColumnsMap
-}
-
-// NewColumnList creates an object given ordered list of column names
-func NewColumnList(names []string) *ColumnList {
- result := &ColumnList{
- columns: NewColumns(names),
- }
- result.Ordinals = NewColumnsMap(result.columns)
- return result
-}
-
-// ParseColumnList parses a comma delimited list of column names
-func ParseColumnList(names string) *ColumnList {
- result := &ColumnList{
- columns: ParseColumns(names),
- }
- result.Ordinals = NewColumnsMap(result.columns)
- return result
-}
-
-// Columns returns the list of columns
-func (l *ColumnList) Columns() []Column {
- return l.columns
-}
-
-// Names returns list of column names
-func (l *ColumnList) Names() []string {
- names := make([]string, len(l.columns))
- for i := range l.columns {
- names[i] = l.columns[i].Name
- }
- return names
-}
-
-// GetColumn gets a column by name
-func (l *ColumnList) GetColumn(columnName string) *Column {
- if ordinal, ok := l.Ordinals[columnName]; ok {
- return &l.columns[ordinal]
- }
- return nil
-}
-
-// ColumnExists returns true if this column list has a column by a given name
-func (l *ColumnList) ColumnExists(columnName string) bool {
- _, ok := l.Ordinals[columnName]
- return ok
-}
-
-// String returns a comma separated list of column names
-func (l *ColumnList) String() string {
- return strings.Join(l.Names(), ",")
-}
-
-// Equals checks for complete (deep) identities of columns, in order.
-func (l *ColumnList) Equals(other *ColumnList) bool {
- return reflect.DeepEqual(l.Columns, other.Columns)
-}
-
-// EqualsByNames checks if the names in this list equals the names of another list, in order. Type is ignored.
-func (l *ColumnList) EqualsByNames(other *ColumnList) bool {
- return reflect.DeepEqual(l.Names(), other.Names())
-}
-
-// IsSubsetOf returns 'true' when column names of this list are a subset of
-// another list, in arbitrary order (order agnostic)
-func (l *ColumnList) IsSubsetOf(other *ColumnList) bool {
- for _, column := range l.columns {
- if _, exists := other.Ordinals[column.Name]; !exists {
- return false
- }
- }
- return true
-}
-
-// Difference returns a (new copy) subset of this column list, consisting of all
-// column NOT in given list.
-// The result is never nil, even if the difference is empty
-func (l *ColumnList) Difference(other *ColumnList) (diff *ColumnList) {
- names := []string{}
- for _, column := range l.columns {
- if !other.ColumnExists(column.Name) {
- names = append(names, column.Name)
- }
- }
- return NewColumnList(names)
-}
-
-// Len returns the length of this list
-func (l *ColumnList) Len() int {
- return len(l.columns)
-}
-
-// MappedNamesColumnList returns a column list based on this list, with names possibly mapped by given map
-func (l *ColumnList) MappedNamesColumnList(columnNamesMap map[string]string) *ColumnList {
- names := l.Names()
- for i := range names {
- if mappedName, ok := columnNamesMap[names[i]]; ok {
- names[i] = mappedName
- }
- }
- return NewColumnList(names)
-}
-
-// SetEnumToTextConversion tells this column list that an enum is converted to text
-func (l *ColumnList) SetEnumToTextConversion(columnName string, enumValues string) {
- l.GetColumn(columnName).EnumToTextConversion = true
- l.GetColumn(columnName).EnumValues = enumValues
-}
-
-// IsEnumToTextConversion tells whether an enum was converted to text
-func (l *ColumnList) IsEnumToTextConversion(columnName string) bool {
- return l.GetColumn(columnName).EnumToTextConversion
-}
-
-// UniqueKey is the combination of a key's name and columns
-type UniqueKey struct {
- Name string
- Columns ColumnList
- HasNullable bool
- HasSubpart bool
- HasFloat bool
- IsAutoIncrement bool
-}
-
-// IsPrimary checks if this unique key is primary
-func (k *UniqueKey) IsPrimary() bool {
- return k.Name == "PRIMARY"
-}
-
-// Len returns the length of this list
-func (k *UniqueKey) Len() int {
- return k.Columns.Len()
-}
-
-// String returns a visual representation of this key
-func (k *UniqueKey) String() string {
- description := k.Name
- if k.IsAutoIncrement {
- description = fmt.Sprintf("%s (auto_increment)", description)
- }
- return fmt.Sprintf("%s: %s; has nullable: %+v", description, k.Columns.Names(), k.HasNullable)
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/types_test.go b/go/vt/vttablet/onlineddl/vrepl/types_test.go
deleted file mode 100644
index d146d286d3a..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/types_test.go
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "fmt"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestParseColumnList(t *testing.T) {
- names := "id,category,max_len"
-
- columnList := ParseColumnList(names)
- assert.Equal(t, columnList.Len(), 3)
- assert.Equal(t, columnList.Names(), []string{"id", "category", "max_len"})
- assert.Equal(t, columnList.Ordinals["id"], 0)
- assert.Equal(t, columnList.Ordinals["category"], 1)
- assert.Equal(t, columnList.Ordinals["max_len"], 2)
-}
-
-func TestGetColumn(t *testing.T) {
- names := "id,category,max_len"
- columnList := ParseColumnList(names)
- {
- column := columnList.GetColumn("category")
- assert.NotNil(t, column)
- assert.Equal(t, column.Name, "category")
- }
- {
- column := columnList.GetColumn("no_such_column")
- assert.True(t, column == nil)
- }
-}
-
-func TestIsSubsetOf(t *testing.T) {
- tt := []struct {
- columns1 *ColumnList
- columns2 *ColumnList
- expectSubset bool
- }{
- {
- columns1: ParseColumnList(""),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList("a,c"),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList("b,c"),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList("b"),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList(""),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: true,
- },
- {
- columns1: ParseColumnList("a,d"),
- columns2: ParseColumnList("a,b,c"),
- expectSubset: false,
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList("a,b"),
- expectSubset: false,
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList(""),
- expectSubset: false,
- },
- }
- for _, tc := range tt {
- name := fmt.Sprintf("%v:%v", tc.columns1.Names(), tc.columns2.Names())
- t.Run(name, func(t *testing.T) {
- isSubset := tc.columns1.IsSubsetOf(tc.columns2)
- assert.Equal(t, tc.expectSubset, isSubset)
- },
- )
- }
-}
-
-func TestDifference(t *testing.T) {
- tt := []struct {
- columns1 *ColumnList
- columns2 *ColumnList
- expect *ColumnList
- }{
- {
- columns1: ParseColumnList(""),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList("a,c"),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList("b,c"),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList("b"),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList(""),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList(""),
- },
- {
- columns1: ParseColumnList("a,d"),
- columns2: ParseColumnList("a,b,c"),
- expect: ParseColumnList("d"),
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList("a,b"),
- expect: ParseColumnList("c"),
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList(""),
- expect: ParseColumnList("a,b,c"),
- },
- {
- columns1: ParseColumnList("a,b,c"),
- columns2: ParseColumnList("b,d,e"),
- expect: ParseColumnList("a,c"),
- },
- }
- for _, tc := range tt {
- name := fmt.Sprintf("%v:%v", tc.columns1.Names(), tc.columns2.Names())
- t.Run(name, func(t *testing.T) {
- diff := tc.columns1.Difference(tc.columns2)
- assert.Equal(t, tc.expect, diff)
- },
- )
- }
-}
-
-func TestMappedNamesColumnList(t *testing.T) {
- tt := []struct {
- columns *ColumnList
- namesMap map[string]string
- expected *ColumnList
- }{
- {
- columns: ParseColumnList("a,b,c"),
- namesMap: map[string]string{},
- expected: ParseColumnList("a,b,c"),
- },
- {
- columns: ParseColumnList("a,b,c"),
- namesMap: map[string]string{"x": "y"},
- expected: ParseColumnList("a,b,c"),
- },
- {
- columns: ParseColumnList("a,b,c"),
- namesMap: map[string]string{"a": "x", "c": "y"},
- expected: ParseColumnList("x,b,y"),
- },
- }
- for _, tc := range tt {
- name := fmt.Sprintf("%v:%v", tc.columns.Names(), tc.namesMap)
- t.Run(name, func(t *testing.T) {
- mappedNames := tc.columns.MappedNamesColumnList(tc.namesMap)
- assert.Equal(t, tc.expected, mappedNames)
- },
- )
- }
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/unique_key.go b/go/vt/vttablet/onlineddl/vrepl/unique_key.go
deleted file mode 100644
index cc649b4ea37..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/unique_key.go
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "strings"
-)
-
-// UniqueKeyValidForIteration returns 'false' if we should not use this unique key as the main
-// iteration key in vreplication.
-func UniqueKeyValidForIteration(uniqueKey *UniqueKey) bool {
- if uniqueKey.HasNullable {
- // NULLable columns in a unique key means the set of values is not really unique (two identical rows with NULLs are allowed).
- // Thus, we cannot use this unique key for iteration.
- return false
- }
- if uniqueKey.HasSubpart {
- // vreplication does not fully support indexes on column prefixes such as:
- // UNIQUE KEY `name_idx` (`name`(15))
- // "HasSubpart" means some column covered by the index has a key length spec.
- return false
- }
- if uniqueKey.HasFloat {
- // float & double data types are imprecise and we cannot use them while iterating unique keys
- return false
- }
- return true // good to go!
-}
-
-// GetSharedUniqueKeys returns the unique keys shared between the source & target tables
-func GetSharedUniqueKeys(sourceUniqueKeys, targetUniqueKeys [](*UniqueKey), columnRenameMap map[string]string) (chosenSourceUniqueKey, chosenTargetUniqueKey *UniqueKey) {
- type ukPair struct{ source, target *UniqueKey }
- var sharedUKPairs []*ukPair
-
- for _, sourceUniqueKey := range sourceUniqueKeys {
- if !UniqueKeyValidForIteration(sourceUniqueKey) {
- continue
- }
- for _, targetUniqueKey := range targetUniqueKeys {
- if !UniqueKeyValidForIteration(targetUniqueKey) {
- continue
- }
- uniqueKeyMatches := func() bool {
- // Compare two unique keys
- if sourceUniqueKey.Columns.Len() != targetUniqueKey.Columns.Len() {
- return false
- }
- // Expect same columns, same order, potentially column name mapping
- sourceUniqueKeyNames := sourceUniqueKey.Columns.Names()
- targetUniqueKeyNames := targetUniqueKey.Columns.Names()
- for i := range sourceUniqueKeyNames {
- sourceColumnName := sourceUniqueKeyNames[i]
- targetColumnName := targetUniqueKeyNames[i]
- mappedSourceColumnName := sourceColumnName
- if mapped, ok := columnRenameMap[sourceColumnName]; ok {
- mappedSourceColumnName = mapped
- }
- if !strings.EqualFold(mappedSourceColumnName, targetColumnName) {
- return false
- }
- }
- return true
- }
- if uniqueKeyMatches() {
- sharedUKPairs = append(sharedUKPairs, &ukPair{source: sourceUniqueKey, target: targetUniqueKey})
- }
- }
- }
- // Now that we know what the shared unique keys are, let's find the "best" shared one.
- // Source and target unique keys can have different name, even though they cover the exact same
- // columns and in same order.
- for _, pair := range sharedUKPairs {
- if pair.source.HasNullable {
- continue
- }
- if pair.target.HasNullable {
- continue
- }
- return pair.source, pair.target
- }
- return nil, nil
-}
-
-// SourceUniqueKeyAsOrMoreConstrainedThanTarget returns 'true' when sourceUniqueKey is at least as constrained as targetUniqueKey.
-// "More constrained" means the uniqueness constraint is "stronger". Thus, if sourceUniqueKey is as-or-more constrained than targetUniqueKey, then
-// rows valid under sourceUniqueKey must also be valid in targetUniqueKey. The opposite is not necessarily so: rows that are valid in targetUniqueKey
-// may cause a unique key violation under sourceUniqueKey
-func SourceUniqueKeyAsOrMoreConstrainedThanTarget(sourceUniqueKey, targetUniqueKey *UniqueKey, columnRenameMap map[string]string) bool {
- // Compare two unique keys
- if sourceUniqueKey.Columns.Len() > targetUniqueKey.Columns.Len() {
- // source can't be more constrained if it covers *more* columns
- return false
- }
- // we know that len(sourceUniqueKeyNames) <= len(targetUniqueKeyNames)
- sourceUniqueKeyNames := sourceUniqueKey.Columns.Names()
- targetUniqueKeyNames := targetUniqueKey.Columns.Names()
- // source is more constrained than target if every column in source is also in target, order is immaterial
- for i := range sourceUniqueKeyNames {
- sourceColumnName := sourceUniqueKeyNames[i]
- mappedSourceColumnName := sourceColumnName
- if mapped, ok := columnRenameMap[sourceColumnName]; ok {
- mappedSourceColumnName = mapped
- }
- columnFoundInTarget := func() bool {
- for _, targetColumnName := range targetUniqueKeyNames {
- if strings.EqualFold(mappedSourceColumnName, targetColumnName) {
- return true
- }
- }
- return false
- }
- if !columnFoundInTarget() {
- return false
- }
- }
- return true
-}
-
-// AddedUniqueKeys returns the unique key constraints added in target. This does not necessarily mean that the unique key itself is new,
-// rather that there's a new, stricter constraint on a set of columns, that didn't exist before. Example:
-//
-// before: unique key `my_key`(c1, c2, c3); after: unique key `my_key`(c1, c2)
-// The constraint on (c1, c2) is new; and `my_key` in target table ("after") is considered a new key
-//
-// Order of columns is immaterial to uniqueness of column combination.
-func AddedUniqueKeys(sourceUniqueKeys, targetUniqueKeys [](*UniqueKey), columnRenameMap map[string]string) (addedUKs [](*UniqueKey)) {
- addedUKs = [](*UniqueKey){}
- for _, targetUniqueKey := range targetUniqueKeys {
- foundAsOrMoreConstrainingSourceKey := func() bool {
- for _, sourceUniqueKey := range sourceUniqueKeys {
- if SourceUniqueKeyAsOrMoreConstrainedThanTarget(sourceUniqueKey, targetUniqueKey, columnRenameMap) {
- // target key does not add a new constraint
- return true
- }
- }
- return false
- }
- if !foundAsOrMoreConstrainingSourceKey() {
- addedUKs = append(addedUKs, targetUniqueKey)
- }
- }
- return addedUKs
-}
-
-// RemovedUniqueKeys returns the list of unique key constraints _removed_ going from source to target.
-func RemovedUniqueKeys(sourceUniqueKeys, targetUniqueKeys [](*UniqueKey), columnRenameMap map[string]string) (removedUKs [](*UniqueKey)) {
- reverseColumnRenameMap := map[string]string{}
- for k, v := range columnRenameMap {
- reverseColumnRenameMap[v] = k
- }
- return AddedUniqueKeys(targetUniqueKeys, sourceUniqueKeys, reverseColumnRenameMap)
-}
-
-// GetUniqueKeyCoveredByColumns returns the first unique key from given list, whose columns all appear
-// in given column list.
-func GetUniqueKeyCoveredByColumns(uniqueKeys [](*UniqueKey), columns *ColumnList) (chosenUniqueKey *UniqueKey) {
- for _, uniqueKey := range uniqueKeys {
- if !UniqueKeyValidForIteration(uniqueKey) {
- continue
- }
- if uniqueKey.Columns.IsSubsetOf(columns) {
- return uniqueKey
- }
- }
- return nil
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl/unique_key_test.go b/go/vt/vttablet/onlineddl/vrepl/unique_key_test.go
deleted file mode 100644
index 3364c55a308..00000000000
--- a/go/vt/vttablet/onlineddl/vrepl/unique_key_test.go
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
-*/
-/*
-Copyright 2021 The Vitess Authors.
-
-Licensed 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 vrepl
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-var (
- columns1 = ParseColumnList("c1")
- columns12 = ParseColumnList("c1,c2")
- columns123 = ParseColumnList("c1,c2,c3")
- columns2 = ParseColumnList("c2")
- columns21 = ParseColumnList("c2,c1")
- columns12A = ParseColumnList("c1,c2,ca")
-)
-
-func TestGetSharedUniqueKeys(t *testing.T) {
- tt := []struct {
- name string
- sourceUKs, targetUKs [](*UniqueKey)
- renameMap map[string]string
- expectSourceUK, expectTargetUK *UniqueKey
- }{
- {
- name: "empty",
- sourceUKs: []*UniqueKey{},
- targetUKs: []*UniqueKey{},
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "half empty",
- sourceUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{},
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "single identical",
- sourceUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "PRIMARY", Columns: *columns1},
- expectTargetUK: &UniqueKey{Name: "PRIMARY", Columns: *columns1},
- },
- {
- name: "single identical non pk",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx", Columns: *columns1},
- expectTargetUK: &UniqueKey{Name: "uidx", Columns: *columns1},
- },
- {
- name: "single identical, source is nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1, HasNullable: true},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "single identical, target is nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1, HasNullable: true},
- },
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "single no shared",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "single no shared different order",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns21},
- },
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "single identical, source has FLOAT",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1, HasFloat: true},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "exact match",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- expectTargetUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- },
- {
- name: "exact match from multiple options",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- expectTargetUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- },
- {
- name: "exact match from multiple options reorder",
- sourceUKs: []*UniqueKey{
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx12", Columns: *columns12},
- expectTargetUK: &UniqueKey{Name: "uidx12", Columns: *columns12},
- },
- {
- name: "match different names",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidxother", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx12", Columns: *columns12},
- expectTargetUK: &UniqueKey{Name: "uidxother", Columns: *columns12},
- },
- {
- name: "match different names, nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123other", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12, HasNullable: true},
- },
- renameMap: map[string]string{},
- expectSourceUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- expectTargetUK: &UniqueKey{Name: "uidx123other", Columns: *columns123},
- },
- {
- name: "match different column names",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "ca"},
- expectSourceUK: &UniqueKey{Name: "uidx123", Columns: *columns123},
- expectTargetUK: &UniqueKey{Name: "uidx12A", Columns: *columns12A},
- },
- {
- // enforce mapping from c3 to ca; will not match c3<->c3
- name: "no match identical column names",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{"c3": "ca"},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- {
- name: "no match different column names",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "cx"},
- expectSourceUK: nil,
- expectTargetUK: nil,
- },
- }
-
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- sourceUK, targetUK := GetSharedUniqueKeys(tc.sourceUKs, tc.targetUKs, tc.renameMap)
- assert.Equal(t, tc.expectSourceUK, sourceUK)
- assert.Equal(t, tc.expectTargetUK, targetUK)
- })
- }
-}
-
-func TestAddedUniqueKeys(t *testing.T) {
- emptyUniqueKeys := []*UniqueKey{}
- tt := []struct {
- name string
- sourceUKs, targetUKs [](*UniqueKey)
- renameMap map[string]string
- expectAddedUKs [](*UniqueKey)
- expectRemovedUKs [](*UniqueKey)
- }{
- {
- name: "empty",
- sourceUKs: emptyUniqueKeys,
- targetUKs: emptyUniqueKeys,
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "UK removed",
- sourceUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- targetUKs: emptyUniqueKeys,
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- },
- {
- name: "NULLable UK removed",
- sourceUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1, HasNullable: true},
- },
- targetUKs: emptyUniqueKeys,
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1, HasNullable: true},
- },
- },
- {
- name: "UK added",
- sourceUKs: emptyUniqueKeys,
- targetUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "single identical",
- sourceUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "PRIMARY", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "single identical non pk",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "single identical, source is nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1, HasNullable: true},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "single identical, target is nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1, HasNullable: true},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "expand columns: not considered added",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- },
- {
- name: "expand columns, different order: not considered added",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns21},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- },
- {
- name: "reduced columns: considered added",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "reduced columns, multiple: considered added",
- sourceUKs: []*UniqueKey{
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidx2", Columns: *columns2},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- renameMap: map[string]string{},
- expectAddedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx2", Columns: *columns2},
- },
- },
- {
- name: "different order: not considered added",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns21},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "no match, different columns",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx2", Columns: *columns2},
- },
- renameMap: map[string]string{},
- expectAddedUKs: []*UniqueKey{
- {Name: "uidx2", Columns: *columns2},
- },
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- name: "one match, one expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- },
- {
- name: "exact match from multiple options",
- sourceUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- },
- {
- name: "exact match from multiple options reorder",
- sourceUKs: []*UniqueKey{
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx", Columns: *columns1},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx", Columns: *columns1},
- },
- },
- {
- name: "match different names",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- {Name: "uidxother", Columns: *columns12},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- name: "match different names, nullable",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123other", Columns: *columns123},
- {Name: "uidx12", Columns: *columns12, HasNullable: true},
- },
- renameMap: map[string]string{},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- name: "match different column names, expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "ca"},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- name: "match different column names, no expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "ca"},
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- // enforce mapping from c3 to ca; will not match c3<->c3
- name: "no match identical column names, expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{"c3": "ca"},
- // 123 expands 12, so even though 3 is mapped to A, 123 is still not more constrained.
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- // enforce mapping from c3 to ca; will not match c3<->c3
- name: "no match identical column names, no expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- renameMap: map[string]string{"c3": "ca"},
- expectAddedUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- expectRemovedUKs: emptyUniqueKeys,
- },
- {
- name: "no match for different column names, expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- {Name: "uidx12", Columns: *columns12},
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx21", Columns: *columns21},
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "cx"},
- // 123 expands 12, so even though 3 is mapped to x, 123 is still not more constrained.
- expectAddedUKs: emptyUniqueKeys,
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx1", Columns: *columns1},
- },
- },
- {
- name: "no match for different column names, no expand",
- sourceUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- targetUKs: []*UniqueKey{
- {Name: "uidx12A", Columns: *columns12A},
- },
- renameMap: map[string]string{"c3": "cx"},
- expectAddedUKs: []*UniqueKey{
- {Name: "uidx12A", Columns: *columns12A},
- },
- expectRemovedUKs: []*UniqueKey{
- {Name: "uidx123", Columns: *columns123},
- },
- },
- }
-
- for _, tc := range tt {
- t.Run(tc.name, func(t *testing.T) {
- addedUKs := AddedUniqueKeys(tc.sourceUKs, tc.targetUKs, tc.renameMap)
- assert.Equal(t, tc.expectAddedUKs, addedUKs)
- removedUKs := RemovedUniqueKeys(tc.sourceUKs, tc.targetUKs, tc.renameMap)
- assert.Equal(t, tc.expectRemovedUKs, removedUKs)
- })
- }
-}
diff --git a/go/vt/vttablet/onlineddl/vrepl_test.go b/go/vt/vttablet/onlineddl/vrepl_test.go
index ddb723ed7b7..b9875c3f6d2 100644
--- a/go/vt/vttablet/onlineddl/vrepl_test.go
+++ b/go/vt/vttablet/onlineddl/vrepl_test.go
@@ -1,6 +1,238 @@
/*
- Copyright 2016 GitHub Inc.
- See https://github.com/github/gh-ost/blob/master/LICENSE
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 onlineddl
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "vitess.io/vitess/go/vt/schemadiff"
+ "vitess.io/vitess/go/vt/vtenv"
+)
+
+func TestRevertible(t *testing.T) {
+
+ type revertibleTestCase struct {
+ name string
+ fromSchema string
+ toSchema string
+ // expectProblems bool
+ removedForeignKeyNames string
+ removedUniqueKeyNames string
+ droppedNoDefaultColumnNames string
+ expandedColumnNames string
+ }
+
+ var testCases = []revertibleTestCase{
+ {
+ name: "identical schemas",
+ fromSchema: `id int primary key, i1 int not null default 0`,
+ toSchema: `id int primary key, i2 int not null default 0`,
+ },
+ {
+ name: "different schemas, nothing to note",
+ fromSchema: `id int primary key, i1 int not null default 0, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i1 int not null default 0, i2 int not null default 0, unique key i1_uidx(i1)`,
+ },
+ {
+ name: "removed non-nullable unique key",
+ fromSchema: `id int primary key, i1 int not null default 0, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i2 int not null default 0`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "removed nullable unique key",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i2 int default null`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "expanding unique key removes unique constraint",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ toSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1, id)`,
+ removedUniqueKeyNames: `i1_uidx`,
+ },
+ {
+ name: "expanding unique key prefix removes unique constraint",
+ fromSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(20))`,
+ toSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(21))`,
+ removedUniqueKeyNames: `v_uidx`,
+ },
+ {
+ name: "reducing unique key does not remove unique constraint",
+ fromSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1, id)`,
+ toSchema: `id int primary key, i1 int default null, unique key i1_uidx(i1)`,
+ removedUniqueKeyNames: ``,
+ },
+ {
+ name: "reducing unique key does not remove unique constraint",
+ fromSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(21))`,
+ toSchema: `id int primary key, v varchar(100) default null, unique key v_uidx(v(20))`,
+ },
+ {
+ name: "removed foreign key",
+ fromSchema: "id int primary key, i int, constraint some_fk_1 foreign key (i) references parent (id) on delete cascade",
+ toSchema: "id int primary key, i int",
+ removedForeignKeyNames: "some_fk_1",
+ },
+
+ {
+ name: "renamed foreign key",
+ fromSchema: "id int primary key, i int, constraint f1 foreign key (i) references parent (id) on delete cascade",
+ toSchema: "id int primary key, i int, constraint f2 foreign key (i) references parent (id) on delete cascade",
+ },
+ {
+ name: "remove column without default",
+ fromSchema: `id int primary key, i1 int not null, i2 int not null default 0, i3 int default null`,
+ toSchema: `id int primary key, i4 int not null default 0`,
+ droppedNoDefaultColumnNames: `i1`,
+ },
+ {
+ name: "expanded: nullable",
+ fromSchema: `id int primary key, i1 int not null, i2 int default null`,
+ toSchema: `id int primary key, i1 int default null, i2 int not null`,
+ expandedColumnNames: `i1`,
+ },
+ {
+ name: "expanded: longer text",
+ fromSchema: `id int primary key, i1 int default null, v1 varchar(40) not null, v2 varchar(5), v3 varchar(3)`,
+ toSchema: `id int primary key, i1 int not null, v1 varchar(100) not null, v2 char(3), v3 char(5)`,
+ expandedColumnNames: `v1,v3`,
+ },
+ {
+ name: "expanded: int numeric precision and scale",
+ fromSchema: `id int primary key, i1 int, i2 tinyint, i3 mediumint, i4 bigint`,
+ toSchema: `id int primary key, i1 int, i2 mediumint, i3 int, i4 tinyint`,
+ expandedColumnNames: `i2,i3`,
+ },
+ {
+ name: "expanded: floating point",
+ fromSchema: `id int primary key, i1 int, n2 bigint, n3 bigint, n4 float, n5 double`,
+ toSchema: `id int primary key, i1 int, n2 float, n3 double, n4 double, n5 float`,
+ expandedColumnNames: `n2,n3,n4`,
+ },
+ {
+ name: "expanded: decimal numeric precision and scale",
+ fromSchema: `id int primary key, i1 int, d1 decimal(10,2), d2 decimal (10,2), d3 decimal (10,2)`,
+ toSchema: `id int primary key, i1 int, d1 decimal(11,2), d2 decimal (9,1), d3 decimal (10,3)`,
+ expandedColumnNames: `d1,d3`,
+ },
+ {
+ name: "expanded: signed, unsigned",
+ fromSchema: `id int primary key, i1 bigint signed, i2 int unsigned, i3 bigint unsigned`,
+ toSchema: `id int primary key, i1 int signed, i2 int signed, i3 int signed`,
+ expandedColumnNames: `i2,i3`,
+ },
+ {
+ name: "expanded: signed, unsigned: range",
+ fromSchema: `id int primary key, i1 int signed, i2 bigint signed, i3 int signed`,
+ toSchema: `id int primary key, i1 int unsigned, i2 int unsigned, i3 bigint unsigned`,
+ expandedColumnNames: `i1,i3`,
+ },
+ {
+ name: "expanded: datetime precision",
+ fromSchema: `id int primary key, dt1 datetime, ts1 timestamp, ti1 time, dt2 datetime(3), dt3 datetime(6), ts2 timestamp(3)`,
+ toSchema: `id int primary key, dt1 datetime(3), ts1 timestamp(6), ti1 time(3), dt2 datetime(6), dt3 datetime(3), ts2 timestamp`,
+ expandedColumnNames: `dt1,ts1,ti1,dt2`,
+ },
+ {
+ name: "expanded: strange data type changes",
+ fromSchema: `id int primary key, dt1 datetime, ts1 timestamp, i1 int, d1 date, e1 enum('a', 'b')`,
+ toSchema: `id int primary key, dt1 char(32), ts1 varchar(32), i1 tinytext, d1 char(2), e1 varchar(2)`,
+ expandedColumnNames: `dt1,ts1,i1,d1,e1`,
+ },
+ {
+ name: "expanded: temporal types",
+ fromSchema: `id int primary key, t1 time, t2 timestamp, t3 date, t4 datetime, t5 time, t6 date`,
+ toSchema: `id int primary key, t1 datetime, t2 datetime, t3 timestamp, t4 timestamp, t5 timestamp, t6 datetime`,
+ expandedColumnNames: `t1,t2,t3,t5,t6`,
+ },
+ {
+ name: "expanded: character sets",
+ fromSchema: `id int primary key, c1 char(3) charset utf8, c2 char(3) charset utf8mb4, c3 char(3) charset ascii, c4 char(3) charset utf8mb4, c5 char(3) charset utf8, c6 char(3) charset latin1`,
+ toSchema: `id int primary key, c1 char(3) charset utf8mb4, c2 char(3) charset utf8, c3 char(3) charset utf8, c4 char(3) charset ascii, c5 char(3) charset utf8, c6 char(3) charset utf8mb4`,
+ expandedColumnNames: `c1,c3,c6`,
+ },
+ {
+ name: "expanded: enum",
+ fromSchema: `id int primary key, e1 enum('a', 'b'), e2 enum('a', 'b'), e3 enum('a', 'b'), e4 enum('a', 'b'), e5 enum('a', 'b'), e6 enum('a', 'b'), e7 enum('a', 'b'), e8 enum('a', 'b')`,
+ toSchema: `id int primary key, e1 enum('a', 'b'), e2 enum('a'), e3 enum('a', 'b', 'c'), e4 enum('a', 'x'), e5 enum('a', 'x', 'b'), e6 enum('b'), e7 varchar(1), e8 tinyint`,
+ expandedColumnNames: `e3,e4,e5,e6,e7,e8`,
+ },
+ {
+ name: "expanded: set",
+ fromSchema: `id int primary key, e1 set('a', 'b'), e2 set('a', 'b'), e3 set('a', 'b'), e4 set('a', 'b'), e5 set('a', 'b'), e6 set('a', 'b'), e7 set('a', 'b'), e8 set('a', 'b')`,
+ toSchema: `id int primary key, e1 set('a', 'b'), e2 set('a'), e3 set('a', 'b', 'c'), e4 set('a', 'x'), e5 set('a', 'x', 'b'), e6 set('b'), e7 varchar(1), e8 tinyint`,
+ expandedColumnNames: `e3,e4,e5,e6,e7,e8`,
+ },
+ }
+
+ var (
+ createTableWrapper = `CREATE TABLE t (%s)`
+ )
+
+ senv := schemadiff.NewTestEnv()
+ venv := vtenv.NewTestEnv()
+ diffHints := &schemadiff.DiffHints{}
+ for _, tcase := range testCases {
+ t.Run(tcase.name, func(t *testing.T) {
+ tcase.fromSchema = fmt.Sprintf(createTableWrapper, tcase.fromSchema)
+ sourceTableEntity, err := schemadiff.NewCreateTableEntityFromSQL(senv, tcase.fromSchema)
+ require.NoError(t, err)
+
+ tcase.toSchema = fmt.Sprintf(createTableWrapper, tcase.toSchema)
+ targetTableEntity, err := schemadiff.NewCreateTableEntityFromSQL(senv, tcase.toSchema)
+ require.NoError(t, err)
+
+ diff, err := sourceTableEntity.TableDiff(targetTableEntity, diffHints)
+ require.NoError(t, err)
+
+ v, err := NewVRepl(
+ venv,
+ "7cee19dd_354b_11eb_82cd_f875a4d24e90",
+ "ks",
+ "0",
+ "mydb",
+ sourceTableEntity.CreateTable,
+ targetTableEntity.CreateTable,
+ diff.AlterTable(),
+ false,
+ )
+ require.NoError(t, err)
+
+ err = v.analyzeAlter()
+ require.NoError(t, err)
+ err = v.analyzeTables()
+ require.NoError(t, err)
+
+ toStringSlice := func(s string) []string {
+ if s == "" {
+ return []string{}
+ }
+ return strings.Split(s, ",")
+ }
+ assert.Equal(t, toStringSlice(tcase.removedForeignKeyNames), v.analysis.RemovedForeignKeyNames)
+ assert.Equal(t, toStringSlice(tcase.removedUniqueKeyNames), v.analysis.RemovedUniqueKeys.Names())
+ assert.Equal(t, toStringSlice(tcase.droppedNoDefaultColumnNames), v.analysis.DroppedNoDefaultColumns.Names())
+ assert.Equal(t, toStringSlice(tcase.expandedColumnNames), v.analysis.ExpandedColumns.Names())
+ })
+ }
+}
diff --git a/go/vt/vttablet/tabletmanager/rpc_throttler.go b/go/vt/vttablet/tabletmanager/rpc_throttler.go
index 8ec3bb592da..ec75db6da43 100644
--- a/go/vt/vttablet/tabletmanager/rpc_throttler.go
+++ b/go/vt/vttablet/tabletmanager/rpc_throttler.go
@@ -53,31 +53,36 @@ func (tm *TabletManager) CheckThrottler(ctx context.Context, req *tabletmanagerd
return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "nil checkResult")
}
resp := &tabletmanagerdatapb.CheckThrottlerResponse{
+ ResponseCode: throttle.ResponseCodeFromStatus(checkResult.ResponseCode, checkResult.StatusCode),
StatusCode: int32(checkResult.StatusCode),
Value: checkResult.Value,
Threshold: checkResult.Threshold,
Message: checkResult.Message,
RecentlyChecked: checkResult.RecentlyChecked,
+ AppName: checkResult.AppName,
+ Summary: checkResult.Summary(),
Metrics: make(map[string]*tabletmanagerdatapb.CheckThrottlerResponse_Metric),
}
for name, metric := range checkResult.Metrics {
resp.Metrics[name] = &tabletmanagerdatapb.CheckThrottlerResponse_Metric{
- Name: name,
- Scope: metric.Scope,
- StatusCode: int32(metric.StatusCode),
- Value: metric.Value,
- Threshold: metric.Threshold,
- Message: metric.Message,
+ Name: name,
+ Scope: metric.Scope,
+ StatusCode: int32(metric.StatusCode),
+ ResponseCode: throttle.ResponseCodeFromStatus(metric.ResponseCode, metric.StatusCode),
+ Value: metric.Value,
+ Threshold: metric.Threshold,
+ Message: metric.Message,
}
}
if len(checkResult.Metrics) == 0 {
// For backwards compatibility, when the checked tablet is of lower version, it does not return a
// matrics map, but only the one metric.
resp.Metrics[base.DefaultMetricName.String()] = &tabletmanagerdatapb.CheckThrottlerResponse_Metric{
- StatusCode: int32(checkResult.StatusCode),
- Value: checkResult.Value,
- Threshold: checkResult.Threshold,
- Message: checkResult.Message,
+ StatusCode: int32(checkResult.StatusCode),
+ ResponseCode: throttle.ResponseCodeFromStatus(checkResult.ResponseCode, checkResult.StatusCode),
+ Value: checkResult.Value,
+ Threshold: checkResult.Threshold,
+ Message: checkResult.Message,
}
}
if checkResult.Error != nil {
@@ -138,8 +143,9 @@ func (tm *TabletManager) GetThrottlerStatus(ctx context.Context, req *tabletmana
}
for _, recentApp := range status.RecentApps {
resp.RecentApps[recentApp.AppName] = &tabletmanagerdatapb.GetThrottlerStatusResponse_RecentApp{
- CheckedAt: protoutil.TimeToProto(recentApp.CheckedAt),
- StatusCode: int32(recentApp.StatusCode),
+ CheckedAt: protoutil.TimeToProto(recentApp.CheckedAt),
+ StatusCode: int32(recentApp.StatusCode),
+ ResponseCode: recentApp.ResponseCode,
}
}
return resp, nil
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go
index 9057a55707f..47e3798acd0 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go
@@ -456,7 +456,7 @@ func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState ma
default:
}
if rows.Throttled {
- _ = vc.vr.updateTimeThrottled(throttlerapp.RowStreamerName)
+ _ = vc.vr.updateTimeThrottled(throttlerapp.RowStreamerName, rows.ThrottledReason)
return nil
}
if rows.Heartbeat {
@@ -464,10 +464,10 @@ func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState ma
return nil
}
// verify throttler is happy, otherwise keep looping
- if vc.vr.vre.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, throttlerapp.Name(vc.throttlerAppName)) {
+ if checkResult, ok := vc.vr.vre.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, throttlerapp.Name(vc.throttlerAppName)); ok {
break // out of 'for' loop
} else { // we're throttled
- _ = vc.vr.updateTimeThrottled(throttlerapp.VCopierName)
+ _ = vc.vr.updateTimeThrottled(throttlerapp.VCopierName, checkResult.Summary())
}
}
if !copyWorkQueue.isOpen {
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go
index c2eba565524..2b8b8130f89 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go
@@ -176,7 +176,7 @@ func newVPlayer(vr *vreplicator, settings binlogplayer.VRSettings, copyState map
timeLastSaved: time.Now(),
tablePlans: make(map[string]*TablePlan),
phase: phase,
- throttlerAppName: throttlerapp.VCopierName.ConcatenateString(vr.throttlerAppName()),
+ throttlerAppName: throttlerapp.VPlayerName.ConcatenateString(vr.throttlerAppName()),
query: queryFunc,
commit: commitFunc,
batchMode: batchMode,
@@ -487,8 +487,8 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error {
return ctx.Err()
}
// Check throttler.
- if !vp.vr.vre.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, throttlerapp.Name(vp.throttlerAppName)) {
- _ = vp.vr.updateTimeThrottled(throttlerapp.VPlayerName)
+ if checkResult, ok := vp.vr.vre.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, throttlerapp.Name(vp.throttlerAppName)); !ok {
+ _ = vp.vr.updateTimeThrottled(throttlerapp.VPlayerName, checkResult.Summary())
continue
}
@@ -794,7 +794,7 @@ func (vp *vplayer) applyEvent(ctx context.Context, event *binlogdatapb.VEvent, m
return io.EOF
case binlogdatapb.VEventType_HEARTBEAT:
if event.Throttled {
- if err := vp.vr.updateTimeThrottled(throttlerapp.VStreamerName); err != nil {
+ if err := vp.vr.updateTimeThrottled(throttlerapp.VStreamerName, event.ThrottledReason); err != nil {
return err
}
}
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
index abeda52b047..2a4d598c960 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
@@ -630,13 +630,13 @@ func (vr *vreplicator) throttlerAppName() string {
// tablet throttler over time. It also increments the global throttled count to keep
// track of how many times in total vreplication has been throttled across all workflows
// (both ones that currently exist and ones that no longer do).
-func (vr *vreplicator) updateTimeThrottled(appThrottled throttlerapp.Name) error {
+func (vr *vreplicator) updateTimeThrottled(appThrottled throttlerapp.Name, reasonThrottled string) error {
appName := appThrottled.String()
vr.stats.ThrottledCounts.Add([]string{"tablet", appName}, 1)
globalStats.ThrottledCount.Add(1)
err := vr.throttleUpdatesRateLimiter.Do(func() error {
tm := time.Now().Unix()
- update, err := binlogplayer.GenerateUpdateTimeThrottled(vr.id, tm, appName)
+ update, err := binlogplayer.GenerateUpdateTimeThrottled(vr.id, tm, appName, reasonThrottled)
if err != nil {
return err
}
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go
index f6eb3ac5958..20a5450741d 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator_test.go
@@ -31,6 +31,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "vitess.io/vitess/go/mysql/replication"
"vitess.io/vitess/go/vt/binlog/binlogplayer"
"vitess.io/vitess/go/vt/dbconfigs"
"vitess.io/vitess/go/vt/mysqlctl"
@@ -815,3 +816,59 @@ func waitForQueryResult(t *testing.T, dbc binlogplayer.DBClient, query, val stri
}
}
}
+
+func TestThrottlerAppNames(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ tablet := addTablet(100)
+ defer deleteTablet(tablet)
+ filter := &binlogdatapb.Filter{
+ Rules: []*binlogdatapb.Rule{{
+ Match: "t1",
+ }},
+ }
+ bls := &binlogdatapb.BinlogSource{
+ Keyspace: env.KeyspaceName,
+ Shard: env.ShardName,
+ Filter: filter,
+ }
+ id := int32(1)
+ vsclient := newTabletConnector(tablet)
+ stats := binlogplayer.NewStats()
+ defer stats.Stop()
+ dbClient := playerEngine.dbClientFactoryFiltered()
+ err := dbClient.Connect()
+ require.NoError(t, err)
+ defer dbClient.Close()
+ dbName := dbClient.DBName()
+ // Ensure there's a dummy vreplication workflow record
+ _, err = dbClient.ExecuteFetch(fmt.Sprintf("insert into _vt.vreplication (id, workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state, db_name, options) values (%d, 'test_workflow', '', '', 99999, 99999, 0, 0, 'Running', '%s', '{}') on duplicate key update workflow='test', source='', pos='', max_tps=99999, max_replication_lag=99999, time_updated=0, transaction_timestamp=0, state='Running', db_name='%s'",
+ id, dbName, dbName), 1)
+ require.NoError(t, err)
+ defer func() {
+ _, err = dbClient.ExecuteFetch(fmt.Sprintf("delete from _vt.vreplication where id = %d", id), 1)
+ require.NoError(t, err)
+ }()
+ vr := newVReplicator(id, bls, vsclient, stats, dbClient, env.Mysqld, playerEngine)
+ settings, _, err := vr.loadSettings(ctx, newVDBClient(dbClient, stats))
+ require.NoError(t, err)
+
+ throttlerAppName := vr.throttlerAppName()
+ assert.Contains(t, throttlerAppName, "test_workflow")
+ assert.Contains(t, throttlerAppName, "vreplication")
+ assert.NotContains(t, throttlerAppName, "vcopier")
+ assert.NotContains(t, throttlerAppName, "vplayer")
+
+ vp := newVPlayer(vr, settings, nil, replication.Position{}, "")
+ assert.Contains(t, vp.throttlerAppName, "test_workflow")
+ assert.Contains(t, vp.throttlerAppName, "vreplication")
+ assert.Contains(t, vp.throttlerAppName, "vplayer")
+ assert.NotContains(t, vp.throttlerAppName, "vcopier")
+
+ vc := newVCopier(vr)
+ assert.Contains(t, vc.throttlerAppName, "test_workflow")
+ assert.Contains(t, vc.throttlerAppName, "vreplication")
+ assert.Contains(t, vc.throttlerAppName, "vcopier")
+ assert.NotContains(t, vc.throttlerAppName, "vplayer")
+}
diff --git a/go/vt/vttablet/tabletserver/debug_2pc.go b/go/vt/vttablet/tabletserver/debug_2pc.go
new file mode 100644
index 00000000000..a0de20104db
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/debug_2pc.go
@@ -0,0 +1,48 @@
+//go:build debug2PC
+
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 tabletserver
+
+import (
+ "os"
+ "path"
+ "strconv"
+ "time"
+
+ "vitess.io/vitess/go/vt/log"
+)
+
+const DebugTwoPc = true
+
+// readFileForTestSynchronization is a test-only function that reads a file
+// that we use for synchronizing some of the tests.
+func readFileForTestSynchronization(fileName string) string {
+ res, _ := os.ReadFile(path.Join(os.Getenv("VTDATAROOT"), fileName))
+ return string(res)
+}
+
+// commitPreparedDelayForTest is a test-only function that delays the commit that have already been prepared.
+func commitPreparedDelayForTest(tsv *TabletServer) {
+ sh := readFileForTestSynchronization("VT_DELAY_COMMIT_SHARD")
+ if tsv.sm.target.Shard == sh {
+ delay := readFileForTestSynchronization("VT_DELAY_COMMIT_TIME")
+ delVal, _ := strconv.Atoi(delay)
+ log.Infof("Delaying commit for shard %v for %d seconds", sh, delVal)
+ time.Sleep(time.Duration(delVal) * time.Second)
+ }
+}
diff --git a/go/vt/vttablet/tabletserver/dt_executor.go b/go/vt/vttablet/tabletserver/dt_executor.go
index edf4438b8b2..9ddca3247a3 100644
--- a/go/vt/vttablet/tabletserver/dt_executor.go
+++ b/go/vt/vttablet/tabletserver/dt_executor.go
@@ -63,14 +63,14 @@ func (dte *DTExecutor) Prepare(transactionID int64, dtid string) error {
// If no queries were executed, we just rollback.
if len(conn.TxProperties().Queries) == 0 {
- conn.Release(tx.TxRollback)
+ dte.te.txPool.RollbackAndRelease(dte.ctx, conn)
return nil
}
// If the connection is tainted, we cannot prepare it. As there could be temporary tables involved.
if conn.IsTainted() {
- conn.Release(tx.TxRollback)
- return vterrors.VT12001("cannot prepare the transaction on a reserved connection")
+ dte.te.txPool.RollbackAndRelease(dte.ctx, conn)
+ return vterrors.VT10002("cannot prepare the transaction on a reserved connection")
}
err = dte.te.preparedPool.Put(conn, dtid)
@@ -88,30 +88,34 @@ func (dte *DTExecutor) Prepare(transactionID int64, dtid string) error {
// CommitPrepared commits a prepared transaction. If the operation
// fails, an error counter is incremented and the transaction is
// marked as failed in the redo log.
-func (dte *DTExecutor) CommitPrepared(dtid string) error {
+func (dte *DTExecutor) CommitPrepared(dtid string) (err error) {
if !dte.te.twopcEnabled {
return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "2pc is not enabled")
}
defer dte.te.env.Stats().QueryTimings.Record("COMMIT_PREPARED", time.Now())
- conn, err := dte.te.preparedPool.FetchForCommit(dtid)
+ var conn *StatefulConnection
+ conn, err = dte.te.preparedPool.FetchForCommit(dtid)
if err != nil {
- return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "cannot commit dtid %s, state: %v", dtid, err)
+ return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "cannot commit dtid %s, err: %v", dtid, err)
}
+ // No connection means the transaction was already committed.
if conn == nil {
return nil
}
// We have to use a context that will never give up,
// even if the original context expires.
ctx := trace.CopySpan(context.Background(), dte.ctx)
- defer dte.te.txPool.RollbackAndRelease(ctx, conn)
- err = dte.te.twoPC.DeleteRedo(ctx, conn, dtid)
- if err != nil {
- dte.markFailed(ctx, dtid)
+ defer func() {
+ if err != nil {
+ dte.markFailed(ctx, dtid)
+ log.Warningf("failed to commit the prepared transaction '%s' with error: %v", dtid, err)
+ }
+ dte.te.txPool.RollbackAndRelease(ctx, conn)
+ }()
+ if err = dte.te.twoPC.DeleteRedo(ctx, conn, dtid); err != nil {
return err
}
- _, err = dte.te.txPool.Commit(ctx, conn)
- if err != nil {
- dte.markFailed(ctx, dtid)
+ if _, err = dte.te.txPool.Commit(ctx, conn); err != nil {
return err
}
dte.te.preparedPool.Forget(dtid)
@@ -207,6 +211,15 @@ func (dte *DTExecutor) StartCommit(transactionID int64, dtid string) error {
}
defer dte.te.txPool.RollbackAndRelease(dte.ctx, conn)
+ // If the connection is tainted, we cannot take a commit decision on it.
+ if conn.IsTainted() {
+ dte.inTransaction(func(conn *StatefulConnection) error {
+ return dte.te.twoPC.Transition(dte.ctx, conn, dtid, querypb.TransactionState_ROLLBACK)
+ })
+ // return the error, defer call above will roll back the transaction.
+ return vterrors.VT10002("cannot commit the transaction on a reserved connection")
+ }
+
err = dte.te.twoPC.Transition(dte.ctx, conn, dtid, querypb.TransactionState_COMMIT)
if err != nil {
return err
@@ -228,6 +241,9 @@ func (dte *DTExecutor) SetRollback(dtid string, transactionID int64) error {
// If the transaction is still open, it will be rolled back.
// Otherwise, it would have been rolled back by other means, like a timeout or vttablet/mysql restart.
dte.te.Rollback(dte.ctx, transactionID)
+ } else {
+ // This is a warning because it should not happen in normal operation.
+ log.Warningf("SetRollback called with no transactionID for dtid %s", dtid)
}
return dte.inTransaction(func(conn *StatefulConnection) error {
diff --git a/go/vt/vttablet/tabletserver/dt_executor_test.go b/go/vt/vttablet/tabletserver/dt_executor_test.go
index 448dd63bf5a..fb45ab454fc 100644
--- a/go/vt/vttablet/tabletserver/dt_executor_test.go
+++ b/go/vt/vttablet/tabletserver/dt_executor_test.go
@@ -21,9 +21,11 @@ import (
"errors"
"fmt"
"reflect"
+ "strings"
"testing"
"time"
+ "vitess.io/vitess/go/event/syslogger"
"vitess.io/vitess/go/vt/vttablet/tabletserver/tx"
"github.com/stretchr/testify/require"
@@ -43,11 +45,42 @@ func TestTxExecutorEmptyPrepare(t *testing.T) {
txe, tsv, db := newTestTxExecutor(t, ctx)
defer db.Close()
defer tsv.StopService()
+
+ // start a transaction.
txid := newTransaction(tsv, nil)
- err := txe.Prepare(txid, "aa")
+
+ // taint the connection.
+ sc, err := tsv.te.txPool.GetAndLock(txid, "taint")
+ require.NoError(t, err)
+ sc.Taint(ctx, nil)
+ sc.Unlock()
+
+ err = txe.Prepare(txid, "aa")
require.NoError(t, err)
// Nothing should be prepared.
require.Empty(t, txe.te.preparedPool.conns, "txe.te.preparedPool.conns")
+ require.False(t, sc.IsInTransaction(), "transaction should be roll back before returning the connection to the pool")
+}
+
+func TestExecutorPrepareFailure(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ txe, tsv, db := newTestTxExecutor(t, ctx)
+ defer db.Close()
+ defer tsv.StopService()
+
+ // start a transaction
+ txid := newTxForPrep(ctx, tsv)
+
+ // taint the connection.
+ sc, err := tsv.te.txPool.GetAndLock(txid, "taint")
+ require.NoError(t, err)
+ sc.Taint(ctx, nil)
+ sc.Unlock()
+
+ // try 2pc commit of Metadata Manager.
+ err = txe.Prepare(txid, "aa")
+ require.EqualError(t, err, "VT10002: atomic distributed transaction not allowed: cannot prepare the transaction on a reserved connection")
}
func TestTxExecutorPrepare(t *testing.T) {
@@ -82,7 +115,7 @@ func TestDTExecutorPrepareResevedConn(t *testing.T) {
txe.te.Reserve(ctx, nil, txid, nil)
err := txe.Prepare(txid, "aa")
- require.ErrorContains(t, err, "VT12001: unsupported: cannot prepare the transaction on a reserved connection")
+ require.ErrorContains(t, err, "VT10002: atomic distributed transaction not allowed: cannot prepare the transaction on a reserved connection")
}
func TestTxExecutorPrepareNotInTx(t *testing.T) {
@@ -174,20 +207,31 @@ func TestTxExecutorCommitRedoFail(t *testing.T) {
txe, tsv, db := newTestTxExecutor(t, ctx)
defer db.Close()
defer tsv.StopService()
+
+ tl := syslogger.NewTestLogger()
+ defer tl.Close()
+
+ // start a transaction.
txid := newTxForPrep(ctx, tsv)
- // Allow all additions to redo logs to succeed
+
+ // prepare the transaction
db.AddQueryPattern("insert into _vt\\.redo_state.*", &sqltypes.Result{})
err := txe.Prepare(txid, "bb")
require.NoError(t, err)
- defer txe.RollbackPrepared("bb", 0)
- db.AddQuery("update _vt.redo_state set state = 'Failed' where dtid = 'bb'", &sqltypes.Result{})
+
+ // fail commit prepare as the delete redo query is in rejected query.
+ db.AddRejectedQuery("delete from _vt.redo_state where dtid = 'bb'", errors.New("delete redo log fail"))
+ db.AddQuery("update _vt.redo_state set state = 0 where dtid = 'bb'", sqltypes.MakeTestResult(nil))
err = txe.CommitPrepared("bb")
- require.Error(t, err)
- require.Contains(t, err.Error(), "is not supported")
- // A retry should fail differently.
+ require.ErrorContains(t, err, "delete redo log fail")
+
+ // A retry should fail differently as the prepared transaction is marked as failed.
err = txe.CommitPrepared("bb")
require.Error(t, err)
- require.Contains(t, err.Error(), "cannot commit dtid bb, state: failed")
+ require.Contains(t, err.Error(), "cannot commit dtid bb, err: VT09025: atomic transaction error: failed to commit")
+
+ require.Contains(t, strings.Join(tl.GetAllLogs(), "|"),
+ "failed to commit the prepared transaction 'bb' with error: unknown error: delete redo log fail")
}
func TestTxExecutorCommitRedoCommitFail(t *testing.T) {
@@ -273,6 +317,31 @@ func TestExecutorStartCommit(t *testing.T) {
require.Contains(t, err.Error(), "could not transition to COMMIT: aa")
}
+func TestExecutorStartCommitFailure(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ txe, tsv, db := newTestTxExecutor(t, ctx)
+ defer db.Close()
+ defer tsv.StopService()
+
+ // start a transaction
+ txid := newTxForPrep(ctx, tsv)
+
+ // taint the connection.
+ sc, err := tsv.te.txPool.GetAndLock(txid, "taint")
+ require.NoError(t, err)
+ sc.Taint(ctx, nil)
+ sc.Unlock()
+
+ // add rollback state update expectation
+ rollbackTransition := fmt.Sprintf("update _vt.dt_state set state = %d where dtid = 'aa' and state = %d", int(querypb.TransactionState_ROLLBACK), int(querypb.TransactionState_PREPARE))
+ db.AddQuery(rollbackTransition, sqltypes.MakeTestResult(nil))
+
+ // try 2pc commit of Metadata Manager.
+ err = txe.StartCommit(txid, "aa")
+ require.EqualError(t, err, "VT10002: atomic distributed transaction not allowed: cannot commit the transaction on a reserved connection")
+}
+
func TestExecutorSetRollback(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
diff --git a/go/vt/vttablet/tabletserver/gc/tablegc.go b/go/vt/vttablet/tabletserver/gc/tablegc.go
index f1d64aebea3..4d1714532a3 100644
--- a/go/vt/vttablet/tabletserver/gc/tablegc.go
+++ b/go/vt/vttablet/tabletserver/gc/tablegc.go
@@ -551,7 +551,7 @@ func (collector *TableGC) purge(ctx context.Context) (tableName string, err erro
// cancelled
return tableName, err
}
- if !collector.throttlerClient.ThrottleCheckOKOrWait(ctx) {
+ if _, ok := collector.throttlerClient.ThrottleCheckOKOrWait(ctx); !ok {
continue
}
// OK, we're clear to go!
diff --git a/go/vt/vttablet/tabletserver/planbuilder/permission.go b/go/vt/vttablet/tabletserver/planbuilder/permission.go
index 79b2f9eb430..dbc6cfccdad 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/permission.go
+++ b/go/vt/vttablet/tabletserver/planbuilder/permission.go
@@ -36,7 +36,13 @@ func BuildPermissions(stmt sqlparser.Statement) []Permission {
var permissions []Permission
// All Statement types myst be covered here.
switch node := stmt.(type) {
- case *sqlparser.Union, *sqlparser.Select:
+ case *sqlparser.Select:
+ role := tableacl.READER
+ if _, ok := node.SelectExprs[0].(*sqlparser.Nextval); ok {
+ role = tableacl.WRITER
+ }
+ permissions = buildSubqueryPermissions(node, role, permissions)
+ case *sqlparser.Union:
permissions = buildSubqueryPermissions(node, tableacl.READER, permissions)
case *sqlparser.Insert:
permissions = buildTableExprPermissions(node.Table, tableacl.WRITER, permissions)
diff --git a/go/vt/vttablet/tabletserver/planbuilder/permission_test.go b/go/vt/vttablet/tabletserver/planbuilder/permission_test.go
index 6d42118cb0b..0ece6ed19b2 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/permission_test.go
+++ b/go/vt/vttablet/tabletserver/planbuilder/permission_test.go
@@ -174,6 +174,12 @@ func TestBuildPermissions(t *testing.T) {
}, {
TableName: "t1", // derived table in update or delete needs reader permission as they cannot be modified.
}},
+ }, {
+ input: "select next 10 values from seq",
+ output: []Permission{{
+ TableName: "seq",
+ Role: tableacl.WRITER,
+ }},
}}
for _, tcase := range tcases {
diff --git a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
index 977b3822050..cafbe43231d 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
+++ b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
@@ -140,7 +140,7 @@
"Permissions": [
{
"TableName": "seq",
- "Role": 0
+ "Role": 1
}
],
"NextCount": "1"
@@ -154,7 +154,7 @@
"Permissions": [
{
"TableName": "seq",
- "Role": 0
+ "Role": 1
}
],
"NextCount": "10"
@@ -169,7 +169,7 @@
"Permissions": [
{
"TableName": "seq",
- "Role": 0
+ "Role": 1
}
],
"NextCount": ":a"
@@ -183,7 +183,7 @@
"Permissions": [
{
"TableName": "seq",
- "Role": 0
+ "Role": 1
}
],
"NextCount": "12345667852342342342323423423"
diff --git a/go/vt/vttablet/tabletserver/production.go b/go/vt/vttablet/tabletserver/production.go
new file mode 100644
index 00000000000..70cb8b092fa
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/production.go
@@ -0,0 +1,30 @@
+//go:build !debug2PC
+
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 tabletserver
+
+// This file defines debug constants that are always false.
+// This file is used for building production code.
+// We use go build directives to include a file that defines the constant to true
+// when certain tags are provided while building binaries.
+// This allows to have debugging code written in normal code flow without affecting
+// production performance.
+
+const DebugTwoPc = false
+
+func commitPreparedDelayForTest(tsv *TabletServer) {}
diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go
index 8a6d1a0be39..e3e951892b7 100644
--- a/go/vt/vttablet/tabletserver/tabletserver.go
+++ b/go/vt/vttablet/tabletserver/tabletserver.go
@@ -46,6 +46,7 @@ import (
"vitess.io/vitess/go/vt/mysqlctl"
binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
querypb "vitess.io/vitess/go/vt/proto/query"
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/servenv"
@@ -659,6 +660,9 @@ func (tsv *TabletServer) CommitPrepared(ctx context.Context, target *querypb.Tar
target, nil, true, /* allowOnShutdown */
func(ctx context.Context, logStats *tabletenv.LogStats) error {
txe := NewDTExecutor(ctx, tsv.te, logStats)
+ if DebugTwoPc {
+ commitPreparedDelayForTest(tsv)
+ }
return txe.CommitPrepared(dtid)
},
)
@@ -1800,8 +1804,9 @@ func (tsv *TabletServer) registerThrottlerCheckHandlers() {
}
metricNames := tsv.lagThrottler.MetricNames(r.URL.Query()["m"])
checkResult := tsv.lagThrottler.Check(ctx, appName, metricNames, flags)
- if checkResult.StatusCode == http.StatusNotFound && flags.OKIfNotExists {
+ if checkResult.ResponseCode == tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC && flags.OKIfNotExists {
checkResult.StatusCode = http.StatusOK // 200
+ checkResult.ResponseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_OK
}
if r.Method == http.MethodGet {
diff --git a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_cache.go b/go/vt/vttablet/tabletserver/throttle/base/metric_cache.go
similarity index 100%
rename from go/vt/vttablet/tabletserver/throttle/base/throttle_metric_cache.go
rename to go/vt/vttablet/tabletserver/throttle/base/metric_cache.go
diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_name.go b/go/vt/vttablet/tabletserver/throttle/base/metric_name.go
new file mode 100644
index 00000000000..98e1288fb23
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/metric_name.go
@@ -0,0 +1,128 @@
+/*
+Copyright 2023 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "fmt"
+ "slices"
+ "strings"
+)
+
+// MetricName is a formalized name for a metric, such as "lag" or "threads_running". A metric name
+// may include a scope, such as "self/lag" or "shard/threads_running". It is possible to add a
+// scope to a name, or to parse the scope out of a name, and there is also always a default scope
+// associated with a metric name.
+type MetricName string
+
+// MetricNames is a formalized list of metric names
+type MetricNames []MetricName
+
+func (names MetricNames) Contains(name MetricName) bool {
+ return slices.Contains(names, name)
+}
+
+func (names MetricNames) String() string {
+ s := make([]string, len(names))
+ for i, name := range names {
+ s[i] = name.String()
+ }
+ return strings.Join(s, ",")
+}
+
+// Unique returns a subset of unique metric names, in same order as the original names
+func (names MetricNames) Unique() MetricNames {
+ if names == nil {
+ return nil
+ }
+ uniqueMetricNamesMap := map[MetricName]bool{}
+ uniqueMetricNames := MetricNames{}
+ for _, metricName := range names {
+ if _, ok := uniqueMetricNamesMap[metricName]; !ok {
+ uniqueMetricNames = append(uniqueMetricNames, metricName)
+ uniqueMetricNamesMap[metricName] = true
+ }
+ }
+ return uniqueMetricNames
+}
+
+const (
+ DefaultMetricName MetricName = "default"
+ LagMetricName MetricName = "lag"
+ ThreadsRunningMetricName MetricName = "threads_running"
+ CustomMetricName MetricName = "custom"
+ LoadAvgMetricName MetricName = "loadavg"
+)
+
+func (metric MetricName) DefaultScope() Scope {
+ if selfMetric := RegisteredSelfMetrics[metric]; selfMetric != nil {
+ return selfMetric.DefaultScope()
+ }
+ return SelfScope
+}
+
+func (metric MetricName) String() string {
+ return string(metric)
+}
+
+// AggregatedName returns the string representation of this metric in the given scope, e.g.:
+// - "self/loadavg"
+// - "shard/lag"
+func (metric MetricName) AggregatedName(scope Scope) string {
+ if metric == DefaultMetricName {
+ // backwards (v20) compatibility
+ return scope.String()
+ }
+ if scope == UndefinedScope {
+ scope = metric.DefaultScope()
+ }
+ return fmt.Sprintf("%s/%s", scope.String(), metric.String())
+}
+
+// Disaggregated returns a breakdown of this metric into scope + name.
+func (metric MetricName) Disaggregated() (scope Scope, metricName MetricName, err error) {
+ return DisaggregateMetricName(metric.String())
+}
+
+type AggregatedMetricName struct {
+ Scope Scope
+ Metric MetricName
+}
+
+var (
+ KnownMetricNames = make(MetricNames, 0)
+ // aggregatedMetricNames precomputes the aggregated metric names for all known metric names,
+ // mapped to their breakdowns. e.g. "self/loadavg" -> {SelfScope, LoadAvgMetricName}
+ // This means:
+ // - no textual parsing is needed in the critical path
+ // - we can easily check if a metric name is valid
+ aggregatedMetricNames = make(map[string]AggregatedMetricName)
+)
+
+// DisaggregateMetricName splits a metric name into its scope name and metric name
+// aggregated metric name could be in the form:
+// - loadavg
+// - self
+// - self/threads_running
+// - shard
+// - shard/lag
+func DisaggregateMetricName(aggregatedMetricName string) (scope Scope, metricName MetricName, err error) {
+ breakdown, ok := aggregatedMetricNames[aggregatedMetricName]
+ if !ok {
+ return UndefinedScope, DefaultMetricName, ErrNoSuchMetric
+ }
+ return breakdown.Scope, breakdown.Metric, nil
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_test.go b/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go
similarity index 93%
rename from go/vt/vttablet/tabletserver/throttle/base/throttle_metric_test.go
rename to go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go
index 8a0f9b85a16..9867ca18db3 100644
--- a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_test.go
+++ b/go/vt/vttablet/tabletserver/throttle/base/metric_name_test.go
@@ -230,3 +230,12 @@ func TestContains(t *testing.T) {
})
}
}
+
+func TestKnownMetricNames(t *testing.T) {
+ assert.NotEmpty(t, KnownMetricNames)
+ assert.Contains(t, KnownMetricNames, LagMetricName)
+ assert.Contains(t, KnownMetricNames, ThreadsRunningMetricName)
+ assert.Contains(t, KnownMetricNames, LoadAvgMetricName)
+ assert.Contains(t, KnownMetricNames, CustomMetricName)
+ assert.Contains(t, KnownMetricNames, DefaultMetricName)
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_result.go b/go/vt/vttablet/tabletserver/throttle/base/metric_result.go
new file mode 100644
index 00000000000..0fa48fe3240
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/metric_result.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "errors"
+ "net"
+)
+
+// MetricResult is what we expect our probes to return. This can be a numeric result, or
+// a special type of result indicating more meta-information
+type MetricResult interface {
+ Get() (float64, error)
+}
+
+// MetricResultFunc is a function that returns a metric result
+type MetricResultFunc func() (metricResult MetricResult, threshold float64)
+
+type MetricResultMap map[MetricName]MetricResult
+
+func NewMetricResultMap() MetricResultMap {
+ result := make(MetricResultMap, len(KnownMetricNames))
+ for _, metricName := range KnownMetricNames {
+ result[metricName] = nil
+ }
+ return result
+}
+
+// ErrThresholdExceeded is the common error one may get checking on metric result
+var ErrThresholdExceeded = errors.New("threshold exceeded")
+var ErrNoResultYet = errors.New("metric not collected yet")
+
+// ErrNoSuchMetric is for when a user requests a metric by an unknown metric name
+var ErrNoSuchMetric = errors.New("no such metric")
+
+// ErrAppDenied is seen when an app is denied access
+var ErrAppDenied = errors.New("app denied")
+
+// ErrInvalidCheckType is an internal error indicating an unknown check type
+var ErrInvalidCheckType = errors.New("unknown throttler check type")
+
+// IsDialTCPError sees if the given error indicates a TCP issue
+func IsDialTCPError(err error) bool {
+ if err == nil {
+ return false
+ }
+ switch err := err.(type) {
+ case *net.OpError:
+ return err.Op == "dial" && err.Net == "tcp"
+ }
+ return false
+}
+
+type noHostsMetricResult struct{}
+
+// Get implements MetricResult
+func (metricResult *noHostsMetricResult) Get() (float64, error) {
+ return 0, nil
+}
+
+// NoHostsMetricResult is a result indicating "no hosts"
+var NoHostsMetricResult = &noHostsMetricResult{}
+
+type noMetricResultYet struct{}
+
+// Get implements MetricResult
+func (metricResult *noMetricResultYet) Get() (float64, error) {
+ return 0, ErrNoResultYet
+}
+
+// NoMetricResultYet is a result indicating "no data"
+var NoMetricResultYet = &noMetricResultYet{}
+
+type noSuchMetric struct{}
+
+// Get implements MetricResult
+func (metricResult *noSuchMetric) Get() (float64, error) {
+ return 0, ErrNoSuchMetric
+}
+
+// NoSuchMetric is a metric results for an unknown metric name
+var NoSuchMetric = &noSuchMetric{}
+
+// simpleMetricResult is a result with float value
+type simpleMetricResult struct {
+ Value float64
+}
+
+// NewSimpleMetricResult creates a simpleMetricResult
+func NewSimpleMetricResult(value float64) MetricResult {
+ return &simpleMetricResult{Value: value}
+}
+
+// Get implements MetricResult
+func (metricResult *simpleMetricResult) Get() (float64, error) {
+ return metricResult.Value, nil
+}
+
+type appDeniedMetric struct{}
+
+// Get implements MetricResult
+func (metricResult *appDeniedMetric) Get() (float64, error) {
+ return 0, ErrAppDenied
+}
+
+// AppDeniedMetric is a special metric indicating a "denied" situation
+var AppDeniedMetric = &appDeniedMetric{}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go b/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go
new file mode 100644
index 00000000000..60d116861c3
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/metric_scope.go
@@ -0,0 +1,44 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "fmt"
+)
+
+// Scope defines the tablet range from which a metric is collected. This can be the local tablet
+// ("self") or the entire shard ("shard")
+type Scope string
+
+const (
+ UndefinedScope Scope = ""
+ ShardScope Scope = "shard"
+ SelfScope Scope = "self"
+)
+
+func (s Scope) String() string {
+ return string(s)
+}
+
+func ScopeFromString(s string) (Scope, error) {
+ switch scope := Scope(s); scope {
+ case UndefinedScope, ShardScope, SelfScope:
+ return scope, nil
+ default:
+ return "", fmt.Errorf("unknown scope: %s", s)
+ }
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/recent_app.go b/go/vt/vttablet/tabletserver/throttle/base/recent_app.go
index 148e6b31fe4..7ae2bf789af 100644
--- a/go/vt/vttablet/tabletserver/throttle/base/recent_app.go
+++ b/go/vt/vttablet/tabletserver/throttle/base/recent_app.go
@@ -42,21 +42,25 @@ package base
import (
"time"
+
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
)
// RecentApp indicates when an app was last checked
type RecentApp struct {
- AppName string
- CheckedAt time.Time
- StatusCode int
+ AppName string
+ CheckedAt time.Time
+ StatusCode int
+ ResponseCode tabletmanagerdatapb.CheckThrottlerResponseCode
}
// NewRecentApp creates a RecentApp
-func NewRecentApp(appName string, statusCode int) *RecentApp {
+func NewRecentApp(appName string, statusCode int, responseCode tabletmanagerdatapb.CheckThrottlerResponseCode) *RecentApp {
result := &RecentApp{
- AppName: appName,
- CheckedAt: time.Now(),
- StatusCode: statusCode,
+ AppName: appName,
+ CheckedAt: time.Now(),
+ StatusCode: statusCode,
+ ResponseCode: responseCode,
}
return result
}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric.go
new file mode 100644
index 00000000000..220dfa6bf60
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric.go
@@ -0,0 +1,91 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+type SelfMetric interface {
+ Name() MetricName
+ DefaultScope() Scope
+ DefaultThreshold() float64
+ RequiresConn() bool
+ Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric
+}
+
+var (
+ RegisteredSelfMetrics = make(map[MetricName]SelfMetric)
+)
+
+func registerSelfMetric(selfMetric SelfMetric) SelfMetric {
+ RegisteredSelfMetrics[selfMetric.Name()] = selfMetric
+ KnownMetricNames = append(KnownMetricNames, selfMetric.Name())
+ aggregatedMetricNames[selfMetric.Name().String()] = AggregatedMetricName{
+ Scope: selfMetric.DefaultScope(),
+ Metric: selfMetric.Name(),
+ }
+ for _, scope := range []Scope{ShardScope, SelfScope} {
+ aggregatedName := selfMetric.Name().AggregatedName(scope)
+ aggregatedMetricNames[aggregatedName] = AggregatedMetricName{
+ Scope: scope,
+ Metric: selfMetric.Name(),
+ }
+ }
+ return selfMetric
+}
+
+// ReadSelfMySQLThrottleMetric reads a metric using a given MySQL connection and a query.
+func ReadSelfMySQLThrottleMetric(ctx context.Context, conn *connpool.Conn, query string) *ThrottleMetric {
+ metric := &ThrottleMetric{
+ Scope: SelfScope,
+ }
+ if query == "" {
+ return metric
+ }
+ if conn == nil {
+ return metric.WithError(fmt.Errorf("conn is nil"))
+ }
+
+ tm, err := conn.Exec(ctx, query, 1, true)
+ if err != nil {
+ return metric.WithError(err)
+ }
+ if len(tm.Rows) == 0 {
+ return metric.WithError(fmt.Errorf("no results in ReadSelfMySQLThrottleMetric for query %s", query))
+ }
+ if len(tm.Rows) > 1 {
+ return metric.WithError(fmt.Errorf("expecting single row in ReadSelfMySQLThrottleMetric for query %s", query))
+ }
+
+ metricsQueryType := GetMetricsQueryType(query)
+ switch metricsQueryType {
+ case MetricsQueryTypeSelect:
+ metric.Value, metric.Err = tm.Rows[0][0].ToFloat64()
+ case MetricsQueryTypeShowGlobal:
+ // Columns are [Variable_name, Value]
+ metric.Value, metric.Err = strconv.ParseFloat(tm.Rows[0][1].ToString(), 64)
+ default:
+ metric.Err = fmt.Errorf("unsupported metrics query type for query: %s", query)
+ }
+
+ return metric
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric_custom_query.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric_custom_query.go
new file mode 100644
index 00000000000..585e63ea285
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric_custom_query.go
@@ -0,0 +1,48 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+var _ SelfMetric = registerSelfMetric(&CustomQuerySelfMetric{})
+
+type CustomQuerySelfMetric struct {
+}
+
+func (m *CustomQuerySelfMetric) Name() MetricName {
+ return CustomMetricName
+}
+
+func (m *CustomQuerySelfMetric) DefaultScope() Scope {
+ return SelfScope
+}
+
+func (m *CustomQuerySelfMetric) DefaultThreshold() float64 {
+ return 0
+}
+
+func (m *CustomQuerySelfMetric) RequiresConn() bool {
+ return true
+}
+
+func (m *CustomQuerySelfMetric) Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric {
+ return ReadSelfMySQLThrottleMetric(ctx, conn, throttler.GetCustomMetricsQuery())
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric_default.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric_default.go
new file mode 100644
index 00000000000..8bce295da7c
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric_default.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+ "fmt"
+
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+var _ SelfMetric = registerSelfMetric(&DefaultSelfMetric{})
+
+type DefaultSelfMetric struct {
+}
+
+func (m *DefaultSelfMetric) Name() MetricName {
+ return DefaultMetricName
+}
+
+func (m *DefaultSelfMetric) DefaultScope() Scope {
+ return SelfScope
+}
+
+func (m *DefaultSelfMetric) DefaultThreshold() float64 {
+ return 0
+}
+
+func (m *DefaultSelfMetric) RequiresConn() bool {
+ return false
+}
+
+func (m *DefaultSelfMetric) Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric {
+ return &ThrottleMetric{
+ Err: fmt.Errorf("unexpected direct call to DefaultSelfMetric.Read"),
+ }
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric_lag.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric_lag.go
new file mode 100644
index 00000000000..dc25ee5622a
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric_lag.go
@@ -0,0 +1,70 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+ "sync/atomic"
+ "time"
+
+ "vitess.io/vitess/go/constants/sidecar"
+ "vitess.io/vitess/go/vt/sqlparser"
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+var (
+ lagSelfMetricQueryBase = "select unix_timestamp(now(6))-max(ts/1000000000) as replication_lag from %s.heartbeat"
+ lagSelfDefaultThreshold = 5 * time.Second
+)
+
+var _ SelfMetric = registerSelfMetric(&LagSelfMetric{})
+
+type LagSelfMetric struct {
+ lagSelfMetricQuery atomic.Value
+}
+
+// SetQuery is only used by unit tests to override the query.
+func (m *LagSelfMetric) SetQuery(query string) {
+ m.lagSelfMetricQuery.Store(query)
+}
+
+func (m *LagSelfMetric) GetQuery() string {
+ if query := m.lagSelfMetricQuery.Load(); query == nil {
+ m.lagSelfMetricQuery.Store(sqlparser.BuildParsedQuery(lagSelfMetricQueryBase, sidecar.GetIdentifier()).Query)
+ }
+ return m.lagSelfMetricQuery.Load().(string)
+}
+
+func (m *LagSelfMetric) Name() MetricName {
+ return LagMetricName
+}
+
+func (m *LagSelfMetric) DefaultScope() Scope {
+ return ShardScope
+}
+
+func (m *LagSelfMetric) DefaultThreshold() float64 {
+ return lagSelfDefaultThreshold.Seconds()
+}
+
+func (m *LagSelfMetric) RequiresConn() bool {
+ return true
+}
+
+func (m *LagSelfMetric) Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric {
+ return ReadSelfMySQLThrottleMetric(ctx, conn, m.GetQuery())
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric_loadavg.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric_loadavg.go
new file mode 100644
index 00000000000..40a2878421a
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric_loadavg.go
@@ -0,0 +1,81 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+var (
+ loadavgOnlyAvailableOnLinuxMetric = &ThrottleMetric{
+ Scope: SelfScope,
+ Err: fmt.Errorf("loadavg metric is only available on Linux"),
+ }
+)
+
+var _ SelfMetric = registerSelfMetric(&LoadAvgSelfMetric{})
+
+type LoadAvgSelfMetric struct {
+}
+
+func (m *LoadAvgSelfMetric) Name() MetricName {
+ return LoadAvgMetricName
+}
+
+func (m *LoadAvgSelfMetric) DefaultScope() Scope {
+ return SelfScope
+}
+
+func (m *LoadAvgSelfMetric) DefaultThreshold() float64 {
+ return 1.0
+}
+
+func (m *LoadAvgSelfMetric) RequiresConn() bool {
+ return false
+}
+
+func (m *LoadAvgSelfMetric) Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric {
+ if runtime.GOOS != "linux" {
+ return loadavgOnlyAvailableOnLinuxMetric
+ }
+ metric := &ThrottleMetric{
+ Scope: SelfScope,
+ }
+ {
+ content, err := os.ReadFile("/proc/loadavg")
+ if err != nil {
+ return metric.WithError(err)
+ }
+ fields := strings.Fields(string(content))
+ if len(fields) == 0 {
+ return metric.WithError(fmt.Errorf("unexpected /proc/loadavg content"))
+ }
+ loadAvg, err := strconv.ParseFloat(fields[0], 64)
+ if err != nil {
+ return metric.WithError(err)
+ }
+ metric.Value = loadAvg / float64(runtime.NumCPU())
+ }
+ return metric
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/self_metric_threads_running.go b/go/vt/vttablet/tabletserver/throttle/base/self_metric_threads_running.go
new file mode 100644
index 00000000000..08f7d408d1c
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/self_metric_threads_running.go
@@ -0,0 +1,52 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+import (
+ "context"
+
+ "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
+)
+
+var (
+ threadsRunningMetricQuery = "show global status like 'threads_running'"
+)
+
+var _ SelfMetric = registerSelfMetric(&ThreadsRunningSelfMetric{})
+
+type ThreadsRunningSelfMetric struct {
+}
+
+func (m *ThreadsRunningSelfMetric) Name() MetricName {
+ return ThreadsRunningMetricName
+}
+
+func (m *ThreadsRunningSelfMetric) DefaultScope() Scope {
+ return SelfScope
+}
+
+func (m *ThreadsRunningSelfMetric) DefaultThreshold() float64 {
+ return 100
+}
+
+func (m *ThreadsRunningSelfMetric) RequiresConn() bool {
+ return true
+}
+
+func (m *ThreadsRunningSelfMetric) Read(ctx context.Context, throttler ThrottlerMetricsPublisher, conn *connpool.Conn) *ThrottleMetric {
+ return ReadSelfMySQLThrottleMetric(ctx, conn, threadsRunningMetricQuery)
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric.go b/go/vt/vttablet/tabletserver/throttle/base/throttle_metric.go
deleted file mode 100644
index 054687cdd3f..00000000000
--- a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric.go
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-Copyright 2023 The Vitess Authors.
-
-Licensed 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 base
-
-import (
- "errors"
- "fmt"
- "slices"
- "strings"
-)
-
-// Scope defines the tablet range from which a metric is collected. This can be the local tablet
-// ("self") or the entire shard ("shard")
-type Scope string
-
-const (
- UndefinedScope Scope = ""
- ShardScope Scope = "shard"
- SelfScope Scope = "self"
-)
-
-func (s Scope) String() string {
- return string(s)
-}
-
-func ScopeFromString(s string) (Scope, error) {
- switch scope := Scope(s); scope {
- case UndefinedScope, ShardScope, SelfScope:
- return scope, nil
- default:
- return "", fmt.Errorf("unknown scope: %s", s)
- }
-}
-
-// MetricName is a formalized name for a metric, such as "lag" or "threads_running". A metric name
-// may include a scope, such as "self/lag" or "shard/threads_running". It is possible to add a
-// scope to a name, or to parse the scope out of a name, and there is also always a default scope
-// associated with a metric name.
-type MetricName string
-
-// MetricNames is a formalized list of metric names
-type MetricNames []MetricName
-
-func (names MetricNames) Contains(name MetricName) bool {
- return slices.Contains(names, name)
-}
-
-func (names MetricNames) String() string {
- s := make([]string, len(names))
- for i, name := range names {
- s[i] = name.String()
- }
- return strings.Join(s, ",")
-}
-
-// Unique returns a subset of unique metric names, in same order as the original names
-func (names MetricNames) Unique() MetricNames {
- if names == nil {
- return nil
- }
- uniqueMetricNamesMap := map[MetricName]bool{}
- uniqueMetricNames := MetricNames{}
- for _, metricName := range names {
- if _, ok := uniqueMetricNamesMap[metricName]; !ok {
- uniqueMetricNames = append(uniqueMetricNames, metricName)
- uniqueMetricNamesMap[metricName] = true
- }
- }
- return uniqueMetricNames
-}
-
-const (
- DefaultMetricName MetricName = "default"
- LagMetricName MetricName = "lag"
- ThreadsRunningMetricName MetricName = "threads_running"
- CustomMetricName MetricName = "custom"
- LoadAvgMetricName MetricName = "loadavg"
-)
-
-func (metric MetricName) DefaultScope() Scope {
- switch metric {
- case LagMetricName:
- return ShardScope
- default:
- return SelfScope
- }
-}
-
-func (metric MetricName) String() string {
- return string(metric)
-}
-
-// AggregatedName returns the string representation of this metric in the given scope, e.g.:
-// - "self/loadavg"
-// - "shard/lag"
-func (metric MetricName) AggregatedName(scope Scope) string {
- if metric == DefaultMetricName {
- // backwards (v20) compatibility
- return scope.String()
- }
- if scope == UndefinedScope {
- scope = metric.DefaultScope()
- }
- return fmt.Sprintf("%s/%s", scope.String(), metric.String())
-}
-
-// Disaggregated returns a breakdown of this metric into scope + name.
-func (metric MetricName) Disaggregated() (scope Scope, metricName MetricName, err error) {
- return DisaggregateMetricName(metric.String())
-}
-
-var KnownMetricNames = MetricNames{
- DefaultMetricName,
- LagMetricName,
- ThreadsRunningMetricName,
- CustomMetricName,
- LoadAvgMetricName,
-}
-
-type AggregatedMetricName struct {
- Scope Scope
- Metric MetricName
-}
-
-var (
- // aggregatedMetricNames precomputes the aggregated metric names for all known metric names,
- // mapped to their breakdowns. e.g. "self/loadavg" -> {SelfScope, LoadAvgMetricName}
- // This means:
- // - no textual parsing is needed in the critical path
- // - we can easily check if a metric name is valid
- aggregatedMetricNames map[string]AggregatedMetricName
-)
-
-func init() {
- aggregatedMetricNames = make(map[string]AggregatedMetricName, 3*len(KnownMetricNames))
- for _, metricName := range KnownMetricNames {
- aggregatedMetricNames[metricName.String()] = AggregatedMetricName{
- Scope: metricName.DefaultScope(),
- Metric: metricName,
- }
- for _, scope := range []Scope{ShardScope, SelfScope} {
- aggregatedName := metricName.AggregatedName(scope)
- aggregatedMetricNames[aggregatedName] = AggregatedMetricName{
- Scope: scope,
- Metric: metricName,
- }
- }
- }
-}
-
-// DisaggregateMetricName splits a metric name into its scope name and metric name
-// aggregated metric name could be in the form:
-// - loadavg
-// - self
-// - self/threads_running
-// - shard
-// - shard/lag
-func DisaggregateMetricName(aggregatedMetricName string) (scope Scope, metricName MetricName, err error) {
- breakdown, ok := aggregatedMetricNames[aggregatedMetricName]
- if !ok {
- return UndefinedScope, DefaultMetricName, ErrNoSuchMetric
- }
- return breakdown.Scope, breakdown.Metric, nil
-}
-
-// MetricResult is what we expect our probes to return. This can be a numeric result, or
-// a special type of result indicating more meta-information
-type MetricResult interface {
- Get() (float64, error)
-}
-
-// MetricResultFunc is a function that returns a metric result
-type MetricResultFunc func() (metricResult MetricResult, threshold float64)
-
-type MetricResultMap map[MetricName]MetricResult
-
-func NewMetricResultMap() MetricResultMap {
- result := make(MetricResultMap, len(KnownMetricNames))
- for _, metricName := range KnownMetricNames {
- result[metricName] = nil
- }
- return result
-}
-
-// ErrThresholdExceeded is the common error one may get checking on metric result
-var ErrThresholdExceeded = errors.New("threshold exceeded")
-var ErrNoResultYet = errors.New("metric not collected yet")
-
-// ErrNoSuchMetric is for when a user requests a metric by an unknown metric name
-var ErrNoSuchMetric = errors.New("no such metric")
-
-// ErrInvalidCheckType is an internal error indicating an unknown check type
-var ErrInvalidCheckType = errors.New("unknown throttler check type")
-
-// IsDialTCPError sees if the given error indicates a TCP issue
-func IsDialTCPError(e error) bool {
- if e == nil {
- return false
- }
- return strings.HasPrefix(e.Error(), "dial tcp")
-}
-
-type noHostsMetricResult struct{}
-
-// Get implements MetricResult
-func (metricResult *noHostsMetricResult) Get() (float64, error) {
- return 0, nil
-}
-
-// NoHostsMetricResult is a result indicating "no hosts"
-var NoHostsMetricResult = &noHostsMetricResult{}
-
-type noMetricResultYet struct{}
-
-// Get implements MetricResult
-func (metricResult *noMetricResultYet) Get() (float64, error) {
- return 0, ErrNoResultYet
-}
-
-// NoMetricResultYet is a result indicating "no data"
-var NoMetricResultYet = &noMetricResultYet{}
-
-type noSuchMetric struct{}
-
-// Get implements MetricResult
-func (metricResult *noSuchMetric) Get() (float64, error) {
- return 0, ErrNoSuchMetric
-}
-
-// NoSuchMetric is a metric results for an unknown metric name
-var NoSuchMetric = &noSuchMetric{}
-
-// simpleMetricResult is a result with float value
-type simpleMetricResult struct {
- Value float64
-}
-
-// NewSimpleMetricResult creates a simpleMetricResult
-func NewSimpleMetricResult(value float64) MetricResult {
- return &simpleMetricResult{Value: value}
-}
-
-// Get implements MetricResult
-func (metricResult *simpleMetricResult) Get() (float64, error) {
- return metricResult.Value, nil
-}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_app.go b/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_app.go
deleted file mode 100644
index 482f319365f..00000000000
--- a/go/vt/vttablet/tabletserver/throttle/base/throttle_metric_app.go
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-Copyright 2023 The Vitess Authors.
-
-Licensed 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.
-*/
-
-// This codebase originates from https://github.com/github/freno, See https://github.com/github/freno/blob/master/LICENSE
-/*
- MIT License
-
- Copyright (c) 2017 GitHub
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-*/
-
-package base
-
-import (
- "errors"
-)
-
-// ErrAppDenied is seen when an app is denied access
-var ErrAppDenied = errors.New("App denied")
-
-type appDeniedMetric struct{}
-
-// Get implements MetricResult
-func (metricResult *appDeniedMetric) Get() (float64, error) {
- return 0, ErrAppDenied
-}
-
-// AppDeniedMetric is a special metric indicating a "denied" situation
-var AppDeniedMetric = &appDeniedMetric{}
diff --git a/go/vt/vttablet/tabletserver/throttle/base/throttler_metrics_publisher.go b/go/vt/vttablet/tabletserver/throttle/base/throttler_metrics_publisher.go
new file mode 100644
index 00000000000..1d2d4d0652c
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/base/throttler_metrics_publisher.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 base
+
+// ThrottlerMetricsPublisher is implemented by throttler.Throttler and is used by SelfMetric
+// implementations to query the throttler.
+type ThrottlerMetricsPublisher interface {
+ GetCustomMetricsQuery() string
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/check.go b/go/vt/vttablet/tabletserver/throttle/check.go
index e43c4cab043..ccdfcb2ce23 100644
--- a/go/vt/vttablet/tabletserver/throttle/check.go
+++ b/go/vt/vttablet/tabletserver/throttle/check.go
@@ -51,6 +51,8 @@ import (
"vitess.io/vitess/go/textutil"
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base"
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp"
+
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
)
const (
@@ -94,54 +96,65 @@ func (check *ThrottlerCheck) checkAppMetricResult(ctx context.Context, appName s
// Handle deprioritized app logic
denyApp := false
//
- metricResult, threshold := check.throttler.AppRequestMetricResult(ctx, appName, metricResultFunc, denyApp)
+ metricResult, threshold, matchedApp := check.throttler.AppRequestMetricResult(ctx, appName, metricResultFunc, denyApp)
if flags.OverrideThreshold > 0 {
threshold = flags.OverrideThreshold
}
value, err := metricResult.Get()
if appName == "" {
- return NewCheckResult(http.StatusExpectationFailed, value, threshold, fmt.Errorf("no app indicated"))
+ return NewCheckResult(tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED, http.StatusExpectationFailed, value, threshold, "", fmt.Errorf("no app indicated"))
}
var statusCode int
+ var responseCode tabletmanagerdatapb.CheckThrottlerResponseCode
switch {
case err == base.ErrAppDenied:
// app specifically not allowed to get metrics
statusCode = http.StatusExpectationFailed // 417
+ responseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED
case err == base.ErrNoSuchMetric:
// not collected yet, or metric does not exist
statusCode = http.StatusNotFound // 404
+ responseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC
case err != nil:
// any error
statusCode = http.StatusInternalServerError // 500
+ responseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_INTERNAL_ERROR
case value > threshold:
// casual throttling
statusCode = http.StatusTooManyRequests // 429
+ responseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED
err = base.ErrThresholdExceeded
default:
// all good!
statusCode = http.StatusOK // 200
+ responseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_OK
}
- return NewCheckResult(statusCode, value, threshold, err)
+ return NewCheckResult(responseCode, statusCode, value, threshold, matchedApp, err)
}
// Check is the core function that runs when a user wants to check a metric
func (check *ThrottlerCheck) Check(ctx context.Context, appName string, scope base.Scope, metricNames base.MetricNames, flags *CheckFlags) (checkResult *CheckResult) {
checkResult = &CheckResult{
- StatusCode: http.StatusOK,
- Metrics: make(map[string]*MetricResult),
+ StatusCode: http.StatusOK,
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ Metrics: make(map[string]*MetricResult),
}
if len(metricNames) == 0 {
metricNames = base.MetricNames{check.throttler.metricNameUsedAsDefault()}
}
metricNames = metricNames.Unique()
- applyMetricToCheckResult := func(metric *MetricResult) {
+ applyMetricToCheckResult := func(metricName base.MetricName, metric *MetricResult) {
checkResult.StatusCode = metric.StatusCode
+ checkResult.ResponseCode = metric.ResponseCode
checkResult.Value = metric.Value
checkResult.Threshold = metric.Threshold
checkResult.Error = metric.Error
checkResult.Message = metric.Message
+ checkResult.AppName = metric.AppName
+ checkResult.Scope = metric.Scope
+ checkResult.MetricName = metricName.String()
}
for _, metricName := range metricNames {
// Make sure not to modify the given scope. We create a new scope variable to work with.
@@ -168,7 +181,7 @@ func (check *ThrottlerCheck) Check(ctx context.Context, appName string, scope ba
metricCheckResult := check.checkAppMetricResult(ctx, appName, metricResultFunc, flags)
if !throttlerapp.VitessName.Equals(appName) {
- go func(statusCode int) {
+ go func(metricCheckResult *CheckResult) {
if metricScope == base.UndefinedScope {
// While we should never get here, the following code will panic if we do
// because it will attempt to recreate ThrottlerCheckAnyTotal.
@@ -176,21 +189,23 @@ func (check *ThrottlerCheck) Check(ctx context.Context, appName string, scope ba
return
}
stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sTotal", textutil.SingleWordCamel(metricScope.String()), textutil.SingleWordCamel(metricName.String())), "").Add(1)
- if statusCode != http.StatusOK {
+ if !metricCheckResult.IsOK() {
stats.GetOrNewCounter(fmt.Sprintf("ThrottlerCheck%s%sError", textutil.SingleWordCamel(metricScope.String()), textutil.SingleWordCamel(metricName.String())), "").Add(1)
}
- }(metricCheckResult.StatusCode)
+ }(metricCheckResult)
}
if metricCheckResult.RecentlyChecked {
checkResult.RecentlyChecked = true
}
metric := &MetricResult{
- StatusCode: metricCheckResult.StatusCode,
- Value: metricCheckResult.Value,
- Threshold: metricCheckResult.Threshold,
- Error: metricCheckResult.Error,
- Message: metricCheckResult.Message,
- Scope: metricScope.String(), // This reports back the actual scope used for the check
+ StatusCode: metricCheckResult.StatusCode,
+ ResponseCode: metricCheckResult.ResponseCode,
+ Value: metricCheckResult.Value,
+ Threshold: metricCheckResult.Threshold,
+ Error: metricCheckResult.Error,
+ Message: metricCheckResult.Message,
+ AppName: metricCheckResult.AppName,
+ Scope: metricScope.String(), // This reports back the actual scope used for the check
}
checkResult.Metrics[metricName.String()] = metric
if flags.MultiMetricsEnabled && !metricCheckResult.IsOK() && metricName != base.DefaultMetricName {
@@ -199,25 +214,26 @@ func (check *ThrottlerCheck) Check(ctx context.Context, appName string, scope ba
// metrics, because a v20 primary would not know how to deal with it, and is not expecting any of those
// metrics.
// The only metric we ever report back is the default metric, see below.
- applyMetricToCheckResult(metric)
+ applyMetricToCheckResult(metricName, metric)
}
}
- if metric, ok := checkResult.Metrics[check.throttler.metricNameUsedAsDefault().String()]; ok && checkResult.IsOK() {
- applyMetricToCheckResult(metric)
+ metricNameUsedAsDefault := check.throttler.metricNameUsedAsDefault()
+ if metric, ok := checkResult.Metrics[metricNameUsedAsDefault.String()]; ok && checkResult.IsOK() {
+ applyMetricToCheckResult(metricNameUsedAsDefault, metric)
}
if metric, ok := checkResult.Metrics[base.DefaultMetricName.String()]; ok && checkResult.IsOK() {
// v20 compatibility: if this v21 server is a replica, reporting to a v20 primary,
// then we must supply the v20-flavor check result.
// If checkResult is not OK, then we will have populated these fields already by the failing metric.
- applyMetricToCheckResult(metric)
+ applyMetricToCheckResult(base.DefaultMetricName, metric)
}
- go func(statusCode int) {
+ go func(checkResult *CheckResult) {
statsThrottlerCheckAnyTotal.Add(1)
- if statusCode != http.StatusOK {
+ if !checkResult.IsOK() {
statsThrottlerCheckAnyError.Add(1)
}
- }(checkResult.StatusCode)
- go check.throttler.markRecentApp(appName, checkResult.StatusCode)
+ }(checkResult)
+ go check.throttler.markRecentApp(appName, checkResult.StatusCode, checkResult.ResponseCode)
return checkResult
}
@@ -229,7 +245,7 @@ func (check *ThrottlerCheck) localCheck(ctx context.Context, aggregatedMetricNam
}
checkResult = check.Check(ctx, throttlerapp.VitessName.String(), scope, base.MetricNames{metricName}, selfCheckFlags)
- if checkResult.StatusCode == http.StatusOK {
+ if checkResult.IsOK() {
check.throttler.markMetricHealthy(aggregatedMetricName)
}
if timeSinceHealthy, found := check.throttler.timeSinceMetricHealthy(aggregatedMetricName); found {
diff --git a/go/vt/vttablet/tabletserver/throttle/check_result.go b/go/vt/vttablet/tabletserver/throttle/check_result.go
index 3c8852e4042..34532b7ce37 100644
--- a/go/vt/vttablet/tabletserver/throttle/check_result.go
+++ b/go/vt/vttablet/tabletserver/throttle/check_result.go
@@ -42,38 +42,78 @@ limitations under the License.
package throttle
import (
+ "fmt"
"net/http"
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base"
)
+// ResponseCodeFromStatus returns a ResponseCode based on either given response code or HTTP status code.
+// It is used to handle the transition period from v20 to v21 where v20 only returns HTTP status code.
+// In v22 and beyond, the HTTP status code will be removed, and so will this function.
+func ResponseCodeFromStatus(responseCode tabletmanagerdatapb.CheckThrottlerResponseCode, statusCode int) tabletmanagerdatapb.CheckThrottlerResponseCode {
+ if responseCode != tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED {
+ return responseCode
+ }
+ switch statusCode {
+ case http.StatusOK:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_OK
+ case http.StatusExpectationFailed:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED
+ case http.StatusTooManyRequests:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED
+ case http.StatusNotFound:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC
+ case http.StatusInternalServerError:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_INTERNAL_ERROR
+ default:
+ return tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED
+ }
+}
+
type MetricResult struct {
- StatusCode int `json:"StatusCode"`
- Scope string `json:"Scope"`
- Value float64 `json:"Value"`
- Threshold float64 `json:"Threshold"`
- Error error `json:"-"`
- Message string `json:"Message"`
+ ResponseCode tabletmanagerdatapb.CheckThrottlerResponseCode `json:"ResponseCode"`
+ StatusCode int `json:"StatusCode"`
+ Scope string `json:"Scope"`
+ Value float64 `json:"Value"`
+ Threshold float64 `json:"Threshold"`
+ Error error `json:"-"`
+ Message string `json:"Message"`
+ AppName string `json:"AppName"`
+}
+
+func (m *MetricResult) IsOK() bool {
+ if m.ResponseCode != tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED {
+ return m.ResponseCode == tabletmanagerdatapb.CheckThrottlerResponseCode_OK
+ }
+ return m.StatusCode == http.StatusOK
}
// CheckResult is the result for an app inquiring on a metric. It also exports as JSON via the API
type CheckResult struct {
- StatusCode int `json:"StatusCode"`
- Value float64 `json:"Value"`
- Threshold float64 `json:"Threshold"`
- Error error `json:"-"`
- Message string `json:"Message"`
- RecentlyChecked bool `json:"RecentlyChecked"`
- Metrics map[string]*MetricResult `json:"Metrics"` // New in multi-metrics support. Will eventually replace the above fields.
+ ResponseCode tabletmanagerdatapb.CheckThrottlerResponseCode `json:"ResponseCode"`
+ StatusCode int `json:"StatusCode"`
+ Value float64 `json:"Value"`
+ Threshold float64 `json:"Threshold"`
+ Error error `json:"-"`
+ Message string `json:"Message"`
+ RecentlyChecked bool `json:"RecentlyChecked"`
+ AppName string `json:"AppName"`
+ MetricName string `json:"MetricName"`
+ Scope string `json:"Scope"`
+ Metrics map[string]*MetricResult `json:"Metrics"` // New in multi-metrics support. Will eventually replace the above fields.
}
// NewCheckResult returns a CheckResult
-func NewCheckResult(statusCode int, value float64, threshold float64, err error) *CheckResult {
+func NewCheckResult(responseCode tabletmanagerdatapb.CheckThrottlerResponseCode, statusCode int, value float64, threshold float64, appName string, err error) *CheckResult {
result := &CheckResult{
- StatusCode: statusCode,
- Value: value,
- Threshold: threshold,
- Error: err,
+ ResponseCode: responseCode,
+ StatusCode: statusCode,
+ Value: value,
+ Threshold: threshold,
+ AppName: appName,
+ Error: err,
}
if err != nil {
result.Message = err.Error()
@@ -82,17 +122,38 @@ func NewCheckResult(statusCode int, value float64, threshold float64, err error)
}
func (c *CheckResult) IsOK() bool {
+ if c.ResponseCode != tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED {
+ return c.ResponseCode == tabletmanagerdatapb.CheckThrottlerResponseCode_OK
+ }
return c.StatusCode == http.StatusOK
}
+// Summary returns a human-readable summary of the check result
+func (c *CheckResult) Summary() string {
+ switch ResponseCodeFromStatus(c.ResponseCode, c.StatusCode) {
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_OK:
+ return fmt.Sprintf("%s is granted access", c.AppName)
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED:
+ return fmt.Sprintf("%s is explicitly denied access", c.AppName)
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_INTERNAL_ERROR:
+ return fmt.Sprintf("%s is denied access due to unexpected error: %v", c.AppName, c.Error)
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED:
+ return fmt.Sprintf("%s is denied access due to %s/%s metric value %v exceeding threshold %v", c.AppName, c.Scope, c.MetricName, c.Value, c.Threshold)
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC:
+ return fmt.Sprintf("%s is denied access due to unknown or uncollected metric", c.AppName)
+ case tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED:
+ return ""
+ default:
+ return fmt.Sprintf("unknown response code: %v", c.ResponseCode)
+ }
+}
+
// NewErrorCheckResult returns a check result that indicates an error
-func NewErrorCheckResult(statusCode int, err error) *CheckResult {
- return NewCheckResult(statusCode, 0, 0, err)
+func NewErrorCheckResult(responseCode tabletmanagerdatapb.CheckThrottlerResponseCode, statusCode int, err error) *CheckResult {
+ return NewCheckResult(responseCode, statusCode, 0, 0, "", err)
}
// NoSuchMetricCheckResult is a result returns when a metric is unknown
-var NoSuchMetricCheckResult = NewErrorCheckResult(http.StatusNotFound, base.ErrNoSuchMetric)
-
-var okMetricCheckResult = NewCheckResult(http.StatusOK, 0, 0, nil)
+var NoSuchMetricCheckResult = NewErrorCheckResult(tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC, http.StatusNotFound, base.ErrNoSuchMetric)
-var invalidCheckTypeCheckResult = NewErrorCheckResult(http.StatusInternalServerError, base.ErrInvalidCheckType)
+var okMetricCheckResult = NewCheckResult(tabletmanagerdatapb.CheckThrottlerResponseCode_OK, http.StatusOK, 0, 0, "", nil)
diff --git a/go/vt/vttablet/tabletserver/throttle/check_result_test.go b/go/vt/vttablet/tabletserver/throttle/check_result_test.go
new file mode 100644
index 00000000000..fdb0ee600ba
--- /dev/null
+++ b/go/vt/vttablet/tabletserver/throttle/check_result_test.go
@@ -0,0 +1,143 @@
+/*
+Copyright 2024 The Vitess Authors.
+
+Licensed 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 throttle
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
+)
+
+func TestReponseCodeFromStatus(t *testing.T) {
+ tcases := []struct {
+ responseCode tabletmanagerdatapb.CheckThrottlerResponseCode
+ statusCode int
+ expect tabletmanagerdatapb.CheckThrottlerResponseCode
+ }{
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED,
+ http.StatusOK,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED,
+ http.StatusExpectationFailed,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED,
+ http.StatusNotFound,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNKNOWN_METRIC,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED,
+ http.StatusInternalServerError,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_INTERNAL_ERROR,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_UNDEFINED,
+ http.StatusTooManyRequests,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ http.StatusTooManyRequests,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ },
+ {
+ tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ http.StatusOK,
+ tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run("", func(t *testing.T) {
+ result := ResponseCodeFromStatus(tcase.responseCode, tcase.statusCode)
+ assert.Equal(t, tcase.expect, result)
+ })
+ }
+}
+
+func TestCheckResultSummary(t *testing.T) {
+ tcases := []struct {
+ checkResult *CheckResult
+ summary string
+ }{
+ {
+ checkResult: &CheckResult{},
+ summary: "",
+ },
+ {
+ checkResult: &CheckResult{
+ StatusCode: http.StatusOK,
+ AppName: "test",
+ },
+ summary: "test is granted access",
+ },
+ {
+ checkResult: &CheckResult{
+ StatusCode: http.StatusTooManyRequests,
+ AppName: "test",
+ MetricName: "bugginess",
+ Threshold: 100,
+ Value: 200,
+ Scope: "self",
+ },
+ summary: "test is denied access due to self/bugginess metric value 200 exceeding threshold 100",
+ },
+ {
+ checkResult: &CheckResult{
+ StatusCode: http.StatusExpectationFailed,
+ AppName: "test",
+ },
+ summary: "test is explicitly denied access",
+ },
+ {
+ checkResult: &CheckResult{
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ AppName: "test",
+ },
+ summary: "test is granted access",
+ },
+ {
+ checkResult: &CheckResult{
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_THRESHOLD_EXCEEDED,
+ AppName: "test",
+ MetricName: "bugginess",
+ Threshold: 100,
+ Value: 200,
+ Scope: "self",
+ },
+ summary: "test is denied access due to self/bugginess metric value 200 exceeding threshold 100",
+ },
+ {
+ checkResult: &CheckResult{
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_APP_DENIED,
+ AppName: "test",
+ },
+ summary: "test is explicitly denied access",
+ },
+ }
+ for _, tcase := range tcases {
+ t.Run(tcase.summary, func(t *testing.T) {
+ assert.Equal(t, tcase.summary, tcase.checkResult.Summary())
+ })
+ }
+}
diff --git a/go/vt/vttablet/tabletserver/throttle/client.go b/go/vt/vttablet/tabletserver/throttle/client.go
index e8eed627e04..8549fb099b6 100644
--- a/go/vt/vttablet/tabletserver/throttle/client.go
+++ b/go/vt/vttablet/tabletserver/throttle/client.go
@@ -18,7 +18,6 @@ package throttle
import (
"context"
- "net/http"
"sync"
"sync/atomic"
"time"
@@ -31,8 +30,11 @@ const (
throttleCheckDuration = 250 * time.Millisecond
)
-var throttleTicks int64
-var throttleInit sync.Once
+var (
+ throttleTicks int64
+ throttleInit sync.Once
+ emptyCheckResult = &CheckResult{}
+)
func initThrottleTicker() {
throttleInit.Do(func() {
@@ -87,14 +89,14 @@ func (c *Client) clearSuccessfulResultsCache() {
// The function caches results for a brief amount of time, hence it's safe and efficient to
// be called very frequently.
// The function is not thread safe.
-func (c *Client) ThrottleCheckOK(ctx context.Context, overrideAppName throttlerapp.Name) (throttleCheckOK bool) {
+func (c *Client) ThrottleCheckOK(ctx context.Context, overrideAppName throttlerapp.Name) (checkResult *CheckResult, throttleCheckOK bool) {
if c == nil {
// no client
- return true
+ return emptyCheckResult, true
}
if c.throttler == nil {
// no throttler
- return true
+ return emptyCheckResult, true
}
checkApp := c.appName
if overrideAppName != "" {
@@ -104,20 +106,20 @@ func (c *Client) ThrottleCheckOK(ctx context.Context, overrideAppName throttlera
defer c.lastSuccessfulThrottleMu.Unlock()
if c.lastSuccessfulThrottle[checkApp.String()] >= atomic.LoadInt64(&throttleTicks) {
// if last check was OK just very recently there is no need to check again
- return true
+ return emptyCheckResult, true
}
// It's time to run a throttler check
- checkResult := c.throttler.Check(ctx, checkApp.String(), nil, &c.flags)
- if checkResult.StatusCode != http.StatusOK {
- return false
+ checkResult = c.throttler.Check(ctx, checkApp.String(), nil, &c.flags)
+ if !checkResult.IsOK() {
+ return checkResult, false
}
for _, metricResult := range checkResult.Metrics {
- if metricResult.StatusCode != http.StatusOK {
- return false
+ if !metricResult.IsOK() {
+ return checkResult, false
}
}
c.lastSuccessfulThrottle[checkApp.String()] = atomic.LoadInt64(&throttleTicks)
- return true
+ return checkResult, true
}
@@ -125,22 +127,23 @@ func (c *Client) ThrottleCheckOK(ctx context.Context, overrideAppName throttlera
// otherwise it briefly sleeps and returns 'false'.
// Non-empty appName overrides the default appName.
// The function is not thread safe.
-func (c *Client) ThrottleCheckOKOrWaitAppName(ctx context.Context, appName throttlerapp.Name) bool {
- if c.ThrottleCheckOK(ctx, appName) {
- return true
+func (c *Client) ThrottleCheckOKOrWaitAppName(ctx context.Context, appName throttlerapp.Name) (checkResult *CheckResult, throttleCheckOK bool) {
+ checkResult, throttleCheckOK = c.ThrottleCheckOK(ctx, appName)
+ if throttleCheckOK {
+ return checkResult, true
}
if ctx.Err() != nil {
// context expired, skip sleeping
- return false
+ return checkResult, false
}
time.Sleep(throttleCheckDuration)
- return false
+ return checkResult, false
}
// ThrottleCheckOKOrWait checks the throttler; if throttler is satisfied, the function returns 'true' immediately,
// otherwise it briefly sleeps and returns 'false'.
// The function is not thread safe.
-func (c *Client) ThrottleCheckOKOrWait(ctx context.Context) bool {
+func (c *Client) ThrottleCheckOKOrWait(ctx context.Context) (checkResult *CheckResult, throttleCheckOK bool) {
return c.ThrottleCheckOKOrWaitAppName(ctx, "")
}
@@ -148,7 +151,10 @@ func (c *Client) ThrottleCheckOKOrWait(ctx context.Context) bool {
// The function sleeps between throttle checks.
// The function is not thread safe.
func (c *Client) Throttle(ctx context.Context) {
- for !c.ThrottleCheckOKOrWait(ctx) {
+ for {
+ if _, ok := c.ThrottleCheckOKOrWait(ctx); ok {
+ return
+ }
// The function incorporates a bit of sleep so this is not a busy wait.
}
}
diff --git a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go
index d4beb40deb4..76d5f2dd298 100644
--- a/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go
+++ b/go/vt/vttablet/tabletserver/throttle/config/mysql_config.go
@@ -41,32 +41,15 @@ limitations under the License.
package config
-import (
- "sync/atomic"
-
- "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base"
-)
-
//
// MySQL-specific configuration
//
-type MySQLMetricConfigurationSettings struct {
- Name base.MetricName
- CustomQuery string
- Threshold atomic.Uint64
-}
-
// MySQLConfigurationSettings has the general configuration for all MySQL clusters
type MySQLConfigurationSettings struct {
- CacheMillis int // optional, if defined then probe result will be cached, and future probes may use cached value
- Port int // Specify if different than 3306; applies to all clusters
- IgnoreDialTCPErrors bool // Skip hosts where a metric cannot be retrieved due to TCP dial errors
- IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds
- IgnoreHostsThreshold float64 // Threshold beyond which IgnoreHostsCount applies (default: 0)
- HTTPCheckPort int // port for HTTP check. -1 to disable.
- HTTPCheckPath string // If non-empty, requires HTTPCheckPort
- IgnoreHosts []string // If non empty, substrings to indicate hosts to be ignored/skipped
-
- Metrics map[base.MetricName]*MySQLMetricConfigurationSettings
+ CacheMillis int // optional, if defined then probe result will be cached, and future probes may use cached value
+ Port int // Specify if different than 3306; applies to all clusters
+ IgnoreDialTCPErrors bool // Skip hosts where a metric cannot be retrieved due to TCP dial errors
+ IgnoreHostsCount int // Number of hosts that can be skipped/ignored even on error or on exceeding thresholds
+ IgnoreHosts []string // If non empty, substrings to indicate hosts to be ignored/skipped
}
diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go
index 73458974dcb..5cd56460713 100644
--- a/go/vt/vttablet/tabletserver/throttle/throttler.go
+++ b/go/vt/vttablet/tabletserver/throttle/throttler.go
@@ -42,15 +42,12 @@ limitations under the License.
package throttle
import (
- "bufio"
"context"
"errors"
"fmt"
"math"
"math/rand/v2"
"net/http"
- "os"
- "strconv"
"strings"
"sync"
"sync/atomic"
@@ -59,17 +56,13 @@ import (
"github.com/patrickmn/go-cache"
"github.com/spf13/pflag"
- "vitess.io/vitess/go/constants/sidecar"
"vitess.io/vitess/go/protoutil"
"vitess.io/vitess/go/stats"
"vitess.io/vitess/go/textutil"
"vitess.io/vitess/go/timer"
"vitess.io/vitess/go/vt/log"
- tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
- topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/servenv"
- "vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/srvtopo"
"vitess.io/vitess/go/vt/topo"
"vitess.io/vitess/go/vt/topo/topoproto"
@@ -80,6 +73,9 @@ import (
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/config"
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp"
"vitess.io/vitess/go/vt/vttablet/tmclient"
+
+ tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
+ topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)
const (
@@ -107,14 +103,6 @@ const (
var (
throttleTabletTypes = "replica"
-
- defaultThresholds = map[base.MetricName]float64{
- base.DefaultMetricName: 5 * time.Second.Seconds(),
- base.LagMetricName: 5 * time.Second.Seconds(),
- base.ThreadsRunningMetricName: 100,
- base.CustomMetricName: 0,
- base.LoadAvgMetricName: 1.0,
- }
)
var (
@@ -186,7 +174,6 @@ type Throttler struct {
inventory *base.Inventory
- metricsQuery atomic.Value
customMetricsQuery atomic.Value
MetricsThreshold atomic.Uint64
checkAsCheckSelf atomic.Bool
@@ -205,10 +192,6 @@ type Throttler struct {
throttledAppsMutex sync.Mutex
readSelfThrottleMetrics func(context.Context) base.ThrottleMetrics // overwritten by unit test
-
- httpClient *http.Client
-
- hostCpuCoreCount atomic.Int32
}
// ThrottlerStatus published some status values from the throttler
@@ -263,7 +246,6 @@ func NewThrottler(env tabletenv.Env, srvTopoServer srvtopo.Server, ts *topo.Serv
throttler.metricsHealth = cache.New(cache.NoExpiration, 0)
throttler.appCheckedMetrics = cache.New(cache.NoExpiration, 0)
- throttler.httpClient = base.SetupHTTPClient(2 * activeCollectInterval)
throttler.initThrottleTabletTypes()
throttler.check = NewThrottlerCheck(throttler)
@@ -280,11 +262,10 @@ func NewThrottler(env tabletenv.Env, srvTopoServer srvtopo.Server, ts *topo.Serv
throttler.recentCheckDiff = 1
}
- throttler.StoreMetricsThreshold(defaultThresholds[base.LagMetricName])
+ throttler.StoreMetricsThreshold(base.RegisteredSelfMetrics[base.LagMetricName].DefaultThreshold())
throttler.readSelfThrottleMetrics = func(ctx context.Context) base.ThrottleMetrics {
return throttler.readSelfThrottleMetricsInternal(ctx)
}
-
return throttler
}
@@ -315,7 +296,14 @@ func (throttler *Throttler) InitDBConfig(keyspace, shard string) {
}
func (throttler *Throttler) GetMetricsQuery() string {
- return throttler.metricsQuery.Load().(string)
+ if customQuery := throttler.GetCustomMetricsQuery(); customQuery != "" {
+ return customQuery
+ }
+ lagSelfMetric, ok := base.RegisteredSelfMetrics[base.LagMetricName].(*base.LagSelfMetric)
+ if !ok {
+ return ""
+ }
+ return lagSelfMetric.GetQuery()
}
func (throttler *Throttler) GetCustomMetricsQuery() string {
@@ -339,27 +327,6 @@ func (throttler *Throttler) initConfig() {
IgnoreDialTCPErrors: true,
},
}
- metrics := make(map[base.MetricName]*config.MySQLMetricConfigurationSettings)
- for _, metricsName := range base.KnownMetricNames {
- metrics[metricsName] = &config.MySQLMetricConfigurationSettings{
- Name: metricsName,
- }
- }
- metrics[base.DefaultMetricName].CustomQuery = ""
- metrics[base.DefaultMetricName].Threshold.Store(throttler.MetricsThreshold.Load())
-
- metrics[base.LagMetricName].CustomQuery = sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query
- metrics[base.LagMetricName].Threshold.Store(throttler.MetricsThreshold.Load())
-
- metrics[base.ThreadsRunningMetricName].CustomQuery = threadsRunningQuery
- metrics[base.ThreadsRunningMetricName].Threshold.Store(math.Float64bits(defaultThresholds[base.ThreadsRunningMetricName]))
-
- metrics[base.CustomMetricName].CustomQuery = ""
- metrics[base.CustomMetricName].Threshold.Store(math.Float64bits(defaultThresholds[base.CustomMetricName]))
-
- metrics[base.LoadAvgMetricName].Threshold.Store(math.Float64bits(defaultThresholds[base.LoadAvgMetricName]))
-
- throttler.configSettings.MySQLStore.Metrics = metrics
}
// readThrottlerConfig proactively reads the throttler's config from SrvKeyspace in local topo
@@ -388,7 +355,7 @@ func (throttler *Throttler) normalizeThrottlerConfig(throttlerConfig *topodatapb
if throttlerConfig.CustomQuery == "" {
// no custom query; we check replication lag
if throttlerConfig.Threshold == 0 {
- throttlerConfig.Threshold = defaultThresholds[base.LagMetricName]
+ throttlerConfig.Threshold = base.RegisteredSelfMetrics[base.LagMetricName].DefaultThreshold()
}
}
return throttlerConfig
@@ -442,11 +409,6 @@ func (throttler *Throttler) convergeMetricThresholds() {
// Note: you should be holding the initMutex when calling this function.
func (throttler *Throttler) applyThrottlerConfig(ctx context.Context, throttlerConfig *topodatapb.ThrottlerConfig) {
log.Infof("Throttler: applying topo config: %+v", throttlerConfig)
- if throttlerConfig.CustomQuery == "" {
- throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query)
- } else {
- throttler.metricsQuery.Store(throttlerConfig.CustomQuery)
- }
throttler.customMetricsQuery.Store(throttlerConfig.CustomQuery)
if throttlerConfig.Threshold > 0 || throttlerConfig.CustomQuery != "" {
// We do not allow Threshold=0, unless there is a custom query.
@@ -646,10 +608,6 @@ func (throttler *Throttler) Open() error {
log.Infof("Throttler: opening")
var ctx context.Context
ctx, throttler.cancelOpenContext = context.WithCancel(context.Background())
- // The query needs to be dynamically built because the sidecar database name
- // is not known when the TabletServer is created, which in turn creates the
- // Throttler.
- throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query) // default
throttler.customMetricsQuery.Store("")
throttler.initConfig()
throttler.pool.Open(throttler.env.Config().DB.AppWithDB(), throttler.env.Config().DB.DbaWithDB(), throttler.env.Config().DB.AppDebugWithDB())
@@ -726,99 +684,6 @@ func (throttler *Throttler) stimulatePrimaryThrottler(ctx context.Context, tmCli
return nil
}
-func (throttler *Throttler) readSelfLoadAvgPerCore(ctx context.Context) *base.ThrottleMetric {
- metric := &base.ThrottleMetric{
- Scope: base.SelfScope,
- Alias: throttler.tabletAlias,
- }
-
- coreCount := throttler.hostCpuCoreCount.Load()
- if coreCount == 0 {
- // Count cores. This number is not going to change in the lifetime of this tablet,
- // hence it makes sense to read it once then cache it.
-
- // We choose to read /proc/cpuinfo over executing "nproc" or similar commands.
- var coreCount int32
- f, err := os.Open("/proc/cpuinfo")
- if err != nil {
- return metric.WithError(err)
- }
- defer f.Close()
-
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- if strings.HasPrefix(scanner.Text(), "processor") {
- coreCount++
- }
- }
-
- if err := scanner.Err(); err != nil {
- return metric.WithError(err)
- }
- throttler.hostCpuCoreCount.Store(coreCount)
- }
- if coreCount == 0 {
- return metric.WithError(fmt.Errorf("could not determine number of cores"))
- }
- {
- content, err := os.ReadFile("/proc/loadavg")
- if err != nil {
- return metric.WithError(err)
- }
- fields := strings.Fields(string(content))
- if len(fields) == 0 {
- return metric.WithError(fmt.Errorf("unexpected /proc/loadavg content"))
- }
- loadAvg, err := strconv.ParseFloat(fields[0], 64)
- if err != nil {
- return metric.WithError(err)
- }
- metric.Value = loadAvg / float64(throttler.hostCpuCoreCount.Load())
- }
- return metric
-}
-
-// readSelfMySQLThrottleMetric reads the metric from this very tablet or from its backend mysql.
-func (throttler *Throttler) readSelfMySQLThrottleMetric(ctx context.Context, query string) *base.ThrottleMetric {
- metric := &base.ThrottleMetric{
- Scope: base.SelfScope,
- Alias: throttler.tabletAlias,
- }
- if query == "" {
- return metric
- }
- conn, err := throttler.pool.Get(ctx, nil)
- if err != nil {
- return metric.WithError(err)
- }
- defer conn.Recycle()
-
- tm, err := conn.Conn.Exec(ctx, query, 1, true)
- if err != nil {
- return metric.WithError(err)
- }
- row := tm.Named().Row()
- if row == nil {
- return metric.WithError(fmt.Errorf("no results for readSelfThrottleMetric"))
- }
-
- metricsQueryType := base.GetMetricsQueryType(query)
- switch metricsQueryType {
- case base.MetricsQueryTypeSelect:
- // We expect a single row, single column result.
- // The "for" iteration below is just a way to get first result without knowing column name
- for k := range row {
- metric.Value, metric.Err = row.ToFloat64(k)
- }
- case base.MetricsQueryTypeShowGlobal:
- metric.Value, metric.Err = strconv.ParseFloat(row["Value"].ToString(), 64)
- default:
- metric.Err = fmt.Errorf("Unsupported metrics query type for query: %s", throttler.GetMetricsQuery())
- }
-
- return metric
-}
-
// throttledAppsSnapshot returns a snapshot (a copy) of current throttled apps
func (throttler *Throttler) throttledAppsSnapshot() map[string]cache.Item {
return throttler.throttledApps.Items()
@@ -878,6 +743,7 @@ func (throttler *Throttler) Operate(ctx context.Context, wg *sync.WaitGroup) {
primaryStimulatorRateLimiter.Stop()
throttler.aggregatedMetrics.Flush()
throttler.recentApps.Flush()
+ clear(throttler.inventory.TabletMetrics)
}()
// we do not flush throttler.throttledApps because this is data submitted by the user; the user expects the data to survive a disable+enable
@@ -977,7 +843,7 @@ func (throttler *Throttler) Operate(ctx context.Context, wg *sync.WaitGroup) {
}
case probes := <-throttler.clusterProbesChan:
// incoming structural update, sparse, as result of refreshInventory()
- throttler.updateClusterProbes(ctx, probes)
+ throttler.updateClusterProbes(probes)
case <-metricsAggregateTicker.C:
if throttler.IsOpen() {
throttler.aggregateMetrics()
@@ -1031,8 +897,11 @@ func (throttler *Throttler) generateTabletProbeFunction(scope base.Scope, tmClie
return metricsWithError(fmt.Errorf("gRPC error accessing tablet %v. Err=%v", probe.Alias, gRPCErr))
}
throttleMetric.Value = resp.Value
+ if resp.ResponseCode == tabletmanagerdatapb.CheckThrottlerResponseCode_INTERNAL_ERROR {
+ throttleMetric.Err = fmt.Errorf("response code: %d", resp.ResponseCode)
+ }
if resp.StatusCode == http.StatusInternalServerError {
- throttleMetric.Err = fmt.Errorf("Status code: %d", resp.StatusCode)
+ throttleMetric.Err = fmt.Errorf("status code: %d", resp.StatusCode)
}
if resp.RecentlyChecked {
// We have just probed a tablet, and it reported back that someone just recently "check"ed it.
@@ -1062,22 +931,40 @@ func (throttler *Throttler) generateTabletProbeFunction(scope base.Scope, tmClie
}
}
+// readSelfThrottleMetricsInternal rreads all registsred self metrics on this tablet (or backend MySQL server).
+// This is the actual place where metrics are read, to be later aggregated and/or propagated to other tablets.
func (throttler *Throttler) readSelfThrottleMetricsInternal(ctx context.Context) base.ThrottleMetrics {
-
- writeMetric := func(metricName base.MetricName, metric *base.ThrottleMetric) {
- metric.Name = metricName
+ result := make(base.ThrottleMetrics, len(base.RegisteredSelfMetrics))
+ writeMetric := func(metric *base.ThrottleMetric) {
select {
case <-ctx.Done():
return
case throttler.throttleMetricChan <- metric:
}
}
+ readMetric := func(selfMetric base.SelfMetric) *base.ThrottleMetric {
+ if !selfMetric.RequiresConn() {
+ return selfMetric.Read(ctx, throttler, nil)
+ }
+ conn, err := throttler.pool.Get(ctx, nil)
+ if err != nil {
+ return &base.ThrottleMetric{Err: err}
+ }
+ defer conn.Recycle()
+ return selfMetric.Read(ctx, throttler, conn.Conn)
+ }
+ for metricName, selfMetric := range base.RegisteredSelfMetrics {
+ if metricName == base.DefaultMetricName {
+ continue
+ }
+ metric := readMetric(selfMetric)
+ metric.Name = metricName
+ metric.Alias = throttler.tabletAlias
- go writeMetric(base.LagMetricName, throttler.readSelfMySQLThrottleMetric(ctx, sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query))
- go writeMetric(base.ThreadsRunningMetricName, throttler.readSelfMySQLThrottleMetric(ctx, threadsRunningQuery))
- go writeMetric(base.CustomMetricName, throttler.readSelfMySQLThrottleMetric(ctx, throttler.GetCustomMetricsQuery()))
- go writeMetric(base.LoadAvgMetricName, throttler.readSelfLoadAvgPerCore(ctx))
- return nil
+ go writeMetric(metric)
+ result[metricName] = metric
+ }
+ return result
}
func (throttler *Throttler) collectSelfMetrics(ctx context.Context) {
@@ -1169,21 +1056,19 @@ func (throttler *Throttler) refreshInventory(ctx context.Context) error {
}
}
- metricsThreshold := throttler.MetricsThreshold.Load()
metricNameUsedAsDefault := throttler.metricNameUsedAsDefault()
- mysqlSettings := &throttler.configSettings.MySQLStore
- mysqlSettings.Metrics[base.DefaultMetricName].Threshold.Store(metricsThreshold)
- for metricName, metricConfig := range mysqlSettings.Metrics {
- threshold := metricConfig.Threshold.Load()
- if metricName == metricNameUsedAsDefault && metricsThreshold != 0 {
+ metricsThreshold := throttler.GetMetricsThreshold()
+ for metricName, selfMetric := range base.RegisteredSelfMetrics {
+ threshold := selfMetric.DefaultThreshold()
+ if (metricName == metricNameUsedAsDefault || metricName == base.DefaultMetricName) && metricsThreshold != 0 {
// backwards compatibility to v20:
threshold = metricsThreshold
}
-
- throttler.metricThresholds.Set(inventoryPrefix+metricName.String(), math.Float64frombits(threshold), cache.DefaultExpiration)
+ throttler.metricThresholds.Set(inventoryPrefix+metricName.String(), threshold, cache.DefaultExpiration)
}
throttler.convergeMetricThresholds()
- clusterSettingsCopy := *mysqlSettings
+
+ var clusterSettingsCopy config.MySQLConfigurationSettings = throttler.configSettings.MySQLStore
// config may dynamically change, but internal structure (config.Settings().MySQLStore.Clusters in our case)
// is immutable and can only be _replaced_. Hence, it's safe to read in a goroutine:
collect := func() error {
@@ -1232,10 +1117,25 @@ func (throttler *Throttler) refreshInventory(ctx context.Context) error {
}
// synchronous update of inventory
-func (throttler *Throttler) updateClusterProbes(ctx context.Context, clusterProbes *base.ClusterProbes) error {
+func (throttler *Throttler) updateClusterProbes(clusterProbes *base.ClusterProbes) error {
throttler.inventory.ClustersProbes = clusterProbes.TabletProbes
throttler.inventory.IgnoreHostsCount = clusterProbes.IgnoreHostsCount
throttler.inventory.IgnoreHostsThreshold = clusterProbes.IgnoreHostsThreshold
+
+ for alias := range throttler.inventory.TabletMetrics {
+ if alias == "" {
+ // *this* tablet uses the empty alias to identify itself.
+ continue
+ }
+ if _, found := clusterProbes.TabletProbes[alias]; !found {
+ // There seems to be a metric stored for some alias, say zone1-0000000102,
+ // but there is no alias for this probe in the new clusterProbes. This
+ // suggests that the corresponding tablet has been removed, or its type was changed
+ // (e.g. from REPLICA to RDONLY). We should therefore remove this cached metric.
+ delete(throttler.inventory.TabletMetrics, alias)
+ }
+ }
+
return nil
}
@@ -1378,8 +1278,8 @@ func (throttler *Throttler) UnthrottleApp(appName string) (appThrottle *base.App
// IsAppThrottled tells whether some app should be throttled.
// Assuming an app is throttled to some extend, it will randomize the result based
// on the throttle ratio
-func (throttler *Throttler) IsAppThrottled(appName string) bool {
- appFound := false
+func (throttler *Throttler) IsAppThrottled(appName string) (bool, string) {
+ appFound := ""
isSingleAppNameThrottled := func(singleAppName string) bool {
object, found := throttler.throttledApps.Get(singleAppName)
if !found {
@@ -1392,7 +1292,7 @@ func (throttler *Throttler) IsAppThrottled(appName string) bool {
}
// From this point on, we consider that this app has some throttling configuration
// of any sort.
- appFound = true
+ appFound = singleAppName
if appThrottle.Exempt {
return false
}
@@ -1403,32 +1303,32 @@ func (throttler *Throttler) IsAppThrottled(appName string) bool {
return false
}
if isSingleAppNameThrottled(appName) {
- return true
+ return true, appName
}
for _, singleAppName := range throttlerapp.Name(appName).SplitStrings() {
if singleAppName == "" {
continue
}
if isSingleAppNameThrottled(singleAppName) {
- return true
+ return true, singleAppName
}
}
// If app was found then there was some explicit throttle instruction for the app, and the app
// passed the test.
- if appFound {
- return false
+ if appFound != "" {
+ return false, appFound
}
// If the app was not found, ie no specific throttle instruction was found for the app, then
// the app should also consider the case where the "all" app is throttled.
if isSingleAppNameThrottled(throttlerapp.AllName.String()) {
// Means the "all" app is throttled. This is a special case, and it means "all apps are throttled"
- return true
+ return true, throttlerapp.AllName.String()
}
- return false
+ return false, appName
}
// IsAppExempt
-func (throttler *Throttler) IsAppExempted(appName string) bool {
+func (throttler *Throttler) IsAppExempted(appName string) (bool, string) {
isSingleAppNameExempted := func(singleAppName string) bool {
if throttlerapp.ExemptFromChecks(appName) { // well known statically exempted apps
return true
@@ -1448,22 +1348,24 @@ func (throttler *Throttler) IsAppExempted(appName string) bool {
return false
}
if isSingleAppNameExempted(appName) {
- return true
+ return true, appName
}
for _, singleAppName := range throttlerapp.Name(appName).SplitStrings() {
if singleAppName == "" {
continue
}
if isSingleAppNameExempted(singleAppName) {
- return true
+ return true, singleAppName
}
}
- if isSingleAppNameExempted(throttlerapp.AllName.String()) && !throttler.IsAppThrottled(appName) {
- return true
+ if isSingleAppNameExempted(throttlerapp.AllName.String()) {
+ if throttled, _ := throttler.IsAppThrottled(appName); !throttled {
+ return true, throttlerapp.AllName.String()
+ }
}
- return false
+ return false, appName
}
// ThrottledAppsMap returns a (copy) map of currently throttled apps
@@ -1478,8 +1380,8 @@ func (throttler *Throttler) ThrottledAppsMap() (result map[string](*base.AppThro
}
// markRecentApp takes note that an app has just asked about throttling, making it "recent"
-func (throttler *Throttler) markRecentApp(appName string, statusCode int) {
- recentApp := base.NewRecentApp(appName, statusCode)
+func (throttler *Throttler) markRecentApp(appName string, statusCode int, responseCode tabletmanagerdatapb.CheckThrottlerResponseCode) {
+ recentApp := base.NewRecentApp(appName, statusCode, responseCode)
throttler.recentApps.Set(appName, recentApp, cache.DefaultExpiration)
}
@@ -1517,14 +1419,16 @@ func (throttler *Throttler) metricsHealthSnapshot() base.MetricHealthMap {
}
// AppRequestMetricResult gets a metric result in the context of a specific app
-func (throttler *Throttler) AppRequestMetricResult(ctx context.Context, appName string, metricResultFunc base.MetricResultFunc, denyApp bool) (metricResult base.MetricResult, threshold float64) {
+func (throttler *Throttler) AppRequestMetricResult(ctx context.Context, appName string, metricResultFunc base.MetricResultFunc, denyApp bool) (metricResult base.MetricResult, threshold float64, matchedApp string) {
if denyApp {
- return base.AppDeniedMetric, 0
+ return base.AppDeniedMetric, 0, appName
}
- if throttler.IsAppThrottled(appName) {
- return base.AppDeniedMetric, 0
+ throttled, matchedApp := throttler.IsAppThrottled(appName)
+ if throttled {
+ return base.AppDeniedMetric, 0, matchedApp
}
- return metricResultFunc()
+ metricResult, threshold = metricResultFunc()
+ return metricResult, threshold, matchedApp
}
// checkScope checks the aggregated value of given store
@@ -1532,12 +1436,15 @@ func (throttler *Throttler) checkScope(ctx context.Context, appName string, scop
if !throttler.IsRunning() {
return okMetricCheckResult
}
- if throttler.IsAppExempted(appName) {
+ if exempted, matchedApp := throttler.IsAppExempted(appName); exempted {
// Some apps are exempt from checks. They are always responded with OK. This is because those apps are
// continuous and do not generate a substantial load.
- return okMetricCheckResult
+ result := okMetricCheckResult
+ result.AppName = matchedApp
+ return result
}
+ matchedApp := appName
if len(metricNames) == 0 {
// No explicit metrics requested.
// Get the metric names mappd to the given app
@@ -1551,6 +1458,7 @@ func (throttler *Throttler) checkScope(ctx context.Context, appName string, scop
case []base.MetricName:
metricNames = append(metricNames, val...)
}
+ matchedApp = appToken
}
}
}
@@ -1564,17 +1472,20 @@ func (throttler *Throttler) checkScope(ctx context.Context, appName string, scop
case []base.MetricName:
metricNames = val
}
+ matchedApp = throttlerapp.AllName.String()
}
}
if throttlerapp.VitessName.Equals(appName) {
// "vitess" always checks all metrics, irrespective of what is mapped.
metricNames = base.KnownMetricNames
+ matchedApp = appName
}
if len(metricNames) == 0 {
// Nothing mapped? For backwards compatibility and as default, we use the "default" metric.
metricNames = base.MetricNames{throttler.metricNameUsedAsDefault()}
}
checkResult = throttler.check.Check(ctx, appName, scope, metricNames, flags)
+ checkResult.AppName = matchedApp
shouldRequestHeartbeats := !flags.SkipRequestHeartbeats
if throttlerapp.VitessName.Equals(appName) {
diff --git a/go/vt/vttablet/tabletserver/throttle/throttler_test.go b/go/vt/vttablet/tabletserver/throttle/throttler_test.go
index 6363143fd43..41036620a60 100644
--- a/go/vt/vttablet/tabletserver/throttle/throttler_test.go
+++ b/go/vt/vttablet/tabletserver/throttle/throttler_test.go
@@ -74,22 +74,27 @@ var (
}
replicaMetrics = map[string]*MetricResult{
base.LagMetricName.String(): {
- StatusCode: http.StatusOK,
- Value: 0.9,
+ StatusCode: http.StatusOK,
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ Value: 0.9,
},
base.ThreadsRunningMetricName.String(): {
- StatusCode: http.StatusOK,
- Value: 13,
+ StatusCode: http.StatusOK,
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ Value: 13,
},
base.CustomMetricName.String(): {
- StatusCode: http.StatusOK,
- Value: 14,
+ StatusCode: http.StatusOK,
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ Value: 14,
},
base.LoadAvgMetricName.String(): {
- StatusCode: http.StatusOK,
- Value: 5.1,
+ StatusCode: http.StatusOK,
+ ResponseCode: tabletmanagerdatapb.CheckThrottlerResponseCode_OK,
+ Value: 5.1,
},
}
+ nonPrimaryTabletType atomic.Int32
)
const (
@@ -116,14 +121,16 @@ func (c *fakeTMClient) CheckThrottler(ctx context.Context, tablet *topodatapb.Ta
RecentlyChecked: false,
}
if !c.v20.Load() {
+ resp.ResponseCode = tabletmanagerdatapb.CheckThrottlerResponseCode_OK
resp.Metrics = make(map[string]*tabletmanagerdatapb.CheckThrottlerResponse_Metric)
for name, metric := range replicaMetrics {
resp.Metrics[name] = &tabletmanagerdatapb.CheckThrottlerResponse_Metric{
- Name: name,
- StatusCode: int32(metric.StatusCode),
- Value: metric.Value,
- Threshold: metric.Threshold,
- Message: metric.Message,
+ Name: name,
+ StatusCode: int32(metric.StatusCode),
+ ResponseCode: metric.ResponseCode,
+ Value: metric.Value,
+ Threshold: metric.Threshold,
+ Message: metric.Message,
}
}
}
@@ -145,7 +152,11 @@ type FakeTopoServer struct {
func (ts *FakeTopoServer) GetTablet(ctx context.Context, alias *topodatapb.TabletAlias) (*topo.TabletInfo, error) {
tabletType := topodatapb.TabletType_PRIMARY
if alias.Uid != 100 {
- tabletType = topodatapb.TabletType_REPLICA
+ val := topodatapb.TabletType(nonPrimaryTabletType.Load())
+ if val == topodatapb.TabletType_UNKNOWN {
+ val = topodatapb.TabletType_REPLICA
+ }
+ tabletType = val
}
tablet := &topo.TabletInfo{
Tablet: &topodatapb.Tablet{
@@ -241,7 +252,8 @@ func newTestThrottler() *Throttler {
tabletTypeFunc: func() topodatapb.TabletType { return topodatapb.TabletType_PRIMARY },
overrideTmClient: &fakeTMClient{},
}
- throttler.metricsQuery.Store(metricsQuery)
+ lagSelfMetric := base.RegisteredSelfMetrics[base.LagMetricName].(*base.LagSelfMetric)
+ lagSelfMetric.SetQuery(metricsQuery)
throttler.MetricsThreshold.Store(math.Float64bits(0.75))
throttler.configSettings = config.NewConfigurationSettings()
throttler.initConfig()
@@ -417,7 +429,9 @@ func TestApplyThrottlerConfigMetricThresholds(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
t.Run("apply low threshold", func(t *testing.T) {
assert.Equal(t, 0.75, throttler.GetMetricsThreshold())
@@ -439,7 +453,9 @@ func TestApplyThrottlerConfigMetricThresholds(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value, "unexpected result: %+v", checkResult) // self lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to self/lag metric value")
})
t.Run("apply low threshold but high 'lag' override", func(t *testing.T) {
throttlerConfig := &topodatapb.ThrottlerConfig{
@@ -462,7 +478,9 @@ func TestApplyThrottlerConfigMetricThresholds(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value, "unexpected result: %+v", checkResult) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
@@ -519,7 +537,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to shard/lag metric value")
})
t.Run("apply high lag threshold", func(t *testing.T) {
throttlerConfig.Threshold = 4444.0
@@ -533,7 +553,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
t.Run("apply low 'loadavg' threshold", func(t *testing.T) {
@@ -547,7 +569,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
t.Run("assign 'loadavg' to test app", func(t *testing.T) {
@@ -565,7 +589,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 2.718, checkResult.Value) // self loadavg value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to self/loadavg metric value")
})
})
t.Run("assign 'shard/loadavg' to test app", func(t *testing.T) {
@@ -583,7 +609,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 5.1, checkResult.Value) // shard loadavg value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to shard/loadavg metric value")
})
})
t.Run("assign 'lag,loadavg' to test app", func(t *testing.T) {
@@ -600,7 +628,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 2.718, checkResult.Value) // self loadavg value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to self/loadavg metric value")
})
})
t.Run("assign 'lag,shard/loadavg' to test app", func(t *testing.T) {
@@ -617,7 +647,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 5.1, checkResult.Value) // shard loadavg value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to shard/loadavg metric value")
})
})
t.Run("clear 'loadavg' threshold", func(t *testing.T) {
@@ -630,7 +662,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 1, len(checkResult.Metrics), "unexpected metrics: %+v", checkResult.Metrics)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
t.Run("assign 'lag,threads_running' to test app", func(t *testing.T) {
@@ -647,7 +681,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
t.Run("assign 'custom,loadavg' to 'all' app", func(t *testing.T) {
@@ -664,7 +700,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 2.718, checkResult.Value) // loadavg self value exceeds threshold
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), throttlerapp.AllName.String()+" is denied access due to self/loadavg metric value")
})
t.Run("check 'test' after assignment", func(t *testing.T) {
// "test" app unaffected by 'all' assignment, because it has
@@ -678,7 +716,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
t.Run("'online-ddl' app affected by 'all'", func(t *testing.T) {
// "online-ddl" app is affected by 'all' assignment, because it has
@@ -691,7 +731,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 2.718, checkResult.Value) // loadavg self value exceeds threshold
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), throttlerapp.AllName.String()+" is denied access due to self/loadavg metric value")
})
})
t.Run("'vreplication:online-ddl:12345' app affected by 'all'", func(t *testing.T) {
@@ -701,7 +743,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 2.718, checkResult.Value) // loadavg self value exceeds threshold
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), throttlerapp.AllName.String()+" is denied access due to self/loadavg metric value")
})
t.Run("'vreplication:online-ddl:test' app affected by 'test' and not by 'all'", func(t *testing.T) {
// "vreplication:online-ddl:test" app is affected by 'test' assignment, because it has
@@ -710,7 +754,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
t.Run("deassign metrics from 'all' app", func(t *testing.T) {
delete(throttlerConfig.AppCheckedMetrics, throttlerapp.AllName.String())
@@ -724,7 +770,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), throttlerapp.AllName.String()+" is granted access")
})
t.Run("check 'test' after assignment", func(t *testing.T) {
// "test" app unaffected by the entire 'all' assignment, because it has
@@ -738,7 +786,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, 2, len(checkResult.Metrics))
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
t.Run("'online-ddl' no longer has 'all' impact", func(t *testing.T) {
// "online-ddl" app is affected by 'all' assignment, because it has
@@ -751,7 +801,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), throttlerapp.OnlineDDLName.String()+" is granted access")
})
})
@@ -767,7 +819,9 @@ func TestApplyThrottlerConfigAppCheckedMetrics(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is granted access")
})
})
@@ -790,10 +844,26 @@ func TestIsAppThrottled(t *testing.T) {
heartbeatWriter: &FakeHeartbeatWriter{},
}
t.Run("initial", func(t *testing.T) {
- assert.False(t, throttler.IsAppThrottled("app1"))
- assert.False(t, throttler.IsAppThrottled("app2"))
- assert.False(t, throttler.IsAppThrottled("app3"))
- assert.False(t, throttler.IsAppThrottled("app4"))
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.False(t, throttled)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.False(t, throttled)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.False(t, throttled)
+ assert.Equal(t, "app3", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.False(t, throttled)
+ assert.Equal(t, "app4", app)
+ }
assert.Equal(t, 0, throttler.throttledApps.ItemCount())
})
@@ -803,11 +873,31 @@ func TestIsAppThrottled(t *testing.T) {
throttler.ThrottleApp("app2", time.Now(), DefaultThrottleRatio, false) // instantly expire
throttler.ThrottleApp("app3", plusOneHour, DefaultThrottleRatio, false)
throttler.ThrottleApp("app4", plusOneHour, 0, false)
- assert.False(t, throttler.IsAppThrottled("app1")) // exempted
- assert.False(t, throttler.IsAppThrottled("app2")) // expired
- assert.True(t, throttler.IsAppThrottled("app3"))
- assert.False(t, throttler.IsAppThrottled("app4")) // ratio is zero
- assert.False(t, throttler.IsAppThrottled("app_other")) // not specified
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.False(t, throttled) // exempted
+ assert.Equal(t, "app1", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.False(t, throttled) // expired
+ assert.Equal(t, "app2", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.True(t, throttled)
+ assert.Equal(t, "app3", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.False(t, throttled) // ratio is zero
+ assert.Equal(t, "app4", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app_other")
+ assert.False(t, throttled) // not specified
+ assert.Equal(t, "app_other", app)
+ }
assert.Equal(t, 3, throttler.throttledApps.ItemCount())
})
@@ -815,12 +905,36 @@ func TestIsAppThrottled(t *testing.T) {
// throttle "all", see how it affects app
throttler.ThrottleApp(throttlerapp.AllName.String(), plusOneHour, DefaultThrottleRatio, false)
defer throttler.UnthrottleApp(throttlerapp.AllName.String())
- assert.True(t, throttler.IsAppThrottled("all")) //
- assert.False(t, throttler.IsAppThrottled("app1")) // exempted
- assert.True(t, throttler.IsAppThrottled("app2")) // expired, so falls under "all"
- assert.True(t, throttler.IsAppThrottled("app3"))
- assert.False(t, throttler.IsAppThrottled("app4")) // ratio is zero, there is a specific instruction for this app, so it doesn't fall under "all"
- assert.True(t, throttler.IsAppThrottled("app_other")) // falls under "all"
+ {
+ throttled, app := throttler.IsAppThrottled("all")
+ assert.True(t, throttled) // explicitly throttled
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.False(t, throttled) // exempted
+ assert.Equal(t, "app1", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.True(t, throttled) // expired, so falls under "all"
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.True(t, throttled)
+ assert.Equal(t, "app3", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.False(t, throttled) // ratio is zero, there is a specific instruction for this app, so it doesn't fall under "all"
+ assert.Equal(t, "app4", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app_other")
+ assert.True(t, throttled) // falls under "all"
+ assert.Equal(t, "all", app)
+ }
// continuing previous test, we had 3 throttled apps. "all" is a new app being throttled.
assert.Equal(t, 4, throttler.throttledApps.ItemCount())
@@ -831,10 +945,27 @@ func TestIsAppThrottled(t *testing.T) {
throttler.UnthrottleApp("app2")
throttler.UnthrottleApp("app3")
throttler.UnthrottleApp("app4")
- assert.False(t, throttler.IsAppThrottled("app1"))
- assert.False(t, throttler.IsAppThrottled("app2"))
- assert.False(t, throttler.IsAppThrottled("app3"))
- assert.False(t, throttler.IsAppThrottled("app4"))
+
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.False(t, throttled)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.False(t, throttled)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.False(t, throttled)
+ assert.Equal(t, "app3", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.False(t, throttled)
+ assert.Equal(t, "app4", app)
+ }
// we've manually unthrottled everything
assert.Equal(t, 0, throttler.throttledApps.ItemCount())
@@ -843,12 +974,37 @@ func TestIsAppThrottled(t *testing.T) {
// throttle "all", see how it affects app
throttler.ThrottleApp(throttlerapp.AllName.String(), plusOneHour, DefaultThrottleRatio, false)
defer throttler.UnthrottleApp(throttlerapp.AllName.String())
- assert.True(t, throttler.IsAppThrottled("all"))
- assert.True(t, throttler.IsAppThrottled("app1"))
- assert.True(t, throttler.IsAppThrottled("app2"))
- assert.True(t, throttler.IsAppThrottled("app3"))
- assert.True(t, throttler.IsAppThrottled("app4"))
- assert.True(t, throttler.IsAppThrottled("app_other"))
+
+ {
+ throttled, app := throttler.IsAppThrottled("all")
+ assert.True(t, throttled) // explicitly throttled
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.True(t, throttled)
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.True(t, throttled)
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.True(t, throttled)
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.True(t, throttled)
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app_other")
+ assert.True(t, throttled)
+ assert.Equal(t, "all", app)
+ }
// one rule, for "all" app
assert.Equal(t, 1, throttler.throttledApps.ItemCount())
@@ -858,43 +1014,120 @@ func TestIsAppThrottled(t *testing.T) {
throttler.ThrottleApp("app3", plusOneHour, DefaultThrottleRatio, false)
throttler.ThrottleApp(throttlerapp.AllName.String(), plusOneHour, DefaultThrottleRatio, true)
defer throttler.UnthrottleApp(throttlerapp.AllName.String())
- assert.False(t, throttler.IsAppThrottled("all"))
- assert.False(t, throttler.IsAppThrottled("app1"))
- assert.False(t, throttler.IsAppThrottled("app2"))
- assert.True(t, throttler.IsAppThrottled("app3"))
- assert.False(t, throttler.IsAppThrottled("app4"))
- assert.False(t, throttler.IsAppThrottled("app_other"))
+ {
+ throttled, app := throttler.IsAppThrottled("all")
+ assert.False(t, throttled) // explicitly throttled
+ assert.Equal(t, "all", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app1")
+ assert.False(t, throttled)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app2")
+ assert.False(t, throttled)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app3")
+ assert.True(t, throttled) // explicitly throttled
+ assert.Equal(t, "app3", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app4")
+ assert.False(t, throttled)
+ assert.Equal(t, "app4", app)
+ }
+ {
+ throttled, app := throttler.IsAppThrottled("app_other")
+ assert.False(t, throttled)
+ assert.Equal(t, "app_other", app)
+ }
assert.Equal(t, 2, throttler.throttledApps.ItemCount())
})
}
func TestIsAppExempted(t *testing.T) {
-
+ plusOneHour := time.Now().Add(time.Hour)
throttler := Throttler{
throttledApps: cache.New(cache.NoExpiration, 0),
heartbeatWriter: &FakeHeartbeatWriter{},
}
- assert.False(t, throttler.IsAppExempted("app1"))
- assert.False(t, throttler.IsAppExempted("app2"))
- assert.False(t, throttler.IsAppExempted("app3"))
- //
- throttler.ThrottleApp("app1", time.Now().Add(time.Hour), DefaultThrottleRatio, true)
- throttler.ThrottleApp("app2", time.Now(), DefaultThrottleRatio, true) // instantly expire
- assert.True(t, throttler.IsAppExempted("app1"))
- assert.True(t, throttler.IsAppExempted("app1:other-tag"))
- assert.False(t, throttler.IsAppExempted("app2")) // expired
- assert.False(t, throttler.IsAppExempted("app3"))
- //
- throttler.UnthrottleApp("app1")
- throttler.ThrottleApp("app2", time.Now().Add(time.Hour), DefaultThrottleRatio, false)
- assert.False(t, throttler.IsAppExempted("app1"))
- assert.False(t, throttler.IsAppExempted("app2"))
- assert.False(t, throttler.IsAppExempted("app3"))
- //
- assert.True(t, throttler.IsAppExempted("schema-tracker"))
- throttler.UnthrottleApp("schema-tracker") // meaningless. App is statically exempted
- assert.True(t, throttler.IsAppExempted("schema-tracker"))
+ t.Run("initial", func(t *testing.T) {
+ {
+ exempted, app := throttler.IsAppExempted("app1")
+ assert.False(t, exempted)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app2")
+ assert.False(t, exempted)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app3")
+ assert.False(t, exempted)
+ assert.Equal(t, "app3", app)
+ }
+ })
+ t.Run("exempt", func(t *testing.T) {
+ throttler.ThrottleApp("app1", time.Now().Add(time.Hour), DefaultThrottleRatio, true)
+ throttler.ThrottleApp("app2", time.Now(), DefaultThrottleRatio, true) // instantly expire
+ {
+ exempted, app := throttler.IsAppExempted("app1")
+ assert.True(t, exempted)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app1:other-tag")
+ assert.True(t, exempted)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app2")
+ assert.False(t, exempted)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app3")
+ assert.False(t, exempted)
+ assert.Equal(t, "app3", app)
+ }
+ })
+ t.Run("throttle", func(t *testing.T) {
+ throttler.UnthrottleApp("app1")
+ throttler.ThrottleApp("app2", time.Now().Add(time.Hour), DefaultThrottleRatio, false)
+ {
+ exempted, app := throttler.IsAppExempted("app1")
+ assert.False(t, exempted)
+ assert.Equal(t, "app1", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app2")
+ assert.False(t, exempted)
+ assert.Equal(t, "app2", app)
+ }
+ {
+ exempted, app := throttler.IsAppExempted("app3")
+ assert.False(t, exempted)
+ assert.Equal(t, "app3", app)
+ }
+ })
+ t.Run("special", func(t *testing.T) {
+ {
+ exempted, app := throttler.IsAppExempted("schema-tracker")
+ assert.True(t, exempted)
+ assert.Equal(t, "schema-tracker", app)
+ }
+ throttler.ThrottleApp("schema-tracker", plusOneHour, 1.0, false) // meaningless. App is statically exempted
+ {
+ exempted, app := throttler.IsAppExempted("schema-tracker")
+ assert.True(t, exempted)
+ assert.Equal(t, "schema-tracker", app)
+ }
+ })
}
// TestRefreshInventory tests the behavior of the throttler's RefreshInventory() function, which
@@ -916,7 +1149,8 @@ func TestRefreshInventory(t *testing.T) {
ts: &FakeTopoServer{},
inventory: base.NewInventory(),
}
- throttler.metricsQuery.Store(metricsQuery)
+ lagSelfMetric := base.RegisteredSelfMetrics[base.LagMetricName].(*base.LagSelfMetric)
+ lagSelfMetric.SetQuery(metricsQuery)
throttler.configSettings = configSettings
throttler.initConfig()
throttler.initThrottleTabletTypes()
@@ -927,9 +1161,9 @@ func TestRefreshInventory(t *testing.T) {
// validateProbesCount expects number of probes according to cluster name and throttler's leadership status
validateProbesCount := func(t *testing.T, probes base.Probes) {
if throttler.isLeader.Load() {
- assert.Equal(t, 3, len(probes))
+ assert.Len(t, probes, 3)
} else {
- assert.Equal(t, 1, len(probes))
+ assert.Len(t, probes, 1)
}
}
t.Run("waiting for probes", func(t *testing.T) {
@@ -942,7 +1176,7 @@ func TestRefreshInventory(t *testing.T) {
// not run, and therefore there is none but us to both populate `clusterProbesChan` as well as
// read from it. We do not compete here with any other goroutine.
assert.NotNil(t, probes)
- throttler.updateClusterProbes(ctx, probes)
+ throttler.updateClusterProbes(probes)
validateProbesCount(t, probes.TabletProbes)
// Achieved our goal
return
@@ -1116,8 +1350,10 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ checkResult, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK) // we expect threshold exceeded
+ assert.NotNil(t, checkResult)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to")
}
})
@@ -1128,7 +1364,7 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.True(t, checkOK)
}
})
@@ -1139,8 +1375,10 @@ func TestProbesWhileOperating(t *testing.T) {
})
client.clearSuccessfulResultsCache() // ensure we don't read the successful result from the test above
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ checkResult, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK)
+ assert.NotNil(t, checkResult)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to")
}
})
})
@@ -1205,8 +1443,9 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ checkResult, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK) // we expect threshold exceeded
+ assert.NotNil(t, checkResult)
}
})
@@ -1217,7 +1456,7 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK) // 0.95 still too low for custom query
}
})
@@ -1227,7 +1466,7 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK) // 15 still too low for custom query because primary has 17
}
})
@@ -1237,7 +1476,7 @@ func TestProbesWhileOperating(t *testing.T) {
throttler.refreshInventory(ctx)
})
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.True(t, checkOK)
}
})
@@ -1248,12 +1487,76 @@ func TestProbesWhileOperating(t *testing.T) {
})
client.clearSuccessfulResultsCache() // ensure we don't read the successful result from the test above
{
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK)
}
})
})
})
+
+ t.Run("metrics", func(t *testing.T) {
+ var results base.TabletResultMap
+ <-runSerialFunction(t, ctx, throttler, func(ctx context.Context) {
+ results = maps.Clone(throttler.inventory.TabletMetrics)
+ })
+ assert.Len(t, results, 3) // 1 self tablet + 2 shard tablets
+ assert.Contains(t, results, "", "TabletMetrics: %+v", results) // primary self identifies with empty alias
+ assert.Contains(t, results, "fakezone1-0000000101", "TabletMetrics: %+v", results)
+ assert.Contains(t, results, "fakezone2-0000000102", "TabletMetrics: %+v", results)
+ })
+
+ t.Run("no REPLICA probes", func(t *testing.T) {
+ nonPrimaryTabletType.Store(int32(topodatapb.TabletType_RDONLY))
+ defer nonPrimaryTabletType.Store(int32(topodatapb.TabletType_REPLICA))
+
+ t.Run("waiting for inventory metrics", func(t *testing.T) {
+ ctx, cancel := context.WithTimeout(ctx, waitForProbesTimeout)
+ defer cancel()
+ ticker := time.NewTicker(100 * time.Millisecond)
+ defer ticker.Stop()
+ for {
+ var results base.TabletResultMap
+ <-runSerialFunction(t, ctx, throttler, func(ctx context.Context) {
+ results = maps.Clone(throttler.inventory.TabletMetrics)
+ })
+ if len(results) == 1 {
+ // That's what we were waiting for. Good.
+ assert.Contains(t, results, "", "TabletMetrics: %+v", results) // primary self identifies with empty alias
+ return
+ }
+
+ select {
+ case <-ticker.C:
+ case <-ctx.Done():
+ assert.FailNowf(t, ctx.Err().Error(), "waiting for inventory metrics")
+ }
+ }
+ })
+ })
+ t.Run("again with probes", func(t *testing.T) {
+ t.Run("waiting for inventory metrics", func(t *testing.T) {
+ ctx, cancel := context.WithTimeout(ctx, waitForProbesTimeout)
+ defer cancel()
+ ticker := time.NewTicker(100 * time.Millisecond)
+ defer ticker.Stop()
+ for {
+ var results base.TabletResultMap
+ <-runSerialFunction(t, ctx, throttler, func(ctx context.Context) {
+ results = maps.Clone(throttler.inventory.TabletMetrics)
+ })
+ if len(results) == 3 {
+ // That's what we were waiting for. Good.
+ return
+ }
+
+ select {
+ case <-ticker.C:
+ case <-ctx.Done():
+ assert.FailNowf(t, ctx.Err().Error(), "waiting for inventory metrics")
+ }
+ }
+ })
+ })
})
}
@@ -1369,7 +1672,7 @@ func TestProbesPostDisable(t *testing.T) {
})
t.Run("metrics", func(t *testing.T) {
- assert.Equal(t, 3, len(throttler.inventory.TabletMetrics)) // 1 self tablet + 2 shard tablets
+ assert.Empty(t, throttler.inventory.TabletMetrics) // map has been cleared
})
t.Run("aggregated", func(t *testing.T) {
@@ -1502,6 +1805,8 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
+ assert.Equal(t, testAppName.String(), checkResult.AppName)
assert.Len(t, checkResult.Metrics, 1)
})
t.Run("explicit names", func(t *testing.T) {
@@ -1513,6 +1818,13 @@ func TestChecks(t *testing.T) {
t.Logf("%s: %+v", k, v)
}
}
+ if !assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult) {
+ for k, v := range checkResult.Metrics {
+ t.Logf("%s: %+v", k, v)
+ }
+ }
+
+ assert.Equal(t, testAppName.String(), checkResult.AppName)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
assert.EqualValues(t, 0.3, checkResult.Metrics[base.LagMetricName.String()].Value) // self lag value, because flags.Scope is set
@@ -1533,6 +1845,7 @@ func TestChecks(t *testing.T) {
t.Run("implicit names, always all known", func(t *testing.T) {
checkResult := throttler.Check(ctx, throttlerapp.VitessName.String(), nil, flags)
// "vitess" app always checks all known metrics:
+ assert.Equal(t, throttlerapp.VitessName.String(), checkResult.AppName)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
})
t.Run("explicit names, irrelevant, always all known", func(t *testing.T) {
@@ -1543,6 +1856,7 @@ func TestChecks(t *testing.T) {
checkResult := throttler.Check(ctx, throttlerapp.VitessName.String(), metricNames, flags)
require.NotNil(t, checkResult)
+ assert.Equal(t, throttlerapp.VitessName.String(), checkResult.AppName)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
})
})
@@ -1557,7 +1871,9 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.ErrorIs(t, checkResult.Error, base.ErrThresholdExceeded)
+ assert.Equal(t, testAppName.String(), checkResult.AppName)
assert.Len(t, checkResult.Metrics, 1)
})
t.Run("explicit names", func(t *testing.T) {
@@ -1565,7 +1881,9 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.ErrorIs(t, checkResult.Error, base.ErrThresholdExceeded)
+ assert.Equal(t, testAppName.String(), checkResult.AppName)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
assert.EqualValues(t, 0.9, checkResult.Metrics[base.LagMetricName.String()].Value) // shard lag value, because flags.Scope is set
@@ -1587,6 +1905,7 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.ErrorIs(t, checkResult.Error, base.ErrThresholdExceeded)
assert.Len(t, checkResult.Metrics, 1)
})
@@ -1595,6 +1914,7 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.ErrorIs(t, checkResult.Error, base.ErrThresholdExceeded)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
@@ -1626,6 +1946,7 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.9, checkResult.Value) // shard lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.ErrorIs(t, checkResult.Error, base.ErrThresholdExceeded)
assert.Equal(t, len(metricNames), len(checkResult.Metrics))
@@ -1654,6 +1975,7 @@ func TestChecks(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value) // explicitly set self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Equal(t, len(metricNames), len(checkResult.Metrics))
assert.EqualValues(t, 0.3, checkResult.Metrics[base.LagMetricName.String()].Value) // self lag value, because scope name is in metric name
@@ -1716,6 +2038,7 @@ func TestReplica(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
select {
case <-ctx.Done():
@@ -1733,6 +2056,7 @@ func TestReplica(t *testing.T) {
require.NotNil(t, checkResult)
assert.EqualValues(t, 0.3, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.Len(t, checkResult.Metrics, 1)
assert.True(t, checkResult.RecentlyChecked)
assert.True(t, throttler.recentlyChecked())
@@ -1740,6 +2064,7 @@ func TestReplica(t *testing.T) {
recentApp, ok := throttler.recentAppsSnapshot()[throttlerapp.OnlineDDLName.String()]
require.True(t, ok)
assert.EqualValues(t, http.StatusOK, recentApp.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, recentApp.ResponseCode)
}
}
{
@@ -1770,6 +2095,7 @@ func TestReplica(t *testing.T) {
// loadavg value exceeds threshold. This will show up in the check result as an error.
assert.EqualValues(t, 2.718, checkResult.Value, "unexpected result: %+v", checkResult) // self lag value
assert.NotEqualValues(t, http.StatusOK, checkResult.StatusCode, "unexpected result: %+v", checkResult)
+ assert.NotEqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode, "unexpected result: %+v", checkResult)
assert.Equal(t, len(base.KnownMetricNames), len(checkResult.Metrics))
})
t.Run("validate v20 non-multi-metric results", func(t *testing.T) {
@@ -1785,6 +2111,7 @@ func TestReplica(t *testing.T) {
// reports the default metric.
assert.EqualValues(t, 0.3, checkResult.Value) // self lag value
assert.EqualValues(t, http.StatusOK, checkResult.StatusCode)
+ assert.EqualValues(t, tabletmanagerdatapb.CheckThrottlerResponseCode_OK, checkResult.ResponseCode)
assert.EqualValues(t, 0.75, checkResult.Threshold)
// The replica will still report the multi-metrics, and that's fine. As long
// as it does not reflect any of their values in the checkResult.Value/StatusCode/Threshold/Error/Message.
@@ -1845,11 +2172,11 @@ func TestReplica(t *testing.T) {
defer throttler.appCheckedMetrics.Delete(testAppName.String())
checkResult := throttler.Check(ctx, testAppName.String(), nil, flags)
require.NotNil(t, checkResult)
- assert.Equal(t, 3, len(checkResult.Metrics))
+ assert.Len(t, checkResult.Metrics, 3)
})
t.Run("client, OK", func(t *testing.T) {
client := NewBackgroundClient(throttler, throttlerapp.TestingName, base.UndefinedScope)
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.True(t, checkOK)
})
t.Run("client, metrics names mapped, OK", func(t *testing.T) {
@@ -1857,7 +2184,7 @@ func TestReplica(t *testing.T) {
throttler.appCheckedMetrics.Set(throttlerapp.TestingName.String(), base.MetricNames{base.LagMetricName, base.ThreadsRunningMetricName}, cache.DefaultExpiration)
defer throttler.appCheckedMetrics.Delete(throttlerapp.TestingName.String())
client := NewBackgroundClient(throttler, throttlerapp.TestingName, base.UndefinedScope)
- checkOK := client.ThrottleCheckOK(ctx, "")
+ _, checkOK := client.ThrottleCheckOK(ctx, "")
assert.True(t, checkOK)
})
t.Run("client, metrics names mapped, not OK", func(t *testing.T) {
@@ -1865,8 +2192,10 @@ func TestReplica(t *testing.T) {
throttler.appCheckedMetrics.Set(throttlerapp.TestingName.String(), base.MetricNames{base.LagMetricName, base.LoadAvgMetricName, base.ThreadsRunningMetricName}, cache.DefaultExpiration)
defer throttler.appCheckedMetrics.Delete(throttlerapp.TestingName.String())
client := NewBackgroundClient(throttler, throttlerapp.TestingName, base.UndefinedScope)
- checkOK := client.ThrottleCheckOK(ctx, "")
+ checkResult, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK)
+ assert.NotNil(t, checkResult)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to")
})
t.Run("custom query, metrics", func(t *testing.T) {
@@ -1900,8 +2229,10 @@ func TestReplica(t *testing.T) {
})
t.Run("client, not OK", func(t *testing.T) {
client := NewBackgroundClient(throttler, throttlerapp.TestingName, base.SelfScope)
- checkOK := client.ThrottleCheckOK(ctx, "")
+ checkResult, checkOK := client.ThrottleCheckOK(ctx, "")
assert.False(t, checkOK)
+ assert.NotNil(t, checkResult)
+ assert.Contains(t, checkResult.Summary(), testAppName.String()+" is denied access due to")
})
}()
})
diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go
index 57c6ff1fd64..33e22e321bc 100644
--- a/go/vt/vttablet/tabletserver/tx_engine.go
+++ b/go/vt/vttablet/tabletserver/tx_engine.go
@@ -160,6 +160,8 @@ func (te *TxEngine) transition(state txEngineState) {
te.txPool.Open(te.env.Config().DB.AppWithDB(), te.env.Config().DB.DbaWithDB(), te.env.Config().DB.AppDebugWithDB())
if te.twopcEnabled && te.state == AcceptingReadAndWrite {
+ // Set the preparedPool to start accepting connections.
+ te.preparedPool.shutdown = false
// If there are errors, we choose to raise an alert and
// continue anyway. Serving traffic is considered more important
// than blocking everything for the sake of a few transactions.
@@ -442,7 +444,7 @@ func (te *TxEngine) shutdownTransactions() {
func (te *TxEngine) rollbackPrepared() {
ctx := tabletenv.LocalContext()
- for _, conn := range te.preparedPool.FetchAll() {
+ for _, conn := range te.preparedPool.FetchAllForRollback() {
te.txPool.Rollback(ctx, conn)
conn.Release(tx.TxRollback)
}
diff --git a/go/vt/vttablet/tabletserver/tx_prep_pool.go b/go/vt/vttablet/tabletserver/tx_prep_pool.go
index 89547570cfc..d5376172856 100644
--- a/go/vt/vttablet/tabletserver/tx_prep_pool.go
+++ b/go/vt/vttablet/tabletserver/tx_prep_pool.go
@@ -17,14 +17,16 @@ limitations under the License.
package tabletserver
import (
- "errors"
"fmt"
"sync"
+
+ vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
+ "vitess.io/vitess/go/vt/vterrors"
)
var (
- errPrepCommitting = errors.New("committing")
- errPrepFailed = errors.New("failed")
+ errPrepCommitting = vterrors.VT09025("locked for committing")
+ errPrepFailed = vterrors.VT09025("failed to commit")
)
// TxPreparedPool manages connections for prepared transactions.
@@ -34,6 +36,8 @@ type TxPreparedPool struct {
mu sync.Mutex
conns map[string]*StatefulConnection
reserved map[string]error
+ // shutdown tells if the prepared pool has been drained and shutdown.
+ shutdown bool
capacity int
}
@@ -55,14 +59,18 @@ func NewTxPreparedPool(capacity int) *TxPreparedPool {
func (pp *TxPreparedPool) Put(c *StatefulConnection, dtid string) error {
pp.mu.Lock()
defer pp.mu.Unlock()
+ // If the pool is shutdown, we don't accept new prepared transactions.
+ if pp.shutdown {
+ return vterrors.VT09025("pool is shutdown")
+ }
if _, ok := pp.reserved[dtid]; ok {
- return errors.New("duplicate DTID in Prepare: " + dtid)
+ return vterrors.VT09025("duplicate DTID in Prepare: " + dtid)
}
if _, ok := pp.conns[dtid]; ok {
- return errors.New("duplicate DTID in Prepare: " + dtid)
+ return vterrors.VT09025("duplicate DTID in Prepare: " + dtid)
}
if len(pp.conns) >= pp.capacity {
- return fmt.Errorf("prepared transactions exceeded limit: %d", pp.capacity)
+ return vterrors.New(vtrpcpb.Code_RESOURCE_EXHAUSTED, fmt.Sprintf("prepared transactions exceeded limit: %d", pp.capacity))
}
pp.conns[dtid] = c
return nil
@@ -95,6 +103,11 @@ func (pp *TxPreparedPool) FetchForRollback(dtid string) *StatefulConnection {
func (pp *TxPreparedPool) FetchForCommit(dtid string) (*StatefulConnection, error) {
pp.mu.Lock()
defer pp.mu.Unlock()
+ // If the pool is shutdown, we don't have any connections to return.
+ // That however doesn't mean this transaction was committed, it could very well have been rollbacked.
+ if pp.shutdown {
+ return nil, vterrors.VT09025("pool is shutdown")
+ }
if err, ok := pp.reserved[dtid]; ok {
return nil, err
}
@@ -121,11 +134,12 @@ func (pp *TxPreparedPool) Forget(dtid string) {
delete(pp.reserved, dtid)
}
-// FetchAll removes all connections and returns them as a list.
+// FetchAllForRollback removes all connections and returns them as a list.
// It also forgets all reserved dtids.
-func (pp *TxPreparedPool) FetchAll() []*StatefulConnection {
+func (pp *TxPreparedPool) FetchAllForRollback() []*StatefulConnection {
pp.mu.Lock()
defer pp.mu.Unlock()
+ pp.shutdown = true
conns := make([]*StatefulConnection, 0, len(pp.conns))
for _, c := range pp.conns {
conns = append(conns, c)
diff --git a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go
index a1cf50edb56..42e2b800e0e 100644
--- a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go
+++ b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go
@@ -19,16 +19,14 @@ package tabletserver
import (
"testing"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestEmptyPrep(t *testing.T) {
pp := NewTxPreparedPool(0)
- want := "prepared transactions exceeded limit: 0"
err := pp.Put(nil, "aa")
- if err == nil || err.Error() != want {
- t.Errorf("Put err: %v, want %s", err, want)
- }
+ require.ErrorContains(t, err, "prepared transactions exceeded limit: 0")
}
func TestPrepPut(t *testing.T) {
@@ -37,23 +35,15 @@ func TestPrepPut(t *testing.T) {
require.NoError(t, err)
err = pp.Put(nil, "bb")
require.NoError(t, err)
- want := "prepared transactions exceeded limit: 2"
err = pp.Put(nil, "cc")
- if err == nil || err.Error() != want {
- t.Errorf("Put err: %v, want %s", err, want)
- }
+ require.ErrorContains(t, err, "prepared transactions exceeded limit: 2")
err = pp.Put(nil, "aa")
- want = "duplicate DTID in Prepare: aa"
- if err == nil || err.Error() != want {
- t.Errorf("Put err: %v, want %s", err, want)
- }
+ require.ErrorContains(t, err, "duplicate DTID in Prepare: aa")
+
_, err = pp.FetchForCommit("aa")
require.NoError(t, err)
err = pp.Put(nil, "aa")
- want = "duplicate DTID in Prepare: aa"
- if err == nil || err.Error() != want {
- t.Errorf("Put err: %v, want %s", err, want)
- }
+ require.ErrorContains(t, err, "duplicate DTID in Prepare: aa")
pp.Forget("aa")
err = pp.Put(nil, "aa")
require.NoError(t, err)
@@ -82,38 +72,28 @@ func TestPrepFetchForCommit(t *testing.T) {
conn := &StatefulConnection{}
got, err := pp.FetchForCommit("aa")
require.NoError(t, err)
- if got != nil {
- t.Errorf("Get(aa): %v, want nil", got)
- }
+ assert.Nil(t, got)
+
pp.Put(conn, "aa")
got, err = pp.FetchForCommit("aa")
require.NoError(t, err)
- if got != conn {
- t.Errorf("pp.Get(aa): %p, want %p", got, conn)
- }
+ assert.Equal(t, conn, got)
+
_, err = pp.FetchForCommit("aa")
- want := "committing"
- if err == nil || err.Error() != want {
- t.Errorf("FetchForCommit err: %v, want %s", err, want)
- }
+ assert.ErrorContains(t, err, "locked for committing")
+
pp.SetFailed("aa")
_, err = pp.FetchForCommit("aa")
- want = "failed"
- if err == nil || err.Error() != want {
- t.Errorf("FetchForCommit err: %v, want %s", err, want)
- }
+ assert.ErrorContains(t, err, "failed to commit")
+
pp.SetFailed("bb")
_, err = pp.FetchForCommit("bb")
- want = "failed"
- if err == nil || err.Error() != want {
- t.Errorf("FetchForCommit err: %v, want %s", err, want)
- }
+ assert.ErrorContains(t, err, "failed to commit")
+
pp.Forget("aa")
got, err = pp.FetchForCommit("aa")
require.NoError(t, err)
- if got != nil {
- t.Errorf("Get(aa): %v, want nil", got)
- }
+ assert.Nil(t, got)
}
func TestPrepFetchAll(t *testing.T) {
@@ -122,11 +102,9 @@ func TestPrepFetchAll(t *testing.T) {
conn2 := &StatefulConnection{}
pp.Put(conn1, "aa")
pp.Put(conn2, "bb")
- got := pp.FetchAll()
- if len(got) != 2 {
- t.Errorf("FetchAll len: %d, want 2", len(got))
- }
- if len(pp.conns) != 0 {
- t.Errorf("len(pp.conns): %d, want 0", len(pp.conns))
- }
+ got := pp.FetchAllForRollback()
+ require.Len(t, got, 2)
+ require.Len(t, pp.conns, 0)
+ _, err := pp.FetchForCommit("aa")
+ require.ErrorContains(t, err, "pool is shutdown")
}
diff --git a/go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go
index 4632bea672b..b6294cd1939 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/resultstreamer.go
@@ -109,7 +109,7 @@ func (rs *resultStreamer) Stream() error {
}
// check throttler.
- if !rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.ResultStreamerName) {
+ if _, ok := rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.ResultStreamerName); !ok {
logger.Infof("throttled.")
continue
}
diff --git a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go
index bb8ff7af85f..6015590dad7 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go
@@ -388,9 +388,9 @@ func (rs *rowStreamer) streamQuery(send func(*binlogdatapb.VStreamRowsResponse)
}
// check throttler.
- if !rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.RowStreamerName) {
+ if checkResult, ok := rs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(rs.ctx, throttlerapp.RowStreamerName); !ok {
throttleResponseRateLimiter.Do(func() error {
- return safeSend(&binlogdatapb.VStreamRowsResponse{Throttled: true})
+ return safeSend(&binlogdatapb.VStreamRowsResponse{Throttled: true, ThrottledReason: checkResult.Summary()})
})
logger.Infof("throttled.")
continue
diff --git a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go
index 2b770c1d4f4..854157b1546 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go
@@ -88,7 +88,7 @@ type uvstreamer struct {
config *uvstreamerConfig
- vs *vstreamer //last vstreamer created in uvstreamer
+ vs *vstreamer // last vstreamer created in uvstreamer
}
type uvstreamerConfig struct {
@@ -138,6 +138,9 @@ func (uvs *uvstreamer) buildTablePlan() error {
uvs.plans = make(map[string]*tablePlan)
tableLastPKs := make(map[string]*binlogdatapb.TableLastPK)
for _, tablePK := range uvs.inTablePKs {
+ if tablePK != nil && tablePK.Lastpk != nil && len(tablePK.Lastpk.Fields) == 0 {
+ return fmt.Errorf("lastpk for table %s has no fields defined", tablePK.TableName)
+ }
tableLastPKs[tablePK.TableName] = tablePK
}
tables := uvs.se.GetSchema()
@@ -313,7 +316,6 @@ func (uvs *uvstreamer) send2(evs []*binlogdatapb.VEvent) error {
}
behind := time.Now().UnixNano() - uvs.lastTimestampNs
uvs.setReplicationLagSeconds(behind / 1e9)
- //log.Infof("sbm set to %d", uvs.ReplicationLagSeconds)
var evs2 []*binlogdatapb.VEvent
if len(uvs.plans) > 0 {
evs2 = uvs.filterEvents(evs)
diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
index 3413c53d811..634c9a5d40c 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
@@ -287,17 +287,18 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog
hbTimer := time.NewTimer(HeartbeatTime)
defer hbTimer.Stop()
- injectHeartbeat := func(throttled bool) error {
+ injectHeartbeat := func(throttled bool, throttledReason string) error {
now := time.Now().UnixNano()
select {
case <-ctx.Done():
return vterrors.Errorf(vtrpcpb.Code_CANCELED, "context has expired")
default:
err := bufferAndTransmit(&binlogdatapb.VEvent{
- Type: binlogdatapb.VEventType_HEARTBEAT,
- Timestamp: now / 1e9,
- CurrentTime: now,
- Throttled: throttled,
+ Type: binlogdatapb.VEventType_HEARTBEAT,
+ Timestamp: now / 1e9,
+ CurrentTime: now,
+ Throttled: throttled,
+ ThrottledReason: throttledReason,
})
return err
}
@@ -309,7 +310,7 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog
defer throttledHeartbeatsRateLimiter.Stop()
for {
// check throttler.
- if !vs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, vs.throttlerApp) {
+ if checkResult, ok := vs.vse.throttlerClient.ThrottleCheckOKOrWaitAppName(ctx, vs.throttlerApp); !ok {
// make sure to leave if context is cancelled
select {
case <-ctx.Done():
@@ -318,7 +319,7 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog
// do nothing special
}
throttledHeartbeatsRateLimiter.Do(func() error {
- return injectHeartbeat(true)
+ return injectHeartbeat(true, checkResult.Summary())
})
// we won't process events, until we're no longer throttling
logger.Infof("throttled.")
@@ -393,7 +394,7 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog
case <-ctx.Done():
return nil
case <-hbTimer.C:
- if err := injectHeartbeat(false); err != nil {
+ if err := injectHeartbeat(false, ""); err != nil {
if err == io.EOF {
return nil
}
diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
index 8d0d182790e..4d9f66f1809 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
@@ -398,6 +398,33 @@ func TestMissingTables(t *testing.T) {
runCases(t, filter, testcases, startPos, nil)
}
+// TestVStreamMissingFieldsInLastPK tests that we error out if the lastpk for a table is missing the fields spec.
+func TestVStreamMissingFieldsInLastPK(t *testing.T) {
+ ts := &TestSpec{
+ t: t,
+ ddls: []string{
+ "create table t1(id11 int, id12 int, primary key(id11))",
+ },
+ }
+ ts.Init()
+ defer ts.Close()
+ filter := &binlogdatapb.Filter{
+ Rules: []*binlogdatapb.Rule{{
+ Match: "t1",
+ Filter: "select * from t1",
+ }},
+ }
+ var tablePKs []*binlogdatapb.TableLastPK
+ tablePKs = append(tablePKs, getTablePK("t1", 1))
+ for _, tpk := range tablePKs {
+ tpk.Lastpk.Fields = nil
+ }
+ ctx := context.Background()
+ ch := make(chan []*binlogdatapb.VEvent)
+ err := vstream(ctx, t, "", tablePKs, filter, ch)
+ require.ErrorContains(t, err, "lastpk for table t1 has no fields defined")
+}
+
func TestVStreamCopySimpleFlow(t *testing.T) {
ts := &TestSpec{
t: t,
diff --git a/proto/binlogdata.proto b/proto/binlogdata.proto
index 1e70275e8b5..5f5bbd59c6e 100644
--- a/proto/binlogdata.proto
+++ b/proto/binlogdata.proto
@@ -458,6 +458,8 @@ message VEvent {
string shard = 23;
// indicate that we are being throttled right now
bool throttled = 24;
+ // ThrottledReason is a human readable string that explains why the stream is throttled
+ string throttled_reason = 25;
}
message MinimalTable {
@@ -511,6 +513,8 @@ message VStreamRowsResponse {
bool throttled = 6;
// Heartbeat indicates that this is a heartbeat message
bool heartbeat = 7;
+ // ThrottledReason is a human readable string that explains why the stream is throttled
+ string throttled_reason = 8;
}
diff --git a/proto/tabletmanagerdata.proto b/proto/tabletmanagerdata.proto
index ffe4aa29abf..cd74e79fa5d 100644
--- a/proto/tabletmanagerdata.proto
+++ b/proto/tabletmanagerdata.proto
@@ -736,6 +736,14 @@ message CheckThrottlerRequest {
bool multi_metrics_enabled = 5;
}
+enum CheckThrottlerResponseCode {
+ UNDEFINED = 0;
+ OK = 1;
+ THRESHOLD_EXCEEDED = 2;
+ APP_DENIED = 3;
+ UNKNOWN_METRIC = 4;
+ INTERNAL_ERROR = 5;
+}
message CheckThrottlerResponse {
// StatusCode is HTTP compliant response code (e.g. 200 for OK)
@@ -767,10 +775,21 @@ message CheckThrottlerResponse {
string message = 6;
// Scope used in this check
string scope = 7;
+ // ResponseCode is the enum representation of the response
+ CheckThrottlerResponseCode response_code = 8;
}
// Metrics is a map (metric name -> metric value/error) so that the client has as much
// information as possible about all the checked metrics.
map metrics = 7;
+
+ // AppName is the name of app that was matched by the throttler
+ string app_name = 8;
+
+ // Summary is a human readable analysis of the result
+ string summary = 9;
+
+ // ResponseCode is the enum representation of the response
+ CheckThrottlerResponseCode response_code = 10;
}
message GetThrottlerStatusRequest {
@@ -829,6 +848,8 @@ message GetThrottlerStatusResponse {
message RecentApp {
vttime.Time checked_at = 1;
int32 status_code = 2;
+ // ResponseCode is the enum representation of the response
+ CheckThrottlerResponseCode response_code = 3;
}
// RecentApps is a map of app names to their recent check status
map recent_apps = 18;
diff --git a/proto/vtctldata.proto b/proto/vtctldata.proto
index 317e8706584..869e50a23df 100644
--- a/proto/vtctldata.proto
+++ b/proto/vtctldata.proto
@@ -1357,6 +1357,8 @@ message PlannedReparentShardRequest {
// acceptable for a tablet to be eligible for promotion when Vitess makes the choice of a new primary.
// A value of 0 indicates that Vitess shouldn't consider the replication lag at all.
vttime.Duration tolerable_replication_lag = 6;
+ // AllowCrossCellPromotion allows cross cell promotion,
+ bool allow_cross_cell_promotion = 7;
}
message PlannedReparentShardResponse {
diff --git a/test/config.json b/test/config.json
index 1cdf92127ef..49f77e1b7fb 100644
--- a/test/config.json
+++ b/test/config.json
@@ -842,6 +842,15 @@
"RetryMax": 1,
"Tags": []
},
+ "vtgate_transaction_twopc_fuzzer": {
+ "File": "unused.go",
+ "Args": ["vitess.io/vitess/go/test/endtoend/transaction/twopc/fuzzer"],
+ "Command": [],
+ "Manual": false,
+ "Shard": "vtgate_transaction",
+ "RetryMax": 1,
+ "Tags": []
+ },
"vtgate_transaction_partial_exec": {
"File": "unused.go",
"Args": ["vitess.io/vitess/go/test/endtoend/vtgate/partialfailure"],
diff --git a/test/templates/cluster_vitess_tester.tpl b/test/templates/cluster_vitess_tester.tpl
index 7660cd05f14..541bfd5c6a0 100644
--- a/test/templates/cluster_vitess_tester.tpl
+++ b/test/templates/cluster_vitess_tester.tpl
@@ -55,7 +55,7 @@ jobs:
end_to_end:
- 'go/**/*.go'
- 'go/vt/sidecardb/**/*.sql'
- - 'go/test/endtoend/onlineddl/vrepl_suite/**'
+ - 'go/test/endtoend/vtgate/vitess_tester/**'
- 'test.go'
- 'Makefile'
- 'build.env'
@@ -110,7 +110,7 @@ jobs:
go install github.com/vitessio/go-junit-report@HEAD
# install vitess tester
- go install github.com/vitessio/vitess-tester@eb953122baba163ed8ccaa6642458ee984f5d7e4
+ go install github.com/vitessio/vitess-tester@89dd933a9ea0e15f69ca58b9c8ea09a358762cca
- name: Setup launchable dependencies
if: steps.skip-workflow.outputs.is_draft == 'false' && steps.skip-workflow.outputs.skip-workflow == 'false' && steps.changes.outputs.end_to_end == 'true' && github.base_ref == 'main'
@@ -142,9 +142,9 @@ jobs:
# We go over all the directories in the given path.
# If there is a vschema file there, we use it, otherwise we let vitess-tester autogenerate it.
if [ -f $dir/vschema.json ]; then
- vitess-tester --sharded --xunit --test-dir $dir --vschema "$dir"vschema.json
+ vitess-tester --xunit --vschema "$dir"vschema.json $dir/*.test
else
- vitess-tester --sharded --xunit --test-dir $dir
+ vitess-tester --sharded --xunit $dir/*.test
fi
# Number the reports by changing their file names.
mv report.xml report"$i".xml
diff --git a/web/vtadmin/package-lock.json b/web/vtadmin/package-lock.json
index a14da6bf0ee..928217e9d4a 100644
--- a/web/vtadmin/package-lock.json
+++ b/web/vtadmin/package-lock.json
@@ -10339,7 +10339,7 @@
"whatwg-encoding": "^2.0.0",
"whatwg-mimetype": "^3.0.0",
"whatwg-url": "^12.0.1",
- "ws": "^8.13.0",
+ "ws": "^8.17.1",
"xml-name-validator": "^4.0.0"
},
"engines": {
@@ -18182,9 +18182,9 @@
}
},
"node_modules/ws": {
- "version": "8.17.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
- "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"dev": true,
"engines": {
"node": ">=10.0.0"
diff --git a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx
index 2d86e1141a6..ef521406e3d 100644
--- a/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx
+++ b/web/vtadmin/src/components/routes/workflow/WorkflowStreams.tsx
@@ -20,7 +20,7 @@ import { Link } from 'react-router-dom';
import { useWorkflow } from '../../../hooks/api';
import { formatAlias } from '../../../util/tablets';
-import { formatDateTime, formatRelativeTime } from '../../../util/time';
+import { formatDateTime } from '../../../util/time';
import { formatStreamKey, getStreams, getStreamSource, getStreamTarget } from '../../../util/workflows';
import { DataCell } from '../../dataTable/DataCell';
import { DataTable } from '../../dataTable/DataTable';
diff --git a/web/vtadmin/src/proto/vtadmin.d.ts b/web/vtadmin/src/proto/vtadmin.d.ts
index bf371914dca..5dc567d11fe 100644
--- a/web/vtadmin/src/proto/vtadmin.d.ts
+++ b/web/vtadmin/src/proto/vtadmin.d.ts
@@ -30630,6 +30630,16 @@ export namespace tabletmanagerdata {
public static getTypeUrl(typeUrlPrefix?: string): string;
}
+ /** CheckThrottlerResponseCode enum. */
+ enum CheckThrottlerResponseCode {
+ UNDEFINED = 0,
+ OK = 1,
+ THRESHOLD_EXCEEDED = 2,
+ APP_DENIED = 3,
+ UNKNOWN_METRIC = 4,
+ INTERNAL_ERROR = 5
+ }
+
/** Properties of a CheckThrottlerResponse. */
interface ICheckThrottlerResponse {
@@ -30653,6 +30663,15 @@ export namespace tabletmanagerdata {
/** CheckThrottlerResponse metrics */
metrics?: ({ [k: string]: tabletmanagerdata.CheckThrottlerResponse.IMetric }|null);
+
+ /** CheckThrottlerResponse app_name */
+ app_name?: (string|null);
+
+ /** CheckThrottlerResponse summary */
+ summary?: (string|null);
+
+ /** CheckThrottlerResponse response_code */
+ response_code?: (tabletmanagerdata.CheckThrottlerResponseCode|null);
}
/** Represents a CheckThrottlerResponse. */
@@ -30685,6 +30704,15 @@ export namespace tabletmanagerdata {
/** CheckThrottlerResponse metrics. */
public metrics: { [k: string]: tabletmanagerdata.CheckThrottlerResponse.IMetric };
+ /** CheckThrottlerResponse app_name. */
+ public app_name: string;
+
+ /** CheckThrottlerResponse summary. */
+ public summary: string;
+
+ /** CheckThrottlerResponse response_code. */
+ public response_code: tabletmanagerdata.CheckThrottlerResponseCode;
+
/**
* Creates a new CheckThrottlerResponse instance using the specified properties.
* @param [properties] Properties to set
@@ -30788,6 +30816,9 @@ export namespace tabletmanagerdata {
/** Metric scope */
scope?: (string|null);
+
+ /** Metric response_code */
+ response_code?: (tabletmanagerdata.CheckThrottlerResponseCode|null);
}
/** Represents a Metric. */
@@ -30820,6 +30851,9 @@ export namespace tabletmanagerdata {
/** Metric scope. */
public scope: string;
+ /** Metric response_code. */
+ public response_code: tabletmanagerdata.CheckThrottlerResponseCode;
+
/**
* Creates a new Metric instance using the specified properties.
* @param [properties] Properties to set
@@ -31405,6 +31439,9 @@ export namespace tabletmanagerdata {
/** RecentApp status_code */
status_code?: (number|null);
+
+ /** RecentApp response_code */
+ response_code?: (tabletmanagerdata.CheckThrottlerResponseCode|null);
}
/** Represents a RecentApp. */
@@ -31422,6 +31459,9 @@ export namespace tabletmanagerdata {
/** RecentApp status_code. */
public status_code: number;
+ /** RecentApp response_code. */
+ public response_code: tabletmanagerdata.CheckThrottlerResponseCode;
+
/**
* Creates a new RecentApp instance using the specified properties.
* @param [properties] Properties to set
@@ -33809,6 +33849,9 @@ export namespace binlogdata {
/** VEvent throttled */
throttled?: (boolean|null);
+
+ /** VEvent throttled_reason */
+ throttled_reason?: (string|null);
}
/** Represents a VEvent. */
@@ -33862,6 +33905,9 @@ export namespace binlogdata {
/** VEvent throttled. */
public throttled: boolean;
+ /** VEvent throttled_reason. */
+ public throttled_reason: string;
+
/**
* Creates a new VEvent instance using the specified properties.
* @param [properties] Properties to set
@@ -34520,6 +34566,9 @@ export namespace binlogdata {
/** VStreamRowsResponse heartbeat */
heartbeat?: (boolean|null);
+
+ /** VStreamRowsResponse throttled_reason */
+ throttled_reason?: (string|null);
}
/** Represents a VStreamRowsResponse. */
@@ -34552,6 +34601,9 @@ export namespace binlogdata {
/** VStreamRowsResponse heartbeat. */
public heartbeat: boolean;
+ /** VStreamRowsResponse throttled_reason. */
+ public throttled_reason: string;
+
/**
* Creates a new VStreamRowsResponse instance using the specified properties.
* @param [properties] Properties to set
@@ -63057,6 +63109,9 @@ export namespace vtctldata {
/** PlannedReparentShardRequest tolerable_replication_lag */
tolerable_replication_lag?: (vttime.IDuration|null);
+
+ /** PlannedReparentShardRequest allow_cross_cell_promotion */
+ allow_cross_cell_promotion?: (boolean|null);
}
/** Represents a PlannedReparentShardRequest. */
@@ -63086,6 +63141,9 @@ export namespace vtctldata {
/** PlannedReparentShardRequest tolerable_replication_lag. */
public tolerable_replication_lag?: (vttime.IDuration|null);
+ /** PlannedReparentShardRequest allow_cross_cell_promotion. */
+ public allow_cross_cell_promotion: boolean;
+
/**
* Creates a new PlannedReparentShardRequest instance using the specified properties.
* @param [properties] Properties to set
diff --git a/web/vtadmin/src/proto/vtadmin.js b/web/vtadmin/src/proto/vtadmin.js
index d3b9f6ead0e..4ff1b8b19aa 100644
--- a/web/vtadmin/src/proto/vtadmin.js
+++ b/web/vtadmin/src/proto/vtadmin.js
@@ -71270,6 +71270,28 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
return CheckThrottlerRequest;
})();
+ /**
+ * CheckThrottlerResponseCode enum.
+ * @name tabletmanagerdata.CheckThrottlerResponseCode
+ * @enum {number}
+ * @property {number} UNDEFINED=0 UNDEFINED value
+ * @property {number} OK=1 OK value
+ * @property {number} THRESHOLD_EXCEEDED=2 THRESHOLD_EXCEEDED value
+ * @property {number} APP_DENIED=3 APP_DENIED value
+ * @property {number} UNKNOWN_METRIC=4 UNKNOWN_METRIC value
+ * @property {number} INTERNAL_ERROR=5 INTERNAL_ERROR value
+ */
+ tabletmanagerdata.CheckThrottlerResponseCode = (function() {
+ const valuesById = {}, values = Object.create(valuesById);
+ values[valuesById[0] = "UNDEFINED"] = 0;
+ values[valuesById[1] = "OK"] = 1;
+ values[valuesById[2] = "THRESHOLD_EXCEEDED"] = 2;
+ values[valuesById[3] = "APP_DENIED"] = 3;
+ values[valuesById[4] = "UNKNOWN_METRIC"] = 4;
+ values[valuesById[5] = "INTERNAL_ERROR"] = 5;
+ return values;
+ })();
+
tabletmanagerdata.CheckThrottlerResponse = (function() {
/**
@@ -71283,6 +71305,9 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
* @property {string|null} [message] CheckThrottlerResponse message
* @property {boolean|null} [recently_checked] CheckThrottlerResponse recently_checked
* @property {Object.|null} [metrics] CheckThrottlerResponse metrics
+ * @property {string|null} [app_name] CheckThrottlerResponse app_name
+ * @property {string|null} [summary] CheckThrottlerResponse summary
+ * @property {tabletmanagerdata.CheckThrottlerResponseCode|null} [response_code] CheckThrottlerResponse response_code
*/
/**
@@ -71357,6 +71382,30 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
*/
CheckThrottlerResponse.prototype.metrics = $util.emptyObject;
+ /**
+ * CheckThrottlerResponse app_name.
+ * @member {string} app_name
+ * @memberof tabletmanagerdata.CheckThrottlerResponse
+ * @instance
+ */
+ CheckThrottlerResponse.prototype.app_name = "";
+
+ /**
+ * CheckThrottlerResponse summary.
+ * @member {string} summary
+ * @memberof tabletmanagerdata.CheckThrottlerResponse
+ * @instance
+ */
+ CheckThrottlerResponse.prototype.summary = "";
+
+ /**
+ * CheckThrottlerResponse response_code.
+ * @member {tabletmanagerdata.CheckThrottlerResponseCode} response_code
+ * @memberof tabletmanagerdata.CheckThrottlerResponse
+ * @instance
+ */
+ CheckThrottlerResponse.prototype.response_code = 0;
+
/**
* Creates a new CheckThrottlerResponse instance using the specified properties.
* @function create
@@ -71398,6 +71447,12 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
writer.uint32(/* id 7, wireType 2 =*/58).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]);
$root.tabletmanagerdata.CheckThrottlerResponse.Metric.encode(message.metrics[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
+ if (message.app_name != null && Object.hasOwnProperty.call(message, "app_name"))
+ writer.uint32(/* id 8, wireType 2 =*/66).string(message.app_name);
+ if (message.summary != null && Object.hasOwnProperty.call(message, "summary"))
+ writer.uint32(/* id 9, wireType 2 =*/74).string(message.summary);
+ if (message.response_code != null && Object.hasOwnProperty.call(message, "response_code"))
+ writer.uint32(/* id 10, wireType 0 =*/80).int32(message.response_code);
return writer;
};
@@ -71479,6 +71534,18 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
message.metrics[key] = value;
break;
}
+ case 8: {
+ message.app_name = reader.string();
+ break;
+ }
+ case 9: {
+ message.summary = reader.string();
+ break;
+ }
+ case 10: {
+ message.response_code = reader.int32();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -71542,6 +71609,24 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
return "metrics." + error;
}
}
+ if (message.app_name != null && message.hasOwnProperty("app_name"))
+ if (!$util.isString(message.app_name))
+ return "app_name: string expected";
+ if (message.summary != null && message.hasOwnProperty("summary"))
+ if (!$util.isString(message.summary))
+ return "summary: string expected";
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ switch (message.response_code) {
+ default:
+ return "response_code: enum value expected";
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ }
return null;
};
@@ -71579,6 +71664,42 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
message.metrics[keys[i]] = $root.tabletmanagerdata.CheckThrottlerResponse.Metric.fromObject(object.metrics[keys[i]]);
}
}
+ if (object.app_name != null)
+ message.app_name = String(object.app_name);
+ if (object.summary != null)
+ message.summary = String(object.summary);
+ switch (object.response_code) {
+ default:
+ if (typeof object.response_code === "number") {
+ message.response_code = object.response_code;
+ break;
+ }
+ break;
+ case "UNDEFINED":
+ case 0:
+ message.response_code = 0;
+ break;
+ case "OK":
+ case 1:
+ message.response_code = 1;
+ break;
+ case "THRESHOLD_EXCEEDED":
+ case 2:
+ message.response_code = 2;
+ break;
+ case "APP_DENIED":
+ case 3:
+ message.response_code = 3;
+ break;
+ case "UNKNOWN_METRIC":
+ case 4:
+ message.response_code = 4;
+ break;
+ case "INTERNAL_ERROR":
+ case 5:
+ message.response_code = 5;
+ break;
+ }
return message;
};
@@ -71604,6 +71725,9 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
object.error = "";
object.message = "";
object.recently_checked = false;
+ object.app_name = "";
+ object.summary = "";
+ object.response_code = options.enums === String ? "UNDEFINED" : 0;
}
if (message.status_code != null && message.hasOwnProperty("status_code"))
object.status_code = message.status_code;
@@ -71623,6 +71747,12 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
for (let j = 0; j < keys2.length; ++j)
object.metrics[keys2[j]] = $root.tabletmanagerdata.CheckThrottlerResponse.Metric.toObject(message.metrics[keys2[j]], options);
}
+ if (message.app_name != null && message.hasOwnProperty("app_name"))
+ object.app_name = message.app_name;
+ if (message.summary != null && message.hasOwnProperty("summary"))
+ object.summary = message.summary;
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ object.response_code = options.enums === String ? $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] === undefined ? message.response_code : $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] : message.response_code;
return object;
};
@@ -71665,6 +71795,7 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
* @property {string|null} [error] Metric error
* @property {string|null} [message] Metric message
* @property {string|null} [scope] Metric scope
+ * @property {tabletmanagerdata.CheckThrottlerResponseCode|null} [response_code] Metric response_code
*/
/**
@@ -71738,6 +71869,14 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
*/
Metric.prototype.scope = "";
+ /**
+ * Metric response_code.
+ * @member {tabletmanagerdata.CheckThrottlerResponseCode} response_code
+ * @memberof tabletmanagerdata.CheckThrottlerResponse.Metric
+ * @instance
+ */
+ Metric.prototype.response_code = 0;
+
/**
* Creates a new Metric instance using the specified properties.
* @function create
@@ -71776,6 +71915,8 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
writer.uint32(/* id 6, wireType 2 =*/50).string(message.message);
if (message.scope != null && Object.hasOwnProperty.call(message, "scope"))
writer.uint32(/* id 7, wireType 2 =*/58).string(message.scope);
+ if (message.response_code != null && Object.hasOwnProperty.call(message, "response_code"))
+ writer.uint32(/* id 8, wireType 0 =*/64).int32(message.response_code);
return writer;
};
@@ -71838,6 +71979,10 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
message.scope = reader.string();
break;
}
+ case 8: {
+ message.response_code = reader.int32();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -71894,6 +72039,18 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
if (message.scope != null && message.hasOwnProperty("scope"))
if (!$util.isString(message.scope))
return "scope: string expected";
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ switch (message.response_code) {
+ default:
+ return "response_code: enum value expected";
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ }
return null;
};
@@ -71923,6 +72080,38 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
message.message = String(object.message);
if (object.scope != null)
message.scope = String(object.scope);
+ switch (object.response_code) {
+ default:
+ if (typeof object.response_code === "number") {
+ message.response_code = object.response_code;
+ break;
+ }
+ break;
+ case "UNDEFINED":
+ case 0:
+ message.response_code = 0;
+ break;
+ case "OK":
+ case 1:
+ message.response_code = 1;
+ break;
+ case "THRESHOLD_EXCEEDED":
+ case 2:
+ message.response_code = 2;
+ break;
+ case "APP_DENIED":
+ case 3:
+ message.response_code = 3;
+ break;
+ case "UNKNOWN_METRIC":
+ case 4:
+ message.response_code = 4;
+ break;
+ case "INTERNAL_ERROR":
+ case 5:
+ message.response_code = 5;
+ break;
+ }
return message;
};
@@ -71947,6 +72136,7 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
object.error = "";
object.message = "";
object.scope = "";
+ object.response_code = options.enums === String ? "UNDEFINED" : 0;
}
if (message.name != null && message.hasOwnProperty("name"))
object.name = message.name;
@@ -71962,6 +72152,8 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
object.message = message.message;
if (message.scope != null && message.hasOwnProperty("scope"))
object.scope = message.scope;
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ object.response_code = options.enums === String ? $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] === undefined ? message.response_code : $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] : message.response_code;
return object;
};
@@ -73480,6 +73672,7 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
* @interface IRecentApp
* @property {vttime.ITime|null} [checked_at] RecentApp checked_at
* @property {number|null} [status_code] RecentApp status_code
+ * @property {tabletmanagerdata.CheckThrottlerResponseCode|null} [response_code] RecentApp response_code
*/
/**
@@ -73513,6 +73706,14 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
*/
RecentApp.prototype.status_code = 0;
+ /**
+ * RecentApp response_code.
+ * @member {tabletmanagerdata.CheckThrottlerResponseCode} response_code
+ * @memberof tabletmanagerdata.GetThrottlerStatusResponse.RecentApp
+ * @instance
+ */
+ RecentApp.prototype.response_code = 0;
+
/**
* Creates a new RecentApp instance using the specified properties.
* @function create
@@ -73541,6 +73742,8 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
$root.vttime.Time.encode(message.checked_at, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
if (message.status_code != null && Object.hasOwnProperty.call(message, "status_code"))
writer.uint32(/* id 2, wireType 0 =*/16).int32(message.status_code);
+ if (message.response_code != null && Object.hasOwnProperty.call(message, "response_code"))
+ writer.uint32(/* id 3, wireType 0 =*/24).int32(message.response_code);
return writer;
};
@@ -73583,6 +73786,10 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
message.status_code = reader.int32();
break;
}
+ case 3: {
+ message.response_code = reader.int32();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -73626,6 +73833,18 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
if (message.status_code != null && message.hasOwnProperty("status_code"))
if (!$util.isInteger(message.status_code))
return "status_code: integer expected";
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ switch (message.response_code) {
+ default:
+ return "response_code: enum value expected";
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ }
return null;
};
@@ -73648,6 +73867,38 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
}
if (object.status_code != null)
message.status_code = object.status_code | 0;
+ switch (object.response_code) {
+ default:
+ if (typeof object.response_code === "number") {
+ message.response_code = object.response_code;
+ break;
+ }
+ break;
+ case "UNDEFINED":
+ case 0:
+ message.response_code = 0;
+ break;
+ case "OK":
+ case 1:
+ message.response_code = 1;
+ break;
+ case "THRESHOLD_EXCEEDED":
+ case 2:
+ message.response_code = 2;
+ break;
+ case "APP_DENIED":
+ case 3:
+ message.response_code = 3;
+ break;
+ case "UNKNOWN_METRIC":
+ case 4:
+ message.response_code = 4;
+ break;
+ case "INTERNAL_ERROR":
+ case 5:
+ message.response_code = 5;
+ break;
+ }
return message;
};
@@ -73667,11 +73918,14 @@ export const tabletmanagerdata = $root.tabletmanagerdata = (() => {
if (options.defaults) {
object.checked_at = null;
object.status_code = 0;
+ object.response_code = options.enums === String ? "UNDEFINED" : 0;
}
if (message.checked_at != null && message.hasOwnProperty("checked_at"))
object.checked_at = $root.vttime.Time.toObject(message.checked_at, options);
if (message.status_code != null && message.hasOwnProperty("status_code"))
object.status_code = message.status_code;
+ if (message.response_code != null && message.hasOwnProperty("response_code"))
+ object.response_code = options.enums === String ? $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] === undefined ? message.response_code : $root.tabletmanagerdata.CheckThrottlerResponseCode[message.response_code] : message.response_code;
return object;
};
@@ -79683,6 +79937,7 @@ export const binlogdata = $root.binlogdata = (() => {
* @property {string|null} [keyspace] VEvent keyspace
* @property {string|null} [shard] VEvent shard
* @property {boolean|null} [throttled] VEvent throttled
+ * @property {string|null} [throttled_reason] VEvent throttled_reason
*/
/**
@@ -79812,6 +80067,14 @@ export const binlogdata = $root.binlogdata = (() => {
*/
VEvent.prototype.throttled = false;
+ /**
+ * VEvent throttled_reason.
+ * @member {string} throttled_reason
+ * @memberof binlogdata.VEvent
+ * @instance
+ */
+ VEvent.prototype.throttled_reason = "";
+
/**
* Creates a new VEvent instance using the specified properties.
* @function create
@@ -79864,6 +80127,8 @@ export const binlogdata = $root.binlogdata = (() => {
writer.uint32(/* id 23, wireType 2 =*/186).string(message.shard);
if (message.throttled != null && Object.hasOwnProperty.call(message, "throttled"))
writer.uint32(/* id 24, wireType 0 =*/192).bool(message.throttled);
+ if (message.throttled_reason != null && Object.hasOwnProperty.call(message, "throttled_reason"))
+ writer.uint32(/* id 25, wireType 2 =*/202).string(message.throttled_reason);
return writer;
};
@@ -79954,6 +80219,10 @@ export const binlogdata = $root.binlogdata = (() => {
message.throttled = reader.bool();
break;
}
+ case 25: {
+ message.throttled_reason = reader.string();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -80065,6 +80334,9 @@ export const binlogdata = $root.binlogdata = (() => {
if (message.throttled != null && message.hasOwnProperty("throttled"))
if (typeof message.throttled !== "boolean")
return "throttled: boolean expected";
+ if (message.throttled_reason != null && message.hasOwnProperty("throttled_reason"))
+ if (!$util.isString(message.throttled_reason))
+ return "throttled_reason: string expected";
return null;
};
@@ -80227,6 +80499,8 @@ export const binlogdata = $root.binlogdata = (() => {
message.shard = String(object.shard);
if (object.throttled != null)
message.throttled = Boolean(object.throttled);
+ if (object.throttled_reason != null)
+ message.throttled_reason = String(object.throttled_reason);
return message;
};
@@ -80266,6 +80540,7 @@ export const binlogdata = $root.binlogdata = (() => {
object.keyspace = "";
object.shard = "";
object.throttled = false;
+ object.throttled_reason = "";
}
if (message.type != null && message.hasOwnProperty("type"))
object.type = options.enums === String ? $root.binlogdata.VEventType[message.type] === undefined ? message.type : $root.binlogdata.VEventType[message.type] : message.type;
@@ -80301,6 +80576,8 @@ export const binlogdata = $root.binlogdata = (() => {
object.shard = message.shard;
if (message.throttled != null && message.hasOwnProperty("throttled"))
object.throttled = message.throttled;
+ if (message.throttled_reason != null && message.hasOwnProperty("throttled_reason"))
+ object.throttled_reason = message.throttled_reason;
return object;
};
@@ -81801,6 +82078,7 @@ export const binlogdata = $root.binlogdata = (() => {
* @property {query.IRow|null} [lastpk] VStreamRowsResponse lastpk
* @property {boolean|null} [throttled] VStreamRowsResponse throttled
* @property {boolean|null} [heartbeat] VStreamRowsResponse heartbeat
+ * @property {string|null} [throttled_reason] VStreamRowsResponse throttled_reason
*/
/**
@@ -81877,6 +82155,14 @@ export const binlogdata = $root.binlogdata = (() => {
*/
VStreamRowsResponse.prototype.heartbeat = false;
+ /**
+ * VStreamRowsResponse throttled_reason.
+ * @member {string} throttled_reason
+ * @memberof binlogdata.VStreamRowsResponse
+ * @instance
+ */
+ VStreamRowsResponse.prototype.throttled_reason = "";
+
/**
* Creates a new VStreamRowsResponse instance using the specified properties.
* @function create
@@ -81918,6 +82204,8 @@ export const binlogdata = $root.binlogdata = (() => {
writer.uint32(/* id 6, wireType 0 =*/48).bool(message.throttled);
if (message.heartbeat != null && Object.hasOwnProperty.call(message, "heartbeat"))
writer.uint32(/* id 7, wireType 0 =*/56).bool(message.heartbeat);
+ if (message.throttled_reason != null && Object.hasOwnProperty.call(message, "throttled_reason"))
+ writer.uint32(/* id 8, wireType 2 =*/66).string(message.throttled_reason);
return writer;
};
@@ -81986,6 +82274,10 @@ export const binlogdata = $root.binlogdata = (() => {
message.heartbeat = reader.bool();
break;
}
+ case 8: {
+ message.throttled_reason = reader.string();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -82062,6 +82354,9 @@ export const binlogdata = $root.binlogdata = (() => {
if (message.heartbeat != null && message.hasOwnProperty("heartbeat"))
if (typeof message.heartbeat !== "boolean")
return "heartbeat: boolean expected";
+ if (message.throttled_reason != null && message.hasOwnProperty("throttled_reason"))
+ if (!$util.isString(message.throttled_reason))
+ return "throttled_reason: string expected";
return null;
};
@@ -82118,6 +82413,8 @@ export const binlogdata = $root.binlogdata = (() => {
message.throttled = Boolean(object.throttled);
if (object.heartbeat != null)
message.heartbeat = Boolean(object.heartbeat);
+ if (object.throttled_reason != null)
+ message.throttled_reason = String(object.throttled_reason);
return message;
};
@@ -82144,6 +82441,7 @@ export const binlogdata = $root.binlogdata = (() => {
object.lastpk = null;
object.throttled = false;
object.heartbeat = false;
+ object.throttled_reason = "";
}
if (message.fields && message.fields.length) {
object.fields = [];
@@ -82168,6 +82466,8 @@ export const binlogdata = $root.binlogdata = (() => {
object.throttled = message.throttled;
if (message.heartbeat != null && message.hasOwnProperty("heartbeat"))
object.heartbeat = message.heartbeat;
+ if (message.throttled_reason != null && message.hasOwnProperty("throttled_reason"))
+ object.throttled_reason = message.throttled_reason;
return object;
};
@@ -154782,6 +155082,7 @@ export const vtctldata = $root.vtctldata = (() => {
* @property {topodata.ITabletAlias|null} [avoid_primary] PlannedReparentShardRequest avoid_primary
* @property {vttime.IDuration|null} [wait_replicas_timeout] PlannedReparentShardRequest wait_replicas_timeout
* @property {vttime.IDuration|null} [tolerable_replication_lag] PlannedReparentShardRequest tolerable_replication_lag
+ * @property {boolean|null} [allow_cross_cell_promotion] PlannedReparentShardRequest allow_cross_cell_promotion
*/
/**
@@ -154847,6 +155148,14 @@ export const vtctldata = $root.vtctldata = (() => {
*/
PlannedReparentShardRequest.prototype.tolerable_replication_lag = null;
+ /**
+ * PlannedReparentShardRequest allow_cross_cell_promotion.
+ * @member {boolean} allow_cross_cell_promotion
+ * @memberof vtctldata.PlannedReparentShardRequest
+ * @instance
+ */
+ PlannedReparentShardRequest.prototype.allow_cross_cell_promotion = false;
+
/**
* Creates a new PlannedReparentShardRequest instance using the specified properties.
* @function create
@@ -154883,6 +155192,8 @@ export const vtctldata = $root.vtctldata = (() => {
$root.vttime.Duration.encode(message.wait_replicas_timeout, writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim();
if (message.tolerable_replication_lag != null && Object.hasOwnProperty.call(message, "tolerable_replication_lag"))
$root.vttime.Duration.encode(message.tolerable_replication_lag, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim();
+ if (message.allow_cross_cell_promotion != null && Object.hasOwnProperty.call(message, "allow_cross_cell_promotion"))
+ writer.uint32(/* id 7, wireType 0 =*/56).bool(message.allow_cross_cell_promotion);
return writer;
};
@@ -154941,6 +155252,10 @@ export const vtctldata = $root.vtctldata = (() => {
message.tolerable_replication_lag = $root.vttime.Duration.decode(reader, reader.uint32());
break;
}
+ case 7: {
+ message.allow_cross_cell_promotion = reader.bool();
+ break;
+ }
default:
reader.skipType(tag & 7);
break;
@@ -155002,6 +155317,9 @@ export const vtctldata = $root.vtctldata = (() => {
if (error)
return "tolerable_replication_lag." + error;
}
+ if (message.allow_cross_cell_promotion != null && message.hasOwnProperty("allow_cross_cell_promotion"))
+ if (typeof message.allow_cross_cell_promotion !== "boolean")
+ return "allow_cross_cell_promotion: boolean expected";
return null;
};
@@ -155041,6 +155359,8 @@ export const vtctldata = $root.vtctldata = (() => {
throw TypeError(".vtctldata.PlannedReparentShardRequest.tolerable_replication_lag: object expected");
message.tolerable_replication_lag = $root.vttime.Duration.fromObject(object.tolerable_replication_lag);
}
+ if (object.allow_cross_cell_promotion != null)
+ message.allow_cross_cell_promotion = Boolean(object.allow_cross_cell_promotion);
return message;
};
@@ -155064,6 +155384,7 @@ export const vtctldata = $root.vtctldata = (() => {
object.avoid_primary = null;
object.wait_replicas_timeout = null;
object.tolerable_replication_lag = null;
+ object.allow_cross_cell_promotion = false;
}
if (message.keyspace != null && message.hasOwnProperty("keyspace"))
object.keyspace = message.keyspace;
@@ -155077,6 +155398,8 @@ export const vtctldata = $root.vtctldata = (() => {
object.wait_replicas_timeout = $root.vttime.Duration.toObject(message.wait_replicas_timeout, options);
if (message.tolerable_replication_lag != null && message.hasOwnProperty("tolerable_replication_lag"))
object.tolerable_replication_lag = $root.vttime.Duration.toObject(message.tolerable_replication_lag, options);
+ if (message.allow_cross_cell_promotion != null && message.hasOwnProperty("allow_cross_cell_promotion"))
+ object.allow_cross_cell_promotion = message.allow_cross_cell_promotion;
return object;
};