diff --git a/data/test/vtexplain/multi-output/options-output.txt b/data/test/vtexplain/multi-output/options-output.txt index cb21cc98a22..5e763a2e749 100644 --- a/data/test/vtexplain/multi-output/options-output.txt +++ b/data/test/vtexplain/multi-output/options-output.txt @@ -14,7 +14,7 @@ select * from user where id in (1,2,3,4,5,6,7,8) 1 ks_sharded/c0-: select * from user where id in (4, 6, 7, 8) limit 10001 ---------------------------------------------------------------------- -insert into user (id, name) values(2, 'bob') +insert into user (id, name) values (2, 'bob') 1 ks_sharded/c0-: begin 1 ks_sharded/c0-: insert into name_user_map(name, user_id) values ('bob', 2) /* _stream name_user_map (name user_id ) ('Ym9i' 2 ); */ /* vtgate:: keyspace_id:da8a82595aa28154c17717955ffeed8b */ diff --git a/data/test/vtexplain/multi-output/target-output.txt b/data/test/vtexplain/multi-output/target-output.txt new file mode 100644 index 00000000000..e7ed228009e --- /dev/null +++ b/data/test/vtexplain/multi-output/target-output.txt @@ -0,0 +1,18 @@ +---------------------------------------------------------------------- +select * from user where email='null@void.com' + +1 ks_sharded/40-80: select * from user where email = 'null@void.com' limit 10001 + +---------------------------------------------------------------------- +select * from user where id in (1,2,3,4,5,6,7,8) + +1 ks_sharded/40-80: select * from user where id in (1, 2, 3, 4, 5, 6, 7, 8) limit 10001 + +---------------------------------------------------------------------- +insert into user (id, name) values (2, 'bob') + +1 ks_sharded/40-80: begin +1 ks_sharded/40-80: insert into user(id, name) values (2, 'bob')/* vtgate:: filtered_replication_unfriendly */ +2 ks_sharded/40-80: commit + +---------------------------------------------------------------------- diff --git a/data/test/vtexplain/options-queries.sql b/data/test/vtexplain/options-queries.sql index 76a72a5adca..9289cae2db2 100644 --- a/data/test/vtexplain/options-queries.sql +++ b/data/test/vtexplain/options-queries.sql @@ -1,3 +1,3 @@ select * from user where email='null@void.com'; select * from user where id in (1,2,3,4,5,6,7,8); -insert into user (id, name) values(2, 'bob'); +insert into user (id, name) values (2, 'bob'); diff --git a/data/test/vtexplain/target-queries.sql b/data/test/vtexplain/target-queries.sql new file mode 100644 index 00000000000..fd2fc48951d --- /dev/null +++ b/data/test/vtexplain/target-queries.sql @@ -0,0 +1,8 @@ +/* + * These are the same set of queries from "options-queries.sql" but + * are run with an explicit shard target of ks_sharded/40-80 which + * bypasses the normal v3 routing. + */ +select * from user where email='null@void.com'; +select * from user where id in (1,2,3,4,5,6,7,8); +insert into user (id, name) values (2, 'bob'); diff --git a/data/test/vtgate/filter_cases.txt b/data/test/vtgate/filter_cases.txt index e06b4723c2a..fc56c2d397b 100644 --- a/data/test/vtgate/filter_cases.txt +++ b/data/test/vtgate/filter_cases.txt @@ -766,4 +766,4 @@ # but they refer to different things. The first reference is to the outermost query, # and the second reference is to the the innermost 'from' subquery. "select id2 from user uu where id in (select id from user where id = uu.id and user.col in (select col from (select id from user_extra where user_id = 5) uu where uu.user_id = uu.id))" -"unsupported: subquery and parent route to different shards" +"unsupported: UNION or subquery on different shards: vindex values are different" diff --git a/data/test/vtgate/schema_test.json b/data/test/vtgate/schema_test.json index 5e6ad7b1c8c..0369446dcb5 100644 --- a/data/test/vtgate/schema_test.json +++ b/data/test/vtgate/schema_test.json @@ -12,7 +12,7 @@ "owner": "multicolvin" }, "user_md5_index": { - "type": "hash_test" + "type": "unicode_loose_md5" }, "music_user_map": { "type": "lookup_test", @@ -156,6 +156,9 @@ } ] }, + "pin_test": { + "pinned": "80" + }, "weird`name": { "column_vindexes": [ { diff --git a/data/test/vtgate/select_cases.txt b/data/test/vtgate/select_cases.txt index 441bee98b92..cfc528b251e 100644 --- a/data/test/vtgate/select_cases.txt +++ b/data/test/vtgate/select_cases.txt @@ -254,6 +254,26 @@ } } +# select from pinned table +"select * from pin_test" +{ + "Original": "select * from pin_test", + "Instructions": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select * from pin_test", + "FieldQuery": "select * from pin_test where 1 != 1", + "Vindex": "binary", + "Values": [ + "\ufffd" + ] + } +} + + # select from dual on sharded keyspace "select @@session.auto_increment_increment from user.dual" { diff --git a/data/test/vtgate/unsupported_cases.txt b/data/test/vtgate/unsupported_cases.txt index 897e4d128a1..d6a610a2aae 100644 --- a/data/test/vtgate/unsupported_cases.txt +++ b/data/test/vtgate/unsupported_cases.txt @@ -1,6 +1,6 @@ # Unions "select * from user union select * from user_extra" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" # SET "set a=1" @@ -29,11 +29,11 @@ # union operations in subqueries (FROM) "select * from (select * from user union all select * from user_extra) as t" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" # union operations in subqueries (expressions) "select * from user where id in (select * from user union select * from user_extra)" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" # subquery with join primitive (expressions) "select * from user where id in (select user.id from user join user_extra)" @@ -77,11 +77,11 @@ # subquery does not depend on unique vindex of outer query "select id from user where id in (select user_id from user_extra where user_extra.user_id = user.col)" -"unsupported: subquery does not depend on scatter outer query" +"unsupported: UNION or subquery containing multi-shard queries" # subquery does not depend on scatter outer query "select id from user where id in (select user_id from user_extra where user_extra.user_id = 4)" -"unsupported: subquery does not depend on scatter outer query" +"unsupported: UNION or subquery containing multi-shard queries" # subquery depends on a cross-shard subquery "select id from (select user.id, user.col from user join user_extra) as t where id in (select t.col from user)" @@ -105,7 +105,7 @@ # subquery and outer query route to different shards "select id from user where id = 5 and id in (select user_id from user_extra where user_extra.user_id = 4)" -"unsupported: subquery and parent route to different shards" +"unsupported: UNION or subquery on different shards: vindex values are different" # last_insert_id for sharded keyspace "select last_insert_id() from user" @@ -433,7 +433,7 @@ # multi-shard union "(select id from user union select id from music) union select 1 from dual" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" # multi-shard union "select 1 from music union (select id from user union all select name from unsharded)" @@ -445,15 +445,19 @@ # multi-shard union "select id from user union all select id from music" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" + +# union with the same target shard because of vindex +"select * from music where id = 1 union select * from user where id = 1" +"unsupported: UNION or subquery on different shards: vindexes are different" # union with different target shards "select 1 from music where id = 1 union select 1 from music where id = 2" -"unsupported: UNION queries with different target shards" +"unsupported: UNION or subquery on different shards: vindex values are different" # Union all "select col1, col2 from user union all select col1, col2 from user_extra" -"unsupported: UNION on multi-shard queries" +"unsupported: UNION or subquery containing multi-shard queries" "(select user.id, user.name from user join user_extra where user_extra.extra = 'asdf') union select 'b','c' from user" "unsupported construct: SELECT of UNION is non-trivial" diff --git a/doc/GettingStarted.md b/doc/GettingStarted.md index 6beb2a00cc6..8d39de3e92e 100644 --- a/doc/GettingStarted.md +++ b/doc/GettingStarted.md @@ -179,45 +179,24 @@ In addition, Vitess requires the software and libraries listed below. 5. Run the following commands: ``` sh - brew install go automake libtool python git bison curl wget homebrew/versions/mysql56 + brew install go automake libtool python git bison curl wget mysql56 pip install --upgrade pip setuptools pip install virtualenv pip install MySQL-python pip install tox + ``` -6. Install Java runtime from this URL: https://support.apple.com/kb/dl1572?locale=en_US - Apple only supports Java 6. If you need to install a newer version, this link might be helpful: - [http://osxdaily.com/2015/10/17/how-to-install-java-in-os-x-el-capitan/](http://osxdaily.com/2015/10/17/how-to-install-java-in-os-x-el-capitan/) - -7. The Vitess bootstrap script makes some checks for the go runtime, so it is recommended to have the following - commands in your ~/.profile or ~/.bashrc or ~/.zshrc: +6. The Vitess bootstrap script makes some checks for the go runtime, so it is recommended to have the following + commands in your ~/.profile or ~/.bashrc or ~/.zshrc or ~/.bash_profile: ``` sh - export PATH=/usr/local/opt/go/libexec/bin:$PATH - export GOROOT=/usr/local/opt/go/libexec - ``` - -8. There is a problem with installing the enum34 Python package using pip, so the following file has to be edited: - ``` - /usr/local/opt/python/Frameworks/Python.framework/Versions/2.7/lib/python2.7/distutils/distutils.cfg - ``` - - and this line: - - ``` - prefix=/usr/local + export PATH="/usr/local/opt/mysql@5.6/bin:$PATH" + export PATH=/usr/local/go/bin:$PATH + export GOROOT=/usr/local/go ``` - has to be commented out: - - ``` - # prefix=/usr/local - ``` - - After running the ./bootstrap.sh script from the next step, you can revert the change. - -9. For the Vitess hostname resolving functions to work correctly, a new entry has to be added into the /etc/hosts file +7. For the Vitess hostname resolving functions to work correctly, a new entry has to be added into the /etc/hosts file with the current LAN IP address of the computer (preferably IPv4) and the current hostname, which you get by typing the 'hostname' command in the terminal. @@ -232,38 +211,40 @@ In addition, Vitess requires the software and libraries listed below. 1. Navigate to the directory where you want to download the Vitess source code and clone the Vitess Github repo. After doing so, - navigate to the `src/vitess.io/vitess` directory. + navigate to the `src/vitess.io/vitess` directory. For go to work + correctly, you should create a symbolic link to this inide your ${HOME}/go/src ``` sh cd $WORKSPACE git clone https://github.com/vitessio/vitess.git \ src/vitess.io/vitess - cd src/vitess.io/vitess + ln -s src/vitess.io ${HOME}/go/src/vitess.io + cd ${HOME}/go/src/vitess.io/vitess ``` 1. Set the `MYSQL_FLAVOR` environment variable. Choose the appropriate value for your database. This value is case-sensitive. ``` sh - export MYSQL_FLAVOR=MariaDB + # export MYSQL_FLAVOR=MariaDB # or (mandatory for OS X) - # export MYSQL_FLAVOR=MySQL56 + export MYSQL_FLAVOR=MySQL56 ``` 1. If your selected database installed in a location other than `/usr/bin`, set the `VT_MYSQL_ROOT` variable to the root directory of your - MariaDB installation. For example, if MariaDB is installed in + MariaDB installation. For example, if mysql is installed in `/usr/local/mysql`, run the following command. ``` sh - export VT_MYSQL_ROOT=/usr/local/mysql + # export VT_MYSQL_ROOT=/usr/local/mysql # on OS X, this is the correct value: - # export VT_MYSQL_ROOT=/usr/local/opt/mysql56 + export VT_MYSQL_ROOT=/usr/local/opt/mysql@5.6 ``` Note that the command indicates that the `mysql` executable should - be found at `/usr/local/mysql/bin/mysql`. + be found at `/usr/local/opt/mysql@5.6/bin/mysql`. 1. Run `mysqld --version` and confirm that you are running the correct version of MariaDB or MySQL. The value should diff --git a/doc/GettingStartedKubernetes.md b/doc/GettingStartedKubernetes.md index 004efecaa5f..d0d358e3f8e 100644 --- a/doc/GettingStartedKubernetes.md +++ b/doc/GettingStartedKubernetes.md @@ -278,7 +278,7 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl 1. **Access vtctld web UI** To access vtctld from outside Kubernetes, use [kubectl proxy] - (http://kubernetes.io/v1.1/docs/user-guide/kubectl/kubectl_proxy.html) + (https://kubernetes.io/docs/tasks/access-kubernetes-api/http-proxy-access-api/) to create an authenticated tunnel on your workstation: **Note:** The proxy command runs in the foreground, @@ -292,13 +292,13 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl You can then load the vtctld web UI on `localhost`: - http://localhost:8001/api/v1/proxy/namespaces/default/services/vtctld:web/ + http://localhost:8001/api/v1/namespaces/default/services/vtctld:web/proxy You can also use this proxy to access the [Kubernetes Dashboard] - (http://kubernetes.io/v1.1/docs/user-guide/ui.html), + (https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/), where you can monitor nodes, pods, and services: - http://localhost:8001/ui + http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/. 1. **Use vtctlclient to send commands to vtctld** diff --git a/doc/VtExplain.md b/doc/VtExplain.md index c619faebc28..cb90924eb32 100644 --- a/doc/VtExplain.md +++ b/doc/VtExplain.md @@ -94,42 +94,50 @@ vtexplain -shards 8 -vschema-file /tmp/vschema.json -schema-file /tmp/schema.sql ---------------------------------------------------------------------- SELECT * from users -[mainkeyspace/c0-]: -select * from users limit 10001 +1 mainkeyspace/-20: select * from users limit 10001 +1 mainkeyspace/20-40: select * from users limit 10001 +1 mainkeyspace/40-60: select * from users limit 10001 +1 mainkeyspace/60-80: select * from users limit 10001 +1 mainkeyspace/80-a0: select * from users limit 10001 +1 mainkeyspace/a0-c0: select * from users limit 10001 +1 mainkeyspace/c0-e0: select * from users limit 10001 +1 mainkeyspace/e0-: select * from users limit 10001 -[mainkeyspace/-40]: -select * from users limit 10001 +---------------------------------------------------------------------- +``` -[mainkeyspace/40-80]: -select * from users limit 10001 +The output shows the sequence of queries run. -[mainkeyspace/80-c0]: -select * from users limit 10001 +In this case, the query planner is a scatter query to all shards, and each line shows: ----------------------------------------------------------------------- -``` +(a) the logical sequence of the query +(b) the keyspace/shard +(c) the query that was executed + +The fact that each query runs at time `1` shows that vitess executes these in parallel, and the `limit 10001` is automatically added as a protection against large results. **Insert:** ```bash -vtexplain -shards 1024 -vschema-file /tmp/vschema.json -schema-file /tmp/schema.sql -replication-mode "ROW" -output-mode text -sql "INSERT INTO users (user_id, name) VALUES(1, 'john')" +vtexplain -shards 128 -vschema-file /tmp/vschema.json -schema-file /tmp/schema.sql -replication-mode "ROW" -output-mode text -sql "INSERT INTO users (user_id, name) VALUES(1, 'john')" ---------------------------------------------------------------------- INSERT INTO users (user_id, name) VALUES(1, 'john') -[mainkeyspace/22c0-2300]: -begin -insert into users_name_idx(name, user_id) values ('john', 1) -commit - -[mainkeyspace/1640-1680]: -begin -insert into users(user_id, name) values (1, 'john') -commit +1 mainkeyspace/22-24: begin +1 mainkeyspace/22-24: insert into users_name_idx(name, user_id) values ('john', 1) /* vtgate:: keyspace_id:22c0c31d7a0b489a16332a5b32b028bc */ +2 mainkeyspace/16-18: begin +2 mainkeyspace/16-18: insert into users(user_id, name) values (1, 'john') /* vtgate:: keyspace_id:166b40b44aba4bd6 */ +3 mainkeyspace/22-24: commit +4 mainkeyspace/16-18: commit ---------------------------------------------------------------------- ``` +This example shows how Vitess handles an insert into a table with a secondary lookup vindex. + +First, at time `1`, a transaction is opened on one shard to insert the row into the `users_name_idx` table. Then at time `2` a second transaction is opened on another shard with the actual insert into the `users` table, and finally each transaction is committed at time `3` and `4`. + **Configuration Options** The `--shards` option specifies the number of shards to simulate. vtexplain will always allocate an evenly divided key range to each. diff --git a/examples/compose/README.md b/examples/compose/README.md index da5d8df5e64..82a54e1acbc 100644 --- a/examples/compose/README.md +++ b/examples/compose/README.md @@ -10,6 +10,7 @@ To start Consul(which saves the topology config), vtctld, vtgate and a few vttab ``` vitess/examples/compose$ docker-compose up -d ``` +Note that the vtgate container will likely fail to start. ### Load the schema We need to create a few tables into our new cluster. To do that, we can run the `ApplySchema` command. @@ -17,6 +18,12 @@ We need to create a few tables into our new cluster. To do that, we can run the vitess/examples/compose$ ./lvtctl.sh ApplySchema -sql "$(cat create_test_table.sql)" test_keyspace ``` +### Complete starting the cluster +Now that schema has been loaded a second start will bring vtgate up as well. +``` +vitess/examples/compose$ docker-compose up -d +``` + ### Run the client to insert and read some data This will build and run the `client.go` file. It will insert and read data from the master and from the replica. ``` diff --git a/examples/compose/vttablet-up.sh b/examples/compose/vttablet-up.sh index 63510ddfecb..91a3c1870e5 100755 --- a/examples/compose/vttablet-up.sh +++ b/examples/compose/vttablet-up.sh @@ -16,6 +16,9 @@ fi init_db_sql_file="$VTROOT/init_db.sql" echo "GRANT ALL ON *.* TO 'root'@'%';" > $init_db_sql_file +echo "GRANT ALL ON *.* TO 'vt_dba'@'%';" >> $init_db_sql_file +echo "GRANT ALL ON *.* TO 'vt_app'@'%';" >> $init_db_sql_file +echo "GRANT ALL ON *.* TO 'vt_repl'@'%';" >> $init_db_sql_file if [ "$tablet_role" = "master" ]; then echo "CREATE DATABASE vt_$keyspace;" >> $init_db_sql_file diff --git a/examples/kubernetes/vtctld-up.sh b/examples/kubernetes/vtctld-up.sh index 5ed5ff5b5a9..ff381129c10 100755 --- a/examples/kubernetes/vtctld-up.sh +++ b/examples/kubernetes/vtctld-up.sh @@ -47,5 +47,4 @@ cat vtctld-controller-template.yaml | sed -e "$sed_script" | $KUBECTL $KUBECTL_O echo echo "To access vtctld web UI, start kubectl proxy in another terminal:" echo " kubectl proxy --port=8001" -echo "Then visit http://localhost:8001/api/v1/proxy/namespaces/$VITESS_NAME/services/vtctld:web/" - +echo "Then visit http://localhost:8001/api/v1/namespaces/$VITESS_NAME/services/vtctld:web/proxy" \ No newline at end of file diff --git a/go/cmd/vtexplain/vtexplain.go b/go/cmd/vtexplain/vtexplain.go index db00e3d06d6..77f7688f4f4 100644 --- a/go/cmd/vtexplain/vtexplain.go +++ b/go/cmd/vtexplain/vtexplain.go @@ -40,6 +40,7 @@ var ( replicationMode = flag.String("replication-mode", "ROW", "The replication mode to simulate -- must be set to either ROW or STATEMENT") normalize = flag.Bool("normalize", false, "Whether to enable vtgate normalization") outputMode = flag.String("output-mode", "text", "Output in human-friendly text or json") + dbName = flag.String("dbname", "", "Optional database target to override normal routing") // vtexplainFlags lists all the flags that should show in usage vtexplainFlags = []string{ @@ -53,6 +54,7 @@ var ( "sql-file", "vschema", "vschema-file", + "dbname", } ) @@ -153,6 +155,7 @@ func parseAndRun() error { ReplicationMode: *replicationMode, NumShards: *numShards, Normalize: *normalize, + Target: *dbName, } log.V(100).Infof("sql %s\n", sql) diff --git a/go/cmd/vttablet/status.go b/go/cmd/vttablet/status.go index 9f43d06645a..850904d8afb 100644 --- a/go/cmd/vttablet/status.go +++ b/go/cmd/vttablet/status.go @@ -24,6 +24,7 @@ import ( _ "vitess.io/vitess/go/vt/status" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vttablet/tabletmanager" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tabletserver" ) @@ -119,48 +120,6 @@ var (
unhealthy
will not serve traffic.
-` - - // binlogTemplate is about the binlog players - binlogTemplate = ` -{{if .Controllers}} -Binlog player state: {{.State}}
- - - - - - - - - - - - - {{range .Controllers}} - - - - - - - - - - - - {{end}} -
IndexSourceShardStateStopPositionLastPositionSecondsBehindMasterCountsRatesLast Error
{{.Index}}{{.SourceShardAsHTML}}{{.State}} - {{if eq .State "Running"}} - {{if .SourceTabletAlias}} - (from {{github_com_vitessio_vitess_vtctld_tablet .SourceTabletAlias}}) - {{else}} - (picking source tablet) - {{end}} - {{end}}{{if .StopPosition}}{{.StopPosition}}{{end}}{{.LastPosition}}{{.SecondsBehindMaster}}{{range $key, $value := .Counts}}{{$key}}: {{$value}}
{{end}}
{{range $key, $values := .Rates}}{{$key}}: {{range $values}}{{.}} {{end}}
{{end}}
{{.LastError}}
-{{else}} -No binlog player is running. -{{end}} ` ) @@ -212,9 +171,7 @@ func addStatusParts(qsc tabletserver.Controller) { } }) qsc.AddStatusPart() - servenv.AddStatusPart("Binlog Player", binlogTemplate, func() interface{} { - return agent.BinlogPlayerMap.Status() - }) + vreplication.AddStatusPart() if onStatusRegistered != nil { onStatusRegistered() } diff --git a/go/cmd/vttablet/vttablet.go b/go/cmd/vttablet/vttablet.go index f4ebedd9f5b..dcc9768daa1 100644 --- a/go/cmd/vttablet/vttablet.go +++ b/go/cmd/vttablet/vttablet.go @@ -36,7 +36,7 @@ import ( var ( enforceTableACLConfig = flag.Bool("enforce-tableacl-config", false, "if this flag is true, vttablet will fail to start if a valid tableacl config does not exist") - tableACLConfig = flag.String("table-acl-config", "", "path to table access checker config file") + tableACLConfig = flag.String("table-acl-config", "", "path to table access checker config file; send SIGHUP to reload this file") tabletPath = flag.String("tablet-path", "", "tablet alias") agent *tabletmanager.ActionAgent @@ -115,19 +115,7 @@ func main() { qsc.StopService() }) - // tabletacl.Init loads ACL from file if *tableACLConfig is not empty - err = tableacl.Init( - *tableACLConfig, - func() { - qsc.ClearQueryPlanCache() - }, - ) - if err != nil { - log.Errorf("Fail to initialize Table ACL: %v", err) - if *enforceTableACLConfig { - log.Exit("Need a valid initial Table ACL when enforce-tableacl-config is set, exiting.") - } - } + qsc.InitACL(*tableACLConfig, *enforceTableACLConfig) // Create mysqld and register the health reporter (needs to be done // before initializing the agent, so the initial health check diff --git a/go/mysql/conn.go b/go/mysql/conn.go index 1292086cc8a..4a08057ead4 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -46,13 +46,13 @@ const ( // ephemeralWriteSingleBuffer means a single buffer was // allocated to write a packet. It is in - // c.currentEphemeralPacket. The first four bytes contain size + // c.currentEphemeralWriteBuffer. The first four bytes contain size // and sequence. ephemeralWriteSingleBuffer // ephemeralWriteBigBuffer means a big buffer was allocated to // write a packet, and will need to be split when sending. - // The allocated buffer is in c.currentEphemeralPacket. + // The allocated buffer is in c.currentEphemeralWriteBuffer. ephemeralWriteBigBuffer // ephemeralReadGlobalBuffer means conn.buffer was used for reading @@ -182,13 +182,37 @@ type Conn struct { // - startEphemeralPacket / writeEphemeralPacket methods for writes. // - readEphemeralPacket / recycleReadPacket methods for reads. currentEphemeralPolicy int - currentEphemeralPacket []byte - currentEphemeralBuffer *[]byte + // TODO (danieltahara): Ultimately get rid of this delineation. + // currentEphemeralWriteBuffer and currentEphemeralReadBuffer used for tracking + // allocated temporary buffers for writes and reads respectively. + currentEphemeralWriteBuffer *[]byte + currentEphemeralReadBuffer *[]byte } // bufPool is used to allocate and free buffers in an efficient way. var bufPool = sync.Pool{} +// length is always > connBufferSize here, for smaller buffers static buffer field is used +func getBuf(length int) *[]byte { + i := bufPool.Get() + if i == nil { + buf := make([]byte, length) + return &buf + } + // We got an array from the pool, see if it's + // big enough. + buf := i.(*[]byte) + if cap(*buf) >= length { + // big enough, shrink to length and use it. + *buf = (*buf)[:length] + return buf + } + // not big enough: allocate a new one, put smaller buffer back to the pool + bufPool.Put(buf) + data := make([]byte, length) + return &data +} + // newConn is an internal method to create a Conn. Used by client and server // side for common creation code. func newConn(conn net.Conn) *Conn { @@ -313,30 +337,11 @@ func (c *Conn) readEphemeralPacket() ([]byte, error) { // Slightly slower path: single packet. Use the bufPool. if length < MaxPacketSize { c.currentEphemeralPolicy = ephemeralReadSingleBuffer - i := bufPool.Get() - if i == nil { - // We couldn't get an array from the pool, allocate one. - data := make([]byte, length) - c.currentEphemeralBuffer = &data - } else { - // We got an array from the pool, see if it's - // big enough. - data := i.(*[]byte) - if cap(*data) >= length { - // big enough, just use it. - *data = (*data)[:length] - c.currentEphemeralBuffer = data - } else { - // not big enough: allocate a new one, discard - // the smaller buffer. - data := make([]byte, length) - c.currentEphemeralBuffer = &data - } - } - if _, err := io.ReadFull(c.reader, *c.currentEphemeralBuffer); err != nil { + c.currentEphemeralReadBuffer = getBuf(length) + if _, err := io.ReadFull(c.reader, *c.currentEphemeralReadBuffer); err != nil { return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err) } - return *c.currentEphemeralBuffer, nil + return *c.currentEphemeralReadBuffer, nil } // Much slower path, revert to allocating everything from scratch. @@ -375,11 +380,12 @@ func (c *Conn) recycleReadPacket() { // We used small built-in buffer, nothing to do. case ephemeralReadSingleBuffer: // We are using the pool, put the buffer back in. - bufPool.Put(c.currentEphemeralBuffer) - c.currentEphemeralBuffer = nil + bufPool.Put(c.currentEphemeralReadBuffer) + c.currentEphemeralReadBuffer = nil case ephemeralReadBigBuffer: // We allocated a one-time buffer we can't re-use. - // Nothing to do. + // Nothing to do. Nil out for safety. + c.currentEphemeralReadBuffer = nil case ephemeralUnused, ephemeralWriteGlobalBuffer, ephemeralWriteSingleBuffer, ephemeralWriteBigBuffer: // Programming error. panic(fmt.Errorf("trying to call recycleReadPacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) @@ -546,28 +552,28 @@ func (c *Conn) startEphemeralPacket(length int) []byte { // Slower path: we can use a single buffer for both the header and the data, but it has to be allocated. if length < MaxPacketSize { c.currentEphemeralPolicy = ephemeralWriteSingleBuffer - c.currentEphemeralPacket = make([]byte, length+4) - c.currentEphemeralPacket[0] = byte(length) - c.currentEphemeralPacket[1] = byte(length >> 8) - c.currentEphemeralPacket[2] = byte(length >> 16) - c.currentEphemeralPacket[3] = c.sequence + + c.currentEphemeralWriteBuffer = getBuf(length + 4) + (*c.currentEphemeralWriteBuffer)[0] = byte(length) + (*c.currentEphemeralWriteBuffer)[1] = byte(length >> 8) + (*c.currentEphemeralWriteBuffer)[2] = byte(length >> 16) + (*c.currentEphemeralWriteBuffer)[3] = c.sequence c.sequence++ - return c.currentEphemeralPacket[4:] + return (*c.currentEphemeralWriteBuffer)[4:] } // Even slower path: create a full size buffer and return it. c.currentEphemeralPolicy = ephemeralWriteBigBuffer - c.currentEphemeralPacket = make([]byte, length) - return c.currentEphemeralPacket + data := make([]byte, length) + c.currentEphemeralWriteBuffer = &data + return *c.currentEphemeralWriteBuffer } // writeEphemeralPacket writes the packet that was allocated by // startEphemeralPacket. If 'direct' is set, we write to the // underlying connection directly, by-passing the write buffer. func (c *Conn) writeEphemeralPacket(direct bool) error { - defer func() { - c.currentEphemeralPolicy = ephemeralUnused - }() + defer c.recycleWritePacket() var w io.Writer = c.writer if direct { @@ -586,16 +592,16 @@ func (c *Conn) writeEphemeralPacket(direct bool) error { case ephemeralWriteSingleBuffer: // Write the allocated buffer as a single buffer. // It has both header and data. - if n, err := w.Write(c.currentEphemeralPacket); err != nil { - return fmt.Errorf("Conn %v: Write(c.currentEphemeralPacket) failed: %v", c.ID(), err) - } else if n != len(c.currentEphemeralPacket) { - return fmt.Errorf("Conn %v: Write(c.currentEphemeralPacket) returned a short write: %v < %v", c.ID(), n, len(c.currentEphemeralPacket)) + if n, err := w.Write(*c.currentEphemeralWriteBuffer); err != nil { + return fmt.Errorf("Conn %v: Write(*c.currentEphemeralWriteBuffer) failed: %v", c.ID(), err) + } else if n != len(*c.currentEphemeralWriteBuffer) { + return fmt.Errorf("Conn %v: Write(*c.currentEphemeralWriteBuffer) returned a short write: %v < %v", c.ID(), n, len(*c.currentEphemeralWriteBuffer)) } case ephemeralWriteBigBuffer: // This is the slower path for big data. // With direct=true, the caller expects a flush, so we call it // manually. - if err := c.writePacket(c.currentEphemeralPacket); err != nil { + if err := c.writePacket(*c.currentEphemeralWriteBuffer); err != nil { return fmt.Errorf("Conn %v: %v", c.ID(), err) } if direct { @@ -609,6 +615,29 @@ func (c *Conn) writeEphemeralPacket(direct bool) error { return nil } +// recycleWritePacket recycles the write packet. It needs to be called +// after writeEphemeralPacket was called. +func (c *Conn) recycleWritePacket() { + switch c.currentEphemeralPolicy { + case ephemeralWriteGlobalBuffer: + // We used small built-in buffer, nothing to do. + case ephemeralWriteSingleBuffer: + // Release our reference so the buffer can be gced + bufPool.Put(c.currentEphemeralWriteBuffer) + c.currentEphemeralWriteBuffer = nil + case ephemeralWriteBigBuffer: + // We allocated a one-time buffer we can't re-use. + // N.B. Unlike the read packet, we actually assign the big buffer to currentEphemeralReadBuffer, + // so we should remove our reference to it. + c.currentEphemeralWriteBuffer = nil + case ephemeralUnused, ephemeralReadGlobalBuffer, + ephemeralReadSingleBuffer, ephemeralReadBigBuffer: + // Programming error. + panic(fmt.Errorf("trying to call recycleWritePacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) + } + c.currentEphemeralPolicy = ephemeralUnused +} + // flush flushes the written data to the socket. // This method returns a generic error, not a SQLError. func (c *Conn) flush() error { diff --git a/go/mysql/conn_params.go b/go/mysql/conn_params.go index 053e662b165..ae739c9b59c 100644 --- a/go/mysql/conn_params.go +++ b/go/mysql/conn_params.go @@ -34,6 +34,10 @@ type ConnParams struct { SslCert string `json:"ssl_cert"` SslKey string `json:"ssl_key"` ServerName string `json:"server_name"` + + // The following is only set when the deprecated "dbname" flags are + // supplied and will be removed. + DeprecatedDBName string } // EnableSSL will set the right flag on the parameters. diff --git a/go/mysql/query_benchmark_test.go b/go/mysql/query_benchmark_test.go index b0aa36e4710..173932ec00c 100644 --- a/go/mysql/query_benchmark_test.go +++ b/go/mysql/query_benchmark_test.go @@ -17,19 +17,15 @@ limitations under the License. package mysql import ( + "math/rand" "net" - "sync" + "strings" "testing" "golang.org/x/net/context" ) -// This file contains various long-running tests for mysql. - -// BenchmarkParallelShortQueries creates N simultaneous connections, then -// executes M queries on them, then closes them. -// It is meant as a somewhat real load test. -func BenchmarkParallelShortQueries(b *testing.B) { +func benchmarkQuery(b *testing.B, threads int, query string) { th := &testHandler{} authServer := &AuthServerNone{} @@ -44,6 +40,11 @@ func BenchmarkParallelShortQueries(b *testing.B) { l.Accept() }() + b.SetParallelism(threads) + if query != "" { + b.SetBytes(int64(len(query))) + } + host := l.Addr().(*net.TCPAddr).IP.String() port := l.Addr().(*net.TCPAddr).Port params := &ConnParams{ @@ -52,46 +53,47 @@ func BenchmarkParallelShortQueries(b *testing.B) { Uname: "user1", Pass: "password1", } - ctx := context.Background() - threadCount := 10 - - wg := sync.WaitGroup{} - conns := make([]*Conn, threadCount) - for i := 0; i < threadCount; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - - var err error - conns[i], err = Connect(ctx, params) - if err != nil { - b.Errorf("cannot connect: %v", err) - return - } - }(i) - } - wg.Wait() b.ResetTimer() - for i := 0; i < threadCount; i++ { - wg.Add(1) - go func(i int) { - defer func() { - wg.Done() - conns[i].writeComQuit() - conns[i].Close() - }() - for j := 0; j < b.N; j++ { - _, err = conns[i].ExecuteFetch("select rows", 1000, true) - if err != nil { - b.Errorf("ExecuteFetch failed: %v", err) - return - } + + b.RunParallel(func(pb *testing.PB) { + conn, err := Connect(ctx, params) + if err != nil { + b.Fatal(err) + } + defer func() { + conn.writeComQuit() + conn.Close() + }() + + for pb.Next() { + execQuery := query + if execQuery == "" { + // generate random query + n := rand.Intn(MaxPacketSize-2) + 1 + execQuery = strings.Repeat("x", n) } - }(i) - } + if _, err := conn.ExecuteFetch(execQuery, 1000, true); err != nil { + b.Fatalf("ExecuteFetch failed: %v", err) + } + } + }) +} + +// This file contains various long-running tests for mysql. + +// BenchmarkParallelShortQueries creates N simultaneous connections, then +// executes M queries on them, then closes them. +// It is meant as a somewhat real load test. +func BenchmarkParallelShortQueries(b *testing.B) { + benchmarkQuery(b, 10, "select rows") +} - wg.Wait() +func BenchmarkParallelMediumQueries(b *testing.B) { + benchmarkQuery(b, 10, "select"+strings.Repeat("x", connBufferSize)) +} +func BenchmarkParallelRandomQueries(b *testing.B) { + benchmarkQuery(b, 10, "") } diff --git a/go/pools/numbered.go b/go/pools/numbered.go index 4482323df69..f9e6107d5cc 100644 --- a/go/pools/numbered.go +++ b/go/pools/numbered.go @@ -64,31 +64,47 @@ func NewNumbered() *Numbered { // It does not lock the object. // It returns an error if the id already exists. func (nu *Numbered) Register(id int64, val interface{}, enforceTimeout bool) error { - nu.mu.Lock() - defer nu.mu.Unlock() - if _, ok := nu.resources[id]; ok { - return fmt.Errorf("already present") - } + // Optimistically assume we're not double registering. now := time.Now() - nu.resources[id] = &numberedWrapper{ + resource := &numberedWrapper{ val: val, timeCreated: now, timeUsed: now, enforceTimeout: enforceTimeout, } + + nu.mu.Lock() + defer nu.mu.Unlock() + + _, ok := nu.resources[id] + if ok { + return fmt.Errorf("already present") + } + nu.resources[id] = resource return nil } -// Unregiester forgets the specified resource. -// If the resource is not present, it's ignored. +// Unregister forgets the specified resource. If the resource is not present, it's ignored. func (nu *Numbered) Unregister(id int64, reason string) { + success := nu.unregister(id, reason) + if success { + nu.recentlyUnregistered.Set( + fmt.Sprintf("%v", id), &unregistered{reason: reason, timeUnregistered: time.Now()}) + } +} + +// unregister forgets the resource, if it exists. Returns whether or not the resource existed at +// time of Unregister. +func (nu *Numbered) unregister(id int64, reason string) bool { nu.mu.Lock() defer nu.mu.Unlock() + + _, ok := nu.resources[id] delete(nu.resources, id) if len(nu.resources) == 0 { nu.empty.Broadcast() } - nu.recentlyUnregistered.Set(fmt.Sprintf("%v", id), &unregistered{reason: reason, timeUnregistered: time.Now()}) + return ok } // Get locks the resource for use. It accepts a purpose as a string. diff --git a/go/pools/numbered_test.go b/go/pools/numbered_test.go index 48cfbb4cbf5..25c737579e5 100644 --- a/go/pools/numbered_test.go +++ b/go/pools/numbered_test.go @@ -17,6 +17,7 @@ limitations under the License. package pools import ( + "math/rand" "strings" "testing" "time" @@ -103,3 +104,35 @@ func TestNumbered(t *testing.T) { }() p.WaitForEmpty() } + +/* +go test --test.run=XXX --test.bench=. --test.benchtime=10s + +golang.org/x/tools/cmd/benchcmp /tmp/bad.out /tmp/good.out + +benchmark old ns/op new ns/op delta +BenchmarkRegisterUnregister-8 667 596 -10.64% +BenchmarkRegisterUnregisterParallel-8 2430 1752 -27.90% +*/ +func BenchmarkRegisterUnregister(b *testing.B) { + p := NewNumbered() + id := int64(1) + val := "foobarbazdummyval" + for i := 0; i < b.N; i++ { + p.Register(id, val, false) + p.Unregister(id, "some reason") + } +} + +func BenchmarkRegisterUnregisterParallel(b *testing.B) { + p := NewNumbered() + val := "foobarbazdummyval" + b.SetParallelism(200) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + id := rand.Int63() + p.Register(id, val, false) + p.Unregister(id, "some reason") + } + }) +} diff --git a/go/sqltypes/arithmetic.go b/go/sqltypes/arithmetic.go index b91cdf9a489..9b02ec56048 100644 --- a/go/sqltypes/arithmetic.go +++ b/go/sqltypes/arithmetic.go @@ -248,7 +248,7 @@ func ToNative(v Value) (interface{}, error) { return ToUint64(v) case v.IsFloat(): return ToFloat64(v) - case v.IsQuoted() || v.Type() == Decimal: + case v.IsQuoted() || v.Type() == Bit || v.Type() == Decimal: out = v.val case v.Type() == Expression: err = vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v cannot be converted to a go type", v) diff --git a/go/sqltypes/bind_variables.go b/go/sqltypes/bind_variables.go index e0b06d68210..f204534d0f9 100644 --- a/go/sqltypes/bind_variables.go +++ b/go/sqltypes/bind_variables.go @@ -17,6 +17,7 @@ limitations under the License. package sqltypes import ( + "bytes" "errors" "fmt" "strconv" @@ -266,3 +267,53 @@ func CopyBindVariables(bindVariables map[string]*querypb.BindVariable) map[strin } return result } + +// FormatBindVariables returns a string representation of the +// bind variables. +// +// If full is false, then large string or tuple values are truncated +// to only print the lengths. +// +// If asJson is true, then the resulting string is a valid JSON +// representation, otherwise it is the golang printed map representation. +func FormatBindVariables(bindVariables map[string]*querypb.BindVariable, full, asJSON bool) string { + var out map[string]*querypb.BindVariable + if full { + out = bindVariables + } else { + // NOTE(szopa): I am getting rid of potentially large bind + // variables. + out = make(map[string]*querypb.BindVariable) + for k, v := range bindVariables { + if IsIntegral(v.Type) || IsFloat(v.Type) { + out[k] = v + } else if v.Type == querypb.Type_TUPLE { + out[k] = StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) + } else { + out[k] = StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) + } + } + } + + if asJSON { + var buf bytes.Buffer + buf.WriteString("{") + first := true + for k, v := range out { + if !first { + buf.WriteString(", ") + } else { + first = false + } + if IsIntegral(v.Type) || IsFloat(v.Type) { + fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) + } else { + fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) + } + } + buf.WriteString("}") + return buf.String() + } + + return fmt.Sprintf("%v", out) +} diff --git a/go/sqltypes/bind_variables_test.go b/go/sqltypes/bind_variables_test.go index 6f6f61c95ad..aecce9db2e6 100644 --- a/go/sqltypes/bind_variables_test.go +++ b/go/sqltypes/bind_variables_test.go @@ -553,3 +553,84 @@ func TestBindVariablesEqual(t *testing.T) { t.Errorf("%v = %v, want not equal", bv1, bv3) } } + +func TestBindVariablesFormat(t *testing.T) { + tupleBindVar, err := BuildBindVariable([]int64{1, 2}) + if err != nil { + t.Fatalf("failed to create a tuple bind var: %v", err) + } + + bindVariables := map[string]*querypb.BindVariable{ + "key_1": StringBindVariable("val_1"), + "key_2": Int64BindVariable(789), + "key_3": BytesBindVariable([]byte("val_3")), + "key_4": tupleBindVar, + } + + formattedStr := FormatBindVariables(bindVariables, true /* full */, false /* asJSON */) + if !strings.Contains(formattedStr, "key_1") || + !strings.Contains(formattedStr, "val_1") { + t.Fatalf("bind variable 'key_1': 'val_1' is not formatted") + } + if !strings.Contains(formattedStr, "key_2") || + !strings.Contains(formattedStr, "789") { + t.Fatalf("bind variable 'key_2': '789' is not formatted") + } + if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "val_3") { + t.Fatalf("bind variable 'key_3': 'val_3' is not formatted") + } + if !strings.Contains(formattedStr, "key_4") || + !strings.Contains(formattedStr, "values: values:") { + t.Fatalf("bind variable 'key_4': (1, 2) is not formatted") + } + + formattedStr = FormatBindVariables(bindVariables, false /* full */, false /* asJSON */) + if !strings.Contains(formattedStr, "key_1") { + t.Fatalf("bind variable 'key_1' is not formatted") + } + if !strings.Contains(formattedStr, "key_2") || + !strings.Contains(formattedStr, "789") { + t.Fatalf("bind variable 'key_2': '789' is not formatted") + } + if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "5 bytes") { + t.Fatalf("bind variable 'key_3' is not formatted") + } + if !strings.Contains(formattedStr, "key_4") || !strings.Contains(formattedStr, "2 items") { + t.Fatalf("bind variable 'key_4' is not formatted") + } + + formattedStr = FormatBindVariables(bindVariables, true /* full */, true /* asJSON */) + t.Logf("%q", formattedStr) + if !strings.Contains(formattedStr, "\"key_1\": {\"type\": \"VARCHAR\", \"value\": \"val_1\"}") { + t.Fatalf("bind variable 'key_1' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_2\": {\"type\": \"INT64\", \"value\": 789}") { + t.Fatalf("bind variable 'key_2' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_3\": {\"type\": \"VARBINARY\", \"value\": \"val_3\"}") { + t.Fatalf("bind variable 'key_3' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_4\": {\"type\": \"TUPLE\", \"value\": \"\"}") { + t.Fatalf("bind variable 'key_4' is not formatted") + } + + formattedStr = FormatBindVariables(bindVariables, false /* full */, true /* asJSON */) + if !strings.Contains(formattedStr, "\"key_1\": {\"type\": \"VARCHAR\", \"value\": \"5 bytes\"}") { + t.Fatalf("bind variable 'key_1' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_2\": {\"type\": \"INT64\", \"value\": 789}") { + t.Fatalf("bind variable 'key_2' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_3\": {\"type\": \"VARCHAR\", \"value\": \"5 bytes\"}") { + t.Fatalf("bind variable 'key_3' is not formatted") + } + + if !strings.Contains(formattedStr, "\"key_4\": {\"type\": \"VARCHAR\", \"value\": \"2 items\"}") { + t.Fatalf("bind variable 'key_4' is not formatted") + } +} diff --git a/go/sqltypes/type.go b/go/sqltypes/type.go index f2032da33bb..cf1bed67a42 100644 --- a/go/sqltypes/type.go +++ b/go/sqltypes/type.go @@ -66,7 +66,7 @@ func IsFloat(t querypb.Type) bool { // IsQuoted returns true if querypb.Type is a quoted text or binary. // If you have a Value object, use its member function. func IsQuoted(t querypb.Type) bool { - return int(t)&flagIsQuoted == flagIsQuoted + return (int(t)&flagIsQuoted == flagIsQuoted) && t != Bit } // IsText returns true if querypb.Type is a text. @@ -95,7 +95,7 @@ func isNumber(t querypb.Type) bool { // instead. // The following conditions are non-overlapping // and cover all types: IsSigned(), IsUnsigned(), -// IsFloat(), IsQuoted(), Null, Decimal, Expression. +// IsFloat(), IsQuoted(), Null, Decimal, Expression, Bit // Also, IsIntegral() == (IsSigned()||IsUnsigned()). // TestCategory needs to be updated accordingly if // you add a new type. diff --git a/go/sqltypes/type_test.go b/go/sqltypes/type_test.go index 74f6cbc1a88..08aed75c81b 100644 --- a/go/sqltypes/type_test.go +++ b/go/sqltypes/type_test.go @@ -192,7 +192,7 @@ func TestCategory(t *testing.T) { } matched = true } - if typ == Null || typ == Decimal || typ == Expression { + if typ == Null || typ == Decimal || typ == Expression || typ == Bit { if matched { t.Errorf("%v matched more than one category", typ) } diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go index 6e64263905b..b788700be81 100644 --- a/go/sqltypes/value.go +++ b/go/sqltypes/value.go @@ -74,7 +74,7 @@ func NewValue(typ querypb.Type, val []byte) (v Value, err error) { return NULL, err } return MakeTrusted(typ, val), nil - case IsQuoted(typ) || typ == Null: + case IsQuoted(typ) || typ == Bit || typ == Null: return MakeTrusted(typ, val), nil } // All other types are unsafe or invalid. @@ -205,7 +205,7 @@ func (v Value) String() string { if v.typ == Null { return "NULL" } - if v.IsQuoted() { + if v.IsQuoted() || v.typ == Bit { return fmt.Sprintf("%v(%q)", v.typ, v.val) } return fmt.Sprintf("%v(%s)", v.typ, v.val) @@ -218,6 +218,8 @@ func (v Value) EncodeSQL(b BinWriter) { b.Write(nullstr) case v.IsQuoted(): encodeBytesSQL(v.val, b) + case v.typ == Bit: + encodeBytesSQLBits(v.val, b) default: b.Write(v.val) } @@ -228,7 +230,7 @@ func (v Value) EncodeASCII(b BinWriter) { switch { case v.typ == Null: b.Write(nullstr) - case v.IsQuoted(): + case v.IsQuoted() || v.typ == Bit: encodeBytesASCII(v.val, b) default: b.Write(v.val) @@ -279,7 +281,7 @@ func (v Value) IsBinary() bool { // It's not a complete implementation. func (v Value) MarshalJSON() ([]byte, error) { switch { - case v.IsQuoted(): + case v.IsQuoted() || v.typ == Bit: return json.Marshal(v.ToString()) case v.typ == Null: return nullstr, nil @@ -333,6 +335,14 @@ func encodeBytesSQL(val []byte, b BinWriter) { b.Write(buf.Bytes()) } +func encodeBytesSQLBits(val []byte, b BinWriter) { + fmt.Fprint(b, "b'") + for _, ch := range val { + fmt.Fprintf(b, "%08b", ch) + } + fmt.Fprint(b, "'") +} + func encodeBytesASCII(val []byte, b BinWriter) { buf := &bytes2.Buffer{} buf.WriteByte('\'') diff --git a/go/sqltypes/value_test.go b/go/sqltypes/value_test.go index 73df210c50b..2a76058bb33 100644 --- a/go/sqltypes/value_test.go +++ b/go/sqltypes/value_test.go @@ -257,7 +257,7 @@ func TestIntegralValue(t *testing.T) { } } -func TestInerfaceValue(t *testing.T) { +func TestInterfaceValue(t *testing.T) { testcases := []struct { in interface{} out Value @@ -382,6 +382,10 @@ func TestEncode(t *testing.T) { in: TestValue(VarChar, "\x00'\"\b\n\r\t\x1A\\"), outSQL: "'\\0\\'\\\"\\b\\n\\r\\t\\Z\\\\'", outASCII: "'ACciCAoNCRpc'", + }, { + in: TestValue(Bit, "a"), + outSQL: "b'01100001'", + outASCII: "'YQ=='", }} for _, tcase := range testcases { buf := &bytes.Buffer{} diff --git a/go/stats/export.go b/go/stats/export.go index 6239cf6cb1a..b5e516cf975 100644 --- a/go/stats/export.go +++ b/go/stats/export.go @@ -149,50 +149,15 @@ func emitToBackend(emitPeriod *time.Duration) { } } -// Float is expvar.Float+Get+hook -type Float struct { - mu sync.Mutex - f float64 -} - -// NewFloat creates a new Float and exports it. -func NewFloat(name string) *Float { - v := new(Float) - publish(name, v) - return v -} - -// Add adds the provided value to the Float -func (v *Float) Add(delta float64) { - v.mu.Lock() - v.f += delta - v.mu.Unlock() -} - -// Set sets the value -func (v *Float) Set(value float64) { - v.mu.Lock() - v.f = value - v.mu.Unlock() -} - -// Get returns the value -func (v *Float) Get() float64 { - v.mu.Lock() - f := v.f - v.mu.Unlock() - return f -} - -// String is the implementation of expvar.var -func (v *Float) String() string { - return strconv.FormatFloat(v.Get(), 'g', -1, 64) -} - // FloatFunc converts a function that returns // a float64 as an expvar. type FloatFunc func() float64 +// Help returns the help string (undefined currently) +func (f FloatFunc) Help() string { + return "help" +} + // String is the implementation of expvar.var func (f FloatFunc) String() string { return strconv.FormatFloat(f(), 'g', -1, 64) @@ -255,41 +220,6 @@ func PublishJSONFunc(name string, f func() string) { publish(name, JSONFunc(f)) } -// StringMap is a map of string -> string -type StringMap struct { - mu sync.Mutex - values map[string]string -} - -// NewStringMap returns a new StringMap -func NewStringMap(name string) *StringMap { - v := &StringMap{values: make(map[string]string)} - publish(name, v) - return v -} - -// Set will set a value (existing or not) -func (v *StringMap) Set(name, value string) { - v.mu.Lock() - v.values[name] = value - v.mu.Unlock() -} - -// Get will return the value, or "" f not set. -func (v *StringMap) Get(name string) string { - v.mu.Lock() - s := v.values[name] - v.mu.Unlock() - return s -} - -// String is the implementation of expvar.Var -func (v *StringMap) String() string { - v.mu.Lock() - defer v.mu.Unlock() - return stringMapToString(v.values) -} - // StringMapFunc is the function equivalent of StringMap type StringMapFunc func() map[string]string diff --git a/go/stats/export_test.go b/go/stats/export_test.go index 32d71057c40..792902a2cab 100644 --- a/go/stats/export_test.go +++ b/go/stats/export_test.go @@ -35,41 +35,6 @@ func TestNoHook(t *testing.T) { } } -func TestFloat(t *testing.T) { - var gotname string - var gotv *Float - clear() - Register(func(name string, v expvar.Var) { - gotname = name - gotv = v.(*Float) - }) - v := NewFloat("Float") - if gotname != "Float" { - t.Errorf("want Float, got %s", gotname) - } - if gotv != v { - t.Errorf("want %#v, got %#v", v, gotv) - } - v.Set(5.1) - if v.Get() != 5.1 { - t.Errorf("want 5.1, got %v", v.Get()) - } - v.Add(1.0) - if v.Get() != 6.1 { - t.Errorf("want 6.1, got %v", v.Get()) - } - if v.String() != "6.1" { - t.Errorf("want 6.1, got %v", v.Get()) - } - - f := FloatFunc(func() float64 { - return 1.234 - }) - if f.String() != "1.234" { - t.Errorf("want 1.234, got %v", f.String()) - } -} - func TestString(t *testing.T) { var gotname string var gotv *String @@ -129,15 +94,21 @@ func f() string { return "abcd" } +type expvarFunc func() string + +func (f expvarFunc) String() string { + return f() +} + func TestPublishFunc(t *testing.T) { var gotname string - var gotv JSONFunc + var gotv expvarFunc clear() Register(func(name string, v expvar.Var) { gotname = name - gotv = v.(JSONFunc) + gotv = v.(expvarFunc) }) - PublishJSONFunc("Myfunc", f) + publish("Myfunc", expvarFunc(f)) if gotname != "Myfunc" { t.Errorf("want Myfunc, got %s", gotname) } @@ -145,26 +116,3 @@ func TestPublishFunc(t *testing.T) { t.Errorf("want %v, got %#v", f(), gotv()) } } - -func TestStringMap(t *testing.T) { - clear() - c := NewStringMap("stringmap1") - c.Set("c1", "val1") - c.Set("c2", "val2") - c.Set("c2", "val3") - want1 := `{"c1": "val1", "c2": "val3"}` - want2 := `{"c2": "val3", "c1": "val1"}` - if s := c.String(); s != want1 && s != want2 { - t.Errorf("want %s or %s, got %s", want1, want2, s) - } - - f := StringMapFunc(func() map[string]string { - return map[string]string{ - "c1": "val1", - "c2": "val3", - } - }) - if s := f.String(); s != want1 && s != want2 { - t.Errorf("want %s or %s, got %s", want1, want2, s) - } -} diff --git a/go/stats/influxdbbackend/influxdb_backend.go b/go/stats/influxdbbackend/influxdb_backend.go index 193522a8f12..54a4e41a820 100644 --- a/go/stats/influxdbbackend/influxdb_backend.go +++ b/go/stats/influxdbbackend/influxdb_backend.go @@ -94,8 +94,6 @@ func (backend *InfluxDBBackend) PushAll() error { // for arbitrary dict values (as tags). func statToValue(v expvar.Var) interface{} { switch v := v.(type) { - case *stats.Float: - return v.Get() case *stats.Counter: return v.Get() case stats.FloatFunc: diff --git a/go/stats/opentsdb/opentsdb.go b/go/stats/opentsdb/opentsdb.go index ccc8cd0e2b5..9b9c1b8fdc4 100644 --- a/go/stats/opentsdb/opentsdb.go +++ b/go/stats/opentsdb/opentsdb.go @@ -181,8 +181,6 @@ func (dc *dataCollector) addFloat(metric string, val float64, tags map[string]st func (dc *dataCollector) addExpVar(kv expvar.KeyValue) { k := kv.Key switch v := kv.Value.(type) { - case *stats.Float: - dc.addFloat(k, v.Get(), nil) case stats.FloatFunc: dc.addFloat(k, v(), nil) case *stats.Counter: diff --git a/go/stats/prometheusbackend/prometheusbackend.go b/go/stats/prometheusbackend/prometheusbackend.go index 00a3b55222b..961d88fe01a 100644 --- a/go/stats/prometheusbackend/prometheusbackend.go +++ b/go/stats/prometheusbackend/prometheusbackend.go @@ -4,12 +4,11 @@ import ( "expvar" "net/http" "strings" - "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/log" ) // PromBackend implements PullBackend using Prometheus as the backing metrics storage. @@ -18,15 +17,13 @@ type PromBackend struct { } var ( - be PromBackend - logUnsupported *logutil.ThrottledLogger + be PromBackend ) // Init initializes the Prometheus be with the given namespace. func Init(namespace string) { http.Handle("/metrics", promhttp.Handler()) be.namespace = namespace - logUnsupported = logutil.NewThrottledLogger("PrometheusUnsupportedMetricType", 1*time.Minute) stats.Register(be.publishPrometheusMetric) } @@ -41,6 +38,8 @@ func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) { newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.Get()) }) case *stats.GaugeFunc: newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return float64(st.F()) }) + case stats.FloatFunc: + newMetricFuncCollector(st, be.buildPromName(name), prometheus.GaugeValue, func() float64 { return (st)() }) case *stats.CountersWithSingleLabel: newCountersWithSingleLabelCollector(st, be.buildPromName(name), st.Label(), prometheus.CounterValue) case *stats.CountersWithMultiLabels: @@ -67,8 +66,11 @@ func (be PromBackend) publishPrometheusMetric(name string, v expvar.Var) { newMultiTimingsCollector(st, be.buildPromName(name)) case *stats.Histogram: newHistogramCollector(st, be.buildPromName(name)) + case *stats.String, stats.StringFunc, stats.StringMapFunc, *stats.Rates: + // Silently ignore these types since they don't make sense to + // export to Prometheus' data model. default: - logUnsupported.Infof("Not exporting to Prometheus an unsupported metric type of %T: %s", st, name) + log.Fatalf("prometheus: Metric type %T (seen for variable: %s) is not covered by type switch. Add it there and to all other plugins which register a NewVarHook.", st, name) } } diff --git a/go/stats/prometheusbackend/prometheusbackend_test.go b/go/stats/prometheusbackend/prometheusbackend_test.go index f85febf31af..0fd906a88d3 100644 --- a/go/stats/prometheusbackend/prometheusbackend_test.go +++ b/go/stats/prometheusbackend/prometheusbackend_test.go @@ -59,6 +59,13 @@ func TestPrometheusGaugeFunc(t *testing.T) { checkHandlerForMetrics(t, name, -3) } +func TestPrometheusFloatFunc(t *testing.T) { + name := "blah_floatfunc" + + stats.Publish(name, stats.FloatFunc(func() float64 { return -4 })) + checkHandlerForMetrics(t, name, -4) +} + func TestPrometheusCounterDuration(t *testing.T) { name := "blah_counterduration" diff --git a/go/streamlog/streamlog.go b/go/streamlog/streamlog.go index f3fe16c8990..b6211d3b131 100644 --- a/go/streamlog/streamlog.go +++ b/go/streamlog/streamlog.go @@ -68,6 +68,10 @@ type StreamLogger struct { subscribed map[chan interface{}]string } +// LogFormatter is the function signature used to format an arbitrary +// message for the given output writer. +type LogFormatter func(out io.Writer, params url.Values, message interface{}) error + // New returns a new StreamLogger that can stream events to subscribers. // The size parameter defines the channel size for the subscribers. func New(name string, size int) *StreamLogger { @@ -121,7 +125,7 @@ func (logger *StreamLogger) Name() string { // ServeLogs registers the URL on which messages will be broadcast. // It is safe to register multiple URLs for the same StreamLogger. -func (logger *StreamLogger) ServeLogs(url string, messageFmt func(url.Values, interface{}) string) { +func (logger *StreamLogger) ServeLogs(url string, logf LogFormatter) { http.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err) @@ -138,7 +142,7 @@ func (logger *StreamLogger) ServeLogs(url string, messageFmt func(url.Values, in w.(http.Flusher).Flush() for message := range ch { - if _, err := io.WriteString(w, messageFmt(r.Form, message)); err != nil { + if err := logf(w, r.Form, message); err != nil { return } w.(http.Flusher).Flush() @@ -152,7 +156,7 @@ func (logger *StreamLogger) ServeLogs(url string, messageFmt func(url.Values, in // // Returns the channel used for the subscription which can be used to close // it. -func (logger *StreamLogger) LogToFile(path string, messageFmt func(url.Values, interface{}) string) (chan interface{}, error) { +func (logger *StreamLogger) LogToFile(path string, logf LogFormatter) (chan interface{}, error) { rotateChan := make(chan os.Signal, 1) signal.Notify(rotateChan, syscall.SIGUSR2) @@ -168,8 +172,7 @@ func (logger *StreamLogger) LogToFile(path string, messageFmt func(url.Values, i for { select { case record, _ := <-logChan: - formatted := messageFmt(formatParams, record) - f.WriteString(formatted) + logf(f, formatParams, record) case _, _ = <-rotateChan: f.Close() f, _ = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) @@ -183,17 +186,18 @@ func (logger *StreamLogger) LogToFile(path string, messageFmt func(url.Values, i // Formatter is a simple interface for objects that expose a Format function // as needed for streamlog. type Formatter interface { - Format(url.Values) string + Logf(io.Writer, url.Values) error } // GetFormatter returns a formatter function for objects conforming to the // Formatter interface -func GetFormatter(logger *StreamLogger) func(url.Values, interface{}) string { - return func(params url.Values, val interface{}) string { +func GetFormatter(logger *StreamLogger) LogFormatter { + return func(w io.Writer, params url.Values, val interface{}) error { fmter, ok := val.(Formatter) if !ok { - return fmt.Sprintf("Error: unexpected value of type %T in %s!", val, logger.Name()) + _, err := fmt.Fprintf(w, "Error: unexpected value of type %T in %s!", val, logger.Name()) + return err } - return fmter.Format(params) + return fmter.Logf(w, params) } } diff --git a/go/streamlog/streamlog_flaky_test.go b/go/streamlog/streamlog_flaky_test.go index 8eb6889bdde..769dceb6df2 100644 --- a/go/streamlog/streamlog_flaky_test.go +++ b/go/streamlog/streamlog_flaky_test.go @@ -19,6 +19,7 @@ package streamlog import ( "bufio" "fmt" + "io" "io/ioutil" "net" "net/http" @@ -38,6 +39,11 @@ func (l *logMessage) Format(params url.Values) string { return l.val + "\n" } +func testLogf(w io.Writer, params url.Values, m interface{}) error { + _, err := io.WriteString(w, m.(*logMessage).Format(params)) + return err +} + func TestHTTP(t *testing.T) { l, err := net.Listen("tcp", ":0") if err != nil { @@ -49,7 +55,7 @@ func TestHTTP(t *testing.T) { go http.Serve(l, nil) logger := New("logger", 1) - logger.ServeLogs("/log", func(params url.Values, x interface{}) string { return x.(*logMessage).Format(params) }) + logger.ServeLogs("/log", testLogf) // This should not block - there are no subscribers yet. logger.Send(&logMessage{"val1"}) @@ -194,7 +200,7 @@ func TestFile(t *testing.T) { } logPath := path.Join(dir, "test.log") - logChan, err := logger.LogToFile(logPath, func(params url.Values, x interface{}) string { return x.(*logMessage).Format(params) }) + logChan, err := logger.LogToFile(logPath, testLogf) defer logger.Unsubscribe(logChan) if err != nil { t.Errorf("error enabling file logger: %v", err) diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go index 28b27a95c1e..3e81c95c639 100644 --- a/go/vt/binlog/binlogplayer/binlog_player.go +++ b/go/vt/binlog/binlogplayer/binlog_player.go @@ -14,12 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package binlogplayer contains the code that plays a filtered replication +// Package binlogplayer contains the code that plays a vreplication // stream on a client database. It usually runs inside the destination master // vttablet process. package binlogplayer import ( + "bytes" "encoding/hex" "fmt" "sync" @@ -50,11 +51,12 @@ var ( // BlplTransaction is the key for the stats map. BlplTransaction = "Transaction" - // flags for the blp_checkpoint table. The database entry is just - // a join(",") of these flags. - - // BlpFlagDontStart means don't start a BinlogPlayer - BlpFlagDontStart = "DontStart" + // BlpRunning is for the Running state. + BlpRunning = "Running" + // BlpStopped is for the Stopped state. + BlpStopped = "Stopped" + // BlpError is for the Error state. + BlpError = "Error" ) // Stats is the internal stats of a player. It is a different @@ -66,9 +68,11 @@ type Stats struct { Rates *stats.Rates // Last saved status - lastPosition mysql.Position - lastPositionMutex sync.RWMutex + lastPositionMutex sync.Mutex + lastPosition mysql.Position + SecondsBehindMaster sync2.AtomicInt64 + LastMessage sync2.AtomicString } // SetLastPosition sets the last replication position. @@ -78,14 +82,14 @@ func (bps *Stats) SetLastPosition(pos mysql.Position) { bps.lastPosition = pos } -// GetLastPosition gets the last replication position. -func (bps *Stats) GetLastPosition() mysql.Position { - bps.lastPositionMutex.RLock() - defer bps.lastPositionMutex.RUnlock() +// LastPosition gets the last replication position. +func (bps *Stats) LastPosition() mysql.Position { + bps.lastPositionMutex.Lock() + defer bps.lastPositionMutex.Unlock() return bps.lastPosition } -// NewStats creates a new Stats structure +// NewStats creates a new Stats structure. func NewStats() *Stats { bps := &Stats{} bps.Timings = stats.NewTimings("", "", "") @@ -93,10 +97,10 @@ func NewStats() *Stats { return bps } -// BinlogPlayer is handling reading a stream of updates from BinlogServer +// BinlogPlayer is for reading a stream of updates from BinlogServer. type BinlogPlayer struct { tablet *topodatapb.Tablet - dbClient VtClient + dbClient DBClient // for key range base requests keyRange *topodatapb.KeyRange @@ -111,215 +115,91 @@ type BinlogPlayer struct { blplStats *Stats defaultCharset *binlogdatapb.Charset currentCharset *binlogdatapb.Charset + deadlockRetry time.Duration } // NewBinlogPlayerKeyRange returns a new BinlogPlayer pointing at the server -// replicating the provided keyrange, starting at the startPosition, -// and updating _vt.blp_checkpoint with uid=startPosition.Uid. +// replicating the provided keyrange and updating _vt.vreplication +// with uid=startPosition.Uid. // If !stopPosition.IsZero(), it will stop when reaching that position. -func NewBinlogPlayerKeyRange(dbClient VtClient, tablet *topodatapb.Tablet, keyRange *topodatapb.KeyRange, uid uint32, startPosition string, stopPosition string, blplStats *Stats) (*BinlogPlayer, error) { +func NewBinlogPlayerKeyRange(dbClient DBClient, tablet *topodatapb.Tablet, keyRange *topodatapb.KeyRange, uid uint32, blplStats *Stats) *BinlogPlayer { result := &BinlogPlayer{ - tablet: tablet, - dbClient: dbClient, - keyRange: keyRange, - uid: uid, - blplStats: blplStats, - } - var err error - result.position, err = mysql.DecodePosition(startPosition) - if err != nil { - return nil, err - } - if stopPosition != "" { - result.stopPosition, err = mysql.DecodePosition(stopPosition) - if err != nil { - return nil, err - } - } - return result, nil + tablet: tablet, + dbClient: dbClient, + keyRange: keyRange, + uid: uid, + blplStats: blplStats, + deadlockRetry: 1 * time.Second, + } + return result } // NewBinlogPlayerTables returns a new BinlogPlayer pointing at the server -// replicating the provided tables, starting at the startPosition, -// and updating _vt.blp_checkpoint with uid=startPosition.Uid. +// replicating the provided tables and updating _vt.vreplication +// with uid=startPosition.Uid. // If !stopPosition.IsZero(), it will stop when reaching that position. -func NewBinlogPlayerTables(dbClient VtClient, tablet *topodatapb.Tablet, tables []string, uid uint32, startPosition string, stopPosition string, blplStats *Stats) (*BinlogPlayer, error) { +func NewBinlogPlayerTables(dbClient DBClient, tablet *topodatapb.Tablet, tables []string, uid uint32, blplStats *Stats) *BinlogPlayer { result := &BinlogPlayer{ - tablet: tablet, - dbClient: dbClient, - tables: tables, - uid: uid, - blplStats: blplStats, - } - var err error - result.position, err = mysql.DecodePosition(startPosition) - if err != nil { - return nil, err - } - if stopPosition != "" { - var err error - result.stopPosition, err = mysql.DecodePosition(stopPosition) - if err != nil { - return nil, err - } - } - return result, nil + tablet: tablet, + dbClient: dbClient, + tables: tables, + uid: uid, + blplStats: blplStats, + deadlockRetry: 1 * time.Second, + } + return result } -// writeRecoveryPosition will write the current GTID as the recovery position -// for the next transaction. -// We will also try to get the timestamp for the transaction. Two cases: -// - we have statements, and they start with a SET TIMESTAMP that we -// can parse: then we update transaction_timestamp in blp_checkpoint -// with it, and set SecondsBehindMaster to now() - transaction_timestamp -// - otherwise (the statements are probably filtered out), we leave -// transaction_timestamp alone (keeping the old value), and we don't -// change SecondsBehindMaster -func (blp *BinlogPlayer) writeRecoveryPosition(tx *binlogdatapb.BinlogTransaction) error { - position, err := mysql.DecodePosition(tx.EventToken.Position) - if err != nil { - return err - } - - now := time.Now().Unix() - updateRecovery := updateBlpCheckpoint(blp.uid, position, now, tx.EventToken.Timestamp) - - qr, err := blp.exec(updateRecovery) - if err != nil { - return fmt.Errorf("Error %v in writing recovery info %v", err, updateRecovery) - } - if qr.RowsAffected != 1 { - return fmt.Errorf("Cannot update blp_recovery table, affected %v rows", qr.RowsAffected) +// ApplyBinlogEvents makes an RPC request to BinlogServer +// and processes the events. It returns nil if the provided context +// was canceled, or if we reached the stopping point. +// If an error is encountered, it updates the vreplication state to "Error". +// If a stop position was specifed, and reached, the state is updated to "Stopped". +func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { + // Clear previous error, if any. + if err := setVReplicationState(blp.dbClient, blp.uid, BlpRunning, ""); err != nil { + log.Errorf("Error writing Running state: %v", err) } + blp.blplStats.LastMessage.Set("") - // Update position after successful write. - blp.position = position - blp.blplStats.SetLastPosition(blp.position) - if tx.EventToken.Timestamp != 0 { - blp.blplStats.SecondsBehindMaster.Set(now - tx.EventToken.Timestamp) + if err := blp.applyEvents(ctx); err != nil { + msg := err.Error() + blp.blplStats.LastMessage.Set(msg) + if err := setVReplicationState(blp.dbClient, blp.uid, BlpError, msg); err != nil { + log.Errorf("Error writing stop state: %v", err) + } + return err } return nil } -// ReadStartPosition will return the current start position and the flags for -// the provided binlog player. -func ReadStartPosition(dbClient VtClient, uid uint32) (string, string, error) { - selectRecovery := QueryBlpCheckpoint(uid) - qr, err := dbClient.ExecuteFetch(selectRecovery, 1) - if err != nil { - return "", "", fmt.Errorf("error %v in selecting from recovery table %v", err, selectRecovery) - } - if qr.RowsAffected != 1 { - return "", "", fmt.Errorf("checkpoint information not available in db for %v", uid) - } - return qr.Rows[0][0].ToString(), qr.Rows[0][1].ToString(), nil -} - -// readThrottlerSettings will retrieve the throttler settings for filtered -// replication from the checkpoint table. -func (blp *BinlogPlayer) readThrottlerSettings() (int64, int64, error) { - selectThrottlerSettings := QueryBlpThrottlerSettings(blp.uid) - qr, err := blp.dbClient.ExecuteFetch(selectThrottlerSettings, 1) +// applyEvents returns a recordable status message on termination or an error otherwise. +func (blp *BinlogPlayer) applyEvents(ctx context.Context) error { + // Read starting values for vreplication. + pos, stopPos, maxTPS, maxReplicationLag, err := readVRSettings(blp.dbClient, blp.uid) if err != nil { - return throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("error %v in selecting the throttler settings %v", err, selectThrottlerSettings) - } - - if qr.RowsAffected != 1 { - return throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("checkpoint information not available in db for %v", blp.uid) - } - - maxTPS, err := sqltypes.ToInt64(qr.Rows[0][0]) - if err != nil { - return throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("failed to parse max_tps column: %v", err) - } - maxReplicationLag, err := sqltypes.ToInt64(qr.Rows[0][1]) - if err != nil { - return throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("failed to parse max_replication_lag column: %v", err) - } - - return maxTPS, maxReplicationLag, nil -} - -func (blp *BinlogPlayer) processTransaction(tx *binlogdatapb.BinlogTransaction) (ok bool, err error) { - txnStartTime := time.Now() - if err = blp.dbClient.Begin(); err != nil { - return false, fmt.Errorf("failed query BEGIN, err: %s", err) - } - for i, stmt := range tx.Statements { - // Make sure the statement is replayed in the proper charset. - if dbClient, ok := blp.dbClient.(*DBClient); ok { - var stmtCharset *binlogdatapb.Charset - if stmt.Charset != nil { - stmtCharset = stmt.Charset - } else { - // Streamer sends a nil Charset for statements that use the - // charset we specified in the request. - stmtCharset = blp.defaultCharset - } - if !proto.Equal(blp.currentCharset, stmtCharset) { - // In regular MySQL replication, the charset is silently adjusted as - // needed during event playback. Here we also adjust so that playback - // proceeds, but in Vitess-land this usually means a misconfigured - // server or a misbehaving client, so we spam the logs with warnings. - log.Warningf("BinlogPlayer changing charset from %v to %v for statement %d in transaction %v", blp.currentCharset, stmtCharset, i, *tx) - err = mysql.SetCharset(dbClient.dbConn, stmtCharset) - if err != nil { - return false, fmt.Errorf("can't set charset for statement %d in transaction %v: %v", i, *tx, err) - } - blp.currentCharset = stmtCharset - } - } - if _, err = blp.exec(string(stmt.Sql)); err == nil { - continue - } - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == 1213 { - // Deadlock: ask for retry - log.Infof("Deadlock: %v", err) - if err = blp.dbClient.Rollback(); err != nil { - return false, err - } - return false, nil - } - _ = blp.dbClient.Rollback() - return false, err - } - // Update recovery position after successful replay. - // This also updates the blp's internal position. - if err = blp.writeRecoveryPosition(tx); err != nil { - _ = blp.dbClient.Rollback() - return false, err - } - if err = blp.dbClient.Commit(); err != nil { - return false, fmt.Errorf("failed query COMMIT, err: %s", err) - } - blp.blplStats.Timings.Record(BlplTransaction, txnStartTime) - return true, nil -} - -func (blp *BinlogPlayer) exec(sql string) (*sqltypes.Result, error) { - queryStartTime := time.Now() - qr, err := blp.dbClient.ExecuteFetch(sql, 0) - blp.blplStats.Timings.Record(BlplQuery, queryStartTime) - if d := time.Now().Sub(queryStartTime); d > SlowQueryThreshold { - log.Infof("SLOW QUERY (took %.2fs) '%s'", d.Seconds(), sql) + log.Error(err) + return err } - return qr, err -} - -// ApplyBinlogEvents makes an RPC request to BinlogServer -// and processes the events. It will return nil if the provided context -// was canceled, or if we reached the stopping point. -// It will return io.EOF if the server stops sending us updates. -// It may return any other error it encounters. -func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { - // Instantiate the throttler based on the configuration stored in the db. - maxTPS, maxReplicationLag, err := blp.readThrottlerSettings() + blp.position, err = mysql.DecodePosition(pos) if err != nil { log.Error(err) return err } + if stopPos != "" { + blp.stopPosition, err = mysql.DecodePosition(stopPos) + if err != nil { + log.Error(err) + return err + } + } t, err := throttler.NewThrottler( - fmt.Sprintf("BinlogPlayer/%d", blp.uid), "transactions", 1 /* threadCount */, maxTPS, maxReplicationLag) + fmt.Sprintf("BinlogPlayer/%d", blp.uid), + "transactions", + 1, /* threadCount */ + maxTPS, + maxReplicationLag, + ) if err != nil { err := fmt.Errorf("failed to instantiate throttler: %v", err) log.Error(err) @@ -345,13 +225,22 @@ func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { ) } if !blp.stopPosition.IsZero() { - // We need to stop at some point. Sanity check the point. switch { case blp.position.Equal(blp.stopPosition): - log.Infof("Not starting BinlogPlayer, we're already at the desired position %v", blp.stopPosition) + msg := fmt.Sprintf("not starting BinlogPlayer, we're already at the desired position %v", blp.stopPosition) + log.Info(msg) + if err := setVReplicationState(blp.dbClient, blp.uid, BlpStopped, msg); err != nil { + log.Errorf("Error writing stop state: %v", err) + } return nil case blp.position.AtLeast(blp.stopPosition): - return fmt.Errorf("starting point %v greater than stopping point %v", blp.position, blp.stopPosition) + msg := fmt.Sprintf("starting point %v greater than stopping point %v", blp.position, blp.stopPosition) + log.Error(msg) + if err := setVReplicationState(blp.dbClient, blp.uid, BlpStopped, msg); err != nil { + log.Errorf("Error writing stop state: %v", err) + } + // Don't return an error. Otherwise, it will keep retrying. + return nil default: log.Infof("Will stop player when reaching %v", blp.stopPosition) } @@ -373,7 +262,7 @@ func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { // Get the current charset of our connection, so we can ask the stream server // to check that they match. The streamer will also only send per-statement // charset data if that statement's charset is different from what we specify. - if dbClient, ok := blp.dbClient.(*DBClient); ok { + if dbClient, ok := blp.dbClient.(*dbClientImpl); ok { blp.defaultCharset, err = mysql.GetCharset(dbClient.dbConn) if err != nil { return fmt.Errorf("can't get charset to request binlog stream: %v", err) @@ -421,24 +310,15 @@ func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { // get the response response, err := stream.Recv() + // Check context before checking error, because canceled + // contexts could be wrapped as regular errors. + select { + case <-ctx.Done(): + return nil + default: + } if err != nil { - switch err { - case context.Canceled: - return nil - default: - // if the context is canceled, we - // return nil (some RPC - // implementations will remap the - // context error to their own errors) - select { - case <-ctx.Done(): - if ctx.Err() == context.Canceled { - return nil - } - default: - } - return fmt.Errorf("Error received from Stream %v", err) - } + return fmt.Errorf("error received from Stream %v", err) } // process the transaction @@ -449,76 +329,256 @@ func (blp *BinlogPlayer) ApplyBinlogEvents(ctx context.Context) error { for _, stmt := range response.Statements { log.Infof("statement: %q", stmt.Sql) } - return fmt.Errorf("Error in processing binlog event %v", err) + return fmt.Errorf("error in processing binlog event %v", err) } if ok { if !blp.stopPosition.IsZero() { if blp.position.AtLeast(blp.stopPosition) { - log.Infof("Reached stopping position, done playing logs") + msg := "Reached stopping position, done playing logs" + log.Info(msg) + if err := setVReplicationState(blp.dbClient, blp.uid, BlpStopped, msg); err != nil { + log.Errorf("Error writing stop state: %v", err) + } return nil } } break } - log.Infof("Retrying txn") - time.Sleep(1 * time.Second) + log.Infof("Retrying txn in %v.", blp.deadlockRetry) + time.Sleep(blp.deadlockRetry) } } } -// CreateBlpCheckpoint returns the statements required to create -// the _vt.blp_checkpoint table -func CreateBlpCheckpoint() []string { +func (blp *BinlogPlayer) processTransaction(tx *binlogdatapb.BinlogTransaction) (ok bool, err error) { + txnStartTime := time.Now() + if err = blp.dbClient.Begin(); err != nil { + return false, fmt.Errorf("failed query BEGIN, err: %s", err) + } + for i, stmt := range tx.Statements { + // Make sure the statement is replayed in the proper charset. + if dbClient, ok := blp.dbClient.(*dbClientImpl); ok { + var stmtCharset *binlogdatapb.Charset + if stmt.Charset != nil { + stmtCharset = stmt.Charset + } else { + // Streamer sends a nil Charset for statements that use the + // charset we specified in the request. + stmtCharset = blp.defaultCharset + } + if !proto.Equal(blp.currentCharset, stmtCharset) { + // In regular MySQL replication, the charset is silently adjusted as + // needed during event playback. Here we also adjust so that playback + // proceeds, but in Vitess-land this usually means a misconfigured + // server or a misbehaving client, so we spam the logs with warnings. + log.Warningf("BinlogPlayer changing charset from %v to %v for statement %d in transaction %v", blp.currentCharset, stmtCharset, i, *tx) + err = mysql.SetCharset(dbClient.dbConn, stmtCharset) + if err != nil { + return false, fmt.Errorf("can't set charset for statement %d in transaction %v: %v", i, *tx, err) + } + blp.currentCharset = stmtCharset + } + } + if _, err = blp.exec(string(stmt.Sql)); err == nil { + continue + } + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == 1213 { + // Deadlock: ask for retry + log.Infof("Deadlock: %v", err) + if err = blp.dbClient.Rollback(); err != nil { + return false, err + } + return false, nil + } + _ = blp.dbClient.Rollback() + return false, err + } + // Update recovery position after successful replay. + // This also updates the blp's internal position. + if err = blp.writeRecoveryPosition(tx); err != nil { + _ = blp.dbClient.Rollback() + return false, err + } + if err = blp.dbClient.Commit(); err != nil { + return false, fmt.Errorf("failed query COMMIT, err: %s", err) + } + blp.blplStats.Timings.Record(BlplTransaction, txnStartTime) + return true, nil +} + +func (blp *BinlogPlayer) exec(sql string) (*sqltypes.Result, error) { + queryStartTime := time.Now() + qr, err := blp.dbClient.ExecuteFetch(sql, 0) + blp.blplStats.Timings.Record(BlplQuery, queryStartTime) + if d := time.Now().Sub(queryStartTime); d > SlowQueryThreshold { + log.Infof("SLOW QUERY (took %.2fs) '%s'", d.Seconds(), sql) + } + return qr, err +} + +// writeRecoveryPosition writes the current GTID as the recovery position +// for the next transaction. +// It also tries to get the timestamp for the transaction. Two cases: +// - we have statements, and they start with a SET TIMESTAMP that we +// can parse: then we update transaction_timestamp in vreplication +// with it, and set SecondsBehindMaster to now() - transaction_timestamp +// - otherwise (the statements are probably filtered out), we leave +// transaction_timestamp alone (keeping the old value), and we don't +// change SecondsBehindMaster +func (blp *BinlogPlayer) writeRecoveryPosition(tx *binlogdatapb.BinlogTransaction) error { + position, err := mysql.DecodePosition(tx.EventToken.Position) + if err != nil { + return err + } + + now := time.Now().Unix() + updateRecovery := updateVReplicationPos(blp.uid, position, now, tx.EventToken.Timestamp) + + qr, err := blp.exec(updateRecovery) + if err != nil { + return fmt.Errorf("error %v in writing recovery info %v", err, updateRecovery) + } + if qr.RowsAffected != 1 { + return fmt.Errorf("cannot update vreplication table, affected %v rows", qr.RowsAffected) + } + + // Update position after successful write. + blp.position = position + blp.blplStats.SetLastPosition(blp.position) + if tx.EventToken.Timestamp != 0 { + blp.blplStats.SecondsBehindMaster.Set(now - tx.EventToken.Timestamp) + } + return nil +} + +// CreateVReplicationTable returns the statements required to create +// the _vt.vreplication table. +// id: is an auto-increment column that identifies the stream. +// workflow: documents the creator/manager of the stream. Example: 'SplitClone'. +// source: contains a string proto representation of binlogpb.BinlogSource. +// pos: initially, a start position, and is updated to the current position by the binlog player. +// stop_pos: optional column that specifies the stop position. +// max_tps: max transactions per second. +// max_replication_lag: if replication lag exceeds this amount writing is throttled accordingly. +// cell: optional column that overrides the current cell to replicate from. +// tablet_types: optional column that overrides the tablet types to look to replicate from. +// time_update: last time an event was applied. +// transaction_timestamp: timestamp of the transaction (from the master). +// state: Running, Error or Stopped. +// message: Reason for current state. +func CreateVReplicationTable() []string { return []string{ "CREATE DATABASE IF NOT EXISTS _vt", - fmt.Sprintf(`CREATE TABLE IF NOT EXISTS _vt.blp_checkpoint ( - source_shard_uid INT(10) UNSIGNED NOT NULL, - pos VARBINARY(%v) DEFAULT NULL, + "DROP TABLE IF EXISTS _vt.blp_checkpoint", + `CREATE TABLE IF NOT EXISTS _vt.vreplication ( + id INT AUTO_INCREMENT, + workflow VARBINARY(1000), + source VARBINARY(10000) NOT NULL, + pos VARBINARY(10000) NOT NULL, + stop_pos VARBINARY(10000) DEFAULT NULL, max_tps BIGINT(20) NOT NULL, max_replication_lag BIGINT(20) NOT NULL, - time_updated BIGINT(20) UNSIGNED NOT NULL, - transaction_timestamp BIGINT(20) UNSIGNED NOT NULL, - flags VARBINARY(250) DEFAULT NULL, - PRIMARY KEY (source_shard_uid) -) ENGINE=InnoDB`, mysql.MaximumPositionSize)} + cell VARBINARY(1000) DEFAULT NULL, + tablet_types VARBINARY(100) DEFAULT NULL, + time_updated BIGINT(20) NOT NULL, + transaction_timestamp BIGINT(20) NOT NULL, + state VARBINARY(100) NOT NULL, + message VARBINARY(1000) DEFAULT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB`} } -// PopulateBlpCheckpoint returns a statement to populate the first value into -// the _vt.blp_checkpoint table. -func PopulateBlpCheckpoint(index uint32, position string, maxTPS int64, maxReplicationLag int64, timeUpdated int64, flags string) string { - return fmt.Sprintf("INSERT INTO _vt.blp_checkpoint "+ - "(source_shard_uid, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, flags) "+ - "VALUES (%v, '%v', %v, %v, %v, 0, '%v')", - index, position, maxTPS, maxReplicationLag, timeUpdated, flags) +// setVReplicationState updates the state in the _vt.vreplication table. +func setVReplicationState(dbClient DBClient, uid uint32, state, message string) error { + query := fmt.Sprintf("update _vt.vreplication set state='%v', message=%v where id=%v", state, encodeString(message), uid) + if _, err := dbClient.ExecuteFetch(query, 1); err != nil { + return fmt.Errorf("could not set state: %v: %v", query, err) + } + return nil } -// updateBlpCheckpoint returns a statement to update a value in the -// _vt.blp_checkpoint table. -func updateBlpCheckpoint(uid uint32, pos mysql.Position, timeUpdated int64, txTimestamp int64) string { +// readVRSettings retrieves the throttler settings for +// vreplication from the checkpoint table. +func readVRSettings(dbClient DBClient, uid uint32) (pos, stopPos string, maxTPS, maxReplicationLag int64, err error) { + query := fmt.Sprintf("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=%v", uid) + qr, err := dbClient.ExecuteFetch(query, 1) + if err != nil { + return "", "", throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("error %v in selecting vreplication settings %v", err, query) + } + + if qr.RowsAffected != 1 { + return "", "", throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("checkpoint information not available in db for %v", uid) + } + + maxTPS, err = sqltypes.ToInt64(qr.Rows[0][2]) + if err != nil { + return "", "", throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("failed to parse max_tps column: %v", err) + } + maxReplicationLag, err = sqltypes.ToInt64(qr.Rows[0][3]) + if err != nil { + return "", "", throttler.InvalidMaxRate, throttler.InvalidMaxReplicationLag, fmt.Errorf("failed to parse max_replication_lag column: %v", err) + } + + return qr.Rows[0][0].ToString(), qr.Rows[0][1].ToString(), maxTPS, maxReplicationLag, nil +} + +// CreateVReplication returns a statement to populate the first value into +// the _vt.vreplication table. +func CreateVReplication(workflow string, source *binlogdatapb.BinlogSource, position string, maxTPS, maxReplicationLag, timeUpdated int64) string { + return fmt.Sprintf("insert into _vt.vreplication "+ + "(workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state) "+ + "values (%v, %v, %v, %v, %v, %v, 0, '%v')", + encodeString(workflow), encodeString(source.String()), encodeString(position), maxTPS, maxReplicationLag, timeUpdated, BlpRunning) +} + +// updateVReplicationPos returns a statement to update a value in the +// _vt.vreplication table. +func updateVReplicationPos(uid uint32, pos mysql.Position, timeUpdated int64, txTimestamp int64) string { if txTimestamp != 0 { return fmt.Sprintf( - "UPDATE _vt.blp_checkpoint "+ - "SET pos='%v', time_updated=%v, transaction_timestamp=%v "+ - "WHERE source_shard_uid=%v", - mysql.EncodePosition(pos), timeUpdated, txTimestamp, uid) + "update _vt.vreplication set pos=%v, time_updated=%v, transaction_timestamp=%v where id=%v", + encodeString(mysql.EncodePosition(pos)), timeUpdated, txTimestamp, uid) } return fmt.Sprintf( - "UPDATE _vt.blp_checkpoint "+ - "SET pos='%v', time_updated=%v "+ - "WHERE source_shard_uid=%v", - mysql.EncodePosition(pos), timeUpdated, uid) + "update _vt.vreplication set pos=%v, time_updated=%v where id=%v", + encodeString(mysql.EncodePosition(pos)), timeUpdated, uid) +} + +// StartVReplication returns a statement to start the replication. +func StartVReplication(uid uint32) string { + return fmt.Sprintf( + "update _vt.vreplication set state='%v', stop_pos=NULL where id=%v", + BlpRunning, uid) +} + +// StartVReplicationUntil returns a statement to start the replication with a stop position. +func StartVReplicationUntil(uid uint32, pos string) string { + return fmt.Sprintf( + "update _vt.vreplication set state='%v', stop_pos=%v where id=%v", + BlpRunning, encodeString(pos), uid) +} + +// StopVReplication returns a statement to stop the replication. +func StopVReplication(uid uint32, message string) string { + return fmt.Sprintf( + "update _vt.vreplication set state='%v', message=%v where id=%v", + BlpStopped, encodeString(message), uid) +} + +// DeleteVReplication returns a statement to delete the replication. +func DeleteVReplication(uid uint32) string { + return fmt.Sprintf("delete from _vt.vreplication where id=%v", uid) } -// QueryBlpCheckpoint returns a statement to query the gtid and flags for a -// given shard from the _vt.blp_checkpoint table. -func QueryBlpCheckpoint(index uint32) string { - return fmt.Sprintf("SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=%v", index) +func encodeString(in string) string { + buf := bytes.NewBuffer(nil) + sqltypes.NewVarChar(in).EncodeSQL(buf) + return buf.String() } -// QueryBlpThrottlerSettings returns a statement to query the throttler settings -// (used by filtered replication) for a given shard from the_vt.blp_checkpoint -// table. -func QueryBlpThrottlerSettings(index uint32) string { - return fmt.Sprintf("SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=%v", index) +// ReadVReplicationPos returns a statement to query the gtid for a +// given shard from the _vt.vreplication table. +func ReadVReplicationPos(index uint32) string { + return fmt.Sprintf("select pos from _vt.vreplication where id=%v", index) } diff --git a/go/vt/binlog/binlogplayer/binlog_player_test.go b/go/vt/binlog/binlogplayer/binlog_player_test.go index da7fafe923c..27ad35c5712 100644 --- a/go/vt/binlog/binlogplayer/binlog_player_test.go +++ b/go/vt/binlog/binlogplayer/binlog_player_test.go @@ -17,58 +17,366 @@ limitations under the License. package binlogplayer import ( + "errors" "testing" + "time" + "golang.org/x/net/context" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/throttler" + + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +var ( + testSettingsResponse = &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NULL, // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + testDMLResponse = &sqltypes.Result{RowsAffected: 1} + testPos = "MariaDB/0-1-1083" ) -func TestPopulateBlpCheckpoint(t *testing.T) { - want := "INSERT INTO _vt.blp_checkpoint " + - "(source_shard_uid, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, flags) " + - "VALUES (18372, 'MariaDB/0-1-1083', 9223372036854775807, 9223372036854775807, 481823, 0, 'myflags')" +func TestNewBinlogPlayerKeyRange(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + fbc := newFakeBinlogClient() + wantTablet := &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "cell", + Uid: 1, + }, + Keyspace: "ks", + Shard: "0", + } + wantKeyRange := &topodatapb.KeyRange{End: []byte{0x80}} + + blp := NewBinlogPlayerKeyRange(dbClient, wantTablet, wantKeyRange, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, nil, &topodatapb.KeyRange{End: []byte{0x80}}) + + if err := errfunc(); err != nil { + t.Error(err) + } +} + +func TestNewBinlogPlayerTables(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + fbc := newFakeBinlogClient() + wantTablet := &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: "cell", + Uid: 1, + }, + Keyspace: "ks", + Shard: "0", + } + wantTables := []string{"a", "b"} + + blp := NewBinlogPlayerTables(dbClient, wantTablet, wantTables, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, wantTables, nil) + + if err := errfunc(); err != nil { + t.Error(err) + } +} + +// TestApplyEventsFail ensures the error is recorded in the vreplication table if there's a failure. +func TestApplyEventsFail(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, errors.New("err")) + dbClient.ExpectRequest("update _vt.vreplication set state='Error', message='error in processing binlog event failed query BEGIN, err: err' where id=1", testDMLResponse, nil) + + _ = newFakeBinlogClient() - got := PopulateBlpCheckpoint(18372, "MariaDB/0-1-1083", throttler.MaxRateModuleDisabled, throttler.ReplicationLagModuleDisabled, 481823, "myflags") + blp := NewBinlogPlayerTables(dbClient, nil, []string{"a"}, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + + want := "error in processing binlog event failed query BEGIN, err: err" + if err := errfunc(); err == nil || err.Error() != want { + t.Errorf("ApplyBinlogEvents err: %v, want %v", err, want) + } +} + +// TestStopPosEqual ensures player stops if stopPos==pos. +func TestStopPosEqual(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + posEqual := &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", posEqual, nil) + dbClient.ExpectRequest(`update _vt.vreplication set state='Stopped', message='not starting BinlogPlayer, we\'re already at the desired position 0-1-1083' where id=1`, testDMLResponse, nil) + + _ = newFakeBinlogClient() + + blp := NewBinlogPlayerTables(dbClient, nil, []string{"a"}, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + + if err := errfunc(); err != nil { + t.Error(err) + } +} + +// TestStopPosLess ensures player stops if stopPospos. +func TestStopPosGreater(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + posEqual := &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NewVarBinary("MariaDB/0-1-1085"), // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", posEqual, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + dbClient.ExpectRequest(`update _vt.vreplication set state='Stopped', message='Reached stopping position, done playing logs' where id=1`, testDMLResponse, nil) + + _ = newFakeBinlogClient() + + blp := NewBinlogPlayerTables(dbClient, nil, []string{"a"}, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + + if err := errfunc(); err != nil { + t.Error(err) + } +} + +// TestContextCancel ensures player does not record error or stop if context is canceled. +func TestContextCancel(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + posEqual := &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NewVarBinary("MariaDB/0-1-1085"), // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", posEqual, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + dbClient.ExpectRequest(`update _vt.vreplication set state='Stopped', message='Reached stopping position, done playing logs' where id=1`, testDMLResponse, nil) + + _ = newFakeBinlogClient() + + blp := NewBinlogPlayerTables(dbClient, nil, []string{"a"}, 1, NewStats()) + errfunc := applyEvents(blp) + + dbClient.Wait() + + // Wait for Apply to return, + // and call dbClient.Wait to ensure + // no new statements were issued. + if err := errfunc(); err != nil { + t.Error(err) + } + + dbClient.Wait() +} + +func TestRetryOnDeadlock(t *testing.T) { + dbClient := NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + deadlocked := &mysql.SQLError{Num: 1213, Message: "deadlocked"} + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", nil, deadlocked) + dbClient.ExpectRequest("rollback", nil, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + blp := NewBinlogPlayerTables(dbClient, nil, []string{"a"}, 1, NewStats()) + blp.deadlockRetry = 10 * time.Millisecond + errfunc := applyEvents(blp) + + dbClient.Wait() + + if err := errfunc(); err != nil { + t.Error(err) + } +} + +// applyEvents starts a goroutine to apply events, and returns an error function. +// The error func must be invoked before exiting the test to ensure that apply +// has finished. Otherwise, it may cause race with other tests. +func applyEvents(blp *BinlogPlayer) func() error { + errChan := make(chan error) + ctx, cancel := context.WithCancel(context.Background()) + + go func() { + errChan <- blp.ApplyBinlogEvents(ctx) + }() + + return func() error { + cancel() + return <-errChan + } +} + +func TestCreateVReplicationKeyRange(t *testing.T) { + want := "insert into _vt.vreplication " + + "(workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state) " + + `values ('Resharding', 'keyspace:\"ks\" shard:\"0\" key_range: ', 'MariaDB/0-1-1083', 9223372036854775807, 9223372036854775807, 481823, 0, 'Running')` + + bls := binlogdatapb.BinlogSource{ + Keyspace: "ks", + Shard: "0", + KeyRange: &topodatapb.KeyRange{ + End: []byte{0x80}, + }, + } + + got := CreateVReplication("Resharding", &bls, "MariaDB/0-1-1083", throttler.MaxRateModuleDisabled, throttler.ReplicationLagModuleDisabled, 481823) if got != want { - t.Errorf("PopulateBlpCheckpoint() = %#v, want %#v", got, want) + t.Errorf("CreateVReplication() =\n%v, want\n%v", got, want) } } -func TestUpdateBlpCheckpoint(t *testing.T) { - gtid := mysql.MustParseGTID("MariaDB", "0-1-8283") - want := "UPDATE _vt.blp_checkpoint " + - "SET pos='MariaDB/0-1-8283', time_updated=88822 " + - "WHERE source_shard_uid=78522" +func TestCreateVReplicationTables(t *testing.T) { + want := "insert into _vt.vreplication " + + "(workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state) " + + `values ('Resharding', 'keyspace:\"ks\" shard:\"0\" tables:\"a\" tables:\"b\" ', 'MariaDB/0-1-1083', 9223372036854775807, 9223372036854775807, 481823, 0, 'Running')` + + bls := binlogdatapb.BinlogSource{ + Keyspace: "ks", + Shard: "0", + Tables: []string{"a", "b"}, + } - got := updateBlpCheckpoint(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 0) + got := CreateVReplication("Resharding", &bls, "MariaDB/0-1-1083", throttler.MaxRateModuleDisabled, throttler.ReplicationLagModuleDisabled, 481823) if got != want { - t.Errorf("updateBlpCheckpoint() = %#v, want %#v", got, want) + t.Errorf("CreateVReplication() =\n%v, want\n%v", got, want) } } -func TestUpdateBlpCheckpointTimestamp(t *testing.T) { - gtid := mysql.MustParseGTID("MariaDB", "0-2-582") - want := "UPDATE _vt.blp_checkpoint " + - "SET pos='MariaDB/0-2-582', time_updated=88822, transaction_timestamp=481828 " + - "WHERE source_shard_uid=78522" +func TestUpdateVReplicationPos(t *testing.T) { + gtid := mysql.MustParseGTID("MariaDB", "0-1-8283") + want := "update _vt.vreplication " + + "set pos='MariaDB/0-1-8283', time_updated=88822 " + + "where id=78522" - got := updateBlpCheckpoint(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 481828) + got := updateVReplicationPos(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 0) if got != want { - t.Errorf("updateBlpCheckpoint() = %#v, want %#v", got, want) + t.Errorf("updateVReplicationPos() = %#v, want %#v", got, want) } } -func TestQueryBlpCheckpoint(t *testing.T) { - want := "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=482821" - got := QueryBlpCheckpoint(482821) +func TestUpdateVReplicationTimestamp(t *testing.T) { + gtid := mysql.MustParseGTID("MariaDB", "0-2-582") + want := "update _vt.vreplication " + + "set pos='MariaDB/0-2-582', time_updated=88822, transaction_timestamp=481828 " + + "where id=78522" + + got := updateVReplicationPos(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 481828) if got != want { - t.Errorf("QueryBlpCheckpoint(482821) = %#v, want %#v", got, want) + t.Errorf("updateVReplicationPos() = %#v, want %#v", got, want) } } -func TestQueryBlpThrottlerSettings(t *testing.T) { - want := "SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=482821" - if got := QueryBlpThrottlerSettings(482821); got != want { - t.Errorf("QueryBlpCheckpoint(482821) = %#v, want %#v", got, want) +func TestReadVReplicationPos(t *testing.T) { + want := "select pos from _vt.vreplication where id=482821" + got := ReadVReplicationPos(482821) + if got != want { + t.Errorf("ReadVReplicationThrottlerSettings(482821) = %#v, want %#v", got, want) } } diff --git a/go/vt/binlog/binlogplayer/dbclient.go b/go/vt/binlog/binlogplayer/dbclient.go index 4ceb692e078..8ebf379bba9 100644 --- a/go/vt/binlog/binlogplayer/dbclient.go +++ b/go/vt/binlog/binlogplayer/dbclient.go @@ -27,27 +27,41 @@ import ( "vitess.io/vitess/go/vt/log" ) -// DBClient is a real VtClient backed by a mysql connection. -type DBClient struct { +// DBClient is a high level interface to the database. +type DBClient interface { + DBName() string + Connect() error + Begin() error + Commit() error + Rollback() error + Close() + ExecuteFetch(query string, maxrows int) (qr *sqltypes.Result, err error) +} + +// dbClientImpl is a real DBClient backed by a mysql connection. +type dbClientImpl struct { dbConfig *mysql.ConnParams dbConn *mysql.Conn } -// NewDbClient creates a DBClient instance -func NewDbClient(params *mysql.ConnParams) *DBClient { - return &DBClient{ +// NewDBClient creates a DBClient instance +func NewDBClient(params *mysql.ConnParams) DBClient { + return &dbClientImpl{ dbConfig: params, } } -func (dc *DBClient) handleError(err error) { +func (dc *dbClientImpl) handleError(err error) { if mysql.IsConnErr(err) { dc.Close() } } -// Connect connects to a db server -func (dc *DBClient) Connect() error { +func (dc *dbClientImpl) DBName() string { + return dc.dbConfig.DbName +} + +func (dc *dbClientImpl) Connect() error { params, err := dbconfigs.WithCredentials(dc.dbConfig) if err != nil { return err @@ -60,8 +74,7 @@ func (dc *DBClient) Connect() error { return nil } -// Begin starts a transaction -func (dc *DBClient) Begin() error { +func (dc *dbClientImpl) Begin() error { _, err := dc.dbConn.ExecuteFetch("begin", 1, false) if err != nil { log.Errorf("BEGIN failed w/ error %v", err) @@ -70,8 +83,7 @@ func (dc *DBClient) Begin() error { return err } -// Commit commits the current transaction -func (dc *DBClient) Commit() error { +func (dc *dbClientImpl) Commit() error { _, err := dc.dbConn.ExecuteFetch("commit", 1, false) if err != nil { log.Errorf("COMMIT failed w/ error %v", err) @@ -80,8 +92,7 @@ func (dc *DBClient) Commit() error { return err } -// Rollback rollbacks the current transaction -func (dc *DBClient) Rollback() error { +func (dc *dbClientImpl) Rollback() error { _, err := dc.dbConn.ExecuteFetch("rollback", 1, false) if err != nil { log.Errorf("ROLLBACK failed w/ error %v", err) @@ -90,17 +101,15 @@ func (dc *DBClient) Rollback() error { return err } -// Close closes connection to the db server -func (dc *DBClient) Close() { +func (dc *dbClientImpl) Close() { if dc.dbConn != nil { dc.dbConn.Close() dc.dbConn = nil } } -// ExecuteFetch sends query to the db server and fetch the result -func (dc *DBClient) ExecuteFetch(query string, maxrows int) (*sqltypes.Result, error) { - mqr, err := dc.dbConn.ExecuteFetch(query, maxrows, false) +func (dc *dbClientImpl) ExecuteFetch(query string, maxrows int) (*sqltypes.Result, error) { + mqr, err := dc.dbConn.ExecuteFetch(query, maxrows, true) if err != nil { log.Errorf("ExecuteFetch failed w/ error %v", err) dc.handleError(err) diff --git a/go/vt/binlog/binlogplayer/fake_dbclient.go b/go/vt/binlog/binlogplayer/fake_dbclient.go new file mode 100644 index 00000000000..a2f4e091fb9 --- /dev/null +++ b/go/vt/binlog/binlogplayer/fake_dbclient.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 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 binlogplayer + +import ( + "fmt" + "strings" + + "vitess.io/vitess/go/sqltypes" +) + +type fakeDBClient struct { +} + +// NewFakeDBClient returns a fake DBClient. Its functions return +// preset responses to requests. +func NewFakeDBClient() DBClient { + return &fakeDBClient{} +} + +func (dc *fakeDBClient) DBName() string { + return "db" +} + +func (dc *fakeDBClient) Connect() error { + return nil +} + +func (dc *fakeDBClient) Begin() error { + return nil +} + +func (dc *fakeDBClient) Commit() error { + return nil +} + +func (dc *fakeDBClient) Rollback() error { + return nil +} + +func (dc *fakeDBClient) Close() { + return +} + +func (dc *fakeDBClient) ExecuteFetch(query string, maxrows int) (qr *sqltypes.Result, err error) { + query = strings.ToLower(query) + switch { + case strings.HasPrefix(query, "insert"): + return &sqltypes.Result{InsertID: 1}, nil + case strings.HasPrefix(query, "update"): + return &sqltypes.Result{RowsAffected: 1}, nil + case strings.HasPrefix(query, "delete"): + return &sqltypes.Result{RowsAffected: 1}, nil + case strings.HasPrefix(query, "select"): + if strings.Contains(query, "where") { + return sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source", + "int64|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: `, + ), nil + } + return &sqltypes.Result{}, nil + } + return nil, fmt.Errorf("unexpected: %v", query) +} diff --git a/go/vt/binlog/binlogplayer/framework_test.go b/go/vt/binlog/binlogplayer/framework_test.go new file mode 100644 index 00000000000..2c761a977ca --- /dev/null +++ b/go/vt/binlog/binlogplayer/framework_test.go @@ -0,0 +1,120 @@ +/* +Copyright 2018 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 binlogplayer + +import ( + "flag" + "reflect" + "testing" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + querypb "vitess.io/vitess/go/vt/proto/query" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +// This partially duplicates code from vreplication/framework_test.go. +// TODO(sougou): merge the functionality when we move this package to vreplication. + +// fakeBinlogClient satisfies Client. +// Not to be used concurrently. +type fakeBinlogClient struct { + lastTablet *topodatapb.Tablet + lastPos string + lastTables []string + lastKeyRange *topodatapb.KeyRange + lastCharset *binlogdatapb.Charset +} + +func newFakeBinlogClient() *fakeBinlogClient { + globalFBC = &fakeBinlogClient{} + return globalFBC +} + +func (fbc *fakeBinlogClient) Dial(tablet *topodatapb.Tablet) error { + fbc.lastTablet = tablet + return nil +} + +func (fbc *fakeBinlogClient) Close() { +} + +func (fbc *fakeBinlogClient) StreamTables(ctx context.Context, position string, tables []string, charset *binlogdatapb.Charset) (BinlogTransactionStream, error) { + fbc.lastPos = position + fbc.lastTables = tables + fbc.lastCharset = charset + return &btStream{ctx: ctx}, nil +} + +func (fbc *fakeBinlogClient) StreamKeyRange(ctx context.Context, position string, keyRange *topodatapb.KeyRange, charset *binlogdatapb.Charset) (BinlogTransactionStream, error) { + fbc.lastPos = position + fbc.lastKeyRange = keyRange + fbc.lastCharset = charset + return &btStream{ctx: ctx}, nil +} + +// btStream satisfies BinlogTransactionStream +type btStream struct { + ctx context.Context + sent bool +} + +func (t *btStream) Recv() (*binlogdatapb.BinlogTransaction, error) { + if !t.sent { + t.sent = true + return &binlogdatapb.BinlogTransaction{ + Statements: []*binlogdatapb.BinlogTransaction_Statement{ + { + Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, + Sql: []byte("insert into t values(1)"), + }, + }, + EventToken: &querypb.EventToken{ + Timestamp: 72, + Position: "MariaDB/0-1-1235", + }, + }, nil + } + <-t.ctx.Done() + return nil, t.ctx.Err() +} + +func expectFBCRequest(t *testing.T, fbc *fakeBinlogClient, tablet *topodatapb.Tablet, pos string, tables []string, kr *topodatapb.KeyRange) { + t.Helper() + if !proto.Equal(tablet, fbc.lastTablet) { + t.Errorf("Request tablet: %v, want %v", fbc.lastTablet, tablet) + } + if pos != fbc.lastPos { + t.Errorf("Request pos: %v, want %v", fbc.lastPos, pos) + } + if !reflect.DeepEqual(tables, fbc.lastTables) { + t.Errorf("Request tables: %v, want %v", fbc.lastTables, tables) + } + if !proto.Equal(kr, fbc.lastKeyRange) { + t.Errorf("Request KeyRange: %v, want %v", fbc.lastKeyRange, kr) + } +} + +// globalFBC is set by newFakeBinlogClient, which is then returned by the client factory below. +var globalFBC *fakeBinlogClient + +func init() { + RegisterClientFactory("test", func() Client { return globalFBC }) + flag.Set("binlog_player_protocol", "test") +} diff --git a/go/vt/binlog/binlogplayer/mock_dbclient.go b/go/vt/binlog/binlogplayer/mock_dbclient.go new file mode 100644 index 00000000000..749ff49cd44 --- /dev/null +++ b/go/vt/binlog/binlogplayer/mock_dbclient.go @@ -0,0 +1,151 @@ +/* +Copyright 2017 Google Inc. + +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 binlogplayer + +import ( + "regexp" + "testing" + "time" + + "vitess.io/vitess/go/sqltypes" +) + +// MockDBClient mocks a DBClient. +// It must be configured to expect requests in a specific order. +type MockDBClient struct { + t *testing.T + expect []*mockExpect + currentResult int + done chan struct{} +} + +type mockExpect struct { + query string + re *regexp.Regexp + result *sqltypes.Result + err error +} + +// NewMockDBClient returns a new DBClientMock. +func NewMockDBClient(t *testing.T) *MockDBClient { + return &MockDBClient{ + t: t, + done: make(chan struct{}), + } +} + +// ExpectRequest adds an expected result to the mock. +// This function should not be called conncurrently with other commands. +func (dc *MockDBClient) ExpectRequest(query string, result *sqltypes.Result, err error) { + select { + case <-dc.done: + dc.done = make(chan struct{}) + default: + } + dc.expect = append(dc.expect, &mockExpect{ + query: query, + result: result, + err: err, + }) +} + +// ExpectRequestRE adds an expected result to the mock. +// queryRE is a regular expression. +// This function should not be called conncurrently with other commands. +func (dc *MockDBClient) ExpectRequestRE(queryRE string, result *sqltypes.Result, err error) { + select { + case <-dc.done: + dc.done = make(chan struct{}) + default: + } + dc.expect = append(dc.expect, &mockExpect{ + query: queryRE, + re: regexp.MustCompile(queryRE), + result: result, + err: err, + }) +} + +// Wait waits for all expected requests to be executed. +// dc.t.Fatalf is executed on 1 second timeout. Wait should +// not be called concurrently with ExpectRequest. +func (dc *MockDBClient) Wait() { + dc.t.Helper() + select { + case <-dc.done: + return + case <-time.After(5 * time.Second): + dc.t.Fatalf("timeout waiting for requests, want: %v", dc.expect[dc.currentResult].query) + } +} + +// DBName is part of the DBClient interface +func (dc *MockDBClient) DBName() string { + return "db" +} + +// Connect is part of the DBClient interface +func (dc *MockDBClient) Connect() error { + return nil +} + +// Begin is part of the DBClient interface +func (dc *MockDBClient) Begin() error { + _, err := dc.ExecuteFetch("begin", 1) + return err +} + +// Commit is part of the DBClient interface +func (dc *MockDBClient) Commit() error { + _, err := dc.ExecuteFetch("commit", 1) + return err +} + +// Rollback is part of the DBClient interface +func (dc *MockDBClient) Rollback() error { + _, err := dc.ExecuteFetch("rollback", 1) + return err +} + +// Close is part of the DBClient interface +func (dc *MockDBClient) Close() { + return +} + +// ExecuteFetch is part of the DBClient interface +func (dc *MockDBClient) ExecuteFetch(query string, maxrows int) (qr *sqltypes.Result, err error) { + dc.t.Helper() + dc.t.Logf("DBClient query: %v", query) + if dc.currentResult >= len(dc.expect) { + dc.t.Fatalf("DBClientMock: query: %s, no more requests are expected", query) + } + result := dc.expect[dc.currentResult] + if result.re == nil { + if query != result.query { + dc.t.Fatalf("DBClientMock: query: %s, want %s", query, result.query) + } + } else { + if !result.re.MatchString(query) { + dc.t.Fatalf("DBClientMock: query: %s, must match %s", query, result.query) + } + } + dc.currentResult++ + if dc.currentResult >= len(dc.expect) { + close(dc.done) + } + return result.result, result.err +} diff --git a/go/vt/binlog/binlogplayer/vtclient.go b/go/vt/binlog/binlogplayer/vtclient.go deleted file mode 100644 index a274d3a536c..00000000000 --- a/go/vt/binlog/binlogplayer/vtclient.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 binlogplayer - -import "vitess.io/vitess/go/sqltypes" - -// VtClient is a high level interface to the database. -type VtClient interface { - Connect() error - Begin() error - Commit() error - Rollback() error - Close() - ExecuteFetch(query string, maxrows int) (qr *sqltypes.Result, err error) -} - -// VtClientMock is a VtClient that writes to a writer instead of executing -// anything. -// It allows to mock out query results for queries. See AddResult(). -type VtClientMock struct { - Stdout []string - results []*sqltypes.Result - CommitChannel chan []string - currentResult int -} - -// NewVtClientMock returns a new VtClientMock -func NewVtClientMock() *VtClientMock { - return &VtClientMock{ - results: make([]*sqltypes.Result, 0), - currentResult: -1, - } -} - -// AddResult appends a mocked query result to the end of the list. -// It will be returned exactly once to a client when it's up. -func (dc *VtClientMock) AddResult(result *sqltypes.Result) { - dc.results = append(dc.results, result) -} - -// Connect is part of the VtClient interface -func (dc *VtClientMock) Connect() error { - return nil -} - -// Begin is part of the VtClient interface -func (dc *VtClientMock) Begin() error { - dc.Stdout = append(dc.Stdout, "BEGIN") - return nil -} - -// Commit is part of the VtClient interface -func (dc *VtClientMock) Commit() error { - dc.Stdout = append(dc.Stdout, "COMMIT") - if dc.CommitChannel != nil { - dc.CommitChannel <- dc.Stdout - dc.Stdout = nil - } - return nil -} - -// Rollback is part of the VtClient interface -func (dc *VtClientMock) Rollback() error { - dc.Stdout = append(dc.Stdout, "ROLLBACK") - return nil -} - -// Close is part of the VtClient interface -func (dc *VtClientMock) Close() { - return -} - -// ExecuteFetch is part of the VtClient interface -func (dc *VtClientMock) ExecuteFetch(query string, maxrows int) (qr *sqltypes.Result, err error) { - dc.Stdout = append(dc.Stdout, query) - if dc.currentResult+1 < len(dc.results) { - dc.currentResult++ - } - result := dc.results[dc.currentResult] - return result, nil -} diff --git a/go/vt/callinfo/plugin_grpc.go b/go/vt/callinfo/plugin_grpc.go index 3a79a08e815..558609069d1 100644 --- a/go/vt/callinfo/plugin_grpc.go +++ b/go/vt/callinfo/plugin_grpc.go @@ -24,6 +24,7 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" + "google.golang.org/grpc/peer" ) // GRPCCallInfo returns an augmented context with a CallInfo structure, @@ -33,17 +34,25 @@ func GRPCCallInfo(ctx context.Context) context.Context { if !ok { return ctx } - return NewContext(ctx, &gRPCCallInfoImpl{ + + callinfo := &gRPCCallInfoImpl{ method: method, - }) + } + peer, ok := peer.FromContext(ctx) + if ok { + callinfo.remoteAddr = peer.Addr.String() + } + + return NewContext(ctx, callinfo) } type gRPCCallInfoImpl struct { - method string + method string + remoteAddr string } func (gci *gRPCCallInfoImpl) RemoteAddr() string { - return "remote" + return gci.remoteAddr } func (gci *gRPCCallInfoImpl) Username() string { @@ -51,9 +60,9 @@ func (gci *gRPCCallInfoImpl) Username() string { } func (gci *gRPCCallInfoImpl) Text() string { - return fmt.Sprintf("%s(gRPC)", gci.method) + return fmt.Sprintf("%s:%s(gRPC)", gci.remoteAddr, gci.method) } func (gci *gRPCCallInfoImpl) HTML() template.HTML { - return template.HTML("Method: " + gci.method) + return template.HTML("Method: " + gci.method + " Remote Addr: " + gci.remoteAddr) } diff --git a/go/vt/callinfo/plugin_mysql.go b/go/vt/callinfo/plugin_mysql.go new file mode 100644 index 00000000000..d82f1ce1704 --- /dev/null +++ b/go/vt/callinfo/plugin_mysql.go @@ -0,0 +1,57 @@ +/* +Copyright 2018 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 agreedto 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 callinfo + +// This file implements the CallInfo interface for Mysql contexts. + +import ( + "fmt" + "html/template" + + "golang.org/x/net/context" + "vitess.io/vitess/go/mysql" +) + +// MysqlCallInfo returns an augmented context with a CallInfo structure, +// only for Mysql contexts. +func MysqlCallInfo(ctx context.Context, c *mysql.Conn) context.Context { + return NewContext(ctx, &mysqlCallInfoImpl{ + remoteAddr: c.RemoteAddr().String(), + user: c.User, + }) +} + +type mysqlCallInfoImpl struct { + remoteAddr string + user string +} + +func (mci *mysqlCallInfoImpl) RemoteAddr() string { + return mci.remoteAddr +} + +func (mci *mysqlCallInfoImpl) Username() string { + return mci.user +} + +func (mci *mysqlCallInfoImpl) Text() string { + return fmt.Sprintf("%s@%s(Mysql)", mci.user, mci.remoteAddr) +} + +func (mci *mysqlCallInfoImpl) HTML() template.HTML { + return template.HTML("MySQL User: " + mci.user + " Remote Addr: " + mci.remoteAddr) +} diff --git a/go/vt/dbconfigs/dbconfigs.go b/go/vt/dbconfigs/dbconfigs.go index 802a5376c7f..5df9aa2d7da 100644 --- a/go/vt/dbconfigs/dbconfigs.go +++ b/go/vt/dbconfigs/dbconfigs.go @@ -124,6 +124,9 @@ func registerPerUserFlags(dbc *userConfig, userKey string) { flag.StringVar(&dbc.param.SslCaPath, "db-config-"+userKey+"-ssl-ca-path", "", "deprecated: use db_ssl_ca_path") flag.StringVar(&dbc.param.SslCert, "db-config-"+userKey+"-ssl-cert", "", "deprecated: use db_ssl_cert") flag.StringVar(&dbc.param.SslKey, "db-config-"+userKey+"-ssl-key", "", "deprecated: use db_ssl_key") + + flag.StringVar(&dbc.param.DeprecatedDBName, "db-config-"+userKey+"-dbname", "", "deprecated: dbname does not need to be explicitly configured") + } // AppWithDB returns connection parameters for app with dbname set. diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go index 3869933f8af..2f78d173d39 100644 --- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go @@ -345,18 +345,12 @@ func (fmd *FakeMysqlDaemon) FetchSuperQuery(ctx context.Context, query string) ( // EnableBinlogPlayback is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) EnableBinlogPlayback() error { - if fmd.BinlogPlayerEnabled { - return fmt.Errorf("binlog player already enabled") - } fmd.BinlogPlayerEnabled = true return nil } // DisableBinlogPlayback disable playback of binlog events func (fmd *FakeMysqlDaemon) DisableBinlogPlayback() error { - if fmd.BinlogPlayerEnabled { - return fmt.Errorf("binlog player already disabled") - } fmd.BinlogPlayerEnabled = false return nil } diff --git a/go/vt/mysqlctl/reparent.go b/go/vt/mysqlctl/reparent.go index 9c228f856bf..803838a4d05 100644 --- a/go/vt/mysqlctl/reparent.go +++ b/go/vt/mysqlctl/reparent.go @@ -117,6 +117,12 @@ func (mysqld *Mysqld) PromoteSlave(hookExtraEnv map[string]string) (mysql.Positi cmds := []string{ conn.StopSlaveCommand(), "RESET SLAVE ALL", // "ALL" makes it forget master host:port. + // When using semi-sync and GTID, a replica first connects to the new master with a given GTID set, + // it can take a long time to scan the current binlog file to find the corresponding position. + // This can cause commits that occur soon after the master is promoted to take a long time waiting + // for a semi-sync ACK, since replication is not fully set up. + // More details in: https://github.com/vitessio/vitess/issues/4161 + "FLUSH BINARY LOGS", } if err := mysqld.executeSuperQueryListConn(ctx, conn, cmds); err != nil { diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 11e64c2dfa1..70e08f625e3 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -300,43 +300,6 @@ func FindSlaves(mysqld MysqlDaemon) ([]string, error) { return addrs, nil } -// WaitBlpPosition will wait for the filtered replication to reach at least -// the provided position. -func WaitBlpPosition(ctx context.Context, mysqld MysqlDaemon, sql string, replicationPosition string) error { - position, err := mysql.DecodePosition(replicationPosition) - if err != nil { - return err - } - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - - qr, err := mysqld.FetchSuperQuery(ctx, sql) - if err != nil { - return err - } - if len(qr.Rows) != 1 { - return fmt.Errorf("QueryBlpCheckpoint(%v) returned unexpected row count: %v", sql, len(qr.Rows)) - } - var pos mysql.Position - if !qr.Rows[0][0].IsNull() { - pos, err = mysql.DecodePosition(qr.Rows[0][0].ToString()) - if err != nil { - return err - } - } - if pos.AtLeast(position) { - return nil - } - - log.Infof("Sleeping 1 second waiting for binlog replication(%v) to catch up: %v != %v", sql, pos, position) - time.Sleep(1 * time.Second) - } -} - // EnableBinlogPlayback prepares the server to play back events from a binlog stream. // Whatever it does for a given flavor, it must be idempotent. func (mysqld *Mysqld) EnableBinlogPlayback() error { diff --git a/go/vt/mysqlctl/tmutils/blp_position.go b/go/vt/mysqlctl/tmutils/blp_position.go deleted file mode 100644 index 73ec9e187a1..00000000000 --- a/go/vt/mysqlctl/tmutils/blp_position.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 tmutils - -// This file contains helper methods for dealing with the proto3 data -// structures related to binlog playback. - -import tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" - -// FindBlpPositionByID returns the BlpPosition with the given id, or error -func FindBlpPositionByID(list []*tabletmanagerdatapb.BlpPosition, uid uint32) *tabletmanagerdatapb.BlpPosition { - for _, pos := range list { - if pos.Uid == uid { - return pos - } - } - return nil -} diff --git a/go/vt/proto/binlogdata/binlogdata.pb.go b/go/vt/proto/binlogdata/binlogdata.pb.go index 1e56d779b32..af305cdbe10 100644 --- a/go/vt/proto/binlogdata/binlogdata.pb.go +++ b/go/vt/proto/binlogdata/binlogdata.pb.go @@ -65,7 +65,7 @@ func (x BinlogTransaction_Statement_Category) String() string { return proto.EnumName(BinlogTransaction_Statement_Category_name, int32(x)) } func (BinlogTransaction_Statement_Category) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{1, 0, 0} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{1, 0, 0} } // Charset is the per-statement charset info from a QUERY_EVENT binlog entry. @@ -85,7 +85,7 @@ func (m *Charset) Reset() { *m = Charset{} } func (m *Charset) String() string { return proto.CompactTextString(m) } func (*Charset) ProtoMessage() {} func (*Charset) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{0} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{0} } func (m *Charset) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Charset.Unmarshal(m, b) @@ -142,7 +142,7 @@ func (m *BinlogTransaction) Reset() { *m = BinlogTransaction{} } func (m *BinlogTransaction) String() string { return proto.CompactTextString(m) } func (*BinlogTransaction) ProtoMessage() {} func (*BinlogTransaction) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{1} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{1} } func (m *BinlogTransaction) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BinlogTransaction.Unmarshal(m, b) @@ -192,7 +192,7 @@ func (m *BinlogTransaction_Statement) Reset() { *m = BinlogTransaction_S func (m *BinlogTransaction_Statement) String() string { return proto.CompactTextString(m) } func (*BinlogTransaction_Statement) ProtoMessage() {} func (*BinlogTransaction_Statement) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{1, 0} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{1, 0} } func (m *BinlogTransaction_Statement) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BinlogTransaction_Statement.Unmarshal(m, b) @@ -250,7 +250,7 @@ func (m *StreamKeyRangeRequest) Reset() { *m = StreamKeyRangeRequest{} } func (m *StreamKeyRangeRequest) String() string { return proto.CompactTextString(m) } func (*StreamKeyRangeRequest) ProtoMessage() {} func (*StreamKeyRangeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{2} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{2} } func (m *StreamKeyRangeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamKeyRangeRequest.Unmarshal(m, b) @@ -303,7 +303,7 @@ func (m *StreamKeyRangeResponse) Reset() { *m = StreamKeyRangeResponse{} func (m *StreamKeyRangeResponse) String() string { return proto.CompactTextString(m) } func (*StreamKeyRangeResponse) ProtoMessage() {} func (*StreamKeyRangeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{3} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{3} } func (m *StreamKeyRangeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamKeyRangeResponse.Unmarshal(m, b) @@ -347,7 +347,7 @@ func (m *StreamTablesRequest) Reset() { *m = StreamTablesRequest{} } func (m *StreamTablesRequest) String() string { return proto.CompactTextString(m) } func (*StreamTablesRequest) ProtoMessage() {} func (*StreamTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{4} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{4} } func (m *StreamTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamTablesRequest.Unmarshal(m, b) @@ -400,7 +400,7 @@ func (m *StreamTablesResponse) Reset() { *m = StreamTablesResponse{} } func (m *StreamTablesResponse) String() string { return proto.CompactTextString(m) } func (*StreamTablesResponse) ProtoMessage() {} func (*StreamTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_ccae9945406a9695, []int{5} + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{5} } func (m *StreamTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamTablesResponse.Unmarshal(m, b) @@ -427,6 +427,84 @@ func (m *StreamTablesResponse) GetBinlogTransaction() *BinlogTransaction { return nil } +// BinlogSource specifies the source and filter parameters for +// Filtered Replication. It currently supports a keyrange +// or a list of tables. +type BinlogSource struct { + // the source keyspace + Keyspace string `protobuf:"bytes,1,opt,name=keyspace" json:"keyspace,omitempty"` + // the source shard + Shard string `protobuf:"bytes,2,opt,name=shard" json:"shard,omitempty"` + // the source tablet type + TabletType topodata.TabletType `protobuf:"varint,3,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"` + // key_range is set if the request is for a keyrange + KeyRange *topodata.KeyRange `protobuf:"bytes,4,opt,name=key_range,json=keyRange" json:"key_range,omitempty"` + // tables is set if the request is for a list of tables + Tables []string `protobuf:"bytes,5,rep,name=tables" json:"tables,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *BinlogSource) Reset() { *m = BinlogSource{} } +func (m *BinlogSource) String() string { return proto.CompactTextString(m) } +func (*BinlogSource) ProtoMessage() {} +func (*BinlogSource) Descriptor() ([]byte, []int) { + return fileDescriptor_binlogdata_ac14f15f6b19a931, []int{6} +} +func (m *BinlogSource) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_BinlogSource.Unmarshal(m, b) +} +func (m *BinlogSource) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_BinlogSource.Marshal(b, m, deterministic) +} +func (dst *BinlogSource) XXX_Merge(src proto.Message) { + xxx_messageInfo_BinlogSource.Merge(dst, src) +} +func (m *BinlogSource) XXX_Size() int { + return xxx_messageInfo_BinlogSource.Size(m) +} +func (m *BinlogSource) XXX_DiscardUnknown() { + xxx_messageInfo_BinlogSource.DiscardUnknown(m) +} + +var xxx_messageInfo_BinlogSource proto.InternalMessageInfo + +func (m *BinlogSource) GetKeyspace() string { + if m != nil { + return m.Keyspace + } + return "" +} + +func (m *BinlogSource) GetShard() string { + if m != nil { + return m.Shard + } + return "" +} + +func (m *BinlogSource) GetTabletType() topodata.TabletType { + if m != nil { + return m.TabletType + } + return topodata.TabletType_UNKNOWN +} + +func (m *BinlogSource) GetKeyRange() *topodata.KeyRange { + if m != nil { + return m.KeyRange + } + return nil +} + +func (m *BinlogSource) GetTables() []string { + if m != nil { + return m.Tables + } + return nil +} + func init() { proto.RegisterType((*Charset)(nil), "binlogdata.Charset") proto.RegisterType((*BinlogTransaction)(nil), "binlogdata.BinlogTransaction") @@ -435,47 +513,52 @@ func init() { proto.RegisterType((*StreamKeyRangeResponse)(nil), "binlogdata.StreamKeyRangeResponse") proto.RegisterType((*StreamTablesRequest)(nil), "binlogdata.StreamTablesRequest") proto.RegisterType((*StreamTablesResponse)(nil), "binlogdata.StreamTablesResponse") + proto.RegisterType((*BinlogSource)(nil), "binlogdata.BinlogSource") proto.RegisterEnum("binlogdata.BinlogTransaction_Statement_Category", BinlogTransaction_Statement_Category_name, BinlogTransaction_Statement_Category_value) } -func init() { proto.RegisterFile("binlogdata.proto", fileDescriptor_binlogdata_ccae9945406a9695) } - -var fileDescriptor_binlogdata_ccae9945406a9695 = []byte{ - // 564 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xdd, 0x4e, 0xdb, 0x30, - 0x14, 0x5e, 0x9a, 0x52, 0xd2, 0x13, 0x06, 0xae, 0x19, 0xa8, 0xaa, 0x34, 0xa9, 0xca, 0x0d, 0xdd, - 0xc5, 0x92, 0x29, 0x7b, 0x02, 0x92, 0x58, 0xa8, 0xe0, 0x16, 0xe4, 0x86, 0x1b, 0x6e, 0xa2, 0xb4, - 0x78, 0x5d, 0x44, 0x89, 0x4b, 0x6c, 0xaa, 0xf5, 0x39, 0xf6, 0x14, 0x7b, 0x91, 0xbd, 0xc9, 0xde, - 0x63, 0xca, 0x0f, 0x69, 0xc7, 0xa4, 0x8d, 0x5d, 0xec, 0xee, 0xfb, 0x8e, 0xbf, 0xf3, 0xf9, 0x9c, - 0x2f, 0x56, 0x00, 0x4d, 0x93, 0x74, 0x21, 0xe6, 0xb7, 0xb1, 0x8a, 0xed, 0x65, 0x26, 0x94, 0xc0, - 0xb0, 0xa9, 0xf4, 0xcc, 0x87, 0x47, 0x9e, 0xad, 0xcb, 0x83, 0xde, 0xbe, 0x12, 0x4b, 0xb1, 0x11, - 0x5a, 0x23, 0xd8, 0xf5, 0x3f, 0xc7, 0x99, 0xe4, 0x0a, 0x1f, 0x43, 0x6b, 0xb6, 0x48, 0x78, 0xaa, - 0xba, 0x5a, 0x5f, 0x1b, 0xec, 0xb0, 0x8a, 0x61, 0x0c, 0xcd, 0x99, 0x48, 0xd3, 0x6e, 0xa3, 0xa8, - 0x16, 0x38, 0xd7, 0x4a, 0x9e, 0xad, 0x78, 0xd6, 0xd5, 0x4b, 0x6d, 0xc9, 0xac, 0x1f, 0x3a, 0x74, - 0xbc, 0xe2, 0xea, 0x30, 0x8b, 0x53, 0x19, 0xcf, 0x54, 0x22, 0x52, 0x7c, 0x06, 0x20, 0x55, 0xac, - 0xf8, 0x3d, 0x4f, 0x95, 0xec, 0x6a, 0x7d, 0x7d, 0x60, 0xba, 0x27, 0xf6, 0xd6, 0xd0, 0xbf, 0xb5, - 0xd8, 0x93, 0x27, 0x3d, 0xdb, 0x6a, 0xc5, 0x2e, 0x98, 0x7c, 0xc5, 0x53, 0x15, 0x29, 0x71, 0xc7, - 0xd3, 0x6e, 0xb3, 0xaf, 0x0d, 0x4c, 0xb7, 0x63, 0x97, 0x0b, 0x92, 0xfc, 0x24, 0xcc, 0x0f, 0x18, - 0xf0, 0x1a, 0xf7, 0xbe, 0x37, 0xa0, 0x5d, 0xbb, 0x61, 0x0a, 0xc6, 0x2c, 0x56, 0x7c, 0x2e, 0xb2, - 0x75, 0xb1, 0xe6, 0xbe, 0xfb, 0xe1, 0x85, 0x83, 0xd8, 0x7e, 0xd5, 0xc7, 0x6a, 0x07, 0xfc, 0x1e, - 0x76, 0x67, 0x65, 0x7a, 0x45, 0x3a, 0xa6, 0x7b, 0xb8, 0x6d, 0x56, 0x05, 0xcb, 0x9e, 0x34, 0x18, - 0x81, 0x2e, 0x1f, 0x16, 0x45, 0x64, 0x7b, 0x2c, 0x87, 0xd6, 0x37, 0x0d, 0x8c, 0x27, 0x5f, 0x7c, - 0x08, 0x07, 0x1e, 0x8d, 0xae, 0xc7, 0x8c, 0xf8, 0x97, 0x67, 0xe3, 0xe1, 0x0d, 0x09, 0xd0, 0x2b, - 0xbc, 0x07, 0x86, 0x47, 0x23, 0x8f, 0x9c, 0x0d, 0xc7, 0x48, 0xc3, 0xaf, 0xa1, 0xed, 0xd1, 0xc8, - 0xbf, 0x1c, 0x8d, 0x86, 0x21, 0x6a, 0xe0, 0x03, 0x30, 0x3d, 0x1a, 0xb1, 0x4b, 0x4a, 0xbd, 0x53, - 0xff, 0x02, 0xe9, 0xf8, 0x08, 0x3a, 0x1e, 0x8d, 0x82, 0x11, 0x8d, 0x02, 0x72, 0xc5, 0x88, 0x7f, - 0x1a, 0x92, 0x00, 0x35, 0x31, 0x40, 0x2b, 0x2f, 0x07, 0x14, 0xed, 0x54, 0x78, 0x42, 0x42, 0xd4, - 0xaa, 0xec, 0x86, 0xe3, 0x09, 0x61, 0x21, 0xda, 0xad, 0xe8, 0xf5, 0x55, 0x70, 0x1a, 0x12, 0x64, - 0x54, 0x34, 0x20, 0x94, 0x84, 0x04, 0xb5, 0xcf, 0x9b, 0x46, 0x03, 0xe9, 0xe7, 0x4d, 0x43, 0x47, - 0x4d, 0xeb, 0xab, 0x06, 0x47, 0x13, 0x95, 0xf1, 0xf8, 0xfe, 0x82, 0xaf, 0x59, 0x9c, 0xce, 0x39, - 0xe3, 0x0f, 0x8f, 0x5c, 0x2a, 0xdc, 0x03, 0x63, 0x29, 0x64, 0x92, 0x67, 0x57, 0x04, 0xdc, 0x66, - 0x35, 0xc7, 0x0e, 0xb4, 0xef, 0xf8, 0x3a, 0xca, 0x72, 0x7d, 0x15, 0x18, 0xb6, 0xeb, 0x07, 0x59, - 0x3b, 0x19, 0x77, 0x15, 0xda, 0xce, 0x57, 0xff, 0x7b, 0xbe, 0xd6, 0x27, 0x38, 0x7e, 0x3e, 0x94, - 0x5c, 0x8a, 0x54, 0x72, 0x4c, 0x01, 0x97, 0x8d, 0x91, 0xda, 0x7c, 0xdb, 0x62, 0x3e, 0xd3, 0x7d, - 0xfb, 0xc7, 0x07, 0xc0, 0x3a, 0xd3, 0xe7, 0x25, 0xeb, 0x0b, 0x1c, 0x96, 0xf7, 0x84, 0xf1, 0x74, - 0xc1, 0xe5, 0x4b, 0x56, 0x3f, 0x86, 0x96, 0x2a, 0xc4, 0xdd, 0x46, 0x5f, 0x1f, 0xb4, 0x59, 0xc5, - 0xfe, 0x75, 0xc3, 0x5b, 0x78, 0xf3, 0xeb, 0xcd, 0xff, 0x63, 0x3f, 0xef, 0xdd, 0xcd, 0xc9, 0x2a, - 0x51, 0x5c, 0x4a, 0x3b, 0x11, 0x4e, 0x89, 0x9c, 0xb9, 0x70, 0x56, 0xca, 0x29, 0x7e, 0x1a, 0xce, - 0xc6, 0x6f, 0xda, 0x2a, 0x2a, 0x1f, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xa0, 0x1b, 0x77, 0x20, - 0x83, 0x04, 0x00, 0x00, +func init() { proto.RegisterFile("binlogdata.proto", fileDescriptor_binlogdata_ac14f15f6b19a931) } + +var fileDescriptor_binlogdata_ac14f15f6b19a931 = []byte{ + // 640 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcd, 0x6e, 0xda, 0x4a, + 0x14, 0xbe, 0xc6, 0x40, 0xec, 0xe3, 0xdc, 0x64, 0x98, 0xfc, 0x08, 0x21, 0x5d, 0x09, 0xb1, 0x09, + 0x77, 0x71, 0xcd, 0x95, 0xab, 0x3e, 0x40, 0x8c, 0xad, 0x88, 0xc4, 0x90, 0x68, 0x70, 0x36, 0xd9, + 0x58, 0xc6, 0x99, 0x12, 0x04, 0xf1, 0x38, 0x9e, 0x09, 0xaa, 0x9f, 0xa3, 0x4f, 0xd1, 0xb7, 0xe8, + 0xaa, 0x6f, 0xd2, 0xf7, 0xa8, 0x3c, 0x36, 0x86, 0xa4, 0x52, 0x9b, 0x2e, 0xba, 0x3b, 0xdf, 0x99, + 0xef, 0x9c, 0x39, 0xdf, 0x37, 0x47, 0x03, 0x68, 0xb6, 0x88, 0x57, 0x6c, 0x7e, 0x1f, 0x8a, 0xd0, + 0x4c, 0x52, 0x26, 0x18, 0x86, 0x6d, 0xa6, 0x63, 0x3c, 0x3d, 0xd3, 0x34, 0x2b, 0x0e, 0x3a, 0x07, + 0x82, 0x25, 0x6c, 0x4b, 0xec, 0x8d, 0x61, 0x6f, 0xf8, 0x10, 0xa6, 0x9c, 0x0a, 0x7c, 0x0a, 0xcd, + 0x68, 0xb5, 0xa0, 0xb1, 0x68, 0x2b, 0x5d, 0xa5, 0xdf, 0x20, 0x25, 0xc2, 0x18, 0xea, 0x11, 0x8b, + 0xe3, 0x76, 0x4d, 0x66, 0x65, 0x9c, 0x73, 0x39, 0x4d, 0xd7, 0x34, 0x6d, 0xab, 0x05, 0xb7, 0x40, + 0xbd, 0x6f, 0x2a, 0xb4, 0x6c, 0x79, 0xb5, 0x9f, 0x86, 0x31, 0x0f, 0x23, 0xb1, 0x60, 0x31, 0xbe, + 0x00, 0xe0, 0x22, 0x14, 0xf4, 0x91, 0xc6, 0x82, 0xb7, 0x95, 0xae, 0xda, 0x37, 0xac, 0x33, 0x73, + 0x67, 0xe8, 0x1f, 0x4a, 0xcc, 0xe9, 0x86, 0x4f, 0x76, 0x4a, 0xb1, 0x05, 0x06, 0x5d, 0xd3, 0x58, + 0x04, 0x82, 0x2d, 0x69, 0xdc, 0xae, 0x77, 0x95, 0xbe, 0x61, 0xb5, 0xcc, 0x42, 0xa0, 0x9b, 0x9f, + 0xf8, 0xf9, 0x01, 0x01, 0x5a, 0xc5, 0x9d, 0xaf, 0x35, 0xd0, 0xab, 0x6e, 0xd8, 0x03, 0x2d, 0x0a, + 0x05, 0x9d, 0xb3, 0x34, 0x93, 0x32, 0x0f, 0xac, 0xff, 0xdf, 0x38, 0x88, 0x39, 0x2c, 0xeb, 0x48, + 0xd5, 0x01, 0xff, 0x07, 0x7b, 0x51, 0xe1, 0x9e, 0x74, 0xc7, 0xb0, 0x8e, 0x76, 0x9b, 0x95, 0xc6, + 0x92, 0x0d, 0x07, 0x23, 0x50, 0xf9, 0xd3, 0x4a, 0x5a, 0xb6, 0x4f, 0xf2, 0xb0, 0xf7, 0x59, 0x01, + 0x6d, 0xd3, 0x17, 0x1f, 0xc1, 0xa1, 0xed, 0x05, 0xb7, 0x13, 0xe2, 0x0e, 0xaf, 0x2f, 0x26, 0xa3, + 0x3b, 0xd7, 0x41, 0x7f, 0xe1, 0x7d, 0xd0, 0x6c, 0x2f, 0xb0, 0xdd, 0x8b, 0xd1, 0x04, 0x29, 0xf8, + 0x6f, 0xd0, 0x6d, 0x2f, 0x18, 0x5e, 0x8f, 0xc7, 0x23, 0x1f, 0xd5, 0xf0, 0x21, 0x18, 0xb6, 0x17, + 0x90, 0x6b, 0xcf, 0xb3, 0xcf, 0x87, 0x57, 0x48, 0xc5, 0x27, 0xd0, 0xb2, 0xbd, 0xc0, 0x19, 0x7b, + 0x81, 0xe3, 0xde, 0x10, 0x77, 0x78, 0xee, 0xbb, 0x0e, 0xaa, 0x63, 0x80, 0x66, 0x9e, 0x76, 0x3c, + 0xd4, 0x28, 0xe3, 0xa9, 0xeb, 0xa3, 0x66, 0xd9, 0x6e, 0x34, 0x99, 0xba, 0xc4, 0x47, 0x7b, 0x25, + 0xbc, 0xbd, 0x71, 0xce, 0x7d, 0x17, 0x69, 0x25, 0x74, 0x5c, 0xcf, 0xf5, 0x5d, 0xa4, 0x5f, 0xd6, + 0xb5, 0x1a, 0x52, 0x2f, 0xeb, 0x9a, 0x8a, 0xea, 0xbd, 0x4f, 0x0a, 0x9c, 0x4c, 0x45, 0x4a, 0xc3, + 0xc7, 0x2b, 0x9a, 0x91, 0x30, 0x9e, 0x53, 0x42, 0x9f, 0x9e, 0x29, 0x17, 0xb8, 0x03, 0x5a, 0xc2, + 0xf8, 0x22, 0xf7, 0x4e, 0x1a, 0xac, 0x93, 0x0a, 0xe3, 0x01, 0xe8, 0x4b, 0x9a, 0x05, 0x69, 0xce, + 0x2f, 0x0d, 0xc3, 0x66, 0xb5, 0x90, 0x55, 0x27, 0x6d, 0x59, 0x46, 0xbb, 0xfe, 0xaa, 0xbf, 0xf6, + 0xb7, 0xf7, 0x01, 0x4e, 0x5f, 0x0f, 0xc5, 0x13, 0x16, 0x73, 0x8a, 0x3d, 0xc0, 0x45, 0x61, 0x20, + 0xb6, 0x6f, 0x2b, 0xe7, 0x33, 0xac, 0x7f, 0x7e, 0xba, 0x00, 0xa4, 0x35, 0x7b, 0x9d, 0xea, 0x7d, + 0x84, 0xa3, 0xe2, 0x1e, 0x3f, 0x9c, 0xad, 0x28, 0x7f, 0x8b, 0xf4, 0x53, 0x68, 0x0a, 0x49, 0x6e, + 0xd7, 0xba, 0x6a, 0x5f, 0x27, 0x25, 0xfa, 0x5d, 0x85, 0xf7, 0x70, 0xfc, 0xf2, 0xe6, 0x3f, 0xa2, + 0xef, 0x8b, 0x02, 0xfb, 0x05, 0x71, 0xca, 0x9e, 0xd3, 0x88, 0xe6, 0xca, 0x96, 0x34, 0xe3, 0x49, + 0x18, 0xd1, 0x8d, 0xb2, 0x0d, 0xc6, 0xc7, 0xd0, 0xe0, 0x0f, 0x61, 0x7a, 0x2f, 0x1f, 0x54, 0x27, + 0x05, 0xc0, 0xef, 0xc1, 0x90, 0x0a, 0x45, 0x20, 0xb2, 0x84, 0x4a, 0x6d, 0x07, 0xd6, 0xf1, 0xf6, + 0xb1, 0xe5, 0xfc, 0xc2, 0xcf, 0x12, 0x4a, 0x40, 0x54, 0xf1, 0xcb, 0x0d, 0xa9, 0xbf, 0x61, 0x43, + 0xb6, 0xbe, 0x36, 0x76, 0x7d, 0xb5, 0xff, 0xbd, 0x3b, 0x5b, 0x2f, 0x04, 0xe5, 0xdc, 0x5c, 0xb0, + 0x41, 0x11, 0x0d, 0xe6, 0x6c, 0xb0, 0x16, 0x03, 0xf9, 0xef, 0x0d, 0xb6, 0x96, 0xcc, 0x9a, 0x32, + 0xf3, 0xee, 0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x08, 0xae, 0x13, 0x46, 0x05, 0x00, 0x00, } diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go index 9bce72c7cfa..34d7c6c7479 100644 --- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go +++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go @@ -46,7 +46,7 @@ func (m *TableDefinition) Reset() { *m = TableDefinition{} } func (m *TableDefinition) String() string { return proto.CompactTextString(m) } func (*TableDefinition) ProtoMessage() {} func (*TableDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{0} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{0} } func (m *TableDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TableDefinition.Unmarshal(m, b) @@ -128,7 +128,7 @@ func (m *SchemaDefinition) Reset() { *m = SchemaDefinition{} } func (m *SchemaDefinition) String() string { return proto.CompactTextString(m) } func (*SchemaDefinition) ProtoMessage() {} func (*SchemaDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{1} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{1} } func (m *SchemaDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaDefinition.Unmarshal(m, b) @@ -183,7 +183,7 @@ func (m *SchemaChangeResult) Reset() { *m = SchemaChangeResult{} } func (m *SchemaChangeResult) String() string { return proto.CompactTextString(m) } func (*SchemaChangeResult) ProtoMessage() {} func (*SchemaChangeResult) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{2} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{2} } func (m *SchemaChangeResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaChangeResult.Unmarshal(m, b) @@ -234,7 +234,7 @@ func (m *UserPermission) Reset() { *m = UserPermission{} } func (m *UserPermission) String() string { return proto.CompactTextString(m) } func (*UserPermission) ProtoMessage() {} func (*UserPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{3} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{3} } func (m *UserPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UserPermission.Unmarshal(m, b) @@ -298,7 +298,7 @@ func (m *DbPermission) Reset() { *m = DbPermission{} } func (m *DbPermission) String() string { return proto.CompactTextString(m) } func (*DbPermission) ProtoMessage() {} func (*DbPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{4} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{4} } func (m *DbPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DbPermission.Unmarshal(m, b) @@ -360,7 +360,7 @@ func (m *Permissions) Reset() { *m = Permissions{} } func (m *Permissions) String() string { return proto.CompactTextString(m) } func (*Permissions) ProtoMessage() {} func (*Permissions) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{5} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{5} } func (m *Permissions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Permissions.Unmarshal(m, b) @@ -394,53 +394,6 @@ func (m *Permissions) GetDbPermissions() []*DbPermission { return nil } -// BlpPosition is a replication position for a given binlog player -type BlpPosition struct { - Uid uint32 `protobuf:"varint,1,opt,name=uid" json:"uid,omitempty"` - Position string `protobuf:"bytes,2,opt,name=position" json:"position,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *BlpPosition) Reset() { *m = BlpPosition{} } -func (m *BlpPosition) String() string { return proto.CompactTextString(m) } -func (*BlpPosition) ProtoMessage() {} -func (*BlpPosition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{6} -} -func (m *BlpPosition) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BlpPosition.Unmarshal(m, b) -} -func (m *BlpPosition) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BlpPosition.Marshal(b, m, deterministic) -} -func (dst *BlpPosition) XXX_Merge(src proto.Message) { - xxx_messageInfo_BlpPosition.Merge(dst, src) -} -func (m *BlpPosition) XXX_Size() int { - return xxx_messageInfo_BlpPosition.Size(m) -} -func (m *BlpPosition) XXX_DiscardUnknown() { - xxx_messageInfo_BlpPosition.DiscardUnknown(m) -} - -var xxx_messageInfo_BlpPosition proto.InternalMessageInfo - -func (m *BlpPosition) GetUid() uint32 { - if m != nil { - return m.Uid - } - return 0 -} - -func (m *BlpPosition) GetPosition() string { - if m != nil { - return m.Position - } - return "" -} - type PingRequest struct { Payload string `protobuf:"bytes,1,opt,name=payload" json:"payload,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -452,7 +405,7 @@ func (m *PingRequest) Reset() { *m = PingRequest{} } func (m *PingRequest) String() string { return proto.CompactTextString(m) } func (*PingRequest) ProtoMessage() {} func (*PingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{7} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{6} } func (m *PingRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingRequest.Unmarshal(m, b) @@ -490,7 +443,7 @@ func (m *PingResponse) Reset() { *m = PingResponse{} } func (m *PingResponse) String() string { return proto.CompactTextString(m) } func (*PingResponse) ProtoMessage() {} func (*PingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{8} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{7} } func (m *PingResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingResponse.Unmarshal(m, b) @@ -529,7 +482,7 @@ func (m *SleepRequest) Reset() { *m = SleepRequest{} } func (m *SleepRequest) String() string { return proto.CompactTextString(m) } func (*SleepRequest) ProtoMessage() {} func (*SleepRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{9} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{8} } func (m *SleepRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepRequest.Unmarshal(m, b) @@ -566,7 +519,7 @@ func (m *SleepResponse) Reset() { *m = SleepResponse{} } func (m *SleepResponse) String() string { return proto.CompactTextString(m) } func (*SleepResponse) ProtoMessage() {} func (*SleepResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{10} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{9} } func (m *SleepResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepResponse.Unmarshal(m, b) @@ -599,7 +552,7 @@ func (m *ExecuteHookRequest) Reset() { *m = ExecuteHookRequest{} } func (m *ExecuteHookRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteHookRequest) ProtoMessage() {} func (*ExecuteHookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{11} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{10} } func (m *ExecuteHookRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookRequest.Unmarshal(m, b) @@ -653,7 +606,7 @@ func (m *ExecuteHookResponse) Reset() { *m = ExecuteHookResponse{} } func (m *ExecuteHookResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteHookResponse) ProtoMessage() {} func (*ExecuteHookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{12} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{11} } func (m *ExecuteHookResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookResponse.Unmarshal(m, b) @@ -707,7 +660,7 @@ func (m *GetSchemaRequest) Reset() { *m = GetSchemaRequest{} } func (m *GetSchemaRequest) String() string { return proto.CompactTextString(m) } func (*GetSchemaRequest) ProtoMessage() {} func (*GetSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{13} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{12} } func (m *GetSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaRequest.Unmarshal(m, b) @@ -759,7 +712,7 @@ func (m *GetSchemaResponse) Reset() { *m = GetSchemaResponse{} } func (m *GetSchemaResponse) String() string { return proto.CompactTextString(m) } func (*GetSchemaResponse) ProtoMessage() {} func (*GetSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{14} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{13} } func (m *GetSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaResponse.Unmarshal(m, b) @@ -796,7 +749,7 @@ func (m *GetPermissionsRequest) Reset() { *m = GetPermissionsRequest{} } func (m *GetPermissionsRequest) String() string { return proto.CompactTextString(m) } func (*GetPermissionsRequest) ProtoMessage() {} func (*GetPermissionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{15} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{14} } func (m *GetPermissionsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsRequest.Unmarshal(m, b) @@ -827,7 +780,7 @@ func (m *GetPermissionsResponse) Reset() { *m = GetPermissionsResponse{} func (m *GetPermissionsResponse) String() string { return proto.CompactTextString(m) } func (*GetPermissionsResponse) ProtoMessage() {} func (*GetPermissionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{16} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{15} } func (m *GetPermissionsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsResponse.Unmarshal(m, b) @@ -864,7 +817,7 @@ func (m *SetReadOnlyRequest) Reset() { *m = SetReadOnlyRequest{} } func (m *SetReadOnlyRequest) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyRequest) ProtoMessage() {} func (*SetReadOnlyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{17} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{16} } func (m *SetReadOnlyRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyRequest.Unmarshal(m, b) @@ -894,7 +847,7 @@ func (m *SetReadOnlyResponse) Reset() { *m = SetReadOnlyResponse{} } func (m *SetReadOnlyResponse) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyResponse) ProtoMessage() {} func (*SetReadOnlyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{18} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{17} } func (m *SetReadOnlyResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyResponse.Unmarshal(m, b) @@ -924,7 +877,7 @@ func (m *SetReadWriteRequest) Reset() { *m = SetReadWriteRequest{} } func (m *SetReadWriteRequest) String() string { return proto.CompactTextString(m) } func (*SetReadWriteRequest) ProtoMessage() {} func (*SetReadWriteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{19} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{18} } func (m *SetReadWriteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteRequest.Unmarshal(m, b) @@ -954,7 +907,7 @@ func (m *SetReadWriteResponse) Reset() { *m = SetReadWriteResponse{} } func (m *SetReadWriteResponse) String() string { return proto.CompactTextString(m) } func (*SetReadWriteResponse) ProtoMessage() {} func (*SetReadWriteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{20} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{19} } func (m *SetReadWriteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteResponse.Unmarshal(m, b) @@ -985,7 +938,7 @@ func (m *ChangeTypeRequest) Reset() { *m = ChangeTypeRequest{} } func (m *ChangeTypeRequest) String() string { return proto.CompactTextString(m) } func (*ChangeTypeRequest) ProtoMessage() {} func (*ChangeTypeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{21} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{20} } func (m *ChangeTypeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeRequest.Unmarshal(m, b) @@ -1022,7 +975,7 @@ func (m *ChangeTypeResponse) Reset() { *m = ChangeTypeResponse{} } func (m *ChangeTypeResponse) String() string { return proto.CompactTextString(m) } func (*ChangeTypeResponse) ProtoMessage() {} func (*ChangeTypeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{22} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{21} } func (m *ChangeTypeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeResponse.Unmarshal(m, b) @@ -1052,7 +1005,7 @@ func (m *RefreshStateRequest) Reset() { *m = RefreshStateRequest{} } func (m *RefreshStateRequest) String() string { return proto.CompactTextString(m) } func (*RefreshStateRequest) ProtoMessage() {} func (*RefreshStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{23} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{22} } func (m *RefreshStateRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateRequest.Unmarshal(m, b) @@ -1082,7 +1035,7 @@ func (m *RefreshStateResponse) Reset() { *m = RefreshStateResponse{} } func (m *RefreshStateResponse) String() string { return proto.CompactTextString(m) } func (*RefreshStateResponse) ProtoMessage() {} func (*RefreshStateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{24} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{23} } func (m *RefreshStateResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateResponse.Unmarshal(m, b) @@ -1112,7 +1065,7 @@ func (m *RunHealthCheckRequest) Reset() { *m = RunHealthCheckRequest{} } func (m *RunHealthCheckRequest) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckRequest) ProtoMessage() {} func (*RunHealthCheckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{25} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{24} } func (m *RunHealthCheckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckRequest.Unmarshal(m, b) @@ -1142,7 +1095,7 @@ func (m *RunHealthCheckResponse) Reset() { *m = RunHealthCheckResponse{} func (m *RunHealthCheckResponse) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckResponse) ProtoMessage() {} func (*RunHealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{26} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{25} } func (m *RunHealthCheckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckResponse.Unmarshal(m, b) @@ -1173,7 +1126,7 @@ func (m *IgnoreHealthErrorRequest) Reset() { *m = IgnoreHealthErrorReque func (m *IgnoreHealthErrorRequest) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorRequest) ProtoMessage() {} func (*IgnoreHealthErrorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{27} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{26} } func (m *IgnoreHealthErrorRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorRequest.Unmarshal(m, b) @@ -1210,7 +1163,7 @@ func (m *IgnoreHealthErrorResponse) Reset() { *m = IgnoreHealthErrorResp func (m *IgnoreHealthErrorResponse) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorResponse) ProtoMessage() {} func (*IgnoreHealthErrorResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{28} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{27} } func (m *IgnoreHealthErrorResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorResponse.Unmarshal(m, b) @@ -1244,7 +1197,7 @@ func (m *ReloadSchemaRequest) Reset() { *m = ReloadSchemaRequest{} } func (m *ReloadSchemaRequest) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaRequest) ProtoMessage() {} func (*ReloadSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{29} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{28} } func (m *ReloadSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaRequest.Unmarshal(m, b) @@ -1281,7 +1234,7 @@ func (m *ReloadSchemaResponse) Reset() { *m = ReloadSchemaResponse{} } func (m *ReloadSchemaResponse) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaResponse) ProtoMessage() {} func (*ReloadSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{30} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{29} } func (m *ReloadSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaResponse.Unmarshal(m, b) @@ -1312,7 +1265,7 @@ func (m *PreflightSchemaRequest) Reset() { *m = PreflightSchemaRequest{} func (m *PreflightSchemaRequest) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaRequest) ProtoMessage() {} func (*PreflightSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{31} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{30} } func (m *PreflightSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaRequest.Unmarshal(m, b) @@ -1352,7 +1305,7 @@ func (m *PreflightSchemaResponse) Reset() { *m = PreflightSchemaResponse func (m *PreflightSchemaResponse) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaResponse) ProtoMessage() {} func (*PreflightSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{32} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{31} } func (m *PreflightSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaResponse.Unmarshal(m, b) @@ -1394,7 +1347,7 @@ func (m *ApplySchemaRequest) Reset() { *m = ApplySchemaRequest{} } func (m *ApplySchemaRequest) String() string { return proto.CompactTextString(m) } func (*ApplySchemaRequest) ProtoMessage() {} func (*ApplySchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{33} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{32} } func (m *ApplySchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaRequest.Unmarshal(m, b) @@ -1461,7 +1414,7 @@ func (m *ApplySchemaResponse) Reset() { *m = ApplySchemaResponse{} } func (m *ApplySchemaResponse) String() string { return proto.CompactTextString(m) } func (*ApplySchemaResponse) ProtoMessage() {} func (*ApplySchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{34} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{33} } func (m *ApplySchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaResponse.Unmarshal(m, b) @@ -1510,7 +1463,7 @@ func (m *ExecuteFetchAsDbaRequest) Reset() { *m = ExecuteFetchAsDbaReque func (m *ExecuteFetchAsDbaRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaRequest) ProtoMessage() {} func (*ExecuteFetchAsDbaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{35} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{34} } func (m *ExecuteFetchAsDbaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaRequest.Unmarshal(m, b) @@ -1576,7 +1529,7 @@ func (m *ExecuteFetchAsDbaResponse) Reset() { *m = ExecuteFetchAsDbaResp func (m *ExecuteFetchAsDbaResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaResponse) ProtoMessage() {} func (*ExecuteFetchAsDbaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{36} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{35} } func (m *ExecuteFetchAsDbaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaResponse.Unmarshal(m, b) @@ -1617,7 +1570,7 @@ func (m *ExecuteFetchAsAllPrivsRequest) Reset() { *m = ExecuteFetchAsAll func (m *ExecuteFetchAsAllPrivsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsRequest) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{37} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{36} } func (m *ExecuteFetchAsAllPrivsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsRequest.Unmarshal(m, b) @@ -1676,7 +1629,7 @@ func (m *ExecuteFetchAsAllPrivsResponse) Reset() { *m = ExecuteFetchAsAl func (m *ExecuteFetchAsAllPrivsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsResponse) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{38} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{37} } func (m *ExecuteFetchAsAllPrivsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsResponse.Unmarshal(m, b) @@ -1715,7 +1668,7 @@ func (m *ExecuteFetchAsAppRequest) Reset() { *m = ExecuteFetchAsAppReque func (m *ExecuteFetchAsAppRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppRequest) ProtoMessage() {} func (*ExecuteFetchAsAppRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{39} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{38} } func (m *ExecuteFetchAsAppRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppRequest.Unmarshal(m, b) @@ -1760,7 +1713,7 @@ func (m *ExecuteFetchAsAppResponse) Reset() { *m = ExecuteFetchAsAppResp func (m *ExecuteFetchAsAppResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppResponse) ProtoMessage() {} func (*ExecuteFetchAsAppResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{40} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{39} } func (m *ExecuteFetchAsAppResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppResponse.Unmarshal(m, b) @@ -1797,7 +1750,7 @@ func (m *SlaveStatusRequest) Reset() { *m = SlaveStatusRequest{} } func (m *SlaveStatusRequest) String() string { return proto.CompactTextString(m) } func (*SlaveStatusRequest) ProtoMessage() {} func (*SlaveStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{41} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{40} } func (m *SlaveStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusRequest.Unmarshal(m, b) @@ -1828,7 +1781,7 @@ func (m *SlaveStatusResponse) Reset() { *m = SlaveStatusResponse{} } func (m *SlaveStatusResponse) String() string { return proto.CompactTextString(m) } func (*SlaveStatusResponse) ProtoMessage() {} func (*SlaveStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{42} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{41} } func (m *SlaveStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusResponse.Unmarshal(m, b) @@ -1865,7 +1818,7 @@ func (m *MasterPositionRequest) Reset() { *m = MasterPositionRequest{} } func (m *MasterPositionRequest) String() string { return proto.CompactTextString(m) } func (*MasterPositionRequest) ProtoMessage() {} func (*MasterPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{43} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{42} } func (m *MasterPositionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionRequest.Unmarshal(m, b) @@ -1896,7 +1849,7 @@ func (m *MasterPositionResponse) Reset() { *m = MasterPositionResponse{} func (m *MasterPositionResponse) String() string { return proto.CompactTextString(m) } func (*MasterPositionResponse) ProtoMessage() {} func (*MasterPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{44} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{43} } func (m *MasterPositionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionResponse.Unmarshal(m, b) @@ -1933,7 +1886,7 @@ func (m *StopSlaveRequest) Reset() { *m = StopSlaveRequest{} } func (m *StopSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveRequest) ProtoMessage() {} func (*StopSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{45} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{44} } func (m *StopSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveRequest.Unmarshal(m, b) @@ -1963,7 +1916,7 @@ func (m *StopSlaveResponse) Reset() { *m = StopSlaveResponse{} } func (m *StopSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveResponse) ProtoMessage() {} func (*StopSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{46} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{45} } func (m *StopSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveResponse.Unmarshal(m, b) @@ -1995,7 +1948,7 @@ func (m *StopSlaveMinimumRequest) Reset() { *m = StopSlaveMinimumRequest func (m *StopSlaveMinimumRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumRequest) ProtoMessage() {} func (*StopSlaveMinimumRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{47} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{46} } func (m *StopSlaveMinimumRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumRequest.Unmarshal(m, b) @@ -2040,7 +1993,7 @@ func (m *StopSlaveMinimumResponse) Reset() { *m = StopSlaveMinimumRespon func (m *StopSlaveMinimumResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumResponse) ProtoMessage() {} func (*StopSlaveMinimumResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{48} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{47} } func (m *StopSlaveMinimumResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumResponse.Unmarshal(m, b) @@ -2077,7 +2030,7 @@ func (m *StartSlaveRequest) Reset() { *m = StartSlaveRequest{} } func (m *StartSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StartSlaveRequest) ProtoMessage() {} func (*StartSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{49} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{48} } func (m *StartSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveRequest.Unmarshal(m, b) @@ -2107,7 +2060,7 @@ func (m *StartSlaveResponse) Reset() { *m = StartSlaveResponse{} } func (m *StartSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StartSlaveResponse) ProtoMessage() {} func (*StartSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{50} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{49} } func (m *StartSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveResponse.Unmarshal(m, b) @@ -2141,7 +2094,7 @@ func (m *TabletExternallyReparentedRequest) Reset() { *m = TabletExterna func (m *TabletExternallyReparentedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedRequest) ProtoMessage() {} func (*TabletExternallyReparentedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{51} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{50} } func (m *TabletExternallyReparentedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedRequest.Unmarshal(m, b) @@ -2178,7 +2131,7 @@ func (m *TabletExternallyReparentedResponse) Reset() { *m = TabletExtern func (m *TabletExternallyReparentedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedResponse) ProtoMessage() {} func (*TabletExternallyReparentedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{52} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{51} } func (m *TabletExternallyReparentedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedResponse.Unmarshal(m, b) @@ -2208,7 +2161,7 @@ func (m *TabletExternallyElectedRequest) Reset() { *m = TabletExternally func (m *TabletExternallyElectedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedRequest) ProtoMessage() {} func (*TabletExternallyElectedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{53} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{52} } func (m *TabletExternallyElectedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedRequest.Unmarshal(m, b) @@ -2238,7 +2191,7 @@ func (m *TabletExternallyElectedResponse) Reset() { *m = TabletExternall func (m *TabletExternallyElectedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedResponse) ProtoMessage() {} func (*TabletExternallyElectedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{54} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{53} } func (m *TabletExternallyElectedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedResponse.Unmarshal(m, b) @@ -2268,7 +2221,7 @@ func (m *GetSlavesRequest) Reset() { *m = GetSlavesRequest{} } func (m *GetSlavesRequest) String() string { return proto.CompactTextString(m) } func (*GetSlavesRequest) ProtoMessage() {} func (*GetSlavesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{55} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{54} } func (m *GetSlavesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesRequest.Unmarshal(m, b) @@ -2299,7 +2252,7 @@ func (m *GetSlavesResponse) Reset() { *m = GetSlavesResponse{} } func (m *GetSlavesResponse) String() string { return proto.CompactTextString(m) } func (*GetSlavesResponse) ProtoMessage() {} func (*GetSlavesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{56} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{55} } func (m *GetSlavesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesResponse.Unmarshal(m, b) @@ -2326,353 +2279,217 @@ func (m *GetSlavesResponse) GetAddrs() []string { return nil } -type WaitBlpPositionRequest struct { - BlpPosition *BlpPosition `protobuf:"bytes,1,opt,name=blp_position,json=blpPosition" json:"blp_position,omitempty"` - WaitTimeout int64 `protobuf:"varint,2,opt,name=wait_timeout,json=waitTimeout" json:"wait_timeout,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *WaitBlpPositionRequest) Reset() { *m = WaitBlpPositionRequest{} } -func (m *WaitBlpPositionRequest) String() string { return proto.CompactTextString(m) } -func (*WaitBlpPositionRequest) ProtoMessage() {} -func (*WaitBlpPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{57} -} -func (m *WaitBlpPositionRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WaitBlpPositionRequest.Unmarshal(m, b) -} -func (m *WaitBlpPositionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WaitBlpPositionRequest.Marshal(b, m, deterministic) -} -func (dst *WaitBlpPositionRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_WaitBlpPositionRequest.Merge(dst, src) -} -func (m *WaitBlpPositionRequest) XXX_Size() int { - return xxx_messageInfo_WaitBlpPositionRequest.Size(m) -} -func (m *WaitBlpPositionRequest) XXX_DiscardUnknown() { - xxx_messageInfo_WaitBlpPositionRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_WaitBlpPositionRequest proto.InternalMessageInfo - -func (m *WaitBlpPositionRequest) GetBlpPosition() *BlpPosition { - if m != nil { - return m.BlpPosition - } - return nil -} - -func (m *WaitBlpPositionRequest) GetWaitTimeout() int64 { - if m != nil { - return m.WaitTimeout - } - return 0 -} - -type WaitBlpPositionResponse struct { +type ResetReplicationRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *WaitBlpPositionResponse) Reset() { *m = WaitBlpPositionResponse{} } -func (m *WaitBlpPositionResponse) String() string { return proto.CompactTextString(m) } -func (*WaitBlpPositionResponse) ProtoMessage() {} -func (*WaitBlpPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{58} +func (m *ResetReplicationRequest) Reset() { *m = ResetReplicationRequest{} } +func (m *ResetReplicationRequest) String() string { return proto.CompactTextString(m) } +func (*ResetReplicationRequest) ProtoMessage() {} +func (*ResetReplicationRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{56} } -func (m *WaitBlpPositionResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WaitBlpPositionResponse.Unmarshal(m, b) +func (m *ResetReplicationRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResetReplicationRequest.Unmarshal(m, b) } -func (m *WaitBlpPositionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WaitBlpPositionResponse.Marshal(b, m, deterministic) +func (m *ResetReplicationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResetReplicationRequest.Marshal(b, m, deterministic) } -func (dst *WaitBlpPositionResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_WaitBlpPositionResponse.Merge(dst, src) +func (dst *ResetReplicationRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetReplicationRequest.Merge(dst, src) } -func (m *WaitBlpPositionResponse) XXX_Size() int { - return xxx_messageInfo_WaitBlpPositionResponse.Size(m) +func (m *ResetReplicationRequest) XXX_Size() int { + return xxx_messageInfo_ResetReplicationRequest.Size(m) } -func (m *WaitBlpPositionResponse) XXX_DiscardUnknown() { - xxx_messageInfo_WaitBlpPositionResponse.DiscardUnknown(m) +func (m *ResetReplicationRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResetReplicationRequest.DiscardUnknown(m) } -var xxx_messageInfo_WaitBlpPositionResponse proto.InternalMessageInfo +var xxx_messageInfo_ResetReplicationRequest proto.InternalMessageInfo -type StopBlpRequest struct { +type ResetReplicationResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *StopBlpRequest) Reset() { *m = StopBlpRequest{} } -func (m *StopBlpRequest) String() string { return proto.CompactTextString(m) } -func (*StopBlpRequest) ProtoMessage() {} -func (*StopBlpRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{59} -} -func (m *StopBlpRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StopBlpRequest.Unmarshal(m, b) -} -func (m *StopBlpRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StopBlpRequest.Marshal(b, m, deterministic) -} -func (dst *StopBlpRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_StopBlpRequest.Merge(dst, src) -} -func (m *StopBlpRequest) XXX_Size() int { - return xxx_messageInfo_StopBlpRequest.Size(m) -} -func (m *StopBlpRequest) XXX_DiscardUnknown() { - xxx_messageInfo_StopBlpRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_StopBlpRequest proto.InternalMessageInfo - -type StopBlpResponse struct { - BlpPositions []*BlpPosition `protobuf:"bytes,1,rep,name=blp_positions,json=blpPositions" json:"blp_positions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StopBlpResponse) Reset() { *m = StopBlpResponse{} } -func (m *StopBlpResponse) String() string { return proto.CompactTextString(m) } -func (*StopBlpResponse) ProtoMessage() {} -func (*StopBlpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{60} +func (m *ResetReplicationResponse) Reset() { *m = ResetReplicationResponse{} } +func (m *ResetReplicationResponse) String() string { return proto.CompactTextString(m) } +func (*ResetReplicationResponse) ProtoMessage() {} +func (*ResetReplicationResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{57} } -func (m *StopBlpResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StopBlpResponse.Unmarshal(m, b) +func (m *ResetReplicationResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResetReplicationResponse.Unmarshal(m, b) } -func (m *StopBlpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StopBlpResponse.Marshal(b, m, deterministic) +func (m *ResetReplicationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResetReplicationResponse.Marshal(b, m, deterministic) } -func (dst *StopBlpResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_StopBlpResponse.Merge(dst, src) +func (dst *ResetReplicationResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResetReplicationResponse.Merge(dst, src) } -func (m *StopBlpResponse) XXX_Size() int { - return xxx_messageInfo_StopBlpResponse.Size(m) +func (m *ResetReplicationResponse) XXX_Size() int { + return xxx_messageInfo_ResetReplicationResponse.Size(m) } -func (m *StopBlpResponse) XXX_DiscardUnknown() { - xxx_messageInfo_StopBlpResponse.DiscardUnknown(m) +func (m *ResetReplicationResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResetReplicationResponse.DiscardUnknown(m) } -var xxx_messageInfo_StopBlpResponse proto.InternalMessageInfo - -func (m *StopBlpResponse) GetBlpPositions() []*BlpPosition { - if m != nil { - return m.BlpPositions - } - return nil -} +var xxx_messageInfo_ResetReplicationResponse proto.InternalMessageInfo -type StartBlpRequest struct { +type VReplicationExecRequest struct { + Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *StartBlpRequest) Reset() { *m = StartBlpRequest{} } -func (m *StartBlpRequest) String() string { return proto.CompactTextString(m) } -func (*StartBlpRequest) ProtoMessage() {} -func (*StartBlpRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{61} +func (m *VReplicationExecRequest) Reset() { *m = VReplicationExecRequest{} } +func (m *VReplicationExecRequest) String() string { return proto.CompactTextString(m) } +func (*VReplicationExecRequest) ProtoMessage() {} +func (*VReplicationExecRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{58} } -func (m *StartBlpRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StartBlpRequest.Unmarshal(m, b) +func (m *VReplicationExecRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VReplicationExecRequest.Unmarshal(m, b) } -func (m *StartBlpRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StartBlpRequest.Marshal(b, m, deterministic) +func (m *VReplicationExecRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VReplicationExecRequest.Marshal(b, m, deterministic) } -func (dst *StartBlpRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_StartBlpRequest.Merge(dst, src) +func (dst *VReplicationExecRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_VReplicationExecRequest.Merge(dst, src) } -func (m *StartBlpRequest) XXX_Size() int { - return xxx_messageInfo_StartBlpRequest.Size(m) +func (m *VReplicationExecRequest) XXX_Size() int { + return xxx_messageInfo_VReplicationExecRequest.Size(m) } -func (m *StartBlpRequest) XXX_DiscardUnknown() { - xxx_messageInfo_StartBlpRequest.DiscardUnknown(m) +func (m *VReplicationExecRequest) XXX_DiscardUnknown() { + xxx_messageInfo_VReplicationExecRequest.DiscardUnknown(m) } -var xxx_messageInfo_StartBlpRequest proto.InternalMessageInfo +var xxx_messageInfo_VReplicationExecRequest proto.InternalMessageInfo -type StartBlpResponse struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StartBlpResponse) Reset() { *m = StartBlpResponse{} } -func (m *StartBlpResponse) String() string { return proto.CompactTextString(m) } -func (*StartBlpResponse) ProtoMessage() {} -func (*StartBlpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{62} -} -func (m *StartBlpResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StartBlpResponse.Unmarshal(m, b) -} -func (m *StartBlpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StartBlpResponse.Marshal(b, m, deterministic) -} -func (dst *StartBlpResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_StartBlpResponse.Merge(dst, src) -} -func (m *StartBlpResponse) XXX_Size() int { - return xxx_messageInfo_StartBlpResponse.Size(m) -} -func (m *StartBlpResponse) XXX_DiscardUnknown() { - xxx_messageInfo_StartBlpResponse.DiscardUnknown(m) +func (m *VReplicationExecRequest) GetQuery() string { + if m != nil { + return m.Query + } + return "" } -var xxx_messageInfo_StartBlpResponse proto.InternalMessageInfo - -type RunBlpUntilRequest struct { - BlpPositions []*BlpPosition `protobuf:"bytes,1,rep,name=blp_positions,json=blpPositions" json:"blp_positions,omitempty"` - WaitTimeout int64 `protobuf:"varint,2,opt,name=wait_timeout,json=waitTimeout" json:"wait_timeout,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +type VReplicationExecResponse struct { + Result *query.QueryResult `protobuf:"bytes,1,opt,name=result" json:"result,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } -func (m *RunBlpUntilRequest) Reset() { *m = RunBlpUntilRequest{} } -func (m *RunBlpUntilRequest) String() string { return proto.CompactTextString(m) } -func (*RunBlpUntilRequest) ProtoMessage() {} -func (*RunBlpUntilRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{63} +func (m *VReplicationExecResponse) Reset() { *m = VReplicationExecResponse{} } +func (m *VReplicationExecResponse) String() string { return proto.CompactTextString(m) } +func (*VReplicationExecResponse) ProtoMessage() {} +func (*VReplicationExecResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{59} } -func (m *RunBlpUntilRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_RunBlpUntilRequest.Unmarshal(m, b) +func (m *VReplicationExecResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VReplicationExecResponse.Unmarshal(m, b) } -func (m *RunBlpUntilRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_RunBlpUntilRequest.Marshal(b, m, deterministic) +func (m *VReplicationExecResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VReplicationExecResponse.Marshal(b, m, deterministic) } -func (dst *RunBlpUntilRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_RunBlpUntilRequest.Merge(dst, src) +func (dst *VReplicationExecResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_VReplicationExecResponse.Merge(dst, src) } -func (m *RunBlpUntilRequest) XXX_Size() int { - return xxx_messageInfo_RunBlpUntilRequest.Size(m) +func (m *VReplicationExecResponse) XXX_Size() int { + return xxx_messageInfo_VReplicationExecResponse.Size(m) } -func (m *RunBlpUntilRequest) XXX_DiscardUnknown() { - xxx_messageInfo_RunBlpUntilRequest.DiscardUnknown(m) +func (m *VReplicationExecResponse) XXX_DiscardUnknown() { + xxx_messageInfo_VReplicationExecResponse.DiscardUnknown(m) } -var xxx_messageInfo_RunBlpUntilRequest proto.InternalMessageInfo +var xxx_messageInfo_VReplicationExecResponse proto.InternalMessageInfo -func (m *RunBlpUntilRequest) GetBlpPositions() []*BlpPosition { +func (m *VReplicationExecResponse) GetResult() *query.QueryResult { if m != nil { - return m.BlpPositions + return m.Result } return nil } -func (m *RunBlpUntilRequest) GetWaitTimeout() int64 { - if m != nil { - return m.WaitTimeout - } - return 0 -} - -type RunBlpUntilResponse struct { - Position string `protobuf:"bytes,1,opt,name=position" json:"position,omitempty"` +type VReplicationWaitForPosRequest struct { + Id int64 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"` + Position string `protobuf:"bytes,2,opt,name=position" json:"position,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *RunBlpUntilResponse) Reset() { *m = RunBlpUntilResponse{} } -func (m *RunBlpUntilResponse) String() string { return proto.CompactTextString(m) } -func (*RunBlpUntilResponse) ProtoMessage() {} -func (*RunBlpUntilResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{64} +func (m *VReplicationWaitForPosRequest) Reset() { *m = VReplicationWaitForPosRequest{} } +func (m *VReplicationWaitForPosRequest) String() string { return proto.CompactTextString(m) } +func (*VReplicationWaitForPosRequest) ProtoMessage() {} +func (*VReplicationWaitForPosRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{60} } -func (m *RunBlpUntilResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_RunBlpUntilResponse.Unmarshal(m, b) +func (m *VReplicationWaitForPosRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VReplicationWaitForPosRequest.Unmarshal(m, b) } -func (m *RunBlpUntilResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_RunBlpUntilResponse.Marshal(b, m, deterministic) +func (m *VReplicationWaitForPosRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VReplicationWaitForPosRequest.Marshal(b, m, deterministic) } -func (dst *RunBlpUntilResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_RunBlpUntilResponse.Merge(dst, src) +func (dst *VReplicationWaitForPosRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_VReplicationWaitForPosRequest.Merge(dst, src) } -func (m *RunBlpUntilResponse) XXX_Size() int { - return xxx_messageInfo_RunBlpUntilResponse.Size(m) +func (m *VReplicationWaitForPosRequest) XXX_Size() int { + return xxx_messageInfo_VReplicationWaitForPosRequest.Size(m) } -func (m *RunBlpUntilResponse) XXX_DiscardUnknown() { - xxx_messageInfo_RunBlpUntilResponse.DiscardUnknown(m) +func (m *VReplicationWaitForPosRequest) XXX_DiscardUnknown() { + xxx_messageInfo_VReplicationWaitForPosRequest.DiscardUnknown(m) } -var xxx_messageInfo_RunBlpUntilResponse proto.InternalMessageInfo +var xxx_messageInfo_VReplicationWaitForPosRequest proto.InternalMessageInfo -func (m *RunBlpUntilResponse) GetPosition() string { +func (m *VReplicationWaitForPosRequest) GetId() int64 { if m != nil { - return m.Position + return m.Id } - return "" -} - -type ResetReplicationRequest struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + return 0 } -func (m *ResetReplicationRequest) Reset() { *m = ResetReplicationRequest{} } -func (m *ResetReplicationRequest) String() string { return proto.CompactTextString(m) } -func (*ResetReplicationRequest) ProtoMessage() {} -func (*ResetReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{65} -} -func (m *ResetReplicationRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ResetReplicationRequest.Unmarshal(m, b) -} -func (m *ResetReplicationRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ResetReplicationRequest.Marshal(b, m, deterministic) -} -func (dst *ResetReplicationRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResetReplicationRequest.Merge(dst, src) -} -func (m *ResetReplicationRequest) XXX_Size() int { - return xxx_messageInfo_ResetReplicationRequest.Size(m) -} -func (m *ResetReplicationRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ResetReplicationRequest.DiscardUnknown(m) +func (m *VReplicationWaitForPosRequest) GetPosition() string { + if m != nil { + return m.Position + } + return "" } -var xxx_messageInfo_ResetReplicationRequest proto.InternalMessageInfo - -type ResetReplicationResponse struct { +type VReplicationWaitForPosResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } -func (m *ResetReplicationResponse) Reset() { *m = ResetReplicationResponse{} } -func (m *ResetReplicationResponse) String() string { return proto.CompactTextString(m) } -func (*ResetReplicationResponse) ProtoMessage() {} -func (*ResetReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{66} +func (m *VReplicationWaitForPosResponse) Reset() { *m = VReplicationWaitForPosResponse{} } +func (m *VReplicationWaitForPosResponse) String() string { return proto.CompactTextString(m) } +func (*VReplicationWaitForPosResponse) ProtoMessage() {} +func (*VReplicationWaitForPosResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{61} } -func (m *ResetReplicationResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ResetReplicationResponse.Unmarshal(m, b) +func (m *VReplicationWaitForPosResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_VReplicationWaitForPosResponse.Unmarshal(m, b) } -func (m *ResetReplicationResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ResetReplicationResponse.Marshal(b, m, deterministic) +func (m *VReplicationWaitForPosResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_VReplicationWaitForPosResponse.Marshal(b, m, deterministic) } -func (dst *ResetReplicationResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResetReplicationResponse.Merge(dst, src) +func (dst *VReplicationWaitForPosResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_VReplicationWaitForPosResponse.Merge(dst, src) } -func (m *ResetReplicationResponse) XXX_Size() int { - return xxx_messageInfo_ResetReplicationResponse.Size(m) +func (m *VReplicationWaitForPosResponse) XXX_Size() int { + return xxx_messageInfo_VReplicationWaitForPosResponse.Size(m) } -func (m *ResetReplicationResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ResetReplicationResponse.DiscardUnknown(m) +func (m *VReplicationWaitForPosResponse) XXX_DiscardUnknown() { + xxx_messageInfo_VReplicationWaitForPosResponse.DiscardUnknown(m) } -var xxx_messageInfo_ResetReplicationResponse proto.InternalMessageInfo +var xxx_messageInfo_VReplicationWaitForPosResponse proto.InternalMessageInfo type InitMasterRequest struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -2684,7 +2501,7 @@ func (m *InitMasterRequest) Reset() { *m = InitMasterRequest{} } func (m *InitMasterRequest) String() string { return proto.CompactTextString(m) } func (*InitMasterRequest) ProtoMessage() {} func (*InitMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{67} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{62} } func (m *InitMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterRequest.Unmarshal(m, b) @@ -2715,7 +2532,7 @@ func (m *InitMasterResponse) Reset() { *m = InitMasterResponse{} } func (m *InitMasterResponse) String() string { return proto.CompactTextString(m) } func (*InitMasterResponse) ProtoMessage() {} func (*InitMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{68} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{63} } func (m *InitMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterResponse.Unmarshal(m, b) @@ -2756,7 +2573,7 @@ func (m *PopulateReparentJournalRequest) Reset() { *m = PopulateReparent func (m *PopulateReparentJournalRequest) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalRequest) ProtoMessage() {} func (*PopulateReparentJournalRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{69} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{64} } func (m *PopulateReparentJournalRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalRequest.Unmarshal(m, b) @@ -2814,7 +2631,7 @@ func (m *PopulateReparentJournalResponse) Reset() { *m = PopulateReparen func (m *PopulateReparentJournalResponse) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalResponse) ProtoMessage() {} func (*PopulateReparentJournalResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{70} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{65} } func (m *PopulateReparentJournalResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalResponse.Unmarshal(m, b) @@ -2847,7 +2664,7 @@ func (m *InitSlaveRequest) Reset() { *m = InitSlaveRequest{} } func (m *InitSlaveRequest) String() string { return proto.CompactTextString(m) } func (*InitSlaveRequest) ProtoMessage() {} func (*InitSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{71} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{66} } func (m *InitSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveRequest.Unmarshal(m, b) @@ -2898,7 +2715,7 @@ func (m *InitSlaveResponse) Reset() { *m = InitSlaveResponse{} } func (m *InitSlaveResponse) String() string { return proto.CompactTextString(m) } func (*InitSlaveResponse) ProtoMessage() {} func (*InitSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{72} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{67} } func (m *InitSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveResponse.Unmarshal(m, b) @@ -2928,7 +2745,7 @@ func (m *DemoteMasterRequest) Reset() { *m = DemoteMasterRequest{} } func (m *DemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*DemoteMasterRequest) ProtoMessage() {} func (*DemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{73} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{68} } func (m *DemoteMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterRequest.Unmarshal(m, b) @@ -2959,7 +2776,7 @@ func (m *DemoteMasterResponse) Reset() { *m = DemoteMasterResponse{} } func (m *DemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*DemoteMasterResponse) ProtoMessage() {} func (*DemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{74} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{69} } func (m *DemoteMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterResponse.Unmarshal(m, b) @@ -2997,7 +2814,7 @@ func (m *PromoteSlaveWhenCaughtUpRequest) Reset() { *m = PromoteSlaveWhe func (m *PromoteSlaveWhenCaughtUpRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpRequest) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{75} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{70} } func (m *PromoteSlaveWhenCaughtUpRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpRequest.Unmarshal(m, b) @@ -3035,7 +2852,7 @@ func (m *PromoteSlaveWhenCaughtUpResponse) Reset() { *m = PromoteSlaveWh func (m *PromoteSlaveWhenCaughtUpResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpResponse) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{76} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{71} } func (m *PromoteSlaveWhenCaughtUpResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpResponse.Unmarshal(m, b) @@ -3072,7 +2889,7 @@ func (m *SlaveWasPromotedRequest) Reset() { *m = SlaveWasPromotedRequest func (m *SlaveWasPromotedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedRequest) ProtoMessage() {} func (*SlaveWasPromotedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{77} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{72} } func (m *SlaveWasPromotedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedRequest.Unmarshal(m, b) @@ -3102,7 +2919,7 @@ func (m *SlaveWasPromotedResponse) Reset() { *m = SlaveWasPromotedRespon func (m *SlaveWasPromotedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedResponse) ProtoMessage() {} func (*SlaveWasPromotedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{78} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{73} } func (m *SlaveWasPromotedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedResponse.Unmarshal(m, b) @@ -3135,7 +2952,7 @@ func (m *SetMasterRequest) Reset() { *m = SetMasterRequest{} } func (m *SetMasterRequest) String() string { return proto.CompactTextString(m) } func (*SetMasterRequest) ProtoMessage() {} func (*SetMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{79} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{74} } func (m *SetMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterRequest.Unmarshal(m, b) @@ -3186,7 +3003,7 @@ func (m *SetMasterResponse) Reset() { *m = SetMasterResponse{} } func (m *SetMasterResponse) String() string { return proto.CompactTextString(m) } func (*SetMasterResponse) ProtoMessage() {} func (*SetMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{80} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{75} } func (m *SetMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterResponse.Unmarshal(m, b) @@ -3218,7 +3035,7 @@ func (m *SlaveWasRestartedRequest) Reset() { *m = SlaveWasRestartedReque func (m *SlaveWasRestartedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedRequest) ProtoMessage() {} func (*SlaveWasRestartedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{81} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{76} } func (m *SlaveWasRestartedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedRequest.Unmarshal(m, b) @@ -3255,7 +3072,7 @@ func (m *SlaveWasRestartedResponse) Reset() { *m = SlaveWasRestartedResp func (m *SlaveWasRestartedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedResponse) ProtoMessage() {} func (*SlaveWasRestartedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{82} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{77} } func (m *SlaveWasRestartedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedResponse.Unmarshal(m, b) @@ -3285,7 +3102,7 @@ func (m *StopReplicationAndGetStatusRequest) Reset() { *m = StopReplicat func (m *StopReplicationAndGetStatusRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusRequest) ProtoMessage() {} func (*StopReplicationAndGetStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{83} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{78} } func (m *StopReplicationAndGetStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusRequest.Unmarshal(m, b) @@ -3316,7 +3133,7 @@ func (m *StopReplicationAndGetStatusResponse) Reset() { *m = StopReplica func (m *StopReplicationAndGetStatusResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusResponse) ProtoMessage() {} func (*StopReplicationAndGetStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{84} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{79} } func (m *StopReplicationAndGetStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusResponse.Unmarshal(m, b) @@ -3353,7 +3170,7 @@ func (m *PromoteSlaveRequest) Reset() { *m = PromoteSlaveRequest{} } func (m *PromoteSlaveRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveRequest) ProtoMessage() {} func (*PromoteSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{85} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{80} } func (m *PromoteSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveRequest.Unmarshal(m, b) @@ -3384,7 +3201,7 @@ func (m *PromoteSlaveResponse) Reset() { *m = PromoteSlaveResponse{} } func (m *PromoteSlaveResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveResponse) ProtoMessage() {} func (*PromoteSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{86} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{81} } func (m *PromoteSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveResponse.Unmarshal(m, b) @@ -3422,7 +3239,7 @@ func (m *BackupRequest) Reset() { *m = BackupRequest{} } func (m *BackupRequest) String() string { return proto.CompactTextString(m) } func (*BackupRequest) ProtoMessage() {} func (*BackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{87} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{82} } func (m *BackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupRequest.Unmarshal(m, b) @@ -3460,7 +3277,7 @@ func (m *BackupResponse) Reset() { *m = BackupResponse{} } func (m *BackupResponse) String() string { return proto.CompactTextString(m) } func (*BackupResponse) ProtoMessage() {} func (*BackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{88} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{83} } func (m *BackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupResponse.Unmarshal(m, b) @@ -3497,7 +3314,7 @@ func (m *RestoreFromBackupRequest) Reset() { *m = RestoreFromBackupReque func (m *RestoreFromBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupRequest) ProtoMessage() {} func (*RestoreFromBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{89} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{84} } func (m *RestoreFromBackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupRequest.Unmarshal(m, b) @@ -3528,7 +3345,7 @@ func (m *RestoreFromBackupResponse) Reset() { *m = RestoreFromBackupResp func (m *RestoreFromBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupResponse) ProtoMessage() {} func (*RestoreFromBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_87488b4d5ae092d8, []int{90} + return fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f, []int{85} } func (m *RestoreFromBackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupResponse.Unmarshal(m, b) @@ -3564,7 +3381,6 @@ func init() { proto.RegisterType((*DbPermission)(nil), "tabletmanagerdata.DbPermission") proto.RegisterMapType((map[string]string)(nil), "tabletmanagerdata.DbPermission.PrivilegesEntry") proto.RegisterType((*Permissions)(nil), "tabletmanagerdata.Permissions") - proto.RegisterType((*BlpPosition)(nil), "tabletmanagerdata.BlpPosition") proto.RegisterType((*PingRequest)(nil), "tabletmanagerdata.PingRequest") proto.RegisterType((*PingResponse)(nil), "tabletmanagerdata.PingResponse") proto.RegisterType((*SleepRequest)(nil), "tabletmanagerdata.SleepRequest") @@ -3616,16 +3432,12 @@ func init() { proto.RegisterType((*TabletExternallyElectedResponse)(nil), "tabletmanagerdata.TabletExternallyElectedResponse") proto.RegisterType((*GetSlavesRequest)(nil), "tabletmanagerdata.GetSlavesRequest") proto.RegisterType((*GetSlavesResponse)(nil), "tabletmanagerdata.GetSlavesResponse") - proto.RegisterType((*WaitBlpPositionRequest)(nil), "tabletmanagerdata.WaitBlpPositionRequest") - proto.RegisterType((*WaitBlpPositionResponse)(nil), "tabletmanagerdata.WaitBlpPositionResponse") - proto.RegisterType((*StopBlpRequest)(nil), "tabletmanagerdata.StopBlpRequest") - proto.RegisterType((*StopBlpResponse)(nil), "tabletmanagerdata.StopBlpResponse") - proto.RegisterType((*StartBlpRequest)(nil), "tabletmanagerdata.StartBlpRequest") - proto.RegisterType((*StartBlpResponse)(nil), "tabletmanagerdata.StartBlpResponse") - proto.RegisterType((*RunBlpUntilRequest)(nil), "tabletmanagerdata.RunBlpUntilRequest") - proto.RegisterType((*RunBlpUntilResponse)(nil), "tabletmanagerdata.RunBlpUntilResponse") proto.RegisterType((*ResetReplicationRequest)(nil), "tabletmanagerdata.ResetReplicationRequest") proto.RegisterType((*ResetReplicationResponse)(nil), "tabletmanagerdata.ResetReplicationResponse") + proto.RegisterType((*VReplicationExecRequest)(nil), "tabletmanagerdata.VReplicationExecRequest") + proto.RegisterType((*VReplicationExecResponse)(nil), "tabletmanagerdata.VReplicationExecResponse") + proto.RegisterType((*VReplicationWaitForPosRequest)(nil), "tabletmanagerdata.VReplicationWaitForPosRequest") + proto.RegisterType((*VReplicationWaitForPosResponse)(nil), "tabletmanagerdata.VReplicationWaitForPosResponse") proto.RegisterType((*InitMasterRequest)(nil), "tabletmanagerdata.InitMasterRequest") proto.RegisterType((*InitMasterResponse)(nil), "tabletmanagerdata.InitMasterResponse") proto.RegisterType((*PopulateReparentJournalRequest)(nil), "tabletmanagerdata.PopulateReparentJournalRequest") @@ -3653,139 +3465,134 @@ func init() { } func init() { - proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_87488b4d5ae092d8) -} - -var fileDescriptor_tabletmanagerdata_87488b4d5ae092d8 = []byte{ - // 2074 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x5b, 0x6f, 0x1b, 0xc7, - 0xf5, 0xc7, 0x8a, 0x92, 0x2c, 0x9d, 0x25, 0x29, 0x72, 0xa9, 0x0b, 0xa5, 0xe0, 0xaf, 0xcb, 0xda, - 0xf9, 0x47, 0x75, 0x51, 0x2a, 0x56, 0xd2, 0x20, 0x48, 0x90, 0xa2, 0xba, 0xda, 0x4e, 0x9c, 0x58, - 0x59, 0xf9, 0x52, 0xe4, 0x65, 0x31, 0xe4, 0x8e, 0xc8, 0x85, 0x96, 0xbb, 0xeb, 0x99, 0x59, 0x4a, - 0x04, 0x8a, 0x7e, 0x84, 0xbe, 0xf5, 0xad, 0x6f, 0x05, 0xda, 0xf7, 0x7e, 0x98, 0x14, 0xfd, 0x24, - 0x7d, 0xe8, 0x4b, 0x31, 0x37, 0x72, 0x96, 0x17, 0x9b, 0x32, 0x5c, 0xa0, 0x2f, 0xc2, 0xce, 0xef, - 0xdc, 0xcf, 0x9c, 0x39, 0xe7, 0x10, 0x82, 0x0d, 0x86, 0x9a, 0x11, 0x66, 0x5d, 0x14, 0xa3, 0x36, - 0x26, 0x01, 0x62, 0xa8, 0x91, 0x92, 0x84, 0x25, 0x4e, 0x75, 0x8c, 0xb0, 0x65, 0xbf, 0xc9, 0x30, - 0xe9, 0x4b, 0xfa, 0x56, 0x99, 0x25, 0x69, 0x32, 0xe4, 0xdf, 0x5a, 0x23, 0x38, 0x8d, 0xc2, 0x16, - 0x62, 0x61, 0x12, 0x1b, 0x70, 0x29, 0x4a, 0xda, 0x19, 0x0b, 0x23, 0x79, 0x74, 0xff, 0x69, 0xc1, - 0xca, 0x0b, 0xae, 0xf8, 0x14, 0x5f, 0x85, 0x71, 0xc8, 0x99, 0x1d, 0x07, 0xe6, 0x63, 0xd4, 0xc5, - 0x75, 0x6b, 0xd7, 0xda, 0x5f, 0xf6, 0xc4, 0xb7, 0xb3, 0x0e, 0x8b, 0xb4, 0xd5, 0xc1, 0x5d, 0x54, - 0x9f, 0x13, 0xa8, 0x3a, 0x39, 0x75, 0xb8, 0xd7, 0x4a, 0xa2, 0xac, 0x1b, 0xd3, 0x7a, 0x61, 0xb7, - 0xb0, 0xbf, 0xec, 0xe9, 0xa3, 0xd3, 0x80, 0x5a, 0x4a, 0xc2, 0x2e, 0x22, 0x7d, 0xff, 0x1a, 0xf7, - 0x7d, 0xcd, 0x35, 0x2f, 0xb8, 0xaa, 0x8a, 0xf4, 0x1d, 0xee, 0x9f, 0x28, 0x7e, 0x07, 0xe6, 0x59, - 0x3f, 0xc5, 0xf5, 0x05, 0x69, 0x95, 0x7f, 0x3b, 0x3b, 0x60, 0x73, 0xd7, 0xfd, 0x08, 0xc7, 0x6d, - 0xd6, 0xa9, 0x2f, 0xee, 0x5a, 0xfb, 0xf3, 0x1e, 0x70, 0xe8, 0x99, 0x40, 0x9c, 0x8f, 0x60, 0x99, - 0x24, 0x37, 0x7e, 0x2b, 0xc9, 0x62, 0x56, 0xbf, 0x27, 0xc8, 0x4b, 0x24, 0xb9, 0x39, 0xe1, 0x67, - 0xf7, 0xaf, 0x16, 0x54, 0x2e, 0x85, 0x9b, 0x46, 0x70, 0x9f, 0xc0, 0x0a, 0x97, 0x6f, 0x22, 0x8a, - 0x7d, 0x15, 0x91, 0x8c, 0xb3, 0xac, 0x61, 0x29, 0xe2, 0x3c, 0x07, 0x99, 0x71, 0x3f, 0x18, 0x08, - 0xd3, 0xfa, 0xdc, 0x6e, 0x61, 0xdf, 0x3e, 0x74, 0x1b, 0xe3, 0x97, 0x34, 0x92, 0x44, 0xaf, 0xc2, - 0xf2, 0x00, 0xe5, 0xa9, 0xea, 0x61, 0x42, 0xc3, 0x24, 0xae, 0x17, 0x84, 0x45, 0x7d, 0xe4, 0x8e, - 0x3a, 0xd2, 0xea, 0x49, 0x07, 0xc5, 0x6d, 0xec, 0x61, 0x9a, 0x45, 0xcc, 0x79, 0x02, 0xa5, 0x26, - 0xbe, 0x4a, 0x48, 0xce, 0x51, 0xfb, 0xf0, 0xfe, 0x04, 0xeb, 0xa3, 0x61, 0x7a, 0x45, 0x29, 0xa9, - 0x62, 0x39, 0x87, 0x22, 0xba, 0x62, 0x98, 0xf8, 0xc6, 0x1d, 0xce, 0xa8, 0xc8, 0x16, 0x82, 0x12, - 0x76, 0xff, 0x65, 0x41, 0xf9, 0x25, 0xc5, 0xe4, 0x02, 0x93, 0x6e, 0x48, 0xa9, 0x2a, 0x96, 0x4e, - 0x42, 0x99, 0x2e, 0x16, 0xfe, 0xcd, 0xb1, 0x8c, 0x62, 0xa2, 0x4a, 0x45, 0x7c, 0x3b, 0xbf, 0x84, - 0x6a, 0x8a, 0x28, 0xbd, 0x49, 0x48, 0xe0, 0xb7, 0x3a, 0xb8, 0x75, 0x4d, 0xb3, 0xae, 0xc8, 0xc3, - 0xbc, 0x57, 0xd1, 0x84, 0x13, 0x85, 0x3b, 0x3f, 0x02, 0xa4, 0x24, 0xec, 0x85, 0x11, 0x6e, 0x63, - 0x59, 0x32, 0xf6, 0xe1, 0xa3, 0x09, 0xde, 0xe6, 0x7d, 0x69, 0x5c, 0x0c, 0x64, 0xce, 0x62, 0x46, - 0xfa, 0x9e, 0xa1, 0x64, 0xeb, 0x1b, 0x58, 0x19, 0x21, 0x3b, 0x15, 0x28, 0x5c, 0xe3, 0xbe, 0xf2, - 0x9c, 0x7f, 0x3a, 0xab, 0xb0, 0xd0, 0x43, 0x51, 0x86, 0x95, 0xe7, 0xf2, 0xf0, 0xd5, 0xdc, 0x97, - 0x96, 0xfb, 0xb3, 0x05, 0xc5, 0xd3, 0xe6, 0x3b, 0xe2, 0x2e, 0xc3, 0x5c, 0xd0, 0x54, 0xb2, 0x73, - 0x41, 0x73, 0x90, 0x87, 0x82, 0x91, 0x87, 0xe7, 0x13, 0x42, 0x3b, 0x98, 0x10, 0x9a, 0x69, 0xec, - 0xbf, 0x19, 0xd8, 0x5f, 0x2c, 0xb0, 0x87, 0x96, 0xa8, 0xf3, 0x0c, 0x2a, 0xdc, 0x4f, 0x3f, 0x1d, - 0x62, 0x75, 0x4b, 0x78, 0xb9, 0xf7, 0xce, 0x0b, 0xf0, 0x56, 0xb2, 0xdc, 0x99, 0x3a, 0xe7, 0x50, - 0x0e, 0x9a, 0x39, 0x5d, 0xf2, 0x05, 0xed, 0xbc, 0x23, 0x62, 0xaf, 0x14, 0x18, 0x27, 0xea, 0x7e, - 0x0d, 0xf6, 0x71, 0x94, 0x5e, 0x24, 0x54, 0x3e, 0xe2, 0x0a, 0x14, 0xb2, 0x30, 0x10, 0x01, 0x96, - 0x3c, 0xfe, 0xe9, 0x6c, 0xc1, 0x52, 0xaa, 0xa8, 0x2a, 0xc6, 0xc1, 0xd9, 0xfd, 0x04, 0xec, 0x8b, - 0x30, 0x6e, 0x7b, 0xf8, 0x4d, 0x86, 0x29, 0xe3, 0xef, 0x30, 0x45, 0xfd, 0x28, 0x41, 0x81, 0xca, - 0x90, 0x3e, 0xba, 0xfb, 0x50, 0x94, 0x8c, 0x34, 0x4d, 0x62, 0x8a, 0xdf, 0xc2, 0xf9, 0x10, 0x8a, - 0x97, 0x11, 0xc6, 0xa9, 0xd6, 0xb9, 0x05, 0x4b, 0x41, 0x46, 0x44, 0xaf, 0x15, 0xac, 0x05, 0x6f, - 0x70, 0x76, 0x57, 0xa0, 0xa4, 0x78, 0xa5, 0x5a, 0xf7, 0x1f, 0x16, 0x38, 0x67, 0xb7, 0xb8, 0x95, - 0x31, 0xfc, 0x24, 0x49, 0xae, 0xb5, 0x8e, 0x49, 0x6d, 0x77, 0x1b, 0x20, 0x45, 0x04, 0x75, 0x31, - 0xc3, 0x44, 0xe6, 0x6e, 0xd9, 0x33, 0x10, 0xe7, 0x02, 0x96, 0xf1, 0x2d, 0x23, 0xc8, 0xc7, 0x71, - 0x4f, 0x34, 0x60, 0xfb, 0xf0, 0xb3, 0x09, 0xa9, 0x1d, 0xb7, 0xd6, 0x38, 0xe3, 0x62, 0x67, 0x71, - 0x4f, 0x16, 0xd4, 0x12, 0x56, 0xc7, 0xad, 0xaf, 0xa1, 0x94, 0x23, 0xdd, 0xa9, 0x98, 0xae, 0xa0, - 0x96, 0x33, 0xa5, 0xf2, 0xb8, 0x03, 0x36, 0xbe, 0x0d, 0x99, 0x4f, 0x19, 0x62, 0x19, 0x55, 0x09, - 0x02, 0x0e, 0x5d, 0x0a, 0x44, 0x4c, 0x17, 0x16, 0x24, 0x19, 0x1b, 0x4c, 0x17, 0x71, 0x52, 0x38, - 0x26, 0xfa, 0x09, 0xa9, 0x93, 0xdb, 0x83, 0xca, 0x63, 0xcc, 0x64, 0x53, 0xd2, 0xe9, 0x5b, 0x87, - 0x45, 0x11, 0xb8, 0x2c, 0xd7, 0x65, 0x4f, 0x9d, 0x9c, 0xfb, 0x50, 0x0a, 0xe3, 0x56, 0x94, 0x05, - 0xd8, 0xef, 0x85, 0xf8, 0x86, 0x0a, 0x13, 0x4b, 0x5e, 0x51, 0x81, 0xaf, 0x38, 0xe6, 0x7c, 0x0c, - 0x65, 0x7c, 0x2b, 0x99, 0x94, 0x12, 0x39, 0xcd, 0x4a, 0x0a, 0x15, 0xdd, 0x9d, 0xba, 0x18, 0xaa, - 0x86, 0x5d, 0x15, 0xdd, 0x05, 0x54, 0x65, 0x5b, 0x35, 0x26, 0xc5, 0x5d, 0x5a, 0x75, 0x85, 0x8e, - 0x20, 0xee, 0x06, 0xac, 0x3d, 0xc6, 0xcc, 0xa8, 0x7f, 0x15, 0xa3, 0xfb, 0x13, 0xac, 0x8f, 0x12, - 0x94, 0x13, 0xbf, 0x05, 0x3b, 0xff, 0x62, 0xb9, 0xf9, 0xed, 0x09, 0xe6, 0x4d, 0x61, 0x53, 0xc4, - 0x5d, 0x05, 0xe7, 0x12, 0x33, 0x0f, 0xa3, 0xe0, 0x79, 0x1c, 0xf5, 0xb5, 0xc5, 0x35, 0xa8, 0xe5, - 0x50, 0x55, 0xc2, 0x43, 0xf8, 0x35, 0x09, 0x19, 0xd6, 0xdc, 0xeb, 0xb0, 0x9a, 0x87, 0x15, 0xfb, - 0xb7, 0x50, 0x95, 0x93, 0xed, 0x45, 0x3f, 0xd5, 0xcc, 0xce, 0xaf, 0xc1, 0x96, 0xee, 0xf9, 0x62, - 0xee, 0x73, 0x97, 0xcb, 0x87, 0xab, 0x8d, 0xc1, 0x1a, 0x23, 0x72, 0xce, 0x84, 0x04, 0xb0, 0xc1, - 0x37, 0xf7, 0xd3, 0xd4, 0x35, 0x74, 0xc8, 0xc3, 0x57, 0x04, 0xd3, 0x0e, 0x2f, 0x29, 0xd3, 0xa1, - 0x3c, 0xac, 0xd8, 0x37, 0x60, 0xcd, 0xcb, 0xe2, 0x27, 0x18, 0x45, 0xac, 0x23, 0xa6, 0x8e, 0x16, - 0xa8, 0xc3, 0xfa, 0x28, 0x41, 0x89, 0x7c, 0x0e, 0xf5, 0xa7, 0xed, 0x38, 0x21, 0x58, 0x12, 0xcf, - 0x08, 0x49, 0x48, 0xae, 0xa5, 0x30, 0x86, 0x49, 0x3c, 0x6c, 0x14, 0xe2, 0xe8, 0x7e, 0x04, 0x9b, - 0x13, 0xa4, 0x94, 0xca, 0xaf, 0xb8, 0xd3, 0xbc, 0x9f, 0xe4, 0x2b, 0xf9, 0x3e, 0x94, 0x6e, 0x50, - 0xc8, 0xfc, 0x41, 0x43, 0x93, 0x3a, 0x8b, 0x1c, 0xd4, 0x2d, 0x50, 0x46, 0x66, 0xca, 0x2a, 0x9d, - 0x87, 0xb0, 0x7e, 0x41, 0xf0, 0x55, 0x14, 0xb6, 0x3b, 0x23, 0x0f, 0x84, 0xaf, 0x6a, 0x22, 0x71, - 0xfa, 0x85, 0xe8, 0xa3, 0xdb, 0x86, 0x8d, 0x31, 0x19, 0x55, 0x57, 0xcf, 0xa0, 0x2c, 0xb9, 0x7c, - 0x22, 0x96, 0x12, 0x3d, 0x0c, 0x3e, 0x9e, 0x5a, 0xd9, 0xe6, 0x0a, 0xe3, 0x95, 0x5a, 0xc6, 0x89, - 0xba, 0xff, 0xb6, 0xc0, 0x39, 0x4a, 0xd3, 0xa8, 0x9f, 0xf7, 0xac, 0x02, 0x05, 0xfa, 0x26, 0xd2, - 0x2d, 0x86, 0xbe, 0x89, 0x78, 0x8b, 0xb9, 0x4a, 0x48, 0x0b, 0xab, 0xc7, 0x2a, 0x0f, 0x7c, 0x87, - 0x40, 0x51, 0x94, 0xdc, 0xf8, 0xc6, 0x6a, 0x2b, 0x3a, 0xc3, 0x92, 0x57, 0x11, 0x04, 0x6f, 0x88, - 0x8f, 0x6f, 0x4f, 0xf3, 0x1f, 0x6a, 0x7b, 0x5a, 0x78, 0xcf, 0xed, 0xe9, 0x6f, 0x16, 0xd4, 0x72, - 0xd1, 0xab, 0x1c, 0xff, 0xef, 0xed, 0x79, 0x7f, 0xb7, 0xa0, 0xae, 0x1a, 0xf9, 0x39, 0x66, 0xad, - 0xce, 0x11, 0x3d, 0x6d, 0x0e, 0x6e, 0x6b, 0x15, 0x16, 0xc4, 0xef, 0x0e, 0xe1, 0x66, 0xd1, 0x93, - 0x07, 0x67, 0x03, 0xee, 0x05, 0x4d, 0x5f, 0x0c, 0x30, 0xd5, 0xc3, 0x83, 0xe6, 0x0f, 0x7c, 0x84, - 0x6d, 0xc2, 0x52, 0x17, 0xdd, 0xfa, 0x24, 0xb9, 0xa1, 0x6a, 0xdf, 0xbb, 0xd7, 0x45, 0xb7, 0x5e, - 0x72, 0x43, 0xc5, 0x2e, 0x1e, 0x52, 0xb1, 0x64, 0x37, 0xc3, 0x38, 0x4a, 0xda, 0x54, 0x5c, 0xd2, - 0x92, 0x57, 0x56, 0xf0, 0xb1, 0x44, 0xf9, 0x8b, 0x20, 0xa2, 0xd8, 0xcd, 0x2b, 0x58, 0xf2, 0x8a, - 0xc4, 0x78, 0x01, 0xee, 0x63, 0xd8, 0x9c, 0xe0, 0xb3, 0xca, 0xf1, 0x43, 0x58, 0x94, 0x05, 0xac, - 0x92, 0xeb, 0x34, 0xe4, 0x6f, 0xa7, 0x1f, 0xf9, 0x5f, 0x55, 0xac, 0x8a, 0xc3, 0xfd, 0xa3, 0x05, - 0xff, 0x97, 0xd7, 0x74, 0x14, 0x45, 0x7c, 0xc7, 0xa2, 0x1f, 0x3e, 0x05, 0x63, 0x91, 0xcd, 0x4f, - 0x88, 0xec, 0x19, 0x6c, 0x4f, 0xf3, 0xe7, 0x3d, 0xc2, 0xfb, 0x6e, 0xf4, 0x6e, 0x8f, 0xd2, 0xf4, - 0xed, 0x81, 0x99, 0xfe, 0xcf, 0xe5, 0xfc, 0x1f, 0x4f, 0xba, 0x50, 0xf6, 0x1e, 0x5e, 0xf1, 0xf1, - 0x13, 0xa1, 0x1e, 0x96, 0x1b, 0x81, 0x6e, 0xc7, 0xe7, 0x50, 0xcb, 0xa1, 0x4a, 0xf1, 0x01, 0xdf, - 0x0b, 0x06, 0xbb, 0x84, 0x7d, 0xb8, 0xd1, 0x18, 0xfd, 0xb1, 0xab, 0x04, 0x14, 0x1b, 0xef, 0xf7, - 0xdf, 0x23, 0xca, 0x30, 0xd1, 0xfd, 0x53, 0x1b, 0xf8, 0x1c, 0xd6, 0x47, 0x09, 0xca, 0x86, 0xb9, - 0x51, 0x5a, 0x23, 0x1b, 0xa5, 0x03, 0x95, 0x4b, 0x96, 0xa4, 0xc2, 0x35, 0xad, 0xa9, 0x06, 0x55, - 0x03, 0x53, 0xdd, 0xf8, 0x77, 0xb0, 0x31, 0x00, 0xbf, 0x0f, 0xe3, 0xb0, 0x9b, 0x75, 0x8d, 0x95, - 0x71, 0x9a, 0x7e, 0x67, 0x0f, 0x44, 0xb3, 0xf7, 0x59, 0xd8, 0xc5, 0x7a, 0x2b, 0x2a, 0x78, 0x36, - 0xc7, 0x5e, 0x48, 0xc8, 0xfd, 0x02, 0xea, 0xe3, 0x9a, 0x67, 0x70, 0x5d, 0xb8, 0x89, 0x08, 0xcb, - 0xf9, 0xce, 0x93, 0x6f, 0x80, 0xca, 0xf9, 0x53, 0xd8, 0x93, 0x33, 0xf8, 0xec, 0x96, 0xcf, 0x32, - 0x14, 0xf1, 0x05, 0x20, 0x45, 0x04, 0xc7, 0x0c, 0x07, 0x3a, 0x0c, 0xb1, 0xdb, 0x49, 0xb2, 0x1f, - 0xea, 0x3d, 0x19, 0x34, 0xf4, 0x34, 0x70, 0x1f, 0x80, 0xfb, 0x36, 0x2d, 0xca, 0xd6, 0x2e, 0x6c, - 0x8f, 0x72, 0x9d, 0x45, 0xb8, 0x35, 0x34, 0xe4, 0xee, 0xc1, 0xce, 0x54, 0x0e, 0xa5, 0xc4, 0x91, - 0x6b, 0x21, 0x0f, 0x62, 0x50, 0x41, 0xbf, 0x90, 0x2b, 0x9b, 0xc2, 0x54, 0x82, 0x56, 0x61, 0x01, - 0x05, 0x01, 0xd1, 0x83, 0x50, 0x1e, 0xdc, 0x3f, 0xc0, 0xfa, 0x6b, 0x14, 0x32, 0xe3, 0x87, 0x86, - 0x0e, 0xf2, 0x08, 0x8a, 0xcd, 0x28, 0xcd, 0x0f, 0xe4, 0xc9, 0xeb, 0x95, 0x29, 0x6c, 0x37, 0x8d, - 0x9f, 0x2c, 0x33, 0x5c, 0xe9, 0x26, 0x6c, 0x8c, 0xd9, 0x57, 0x91, 0x55, 0xa0, 0xcc, 0x6f, 0xfb, - 0x38, 0xd2, 0x2f, 0xd5, 0x7d, 0x05, 0x2b, 0x03, 0x44, 0x45, 0x75, 0x02, 0x25, 0xd3, 0x4b, 0x3d, - 0xaa, 0xdf, 0xe5, 0x66, 0xd1, 0x70, 0x93, 0xba, 0x55, 0xae, 0x17, 0x11, 0x66, 0x98, 0x12, 0xd5, - 0xae, 0x21, 0xe5, 0xd0, 0xef, 0xc1, 0xf1, 0xb2, 0xf8, 0x38, 0x4a, 0x5f, 0xc6, 0x2c, 0x8c, 0x74, - 0x9e, 0x3e, 0x84, 0x07, 0xb3, 0x64, 0xea, 0x11, 0xd4, 0x72, 0xd6, 0x67, 0xa8, 0xfb, 0x4d, 0xd8, - 0xf0, 0x30, 0xe5, 0xcb, 0xe9, 0xa0, 0x51, 0xe8, 0xf8, 0xb6, 0xa0, 0x3e, 0x4e, 0x52, 0x71, 0xd6, - 0xa0, 0xfa, 0x34, 0x0e, 0x99, 0xec, 0x11, 0x5a, 0xe0, 0x53, 0x70, 0x4c, 0x70, 0x06, 0xeb, 0x3f, - 0x5b, 0xb0, 0x7d, 0x91, 0xa4, 0x59, 0x24, 0x96, 0x50, 0x59, 0xfd, 0xdf, 0x26, 0x19, 0x2f, 0x63, - 0x9d, 0xbb, 0xff, 0x87, 0x15, 0x1e, 0xb1, 0xdf, 0x22, 0x18, 0x31, 0x1c, 0xf8, 0xb1, 0xfe, 0xa1, - 0x54, 0xe2, 0xf0, 0x89, 0x44, 0x7f, 0xa0, 0xfc, 0xc1, 0xa1, 0x16, 0x57, 0x6a, 0x4e, 0x1a, 0x90, - 0x90, 0x98, 0x36, 0x5f, 0x42, 0xb1, 0x2b, 0x3c, 0xf3, 0x51, 0x14, 0x22, 0x39, 0x71, 0xec, 0xc3, - 0xb5, 0xd1, 0xc5, 0xfa, 0x88, 0x13, 0x3d, 0x5b, 0xb2, 0x8a, 0x83, 0xf3, 0x08, 0x56, 0x8d, 0x3e, - 0x3a, 0x2c, 0xf7, 0x79, 0x61, 0xa3, 0x66, 0xd0, 0x06, 0x6b, 0xe8, 0x1e, 0xec, 0x4c, 0x8d, 0x4b, - 0xa5, 0xf0, 0xcf, 0x16, 0x54, 0x78, 0xba, 0xcc, 0x8e, 0xe3, 0xfc, 0x0a, 0x16, 0x25, 0xb7, 0x7a, - 0x4b, 0x53, 0xdc, 0x53, 0x4c, 0x53, 0x3d, 0x9b, 0x9b, 0xea, 0xd9, 0xa4, 0x7c, 0x16, 0x26, 0xe4, - 0x53, 0xdf, 0x70, 0xbe, 0xf5, 0xad, 0x41, 0xed, 0x14, 0x77, 0x13, 0x86, 0xf3, 0x17, 0x7f, 0x08, - 0xab, 0x79, 0x78, 0x86, 0xab, 0xff, 0x06, 0x76, 0x2e, 0x48, 0xc2, 0x85, 0x84, 0x89, 0xd7, 0x1d, - 0x1c, 0x9f, 0xa0, 0xac, 0xdd, 0x61, 0x2f, 0xd3, 0x19, 0x46, 0x81, 0xfb, 0x1b, 0xd8, 0x9d, 0x2e, - 0x3e, 0x5b, 0xdd, 0x4b, 0x41, 0x44, 0x95, 0x9e, 0xc0, 0xa8, 0xfb, 0x71, 0x92, 0x4a, 0xc0, 0x9f, - 0x2c, 0xa8, 0x5c, 0xe2, 0x7c, 0xdd, 0xdf, 0xf5, 0xd2, 0x26, 0xdc, 0xc0, 0xdc, 0xa4, 0x8a, 0x7e, - 0x08, 0x55, 0xb1, 0xdf, 0xfb, 0x94, 0x77, 0x19, 0x9f, 0x72, 0x9f, 0xd4, 0x5a, 0xbf, 0x22, 0x08, - 0xc3, 0xd9, 0x24, 0xc6, 0x17, 0x1e, 0x79, 0x79, 0xee, 0xd3, 0x61, 0x20, 0x1e, 0x16, 0x4a, 0x86, - 0xf3, 0xe9, 0x6e, 0x3e, 0xf3, 0xdf, 0x6b, 0x13, 0x54, 0x29, 0x3b, 0x0f, 0xc0, 0xe5, 0x3d, 0xd7, - 0xe8, 0x13, 0x47, 0x71, 0xc0, 0xa7, 0x4b, 0x6e, 0x67, 0x79, 0x05, 0xf7, 0xdf, 0xca, 0xf5, 0xbe, - 0x3b, 0xcc, 0x1a, 0xd4, 0xcc, 0x4a, 0x30, 0x6a, 0x32, 0x0f, 0xcf, 0x50, 0x14, 0x8f, 0xa0, 0x74, - 0x8c, 0x5a, 0xd7, 0xd9, 0xa0, 0x02, 0x77, 0xc1, 0x6e, 0x25, 0x71, 0x2b, 0x23, 0x04, 0xc7, 0xad, - 0xbe, 0x6a, 0x3c, 0x26, 0xe4, 0x7e, 0x01, 0x65, 0x2d, 0xa2, 0x0c, 0x3c, 0x80, 0x05, 0xdc, 0x1b, - 0x26, 0xb6, 0xdc, 0xd0, 0xff, 0x59, 0x38, 0xe3, 0xa8, 0x27, 0x89, 0xaa, 0xb9, 0xb2, 0x84, 0xe0, - 0x73, 0x92, 0x74, 0x73, 0x56, 0xdd, 0x23, 0xd8, 0x9c, 0x40, 0xbb, 0x8b, 0xfa, 0xe3, 0x4f, 0x7f, - 0x6a, 0xf4, 0x42, 0x86, 0x29, 0x6d, 0x84, 0xc9, 0x81, 0xfc, 0x3a, 0x68, 0x27, 0x07, 0x3d, 0x76, - 0x20, 0xfe, 0xbf, 0x71, 0x30, 0x36, 0x78, 0x9a, 0x8b, 0x82, 0xf0, 0xd9, 0x7f, 0x02, 0x00, 0x00, - 0xff, 0xff, 0xc0, 0x7c, 0x4c, 0x9e, 0x69, 0x19, 0x00, 0x00, + proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f) +} + +var fileDescriptor_tabletmanagerdata_7a10c2dfddcc994f = []byte{ + // 1999 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x5b, 0x6f, 0x1b, 0xc7, + 0x15, 0x06, 0x49, 0x49, 0x96, 0x0e, 0x2f, 0xa2, 0x96, 0x92, 0x48, 0x29, 0x88, 0x24, 0xaf, 0x9d, + 0x46, 0x75, 0x51, 0x2a, 0x56, 0xd2, 0x20, 0x48, 0x91, 0xa2, 0xb2, 0x2e, 0xb6, 0x13, 0x27, 0x66, + 0x56, 0x8e, 0x5d, 0xe4, 0x65, 0x31, 0xe4, 0x1e, 0x91, 0x0b, 0x2d, 0x77, 0xd6, 0x33, 0xb3, 0x94, + 0xf8, 0x27, 0xfa, 0xd6, 0xb7, 0xbe, 0x15, 0x68, 0xdf, 0xfb, 0x63, 0x52, 0xf4, 0x97, 0xf4, 0xa1, + 0x2f, 0xc5, 0x5c, 0x96, 0xdc, 0xe5, 0xc5, 0x96, 0x84, 0x14, 0xc8, 0x8b, 0xc0, 0xf3, 0x9d, 0xfb, + 0x99, 0x33, 0x67, 0xce, 0x0a, 0xea, 0x82, 0xb4, 0x03, 0x14, 0x7d, 0x12, 0x92, 0x2e, 0x32, 0x8f, + 0x08, 0xd2, 0x8c, 0x18, 0x15, 0xd4, 0x5a, 0x9b, 0x62, 0x6c, 0x17, 0xdf, 0xc6, 0xc8, 0x86, 0x9a, + 0xbf, 0x5d, 0x11, 0x34, 0xa2, 0x63, 0xf9, 0xed, 0x0d, 0x86, 0x51, 0xe0, 0x77, 0x88, 0xf0, 0x69, + 0x98, 0x82, 0xcb, 0x01, 0xed, 0xc6, 0xc2, 0x0f, 0x34, 0x69, 0xff, 0x3b, 0x07, 0xab, 0xaf, 0xa4, + 0xe1, 0x13, 0xbc, 0xf0, 0x43, 0x5f, 0x0a, 0x5b, 0x16, 0x2c, 0x84, 0xa4, 0x8f, 0x8d, 0xdc, 0x5e, + 0x6e, 0x7f, 0xc5, 0x51, 0xbf, 0xad, 0x4d, 0x58, 0xe2, 0x9d, 0x1e, 0xf6, 0x49, 0x23, 0xaf, 0x50, + 0x43, 0x59, 0x0d, 0xb8, 0xd7, 0xa1, 0x41, 0xdc, 0x0f, 0x79, 0xa3, 0xb0, 0x57, 0xd8, 0x5f, 0x71, + 0x12, 0xd2, 0x6a, 0x42, 0x2d, 0x62, 0x7e, 0x9f, 0xb0, 0xa1, 0x7b, 0x89, 0x43, 0x37, 0x91, 0x5a, + 0x50, 0x52, 0x6b, 0x86, 0xf5, 0x0d, 0x0e, 0x8f, 0x8d, 0xbc, 0x05, 0x0b, 0x62, 0x18, 0x61, 0x63, + 0x51, 0x7b, 0x95, 0xbf, 0xad, 0x5d, 0x28, 0xca, 0xd0, 0xdd, 0x00, 0xc3, 0xae, 0xe8, 0x35, 0x96, + 0xf6, 0x72, 0xfb, 0x0b, 0x0e, 0x48, 0xe8, 0x85, 0x42, 0xac, 0x0f, 0x60, 0x85, 0xd1, 0x2b, 0xb7, + 0x43, 0xe3, 0x50, 0x34, 0xee, 0x29, 0xf6, 0x32, 0xa3, 0x57, 0xc7, 0x92, 0xb6, 0xff, 0x9e, 0x83, + 0xea, 0xb9, 0x0a, 0x33, 0x95, 0xdc, 0xc7, 0xb0, 0x2a, 0xf5, 0xdb, 0x84, 0xa3, 0x6b, 0x32, 0xd2, + 0x79, 0x56, 0x12, 0x58, 0xab, 0x58, 0x2f, 0x41, 0x57, 0xdc, 0xf5, 0x46, 0xca, 0xbc, 0x91, 0xdf, + 0x2b, 0xec, 0x17, 0x0f, 0xed, 0xe6, 0xf4, 0x21, 0x4d, 0x14, 0xd1, 0xa9, 0x8a, 0x2c, 0xc0, 0x65, + 0xa9, 0x06, 0xc8, 0xb8, 0x4f, 0xc3, 0x46, 0x41, 0x79, 0x4c, 0x48, 0x19, 0xa8, 0xa5, 0xbd, 0x1e, + 0xf7, 0x48, 0xd8, 0x45, 0x07, 0x79, 0x1c, 0x08, 0xeb, 0x19, 0x94, 0xdb, 0x78, 0x41, 0x59, 0x26, + 0xd0, 0xe2, 0xe1, 0x83, 0x19, 0xde, 0x27, 0xd3, 0x74, 0x4a, 0x5a, 0xd3, 0xe4, 0x72, 0x06, 0x25, + 0x72, 0x21, 0x90, 0xb9, 0xa9, 0x33, 0xbc, 0xa1, 0xa1, 0xa2, 0x52, 0xd4, 0xb0, 0xfd, 0x9f, 0x1c, + 0x54, 0x7e, 0xe0, 0xc8, 0x5a, 0xc8, 0xfa, 0x3e, 0xe7, 0xa6, 0x59, 0x7a, 0x94, 0x8b, 0xa4, 0x59, + 0xe4, 0x6f, 0x89, 0xc5, 0x1c, 0x99, 0x69, 0x15, 0xf5, 0xdb, 0xfa, 0x0d, 0xac, 0x45, 0x84, 0xf3, + 0x2b, 0xca, 0x3c, 0xb7, 0xd3, 0xc3, 0xce, 0x25, 0x8f, 0xfb, 0xaa, 0x0e, 0x0b, 0x4e, 0x35, 0x61, + 0x1c, 0x1b, 0xdc, 0xfa, 0x1e, 0x20, 0x62, 0xfe, 0xc0, 0x0f, 0xb0, 0x8b, 0xba, 0x65, 0x8a, 0x87, + 0x8f, 0x67, 0x44, 0x9b, 0x8d, 0xa5, 0xd9, 0x1a, 0xe9, 0x9c, 0x86, 0x82, 0x0d, 0x9d, 0x94, 0x91, + 0xed, 0xaf, 0x60, 0x75, 0x82, 0x6d, 0x55, 0xa1, 0x70, 0x89, 0x43, 0x13, 0xb9, 0xfc, 0x69, 0xad, + 0xc3, 0xe2, 0x80, 0x04, 0x31, 0x9a, 0xc8, 0x35, 0xf1, 0x65, 0xfe, 0x8b, 0x9c, 0xfd, 0x53, 0x0e, + 0x4a, 0x27, 0xed, 0xf7, 0xe4, 0x5d, 0x81, 0xbc, 0xd7, 0x36, 0xba, 0x79, 0xaf, 0x3d, 0xaa, 0x43, + 0x21, 0x55, 0x87, 0x97, 0x33, 0x52, 0x3b, 0x98, 0x91, 0x5a, 0xda, 0xd9, 0xff, 0x33, 0xb1, 0xbf, + 0xe5, 0xa0, 0x38, 0xf6, 0xc4, 0xad, 0x17, 0x50, 0x95, 0x71, 0xba, 0xd1, 0x18, 0x6b, 0xe4, 0x54, + 0x94, 0xf7, 0xdf, 0x7b, 0x00, 0xce, 0x6a, 0x9c, 0xa1, 0xb9, 0x75, 0x06, 0x15, 0xaf, 0x9d, 0xb1, + 0xa5, 0x6f, 0xd0, 0xee, 0x7b, 0x32, 0x76, 0xca, 0x5e, 0x8a, 0xe2, 0xf6, 0xc7, 0x50, 0x6c, 0xf9, + 0x61, 0xd7, 0xc1, 0xb7, 0x31, 0x72, 0x21, 0xaf, 0x52, 0x44, 0x86, 0x01, 0x25, 0x9e, 0x49, 0x32, + 0x21, 0xed, 0x7d, 0x28, 0x69, 0x41, 0x1e, 0xd1, 0x90, 0xe3, 0x3b, 0x24, 0x1f, 0x41, 0xe9, 0x3c, + 0x40, 0x8c, 0x12, 0x9b, 0xdb, 0xb0, 0xec, 0xc5, 0x4c, 0x8d, 0x4b, 0x25, 0x5a, 0x70, 0x46, 0xb4, + 0xbd, 0x0a, 0x65, 0x23, 0xab, 0xcd, 0xda, 0xff, 0xca, 0x81, 0x75, 0x7a, 0x8d, 0x9d, 0x58, 0xe0, + 0x33, 0x4a, 0x2f, 0x13, 0x1b, 0xb3, 0x26, 0xe7, 0x0e, 0x40, 0x44, 0x18, 0xe9, 0xa3, 0x40, 0xa6, + 0xd3, 0x5f, 0x71, 0x52, 0x88, 0xd5, 0x82, 0x15, 0xbc, 0x16, 0x8c, 0xb8, 0x18, 0x0e, 0xd4, 0x0c, + 0x2d, 0x1e, 0x7e, 0x3a, 0xa3, 0x3a, 0xd3, 0xde, 0x9a, 0xa7, 0x52, 0xed, 0x34, 0x1c, 0xe8, 0x9e, + 0x58, 0x46, 0x43, 0x6e, 0xff, 0x1e, 0xca, 0x19, 0xd6, 0xad, 0xfa, 0xe1, 0x02, 0x6a, 0x19, 0x57, + 0xa6, 0x8e, 0xbb, 0x50, 0xc4, 0x6b, 0x5f, 0xb8, 0x5c, 0x10, 0x11, 0x73, 0x53, 0x20, 0x90, 0xd0, + 0xb9, 0x42, 0xd4, 0x03, 0x21, 0x3c, 0x1a, 0x8b, 0xd1, 0x03, 0xa1, 0x28, 0x83, 0x23, 0x4b, 0x6e, + 0x81, 0xa1, 0xec, 0x01, 0x54, 0x9f, 0xa2, 0xd0, 0x73, 0x25, 0x29, 0xdf, 0x26, 0x2c, 0xa9, 0xc4, + 0x75, 0xc7, 0xad, 0x38, 0x86, 0xb2, 0x1e, 0x40, 0xd9, 0x0f, 0x3b, 0x41, 0xec, 0xa1, 0x3b, 0xf0, + 0xf1, 0x8a, 0x2b, 0x17, 0xcb, 0x4e, 0xc9, 0x80, 0xaf, 0x25, 0x66, 0x7d, 0x04, 0x15, 0xbc, 0xd6, + 0x42, 0xc6, 0x88, 0x7e, 0x90, 0xca, 0x06, 0x55, 0x03, 0x9a, 0xdb, 0x08, 0x6b, 0x29, 0xbf, 0x26, + 0xbb, 0x16, 0xac, 0xe9, 0xc9, 0x98, 0x1a, 0xf6, 0xb7, 0x99, 0xb6, 0x55, 0x3e, 0x81, 0xd8, 0x75, + 0xd8, 0x78, 0x8a, 0x22, 0xd5, 0xc2, 0x26, 0x47, 0xfb, 0x47, 0xd8, 0x9c, 0x64, 0x98, 0x20, 0xfe, + 0x08, 0xc5, 0xec, 0xa5, 0x93, 0xee, 0x77, 0x66, 0xb8, 0x4f, 0x2b, 0xa7, 0x55, 0xec, 0x75, 0xb0, + 0xce, 0x51, 0x38, 0x48, 0xbc, 0x97, 0x61, 0x30, 0x4c, 0x3c, 0x6e, 0x40, 0x2d, 0x83, 0x9a, 0x16, + 0x1e, 0xc3, 0x6f, 0x98, 0x2f, 0x30, 0x91, 0xde, 0x84, 0xf5, 0x2c, 0x6c, 0xc4, 0xbf, 0x86, 0x35, + 0xfd, 0x38, 0xbd, 0x1a, 0x46, 0x89, 0xb0, 0xf5, 0x3b, 0x28, 0xea, 0xf0, 0x5c, 0xf5, 0x74, 0xcb, + 0x90, 0x2b, 0x87, 0xeb, 0xcd, 0xd1, 0x26, 0xa2, 0x6a, 0x2e, 0x94, 0x06, 0x88, 0xd1, 0x6f, 0x19, + 0x67, 0xda, 0xd6, 0x38, 0x20, 0x07, 0x2f, 0x18, 0xf2, 0x9e, 0x6c, 0xa9, 0x74, 0x40, 0x59, 0xd8, + 0x88, 0xd7, 0x61, 0xc3, 0x89, 0xc3, 0x67, 0x48, 0x02, 0xd1, 0x53, 0x0f, 0x47, 0xa2, 0xd0, 0x80, + 0xcd, 0x49, 0x86, 0x51, 0xf9, 0x0c, 0x1a, 0xcf, 0xbb, 0x21, 0x65, 0xa8, 0x99, 0xa7, 0x8c, 0x51, + 0x96, 0x19, 0x29, 0x42, 0x20, 0x0b, 0xc7, 0x83, 0x42, 0x91, 0xf6, 0x07, 0xb0, 0x35, 0x43, 0xcb, + 0x98, 0xfc, 0x52, 0x06, 0x2d, 0xe7, 0x49, 0xb6, 0x93, 0x1f, 0x40, 0xf9, 0x8a, 0xf8, 0xc2, 0x8d, + 0x28, 0x1f, 0x37, 0xd3, 0x8a, 0x53, 0x92, 0x60, 0xcb, 0x60, 0x3a, 0xb3, 0xb4, 0xae, 0xb1, 0x79, + 0x08, 0x9b, 0x2d, 0x86, 0x17, 0x81, 0xdf, 0xed, 0x4d, 0x5c, 0x10, 0xb9, 0x6d, 0xa9, 0xc2, 0x25, + 0x37, 0x24, 0x21, 0xed, 0x2e, 0xd4, 0xa7, 0x74, 0x4c, 0x5f, 0xbd, 0x80, 0x8a, 0x96, 0x72, 0x99, + 0xda, 0x2b, 0x92, 0x79, 0xfe, 0xd1, 0xdc, 0xce, 0x4e, 0x6f, 0x21, 0x4e, 0xb9, 0x93, 0xa2, 0xb8, + 0xfd, 0xdf, 0x1c, 0x58, 0x47, 0x51, 0x14, 0x0c, 0xb3, 0x91, 0x55, 0xa1, 0xc0, 0xdf, 0x06, 0xc9, + 0x88, 0xe1, 0x6f, 0x03, 0x39, 0x62, 0x2e, 0x28, 0xeb, 0xa0, 0xb9, 0xac, 0x9a, 0x90, 0x6b, 0x00, + 0x09, 0x02, 0x7a, 0xe5, 0xa6, 0xb6, 0x53, 0x35, 0x19, 0x96, 0x9d, 0xaa, 0x62, 0x38, 0x63, 0x7c, + 0x7a, 0x01, 0x5a, 0xf8, 0xb9, 0x16, 0xa0, 0xc5, 0x3b, 0x2e, 0x40, 0xff, 0xc8, 0x41, 0x2d, 0x93, + 0xbd, 0xa9, 0xf1, 0x2f, 0x6f, 0x55, 0xfb, 0x67, 0x0e, 0x1a, 0x66, 0x90, 0x9f, 0xa1, 0xe8, 0xf4, + 0x8e, 0xf8, 0x49, 0x7b, 0x74, 0x5a, 0xeb, 0xb0, 0xa8, 0x3e, 0x1d, 0x54, 0x98, 0x25, 0x47, 0x13, + 0x56, 0x1d, 0xee, 0x79, 0x6d, 0x57, 0x3d, 0x60, 0x66, 0x86, 0x7b, 0xed, 0xef, 0xe4, 0x13, 0xb6, + 0x05, 0xcb, 0x7d, 0x72, 0xed, 0x32, 0x7a, 0xc5, 0xcd, 0xca, 0x76, 0xaf, 0x4f, 0xae, 0x1d, 0x7a, + 0xc5, 0xd5, 0x3a, 0xed, 0x73, 0xb5, 0x27, 0xb7, 0xfd, 0x30, 0xa0, 0x5d, 0xae, 0x0e, 0x69, 0xd9, + 0xa9, 0x18, 0xf8, 0x89, 0x46, 0xe5, 0x8d, 0x60, 0xaa, 0xd9, 0xd3, 0x47, 0xb0, 0xec, 0x94, 0x58, + 0xea, 0x06, 0xd8, 0x4f, 0x61, 0x6b, 0x46, 0xcc, 0xa6, 0xc6, 0x8f, 0x60, 0x49, 0x37, 0xb0, 0x29, + 0xae, 0xd5, 0xd4, 0x9f, 0x3f, 0xdf, 0xcb, 0xbf, 0xa6, 0x59, 0x8d, 0x84, 0xfd, 0xe7, 0x1c, 0x7c, + 0x98, 0xb5, 0x74, 0x14, 0x04, 0x72, 0x4d, 0xe2, 0x3f, 0x7f, 0x09, 0xa6, 0x32, 0x5b, 0x98, 0x91, + 0xd9, 0x0b, 0xd8, 0x99, 0x17, 0xcf, 0x1d, 0xd2, 0xfb, 0x66, 0xf2, 0x6c, 0x8f, 0xa2, 0xe8, 0xdd, + 0x89, 0xa5, 0xe3, 0xcf, 0x67, 0xe2, 0x9f, 0x2e, 0xba, 0x32, 0x76, 0x87, 0xa8, 0xe4, 0xf3, 0x13, + 0x90, 0x01, 0xea, 0x8d, 0x20, 0x19, 0xc7, 0x67, 0x50, 0xcb, 0xa0, 0xc6, 0xf0, 0x81, 0xdc, 0x0b, + 0x46, 0xbb, 0x44, 0xf1, 0xb0, 0xde, 0x9c, 0xfc, 0x5e, 0x35, 0x0a, 0x46, 0x4c, 0xce, 0xfb, 0x6f, + 0x09, 0x17, 0xc8, 0x92, 0xf9, 0x99, 0x38, 0xf8, 0x0c, 0x36, 0x27, 0x19, 0xc6, 0xc7, 0x36, 0x2c, + 0x4f, 0x0c, 0xe0, 0x11, 0x6d, 0x5b, 0x50, 0x3d, 0x17, 0x34, 0x52, 0xa1, 0x25, 0x96, 0x6a, 0xb0, + 0x96, 0xc2, 0xcc, 0x34, 0xfe, 0x13, 0xd4, 0x47, 0xe0, 0xb7, 0x7e, 0xe8, 0xf7, 0xe3, 0x7e, 0x6a, + 0x65, 0x9c, 0x67, 0xdf, 0xba, 0x0f, 0x6a, 0xd8, 0xbb, 0xc2, 0xef, 0x63, 0xb2, 0x15, 0x15, 0x9c, + 0xa2, 0xc4, 0x5e, 0x69, 0xc8, 0xfe, 0x1c, 0x1a, 0xd3, 0x96, 0x6f, 0x10, 0xba, 0x0a, 0x93, 0x30, + 0x91, 0x89, 0x5d, 0x16, 0x3f, 0x05, 0x9a, 0xe0, 0x4f, 0xe0, 0xbe, 0x7e, 0x83, 0x4f, 0xaf, 0xe5, + 0x5b, 0x46, 0x02, 0xb9, 0x00, 0x44, 0x84, 0x61, 0x28, 0xd0, 0x4b, 0xd2, 0x50, 0xbb, 0x9d, 0x66, + 0xbb, 0x7e, 0xb2, 0x27, 0x43, 0x02, 0x3d, 0xf7, 0xec, 0x87, 0x60, 0xbf, 0xcb, 0x8a, 0xf1, 0xb5, + 0x07, 0x3b, 0x93, 0x52, 0xa7, 0x01, 0x76, 0xc6, 0x8e, 0xec, 0xfb, 0xb0, 0x3b, 0x57, 0xc2, 0x18, + 0xb1, 0xf4, 0x5a, 0x28, 0x93, 0x18, 0x75, 0xd0, 0xaf, 0xf5, 0xca, 0x66, 0x30, 0x53, 0xa0, 0x75, + 0x58, 0x24, 0x9e, 0xc7, 0x92, 0x87, 0x50, 0x13, 0xf6, 0x16, 0xd4, 0x1d, 0xe4, 0x72, 0x7f, 0x19, + 0xf5, 0x52, 0x62, 0x65, 0x1b, 0x1a, 0xd3, 0x2c, 0xe3, 0xf5, 0x00, 0xea, 0xaf, 0x53, 0xb8, 0xbc, + 0x0e, 0x33, 0xaf, 0xd3, 0x8a, 0xb9, 0x4e, 0xf6, 0x19, 0x34, 0xa6, 0x15, 0xee, 0x74, 0x91, 0x3f, + 0x4c, 0xdb, 0x79, 0x43, 0x7c, 0x71, 0x46, 0x65, 0x23, 0x27, 0xee, 0x2b, 0x90, 0x37, 0x47, 0x52, + 0x70, 0xf2, 0xbe, 0x97, 0xe9, 0x8b, 0xfc, 0x44, 0x5f, 0xec, 0xc1, 0xce, 0x3c, 0x63, 0x26, 0xcf, + 0x1a, 0xac, 0x3d, 0x0f, 0x7d, 0xa1, 0xaf, 0x4b, 0x52, 0x98, 0x4f, 0xc0, 0x4a, 0x83, 0x37, 0x68, + 0xc0, 0x9f, 0x72, 0xb0, 0xd3, 0xa2, 0x51, 0x1c, 0xa8, 0x7d, 0x4c, 0x37, 0xc2, 0xd7, 0x34, 0x96, + 0x27, 0x9a, 0xc4, 0xfd, 0x2b, 0x58, 0x95, 0x9d, 0xef, 0x76, 0x18, 0x12, 0x81, 0x9e, 0x1b, 0x26, + 0xdf, 0x0c, 0x65, 0x09, 0x1f, 0x6b, 0xf4, 0x3b, 0x2e, 0x7b, 0x8f, 0x74, 0xa4, 0xd1, 0xf4, 0xd0, + 0x05, 0x0d, 0xa9, 0xc1, 0xfb, 0x05, 0x94, 0xfa, 0x2a, 0x32, 0x97, 0x04, 0x3e, 0xd1, 0xc3, 0xb7, + 0x78, 0xb8, 0x31, 0xb9, 0x63, 0x1e, 0x49, 0xa6, 0x53, 0xd4, 0xa2, 0x8a, 0xb0, 0x1e, 0xc3, 0x7a, + 0x6a, 0xa4, 0x8c, 0x57, 0xb1, 0x05, 0xe5, 0xa3, 0x96, 0xe2, 0x8d, 0x36, 0xb2, 0xfb, 0xb0, 0x3b, + 0x37, 0x2f, 0x53, 0xc2, 0xbf, 0xe6, 0xa0, 0x2a, 0xcb, 0x95, 0xbe, 0x7c, 0xd6, 0x6f, 0x61, 0x49, + 0x4b, 0x9b, 0x23, 0x9f, 0x13, 0x9e, 0x11, 0x9a, 0x1b, 0x59, 0x7e, 0x6e, 0x64, 0xb3, 0xea, 0x59, + 0x98, 0x51, 0xcf, 0xe4, 0x84, 0xb3, 0x53, 0x60, 0x03, 0x6a, 0x27, 0xd8, 0xa7, 0x02, 0xb3, 0x07, + 0x7f, 0x08, 0xeb, 0x59, 0xf8, 0x06, 0x47, 0xff, 0x15, 0xec, 0xb6, 0x18, 0x95, 0x4a, 0xca, 0xc5, + 0x9b, 0x1e, 0x86, 0xc7, 0x24, 0xee, 0xf6, 0xc4, 0x0f, 0xd1, 0x0d, 0xa6, 0xa2, 0xfd, 0x07, 0xd8, + 0x9b, 0xaf, 0x7e, 0x03, 0xf7, 0x5b, 0x50, 0xd7, 0x8a, 0x84, 0x1b, 0x3b, 0x5e, 0xea, 0x7e, 0x4f, + 0xb3, 0x4c, 0x01, 0xfe, 0x92, 0x83, 0xea, 0x39, 0x66, 0xfb, 0xfe, 0xb6, 0x87, 0x36, 0xe3, 0x04, + 0xf2, 0xb3, 0x3a, 0xfa, 0x11, 0xac, 0xa9, 0x55, 0x57, 0x7e, 0x2a, 0x33, 0xe1, 0x72, 0x19, 0x93, + 0xd9, 0x70, 0x57, 0x15, 0x63, 0x3c, 0xa6, 0xd5, 0x24, 0xc7, 0x89, 0x9b, 0x67, 0x3f, 0x1f, 0x27, + 0xe2, 0xa0, 0x32, 0x32, 0x1e, 0xd5, 0xb7, 0x8b, 0x59, 0x7e, 0xba, 0xcc, 0x30, 0x65, 0xfc, 0x3c, + 0x04, 0x5b, 0x3e, 0x3f, 0xa9, 0x89, 0x71, 0x14, 0x7a, 0x72, 0xd0, 0x66, 0x9e, 0xef, 0xd7, 0xf0, + 0xe0, 0x9d, 0x52, 0x77, 0x7d, 0xce, 0x37, 0xa0, 0x96, 0xee, 0x84, 0x54, 0x4f, 0x66, 0xe1, 0x1b, + 0x34, 0xc5, 0x63, 0x28, 0x3f, 0x21, 0x9d, 0xcb, 0x78, 0xd4, 0x81, 0x7b, 0x50, 0xec, 0xd0, 0xb0, + 0x13, 0x33, 0x86, 0x61, 0x67, 0x68, 0x06, 0x4f, 0x1a, 0xb2, 0x3f, 0x87, 0x4a, 0xa2, 0x62, 0x1c, + 0x3c, 0x84, 0x45, 0x1c, 0x8c, 0x0b, 0x5b, 0x69, 0x26, 0xff, 0x27, 0x3f, 0x95, 0xa8, 0xa3, 0x99, + 0xe6, 0x11, 0x11, 0x94, 0xe1, 0x19, 0xa3, 0xfd, 0x8c, 0x57, 0xfb, 0x08, 0xb6, 0x66, 0xf0, 0x6e, + 0x63, 0xfe, 0xc9, 0x27, 0x3f, 0x36, 0x07, 0xbe, 0x40, 0xce, 0x9b, 0x3e, 0x3d, 0xd0, 0xbf, 0x0e, + 0xba, 0xf4, 0x60, 0x20, 0x0e, 0xd4, 0x7f, 0xeb, 0x0f, 0xa6, 0x3e, 0x02, 0xda, 0x4b, 0x8a, 0xf1, + 0xe9, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x8b, 0x0f, 0x3a, 0x37, 0x18, 0x00, 0x00, } diff --git a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go index f26652a1f22..ab1ac62d4e7 100644 --- a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go +++ b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go @@ -97,16 +97,9 @@ type TabletManagerClient interface { TabletExternallyElected(ctx context.Context, in *tabletmanagerdata.TabletExternallyElectedRequest, opts ...grpc.CallOption) (*tabletmanagerdata.TabletExternallyElectedResponse, error) // GetSlaves asks for the list of mysql slaves GetSlaves(ctx context.Context, in *tabletmanagerdata.GetSlavesRequest, opts ...grpc.CallOption) (*tabletmanagerdata.GetSlavesResponse, error) - // WaitBlpPosition tells the remote tablet to wait until it reaches - // the specified binolg player position - WaitBlpPosition(ctx context.Context, in *tabletmanagerdata.WaitBlpPositionRequest, opts ...grpc.CallOption) (*tabletmanagerdata.WaitBlpPositionResponse, error) - // StopBlp asks the tablet to stop all its binlog players, - // and returns the current position for all of them - StopBlp(ctx context.Context, in *tabletmanagerdata.StopBlpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.StopBlpResponse, error) - // StartBlp asks the tablet to restart its binlog players - StartBlp(ctx context.Context, in *tabletmanagerdata.StartBlpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.StartBlpResponse, error) - // RunBlpUntil asks the tablet to restart its binlog players - RunBlpUntil(ctx context.Context, in *tabletmanagerdata.RunBlpUntilRequest, opts ...grpc.CallOption) (*tabletmanagerdata.RunBlpUntilResponse, error) + // VReplication API + VReplicationExec(ctx context.Context, in *tabletmanagerdata.VReplicationExecRequest, opts ...grpc.CallOption) (*tabletmanagerdata.VReplicationExecResponse, error) + VReplicationWaitForPos(ctx context.Context, in *tabletmanagerdata.VReplicationWaitForPosRequest, opts ...grpc.CallOption) (*tabletmanagerdata.VReplicationWaitForPosResponse, error) // ResetReplication makes the target not replicating ResetReplication(ctx context.Context, in *tabletmanagerdata.ResetReplicationRequest, opts ...grpc.CallOption) (*tabletmanagerdata.ResetReplicationResponse, error) // InitMaster initializes the tablet as a master @@ -370,36 +363,18 @@ func (c *tabletManagerClient) GetSlaves(ctx context.Context, in *tabletmanagerda return out, nil } -func (c *tabletManagerClient) WaitBlpPosition(ctx context.Context, in *tabletmanagerdata.WaitBlpPositionRequest, opts ...grpc.CallOption) (*tabletmanagerdata.WaitBlpPositionResponse, error) { - out := new(tabletmanagerdata.WaitBlpPositionResponse) - err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/WaitBlpPosition", in, out, c.cc, opts...) +func (c *tabletManagerClient) VReplicationExec(ctx context.Context, in *tabletmanagerdata.VReplicationExecRequest, opts ...grpc.CallOption) (*tabletmanagerdata.VReplicationExecResponse, error) { + out := new(tabletmanagerdata.VReplicationExecResponse) + err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/VReplicationExec", in, out, c.cc, opts...) if err != nil { return nil, err } return out, nil } -func (c *tabletManagerClient) StopBlp(ctx context.Context, in *tabletmanagerdata.StopBlpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.StopBlpResponse, error) { - out := new(tabletmanagerdata.StopBlpResponse) - err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/StopBlp", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *tabletManagerClient) StartBlp(ctx context.Context, in *tabletmanagerdata.StartBlpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.StartBlpResponse, error) { - out := new(tabletmanagerdata.StartBlpResponse) - err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/StartBlp", in, out, c.cc, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *tabletManagerClient) RunBlpUntil(ctx context.Context, in *tabletmanagerdata.RunBlpUntilRequest, opts ...grpc.CallOption) (*tabletmanagerdata.RunBlpUntilResponse, error) { - out := new(tabletmanagerdata.RunBlpUntilResponse) - err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/RunBlpUntil", in, out, c.cc, opts...) +func (c *tabletManagerClient) VReplicationWaitForPos(ctx context.Context, in *tabletmanagerdata.VReplicationWaitForPosRequest, opts ...grpc.CallOption) (*tabletmanagerdata.VReplicationWaitForPosResponse, error) { + out := new(tabletmanagerdata.VReplicationWaitForPosResponse) + err := grpc.Invoke(ctx, "/tabletmanagerservice.TabletManager/VReplicationWaitForPos", in, out, c.cc, opts...) if err != nil { return nil, err } @@ -634,16 +609,9 @@ type TabletManagerServer interface { TabletExternallyElected(context.Context, *tabletmanagerdata.TabletExternallyElectedRequest) (*tabletmanagerdata.TabletExternallyElectedResponse, error) // GetSlaves asks for the list of mysql slaves GetSlaves(context.Context, *tabletmanagerdata.GetSlavesRequest) (*tabletmanagerdata.GetSlavesResponse, error) - // WaitBlpPosition tells the remote tablet to wait until it reaches - // the specified binolg player position - WaitBlpPosition(context.Context, *tabletmanagerdata.WaitBlpPositionRequest) (*tabletmanagerdata.WaitBlpPositionResponse, error) - // StopBlp asks the tablet to stop all its binlog players, - // and returns the current position for all of them - StopBlp(context.Context, *tabletmanagerdata.StopBlpRequest) (*tabletmanagerdata.StopBlpResponse, error) - // StartBlp asks the tablet to restart its binlog players - StartBlp(context.Context, *tabletmanagerdata.StartBlpRequest) (*tabletmanagerdata.StartBlpResponse, error) - // RunBlpUntil asks the tablet to restart its binlog players - RunBlpUntil(context.Context, *tabletmanagerdata.RunBlpUntilRequest) (*tabletmanagerdata.RunBlpUntilResponse, error) + // VReplication API + VReplicationExec(context.Context, *tabletmanagerdata.VReplicationExecRequest) (*tabletmanagerdata.VReplicationExecResponse, error) + VReplicationWaitForPos(context.Context, *tabletmanagerdata.VReplicationWaitForPosRequest) (*tabletmanagerdata.VReplicationWaitForPosResponse, error) // ResetReplication makes the target not replicating ResetReplication(context.Context, *tabletmanagerdata.ResetReplicationRequest) (*tabletmanagerdata.ResetReplicationResponse, error) // InitMaster initializes the tablet as a master @@ -1128,74 +1096,38 @@ func _TabletManager_GetSlaves_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } -func _TabletManager_WaitBlpPosition_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(tabletmanagerdata.WaitBlpPositionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TabletManagerServer).WaitBlpPosition(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/tabletmanagerservice.TabletManager/WaitBlpPosition", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TabletManagerServer).WaitBlpPosition(ctx, req.(*tabletmanagerdata.WaitBlpPositionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TabletManager_StopBlp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(tabletmanagerdata.StopBlpRequest) +func _TabletManager_VReplicationExec_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(tabletmanagerdata.VReplicationExecRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(TabletManagerServer).StopBlp(ctx, in) + return srv.(TabletManagerServer).VReplicationExec(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/tabletmanagerservice.TabletManager/StopBlp", + FullMethod: "/tabletmanagerservice.TabletManager/VReplicationExec", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TabletManagerServer).StopBlp(ctx, req.(*tabletmanagerdata.StopBlpRequest)) + return srv.(TabletManagerServer).VReplicationExec(ctx, req.(*tabletmanagerdata.VReplicationExecRequest)) } return interceptor(ctx, in, info, handler) } -func _TabletManager_StartBlp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(tabletmanagerdata.StartBlpRequest) +func _TabletManager_VReplicationWaitForPos_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(tabletmanagerdata.VReplicationWaitForPosRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(TabletManagerServer).StartBlp(ctx, in) + return srv.(TabletManagerServer).VReplicationWaitForPos(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/tabletmanagerservice.TabletManager/StartBlp", + FullMethod: "/tabletmanagerservice.TabletManager/VReplicationWaitForPos", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TabletManagerServer).StartBlp(ctx, req.(*tabletmanagerdata.StartBlpRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _TabletManager_RunBlpUntil_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(tabletmanagerdata.RunBlpUntilRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TabletManagerServer).RunBlpUntil(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/tabletmanagerservice.TabletManager/RunBlpUntil", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TabletManagerServer).RunBlpUntil(ctx, req.(*tabletmanagerdata.RunBlpUntilRequest)) + return srv.(TabletManagerServer).VReplicationWaitForPos(ctx, req.(*tabletmanagerdata.VReplicationWaitForPosRequest)) } return interceptor(ctx, in, info, handler) } @@ -1545,20 +1477,12 @@ var _TabletManager_serviceDesc = grpc.ServiceDesc{ Handler: _TabletManager_GetSlaves_Handler, }, { - MethodName: "WaitBlpPosition", - Handler: _TabletManager_WaitBlpPosition_Handler, - }, - { - MethodName: "StopBlp", - Handler: _TabletManager_StopBlp_Handler, - }, - { - MethodName: "StartBlp", - Handler: _TabletManager_StartBlp_Handler, + MethodName: "VReplicationExec", + Handler: _TabletManager_VReplicationExec_Handler, }, { - MethodName: "RunBlpUntil", - Handler: _TabletManager_RunBlpUntil_Handler, + MethodName: "VReplicationWaitForPos", + Handler: _TabletManager_VReplicationWaitForPos_Handler, }, { MethodName: "ResetReplication", @@ -1621,72 +1545,69 @@ var _TabletManager_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("tabletmanagerservice.proto", fileDescriptor_tabletmanagerservice_699086f6f76bf731) -} - -var fileDescriptor_tabletmanagerservice_699086f6f76bf731 = []byte{ - // 996 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x6d, 0x6f, 0x5b, 0x35, - 0x14, 0xc7, 0x89, 0x04, 0x03, 0xcc, 0xe3, 0x2c, 0xc4, 0x50, 0x91, 0x80, 0xb5, 0x1b, 0x0f, 0x1d, - 0x6a, 0xd6, 0x95, 0xf1, 0x3e, 0xe9, 0xba, 0xad, 0x88, 0x8a, 0x90, 0xac, 0x2a, 0x02, 0x09, 0xc9, - 0x4d, 0xce, 0x72, 0x2f, 0x75, 0x6c, 0x63, 0xfb, 0x46, 0xed, 0x2b, 0x24, 0x24, 0x5e, 0x21, 0xf1, - 0x09, 0xf8, 0xb0, 0xd3, 0x7d, 0xb0, 0x63, 0x27, 0xe7, 0x3a, 0xc9, 0xbb, 0xaa, 0xff, 0xdf, 0x39, - 0xc7, 0xf7, 0xf8, 0x9c, 0xe3, 0xd3, 0x92, 0x1d, 0xcb, 0x2e, 0x39, 0xd8, 0x19, 0x13, 0x6c, 0x0a, - 0xda, 0x80, 0x9e, 0xe7, 0x63, 0x38, 0x50, 0x5a, 0x5a, 0x49, 0x3f, 0xc2, 0xb4, 0x9d, 0x3b, 0xd1, - 0x6f, 0x27, 0xcc, 0xb2, 0x1a, 0x7f, 0xf4, 0xff, 0x2e, 0x79, 0xef, 0x45, 0xa5, 0x9d, 0xd5, 0x1a, - 0x3d, 0x25, 0xaf, 0x0f, 0x72, 0x31, 0xa5, 0x9f, 0x1d, 0xac, 0xda, 0x94, 0xc2, 0x10, 0xfe, 0x2c, - 0xc0, 0xd8, 0x9d, 0xcf, 0x5b, 0x75, 0xa3, 0xa4, 0x30, 0xb0, 0xfb, 0x1a, 0xfd, 0x91, 0xbc, 0x31, - 0xe2, 0x00, 0x8a, 0x62, 0x6c, 0xa5, 0x38, 0x67, 0x5f, 0xb4, 0x03, 0xde, 0xdb, 0xef, 0xe4, 0x9d, - 0x93, 0x6b, 0x18, 0x17, 0x16, 0x9e, 0x4b, 0x79, 0x45, 0xef, 0x23, 0x26, 0x81, 0xee, 0x3c, 0x7f, - 0xb9, 0x0e, 0xf3, 0xfe, 0x7f, 0x21, 0x6f, 0x3f, 0x03, 0x3b, 0x1a, 0x67, 0x30, 0x63, 0x74, 0x0f, - 0x31, 0xf3, 0xaa, 0xf3, 0x7d, 0x2f, 0x0d, 0x79, 0xcf, 0x53, 0xf2, 0xfe, 0x33, 0xb0, 0x03, 0xd0, - 0xb3, 0xdc, 0x98, 0x5c, 0x0a, 0x43, 0xbf, 0xc6, 0x2d, 0x03, 0xc4, 0xc5, 0xf8, 0x66, 0x03, 0x32, - 0x4c, 0xd1, 0x08, 0xec, 0x10, 0xd8, 0xe4, 0x27, 0xc1, 0x6f, 0xd0, 0x14, 0x05, 0x7a, 0x2a, 0x45, - 0x11, 0xe6, 0xfd, 0x33, 0xf2, 0x6e, 0x23, 0x5c, 0xe8, 0xdc, 0x02, 0x4d, 0x58, 0x56, 0x80, 0x8b, - 0xf0, 0xd5, 0x5a, 0xce, 0x87, 0xf8, 0x8d, 0x90, 0xe3, 0x8c, 0x89, 0x29, 0xbc, 0xb8, 0x51, 0x40, - 0xb1, 0x0c, 0x2f, 0x64, 0xe7, 0xfe, 0xfe, 0x1a, 0x2a, 0x3c, 0xff, 0x10, 0x5e, 0x6a, 0x30, 0xd9, - 0xc8, 0xb2, 0x96, 0xf3, 0x87, 0x40, 0xea, 0xfc, 0x31, 0x17, 0xde, 0xf5, 0xb0, 0x10, 0xcf, 0x81, - 0x71, 0x9b, 0x1d, 0x67, 0x30, 0xbe, 0x42, 0xef, 0x3a, 0x46, 0x52, 0x77, 0xbd, 0x4c, 0xfa, 0x40, - 0x8a, 0xdc, 0x3e, 0x9d, 0x0a, 0xa9, 0xa1, 0x96, 0x4f, 0xb4, 0x96, 0x9a, 0x3e, 0x40, 0x3c, 0xac, - 0x50, 0x2e, 0xdc, 0xb7, 0x9b, 0xc1, 0x71, 0xf6, 0xb8, 0x64, 0x93, 0xa6, 0x47, 0xf0, 0xec, 0x2d, - 0x80, 0x74, 0xf6, 0x42, 0xce, 0x87, 0xf8, 0x83, 0x7c, 0x30, 0xd0, 0xf0, 0x92, 0xe7, 0xd3, 0xcc, - 0x75, 0x22, 0x96, 0x94, 0x25, 0xc6, 0x05, 0xda, 0xdf, 0x04, 0x0d, 0x9b, 0xa5, 0xa7, 0x14, 0xbf, - 0x69, 0xe2, 0x60, 0x45, 0x14, 0xe8, 0xa9, 0x66, 0x89, 0xb0, 0xf0, 0x82, 0x9a, 0x41, 0xf3, 0x14, - 0xec, 0x38, 0xeb, 0x99, 0x27, 0x97, 0x0c, 0xbd, 0xa0, 0x15, 0x2a, 0x75, 0x41, 0x08, 0xec, 0x23, - 0xfe, 0x45, 0x3e, 0x8e, 0xe5, 0x1e, 0xe7, 0x03, 0x9d, 0xcf, 0x0d, 0x7d, 0xb8, 0xd6, 0x93, 0x43, - 0x5d, 0xec, 0xc3, 0x2d, 0x2c, 0xda, 0x3f, 0xb9, 0xa7, 0xd4, 0x06, 0x9f, 0xdc, 0x53, 0x6a, 0xf3, - 0x4f, 0xae, 0xe0, 0x68, 0xe2, 0x71, 0x36, 0x87, 0xb2, 0x0d, 0x0b, 0x83, 0x4f, 0xbc, 0x85, 0x9e, - 0x9c, 0x78, 0x21, 0x16, 0xb6, 0xf3, 0x19, 0x33, 0x16, 0xf4, 0x40, 0x9a, 0xdc, 0xe6, 0x52, 0xa0, - 0xed, 0x1c, 0x23, 0xa9, 0x76, 0x5e, 0x26, 0xc3, 0xd7, 0x67, 0x64, 0xa5, 0xaa, 0x4e, 0x81, 0xbe, - 0x3e, 0x5e, 0x4d, 0xbd, 0x3e, 0x01, 0xe4, 0x3d, 0xcf, 0xc8, 0x87, 0xfe, 0xd7, 0x67, 0xb9, 0xc8, - 0x67, 0xc5, 0x8c, 0xee, 0xa7, 0x6c, 0x1b, 0xc8, 0xc5, 0x79, 0xb0, 0x11, 0x1b, 0x0e, 0xf0, 0x91, - 0x65, 0xda, 0xd6, 0x5f, 0x82, 0x1f, 0xd2, 0xc9, 0xa9, 0x01, 0x1e, 0x52, 0xde, 0xf9, 0xbf, 0x1d, - 0xb2, 0x53, 0xaf, 0x2b, 0x27, 0xd7, 0x16, 0xb4, 0x60, 0xbc, 0x7c, 0x9f, 0x14, 0xd3, 0x20, 0x2c, - 0x4c, 0xe8, 0x77, 0x88, 0x9f, 0x76, 0xdc, 0x45, 0x7f, 0xbc, 0xa5, 0x95, 0x3f, 0xcd, 0xdf, 0x1d, - 0x72, 0x67, 0x19, 0x3c, 0xe1, 0x30, 0x2e, 0x8f, 0x72, 0xb8, 0x81, 0xd3, 0x86, 0x75, 0xe7, 0x78, - 0xb4, 0x8d, 0xc9, 0xf2, 0xda, 0x52, 0x26, 0xca, 0xb4, 0xae, 0x2d, 0x95, 0xba, 0x6e, 0x6d, 0x69, - 0xa0, 0x70, 0x18, 0x5f, 0xb0, 0xdc, 0xf6, 0xb9, 0xf2, 0xc5, 0x8f, 0x95, 0xf4, 0x12, 0x93, 0x1a, - 0xc6, 0x2b, 0xa8, 0x8f, 0x35, 0x24, 0x6f, 0x96, 0x35, 0xd5, 0xe7, 0x8a, 0xde, 0x6d, 0xa9, 0xb7, - 0x3e, 0xf7, 0x53, 0x62, 0x37, 0x85, 0x78, 0x9f, 0xe7, 0xe4, 0xad, 0xaa, 0x88, 0x4a, 0xa7, 0xbb, - 0x6d, 0x15, 0x16, 0x78, 0xdd, 0x4b, 0x32, 0xe1, 0xc8, 0x19, 0x16, 0xa2, 0xcf, 0xd5, 0xb9, 0xb0, - 0x39, 0x47, 0x47, 0x4e, 0xa0, 0xa7, 0x46, 0x4e, 0x84, 0x85, 0xfd, 0x3a, 0x04, 0x53, 0x6e, 0x47, - 0x8a, 0xe7, 0x63, 0x56, 0xe5, 0x7d, 0x1f, 0x7d, 0x42, 0x63, 0x28, 0xd5, 0xaf, 0xab, 0x6c, 0xd8, - 0xaf, 0xa7, 0x22, 0xb7, 0xf5, 0x60, 0x42, 0xfb, 0x75, 0x21, 0xa7, 0xfa, 0x35, 0xa4, 0xa2, 0x0e, - 0x19, 0x48, 0x55, 0xf0, 0x6a, 0x49, 0xaa, 0x5b, 0xe8, 0x07, 0x59, 0x94, 0xb5, 0x8c, 0x76, 0x48, - 0x0b, 0x9b, 0xea, 0x90, 0x56, 0x93, 0xb0, 0x43, 0xca, 0xc3, 0xb5, 0x8f, 0x56, 0xaf, 0xa6, 0x3a, - 0x24, 0x80, 0xc2, 0x8d, 0xe8, 0x09, 0xcc, 0xa4, 0x85, 0x26, 0x7b, 0xd8, 0x25, 0x87, 0x40, 0x6a, - 0x23, 0x8a, 0x39, 0x1f, 0xe2, 0x9f, 0x0e, 0xf9, 0x64, 0xa0, 0x65, 0xa9, 0x55, 0xd1, 0x2f, 0x32, - 0x10, 0xc7, 0xac, 0x98, 0x66, 0xf6, 0x5c, 0x51, 0x34, 0x1f, 0x2d, 0xb0, 0x8b, 0x7d, 0xb4, 0x95, - 0x4d, 0xf4, 0x8a, 0x54, 0x32, 0x33, 0x0d, 0x3d, 0xc1, 0x5f, 0x91, 0x25, 0x28, 0xf9, 0x8a, 0xac, - 0xb0, 0xd1, 0x73, 0x08, 0xae, 0x28, 0xf7, 0xf0, 0x3f, 0x1f, 0xe2, 0x9c, 0xde, 0x4b, 0x43, 0xe1, - 0x8e, 0xe2, 0xe2, 0x0e, 0xc1, 0x94, 0xed, 0x0d, 0x13, 0x9a, 0x3a, 0x9d, 0xa7, 0x52, 0x3b, 0x0a, - 0x02, 0xfb, 0x88, 0xff, 0x75, 0xc8, 0xa7, 0xe5, 0x74, 0x0a, 0xfa, 0xaf, 0x27, 0x26, 0xe5, 0xc4, - 0xad, 0x97, 0x96, 0xc7, 0x2d, 0xd3, 0xac, 0x85, 0x77, 0xc7, 0xf8, 0x7e, 0x5b, 0xb3, 0xb0, 0x6c, - 0xc3, 0x1b, 0x47, 0xcb, 0x36, 0x04, 0x52, 0x65, 0x1b, 0x73, 0x3e, 0xc4, 0xcf, 0xe4, 0x56, 0x9f, - 0x8d, 0xaf, 0x0a, 0x45, 0xb1, 0x3f, 0xed, 0x6b, 0xc9, 0xb9, 0xbd, 0x9b, 0x20, 0x9c, 0xc3, 0x87, - 0x1d, 0xaa, 0xc9, 0xed, 0x32, 0xbb, 0x52, 0xc3, 0x53, 0x2d, 0x67, 0x8d, 0xf7, 0x96, 0x61, 0x17, - 0x53, 0xa9, 0x8b, 0x43, 0xe0, 0x45, 0xcc, 0xfe, 0xd1, 0xaf, 0x87, 0xf3, 0xdc, 0x82, 0x31, 0x07, - 0xb9, 0xec, 0xd6, 0x3f, 0x75, 0xa7, 0xb2, 0x3b, 0xb7, 0xdd, 0xea, 0xdf, 0x27, 0x5d, 0xec, 0x9f, - 0x2d, 0x97, 0xb7, 0x2a, 0xed, 0xe8, 0x55, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x82, 0xa2, 0xe2, - 0xa7, 0x11, 0x00, 0x00, + proto.RegisterFile("tabletmanagerservice.proto", fileDescriptor_tabletmanagerservice_a64e2f6154f58360) +} + +var fileDescriptor_tabletmanagerservice_a64e2f6154f58360 = []byte{ + // 956 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0xdf, 0x8f, 0x1b, 0x35, + 0x10, 0xc7, 0x89, 0x04, 0x95, 0x30, 0x3f, 0x6b, 0x21, 0x8a, 0x0e, 0x09, 0x28, 0x6d, 0xf9, 0xd1, + 0xa2, 0x4b, 0xaf, 0x47, 0x79, 0x4f, 0xaf, 0x77, 0xed, 0x21, 0x4e, 0x84, 0xa4, 0x70, 0x08, 0x24, + 0x24, 0x5f, 0x32, 0xcd, 0x2e, 0xb7, 0x59, 0x1b, 0xdb, 0x1b, 0xdd, 0x3d, 0x21, 0x21, 0xf1, 0x84, + 0xc4, 0x1b, 0xff, 0x2f, 0xf2, 0xee, 0xda, 0x19, 0x27, 0xb3, 0x4e, 0xf2, 0x76, 0xca, 0xf7, 0x33, + 0x33, 0xf6, 0x78, 0x66, 0xec, 0x5b, 0xb6, 0x67, 0xc5, 0x45, 0x01, 0x76, 0x2e, 0x4a, 0x31, 0x03, + 0x6d, 0x40, 0x2f, 0xf2, 0x09, 0xec, 0x2b, 0x2d, 0xad, 0xe4, 0xef, 0x51, 0xda, 0xde, 0xad, 0xe8, + 0xd7, 0xa9, 0xb0, 0xa2, 0xc1, 0x1f, 0xfd, 0x77, 0x9b, 0xbd, 0xf5, 0xa2, 0xd6, 0xce, 0x1a, 0x8d, + 0x9f, 0xb2, 0x57, 0x87, 0x79, 0x39, 0xe3, 0x1f, 0xed, 0xaf, 0xdb, 0x38, 0x61, 0x04, 0x7f, 0x54, + 0x60, 0xec, 0xde, 0xc7, 0x9d, 0xba, 0x51, 0xb2, 0x34, 0xf0, 0xe9, 0x2b, 0xfc, 0x3b, 0xf6, 0xda, + 0xb8, 0x00, 0x50, 0x9c, 0x62, 0x6b, 0xc5, 0x3b, 0xfb, 0xa4, 0x1b, 0x08, 0xde, 0x7e, 0x63, 0x6f, + 0x1c, 0x5f, 0xc1, 0xa4, 0xb2, 0xf0, 0x5c, 0xca, 0x4b, 0x7e, 0x8f, 0x30, 0x41, 0xba, 0xf7, 0xfc, + 0xd9, 0x26, 0x2c, 0xf8, 0xff, 0x99, 0xbd, 0xfe, 0x0c, 0xec, 0x78, 0x92, 0xc1, 0x5c, 0xf0, 0x3b, + 0x84, 0x59, 0x50, 0xbd, 0xef, 0xbb, 0x69, 0x28, 0x78, 0x9e, 0xb1, 0xb7, 0x9f, 0x81, 0x1d, 0x82, + 0x9e, 0xe7, 0xc6, 0xe4, 0xb2, 0x34, 0xfc, 0x0b, 0xda, 0x12, 0x21, 0x3e, 0xc6, 0x97, 0x5b, 0x90, + 0x38, 0x45, 0x63, 0xb0, 0x23, 0x10, 0xd3, 0xef, 0xcb, 0xe2, 0x9a, 0x4c, 0x11, 0xd2, 0x53, 0x29, + 0x8a, 0xb0, 0xe0, 0x5f, 0xb0, 0x37, 0x5b, 0xe1, 0x5c, 0xe7, 0x16, 0x78, 0xc2, 0xb2, 0x06, 0x7c, + 0x84, 0xcf, 0x37, 0x72, 0x21, 0xc4, 0xaf, 0x8c, 0x1d, 0x65, 0xa2, 0x9c, 0xc1, 0x8b, 0x6b, 0x05, + 0x9c, 0xca, 0xf0, 0x52, 0xf6, 0xee, 0xef, 0x6d, 0xa0, 0xf0, 0xfa, 0x47, 0xf0, 0x52, 0x83, 0xc9, + 0xc6, 0x56, 0x74, 0xac, 0x1f, 0x03, 0xa9, 0xf5, 0xc7, 0x1c, 0x3e, 0xeb, 0x51, 0x55, 0x3e, 0x07, + 0x51, 0xd8, 0xec, 0x28, 0x83, 0xc9, 0x25, 0x79, 0xd6, 0x31, 0x92, 0x3a, 0xeb, 0x55, 0x32, 0x04, + 0x52, 0xec, 0xe6, 0xe9, 0xac, 0x94, 0x1a, 0x1a, 0xf9, 0x58, 0x6b, 0xa9, 0xf9, 0x03, 0xc2, 0xc3, + 0x1a, 0xe5, 0xc3, 0x7d, 0xb5, 0x1d, 0x1c, 0x67, 0xaf, 0x90, 0x62, 0xda, 0xf6, 0x08, 0x9d, 0xbd, + 0x25, 0x90, 0xce, 0x1e, 0xe6, 0x42, 0x88, 0xdf, 0xd9, 0x3b, 0x43, 0x0d, 0x2f, 0x8b, 0x7c, 0x96, + 0xf9, 0x4e, 0xa4, 0x92, 0xb2, 0xc2, 0xf8, 0x40, 0xf7, 0xb7, 0x41, 0x71, 0xb3, 0x0c, 0x94, 0x2a, + 0xae, 0xdb, 0x38, 0x54, 0x11, 0x21, 0x3d, 0xd5, 0x2c, 0x11, 0x86, 0x0f, 0xa8, 0x1d, 0x34, 0x27, + 0x60, 0x27, 0xd9, 0xc0, 0x3c, 0xbd, 0x10, 0xe4, 0x01, 0xad, 0x51, 0xa9, 0x03, 0x22, 0xe0, 0x10, + 0xf1, 0x4f, 0xf6, 0x7e, 0x2c, 0x0f, 0x8a, 0x62, 0xa8, 0xf3, 0x85, 0xe1, 0x0f, 0x37, 0x7a, 0xf2, + 0xa8, 0x8f, 0x7d, 0xb0, 0x83, 0x45, 0xf7, 0x96, 0x07, 0x4a, 0x6d, 0xb1, 0xe5, 0x81, 0x52, 0xdb, + 0x6f, 0xb9, 0x86, 0xa3, 0x89, 0x57, 0x88, 0x05, 0xb8, 0x36, 0xac, 0x0c, 0x3d, 0xf1, 0x96, 0x7a, + 0x72, 0xe2, 0x61, 0x0c, 0xb7, 0xf3, 0x99, 0x30, 0x16, 0xf4, 0x50, 0x9a, 0xdc, 0xe6, 0xb2, 0x24, + 0xdb, 0x39, 0x46, 0x52, 0xed, 0xbc, 0x4a, 0xe2, 0xdb, 0x67, 0x6c, 0xa5, 0xaa, 0x57, 0x41, 0xde, + 0x3e, 0x41, 0x4d, 0xdd, 0x3e, 0x08, 0x0a, 0x9e, 0xe7, 0xec, 0xdd, 0xf0, 0xf3, 0x59, 0x5e, 0xe6, + 0xf3, 0x6a, 0xce, 0xef, 0xa7, 0x6c, 0x5b, 0xc8, 0xc7, 0x79, 0xb0, 0x15, 0x8b, 0x07, 0xf8, 0xd8, + 0x0a, 0x6d, 0x9b, 0x9d, 0xd0, 0x8b, 0xf4, 0x72, 0x6a, 0x80, 0x63, 0x2a, 0x38, 0xff, 0xa7, 0xc7, + 0xf6, 0x9a, 0xe7, 0xca, 0xf1, 0x95, 0x05, 0x5d, 0x8a, 0xc2, 0xdd, 0x4f, 0x4a, 0x68, 0x28, 0x2d, + 0x4c, 0xf9, 0xd7, 0x84, 0x9f, 0x6e, 0xdc, 0x47, 0x7f, 0xbc, 0xa3, 0x55, 0x58, 0xcd, 0x5f, 0x3d, + 0x76, 0x6b, 0x15, 0x3c, 0x2e, 0x60, 0xe2, 0x96, 0x72, 0xb0, 0x85, 0xd3, 0x96, 0xf5, 0xeb, 0x78, + 0xb4, 0x8b, 0xc9, 0xea, 0xb3, 0xc5, 0x25, 0xca, 0x74, 0x3e, 0x5b, 0x6a, 0x75, 0xd3, 0xb3, 0xa5, + 0x85, 0x70, 0xe1, 0xfc, 0x34, 0x02, 0x55, 0xe4, 0x13, 0xe1, 0x8a, 0xd5, 0xb5, 0x21, 0x59, 0x38, + 0xab, 0x50, 0xaa, 0x70, 0xd6, 0x59, 0x3c, 0xbd, 0xb0, 0x7a, 0x2e, 0x72, 0x7b, 0x22, 0x5d, 0xab, + 0x90, 0xd3, 0x8b, 0x46, 0x53, 0xd3, 0xab, 0xcb, 0x02, 0xef, 0x77, 0x04, 0xc6, 0x3d, 0x4b, 0x02, + 0x47, 0xee, 0x77, 0x15, 0x4a, 0xed, 0x77, 0x9d, 0xc5, 0x8d, 0x72, 0x5a, 0xe6, 0xb6, 0x99, 0x08, + 0x64, 0xa3, 0x2c, 0xe5, 0x54, 0xa3, 0x60, 0x2a, 0x2a, 0xcd, 0xa1, 0x54, 0x55, 0x51, 0xbf, 0x4e, + 0x9a, 0xda, 0xfd, 0x56, 0x56, 0xae, 0x88, 0xc8, 0xd2, 0xec, 0x60, 0x53, 0xa5, 0xd9, 0x69, 0x82, + 0x4b, 0xd3, 0x2d, 0xae, 0x7b, 0xa6, 0x05, 0x35, 0x55, 0x9a, 0x08, 0xc2, 0x4f, 0x91, 0xa7, 0x30, + 0x97, 0x16, 0xda, 0xec, 0x51, 0x03, 0x1d, 0x03, 0xa9, 0xa7, 0x48, 0xcc, 0x85, 0x10, 0x7f, 0xf7, + 0xd8, 0x07, 0x43, 0x2d, 0x9d, 0x56, 0x47, 0x3f, 0xcf, 0xa0, 0x3c, 0x12, 0xd5, 0x2c, 0xb3, 0x3f, + 0x2a, 0x4e, 0xe6, 0xa3, 0x03, 0xf6, 0xb1, 0x0f, 0x77, 0xb2, 0x89, 0xc6, 0x77, 0x2d, 0x0b, 0xd3, + 0xd2, 0x53, 0x7a, 0x7c, 0xaf, 0x40, 0xc9, 0xf1, 0xbd, 0xc6, 0x46, 0xf7, 0x10, 0xf8, 0xa2, 0xbc, + 0x43, 0xbf, 0xdb, 0xe3, 0x9c, 0xde, 0x4d, 0x43, 0xf8, 0x71, 0xe0, 0xe3, 0x8e, 0xc0, 0xb8, 0xe9, + 0x0e, 0x53, 0x9e, 0x5a, 0x5d, 0xa0, 0x52, 0x8f, 0x03, 0x02, 0x0e, 0x11, 0xff, 0xed, 0xb1, 0x0f, + 0xdd, 0x4d, 0x85, 0xfa, 0x6f, 0x50, 0x4e, 0xdd, 0xa8, 0x6b, 0x5e, 0x0b, 0x8f, 0x3b, 0x6e, 0xb6, + 0x0e, 0xde, 0x2f, 0xe3, 0x9b, 0x5d, 0xcd, 0x70, 0xd9, 0xe2, 0x13, 0x27, 0xcb, 0x16, 0x03, 0xa9, + 0xb2, 0x8d, 0xb9, 0x10, 0xe2, 0x07, 0x76, 0xe3, 0x89, 0x98, 0x5c, 0x56, 0x8a, 0x53, 0xff, 0x53, + 0x37, 0x92, 0x77, 0x7b, 0x3b, 0x41, 0x78, 0x87, 0x0f, 0x7b, 0x5c, 0xb3, 0x9b, 0x2e, 0xbb, 0x52, + 0xc3, 0x89, 0x96, 0xf3, 0xd6, 0x7b, 0xc7, 0xb0, 0x8b, 0xa9, 0xd4, 0xc1, 0x11, 0xf0, 0x32, 0xe6, + 0x93, 0xc3, 0x5f, 0x0e, 0x16, 0xb9, 0x05, 0x63, 0xf6, 0x73, 0xd9, 0x6f, 0xfe, 0xea, 0xcf, 0x64, + 0x7f, 0x61, 0xfb, 0xf5, 0x77, 0x8b, 0x3e, 0xf5, 0x95, 0xe3, 0xe2, 0x46, 0xad, 0x1d, 0xfe, 0x1f, + 0x00, 0x00, 0xff, 0xff, 0x2e, 0xeb, 0x66, 0x65, 0x20, 0x11, 0x00, 0x00, } diff --git a/go/vt/proto/vschema/vschema.pb.go b/go/vt/proto/vschema/vschema.pb.go index dbf7953a8c7..938a617d117 100644 --- a/go/vt/proto/vschema/vschema.pb.go +++ b/go/vt/proto/vschema/vschema.pb.go @@ -34,7 +34,7 @@ func (m *Keyspace) Reset() { *m = Keyspace{} } func (m *Keyspace) String() string { return proto.CompactTextString(m) } func (*Keyspace) ProtoMessage() {} func (*Keyspace) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{0} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{0} } func (m *Keyspace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Keyspace.Unmarshal(m, b) @@ -99,7 +99,7 @@ func (m *Vindex) Reset() { *m = Vindex{} } func (m *Vindex) String() string { return proto.CompactTextString(m) } func (*Vindex) ProtoMessage() {} func (*Vindex) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{1} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{1} } func (m *Vindex) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Vindex.Unmarshal(m, b) @@ -151,17 +151,22 @@ type Table struct { // to be associated with a sequence. AutoIncrement *AutoIncrement `protobuf:"bytes,3,opt,name=auto_increment,json=autoIncrement" json:"auto_increment,omitempty"` // columns lists the columns for the table. - Columns []*Column `protobuf:"bytes,4,rep,name=columns" json:"columns,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Columns []*Column `protobuf:"bytes,4,rep,name=columns" json:"columns,omitempty"` + // pinned pins an unsharded table to a specific + // shard, as dictated by the keyspace id. + // The keyspace id is represened in hex form + // like in keyranges. + Pinned string `protobuf:"bytes,5,opt,name=pinned" json:"pinned,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Table) Reset() { *m = Table{} } func (m *Table) String() string { return proto.CompactTextString(m) } func (*Table) ProtoMessage() {} func (*Table) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{2} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{2} } func (m *Table) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Table.Unmarshal(m, b) @@ -209,6 +214,13 @@ func (m *Table) GetColumns() []*Column { return nil } +func (m *Table) GetPinned() string { + if m != nil { + return m.Pinned + } + return "" +} + // ColumnVindex is used to associate a column to a vindex. type ColumnVindex struct { // Legacy implemenation, moving forward all vindexes should define a list of columns. @@ -226,7 +238,7 @@ func (m *ColumnVindex) Reset() { *m = ColumnVindex{} } func (m *ColumnVindex) String() string { return proto.CompactTextString(m) } func (*ColumnVindex) ProtoMessage() {} func (*ColumnVindex) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{3} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{3} } func (m *ColumnVindex) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ColumnVindex.Unmarshal(m, b) @@ -281,7 +293,7 @@ func (m *AutoIncrement) Reset() { *m = AutoIncrement{} } func (m *AutoIncrement) String() string { return proto.CompactTextString(m) } func (*AutoIncrement) ProtoMessage() {} func (*AutoIncrement) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{4} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{4} } func (m *AutoIncrement) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AutoIncrement.Unmarshal(m, b) @@ -328,7 +340,7 @@ func (m *Column) Reset() { *m = Column{} } func (m *Column) String() string { return proto.CompactTextString(m) } func (*Column) ProtoMessage() {} func (*Column) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{5} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{5} } func (m *Column) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Column.Unmarshal(m, b) @@ -375,7 +387,7 @@ func (m *SrvVSchema) Reset() { *m = SrvVSchema{} } func (m *SrvVSchema) String() string { return proto.CompactTextString(m) } func (*SrvVSchema) ProtoMessage() {} func (*SrvVSchema) Descriptor() ([]byte, []int) { - return fileDescriptor_vschema_af169a2691d671e0, []int{6} + return fileDescriptor_vschema_f0f3bc4bc6c5c748, []int{6} } func (m *SrvVSchema) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvVSchema.Unmarshal(m, b) @@ -416,41 +428,42 @@ func init() { proto.RegisterMapType((map[string]*Keyspace)(nil), "vschema.SrvVSchema.KeyspacesEntry") } -func init() { proto.RegisterFile("vschema.proto", fileDescriptor_vschema_af169a2691d671e0) } - -var fileDescriptor_vschema_af169a2691d671e0 = []byte{ - // 518 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0x5d, 0x8b, 0xd3, 0x40, - 0x14, 0x25, 0xed, 0x36, 0x6d, 0x6f, 0x6c, 0xaa, 0xc3, 0xba, 0x84, 0x88, 0x6c, 0x09, 0xab, 0xd6, - 0x97, 0x04, 0xba, 0x08, 0x7e, 0xb0, 0xa2, 0x16, 0x1f, 0x16, 0x05, 0x25, 0x5b, 0xf6, 0xc1, 0x97, - 0x65, 0x36, 0xbd, 0xb8, 0x65, 0x9b, 0x8f, 0xcd, 0x24, 0xd1, 0xfc, 0x1a, 0xc1, 0x7f, 0xe0, 0x8f, - 0xf0, 0x7f, 0x49, 0x66, 0x26, 0xe9, 0xa4, 0xad, 0x6f, 0x73, 0x7a, 0xee, 0x39, 0xf7, 0xcc, 0xcd, - 0x9d, 0xc2, 0xa8, 0x60, 0xc1, 0x0d, 0x86, 0xd4, 0x4d, 0xd2, 0x38, 0x8b, 0x49, 0x5f, 0x42, 0xdb, - 0xb8, 0xcb, 0x31, 0x2d, 0xc5, 0xaf, 0xce, 0x9f, 0x0e, 0x0c, 0x3e, 0x61, 0xc9, 0x12, 0x1a, 0x20, - 0xb1, 0xa0, 0xcf, 0x6e, 0x68, 0xba, 0xc4, 0xa5, 0xa5, 0x4d, 0xb4, 0xe9, 0xc0, 0xaf, 0x21, 0x79, - 0x03, 0x83, 0x62, 0x15, 0x2d, 0xf1, 0x27, 0x32, 0xab, 0x33, 0xe9, 0x4e, 0x8d, 0xd9, 0xb1, 0x5b, - 0xdb, 0xd7, 0x72, 0xf7, 0x52, 0x56, 0x7c, 0x8c, 0xb2, 0xb4, 0xf4, 0x1b, 0x01, 0x79, 0x01, 0x7a, - 0x46, 0xaf, 0xd7, 0xc8, 0xac, 0x2e, 0x97, 0x3e, 0xde, 0x95, 0x2e, 0x38, 0x2f, 0x84, 0xb2, 0xd8, - 0xfe, 0x0c, 0xa3, 0x96, 0x23, 0xb9, 0x0f, 0xdd, 0x5b, 0x2c, 0x79, 0xb4, 0xa1, 0x5f, 0x1d, 0xc9, - 0x13, 0xe8, 0x15, 0x74, 0x9d, 0xa3, 0xd5, 0x99, 0x68, 0x53, 0x63, 0x36, 0x6e, 0x8c, 0x85, 0xd0, - 0x17, 0xec, 0xeb, 0xce, 0x4b, 0xcd, 0x3e, 0x07, 0x43, 0x69, 0xb2, 0xc7, 0xeb, 0xa4, 0xed, 0x65, - 0x36, 0x5e, 0x5c, 0xa6, 0x58, 0x39, 0xbf, 0x35, 0xd0, 0x45, 0x03, 0x42, 0xe0, 0x20, 0x2b, 0x13, - 0x94, 0x3e, 0xfc, 0x4c, 0x4e, 0x41, 0x4f, 0x68, 0x4a, 0xc3, 0x7a, 0x52, 0x8f, 0xb6, 0x52, 0xb9, - 0x5f, 0x39, 0x2b, 0x2f, 0x2b, 0x4a, 0xc9, 0x21, 0xf4, 0xe2, 0x1f, 0x11, 0xa6, 0x56, 0x97, 0x3b, - 0x09, 0x60, 0xbf, 0x02, 0x43, 0x29, 0xde, 0x13, 0xfa, 0x50, 0x0d, 0x3d, 0x54, 0x43, 0xfe, 0xd5, - 0xa0, 0xc7, 0x93, 0xef, 0xcd, 0xf8, 0x16, 0xc6, 0x41, 0xbc, 0xce, 0xc3, 0xe8, 0x6a, 0xeb, 0xb3, - 0x3e, 0x6c, 0xc2, 0xce, 0x39, 0x2f, 0x07, 0x69, 0x06, 0x0a, 0x42, 0x46, 0xce, 0xc0, 0xa4, 0x79, - 0x16, 0x5f, 0xad, 0xa2, 0x20, 0xc5, 0x10, 0xa3, 0x8c, 0xe7, 0x36, 0x66, 0x47, 0x8d, 0xfc, 0x7d, - 0x9e, 0xc5, 0xe7, 0x35, 0xeb, 0x8f, 0xa8, 0x0a, 0xc9, 0x73, 0xe8, 0x0b, 0x43, 0x66, 0x1d, 0xf0, - 0xb6, 0xe3, 0xad, 0xb6, 0x7e, 0xcd, 0x3b, 0x0b, 0xb8, 0xa7, 0x26, 0x21, 0x47, 0xa0, 0x0b, 0x4a, - 0xde, 0x47, 0xa2, 0xea, 0x96, 0x11, 0x0d, 0xeb, 0x41, 0xf0, 0x73, 0xb5, 0xcf, 0x75, 0x9b, 0x6a, - 0xf3, 0x86, 0x1b, 0xd7, 0x39, 0x8c, 0x5a, 0x01, 0xff, 0x6b, 0x6b, 0xc3, 0x80, 0xe1, 0x5d, 0x8e, - 0x51, 0x50, 0x5b, 0x37, 0xd8, 0x39, 0x03, 0x7d, 0xde, 0x6e, 0xae, 0x29, 0xcd, 0x8f, 0xe5, 0xd8, - 0x2b, 0x95, 0x39, 0x33, 0x5c, 0xf1, 0xea, 0x16, 0x65, 0x82, 0xe2, 0x1b, 0x38, 0xbf, 0x34, 0x80, - 0x8b, 0xb4, 0xb8, 0xbc, 0xe0, 0x17, 0x27, 0xef, 0x60, 0x78, 0x2b, 0x9f, 0x03, 0xb3, 0x34, 0x3e, - 0x15, 0xa7, 0x99, 0xca, 0xa6, 0xae, 0x79, 0x33, 0x72, 0x81, 0x36, 0x22, 0xfb, 0x0b, 0x98, 0x6d, - 0x72, 0xcf, 0xc2, 0x3c, 0x6b, 0x6f, 0xf9, 0x83, 0x9d, 0xa7, 0xa8, 0xec, 0xd0, 0x87, 0xa7, 0xdf, - 0x4e, 0x8a, 0x55, 0x86, 0x8c, 0xb9, 0xab, 0xd8, 0x13, 0x27, 0xef, 0x7b, 0xec, 0x15, 0x99, 0xc7, - 0xff, 0x3c, 0x3c, 0xa9, 0xbd, 0xd6, 0x39, 0x3c, 0xfd, 0x17, 0x00, 0x00, 0xff, 0xff, 0x7a, 0x29, - 0xa2, 0x18, 0x72, 0x04, 0x00, 0x00, +func init() { proto.RegisterFile("vschema.proto", fileDescriptor_vschema_f0f3bc4bc6c5c748) } + +var fileDescriptor_vschema_f0f3bc4bc6c5c748 = []byte{ + // 530 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x54, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0x96, 0x93, 0xc6, 0x49, 0xc6, 0x24, 0x81, 0x55, 0xa9, 0x2c, 0x23, 0xd4, 0xc8, 0x2a, 0x10, + 0x2e, 0x8e, 0x94, 0x0a, 0x89, 0x1f, 0x15, 0x01, 0x11, 0x87, 0x0a, 0x24, 0x90, 0x1b, 0xf5, 0xc0, + 0xa5, 0xda, 0x3a, 0x23, 0x6a, 0x35, 0x5e, 0xbb, 0x5e, 0xdb, 0xe0, 0xa7, 0x41, 0xe2, 0x0d, 0x78, + 0x20, 0xde, 0x05, 0x79, 0x77, 0xed, 0xae, 0xd3, 0x70, 0xdb, 0xcf, 0x33, 0xdf, 0x37, 0xdf, 0xce, + 0xce, 0x18, 0x46, 0x05, 0x0f, 0xae, 0x30, 0xa2, 0x5e, 0x92, 0xc6, 0x59, 0x4c, 0xfa, 0x0a, 0x3a, + 0xd6, 0x4d, 0x8e, 0x69, 0x29, 0xbf, 0xba, 0x7f, 0x3a, 0x30, 0xf8, 0x84, 0x25, 0x4f, 0x68, 0x80, + 0xc4, 0x86, 0x3e, 0xbf, 0xa2, 0xe9, 0x1a, 0xd7, 0xb6, 0x31, 0x35, 0x66, 0x03, 0xbf, 0x86, 0xe4, + 0x0d, 0x0c, 0x8a, 0x90, 0xad, 0xf1, 0x27, 0x72, 0xbb, 0x33, 0xed, 0xce, 0xac, 0xc5, 0xa1, 0x57, + 0xcb, 0xd7, 0x74, 0xef, 0x5c, 0x65, 0x7c, 0x64, 0x59, 0x5a, 0xfa, 0x0d, 0x81, 0xbc, 0x00, 0x33, + 0xa3, 0x97, 0x1b, 0xe4, 0x76, 0x57, 0x50, 0x1f, 0xdf, 0xa5, 0xae, 0x44, 0x5c, 0x12, 0x55, 0xb2, + 0xf3, 0x19, 0x46, 0x2d, 0x45, 0x72, 0x1f, 0xba, 0xd7, 0x58, 0x0a, 0x6b, 0x43, 0xbf, 0x3a, 0x92, + 0x27, 0xd0, 0x2b, 0xe8, 0x26, 0x47, 0xbb, 0x33, 0x35, 0x66, 0xd6, 0x62, 0xd2, 0x08, 0x4b, 0xa2, + 0x2f, 0xa3, 0xaf, 0x3b, 0x2f, 0x0d, 0xe7, 0x14, 0x2c, 0xad, 0xc8, 0x0e, 0xad, 0xa3, 0xb6, 0xd6, + 0xb8, 0xd1, 0x12, 0x34, 0x4d, 0xca, 0xfd, 0x6d, 0x80, 0x29, 0x0b, 0x10, 0x02, 0x7b, 0x59, 0x99, + 0xa0, 0xd2, 0x11, 0x67, 0x72, 0x0c, 0x66, 0x42, 0x53, 0x1a, 0xd5, 0x9d, 0x7a, 0xb4, 0xe5, 0xca, + 0xfb, 0x2a, 0xa2, 0xea, 0xb2, 0x32, 0x95, 0xec, 0x43, 0x2f, 0xfe, 0xc1, 0x30, 0xb5, 0xbb, 0x42, + 0x49, 0x02, 0xe7, 0x15, 0x58, 0x5a, 0xf2, 0x0e, 0xd3, 0xfb, 0xba, 0xe9, 0xa1, 0x6e, 0xf2, 0xaf, + 0x01, 0x3d, 0xe1, 0x7c, 0xa7, 0xc7, 0xb7, 0x30, 0x09, 0xe2, 0x4d, 0x1e, 0xb1, 0x8b, 0xad, 0x67, + 0x7d, 0xd8, 0x98, 0x5d, 0x8a, 0xb8, 0x6a, 0xe4, 0x38, 0xd0, 0x10, 0x72, 0x72, 0x02, 0x63, 0x9a, + 0x67, 0xf1, 0x45, 0xc8, 0x82, 0x14, 0x23, 0x64, 0x99, 0xf0, 0x6d, 0x2d, 0x0e, 0x1a, 0xfa, 0xfb, + 0x3c, 0x8b, 0x4f, 0xeb, 0xa8, 0x3f, 0xa2, 0x3a, 0x24, 0xcf, 0xa1, 0x2f, 0x05, 0xb9, 0xbd, 0x27, + 0xca, 0x4e, 0xb6, 0xca, 0xfa, 0x75, 0x9c, 0x1c, 0x80, 0x99, 0x84, 0x8c, 0xe1, 0xda, 0xee, 0x09, + 0xff, 0x0a, 0xb9, 0x2b, 0xb8, 0xa7, 0x3b, 0xac, 0xf2, 0x24, 0x45, 0xdd, 0x53, 0xa1, 0xea, 0xf6, + 0x8c, 0x46, 0x75, 0x83, 0xc4, 0xb9, 0x9a, 0xf3, 0xba, 0x7c, 0x35, 0x91, 0xc3, 0xa6, 0x9a, 0xbb, + 0x84, 0x51, 0xcb, 0xf8, 0x7f, 0x65, 0x1d, 0x18, 0x70, 0xbc, 0xc9, 0x91, 0x05, 0xb5, 0x74, 0x83, + 0xdd, 0x13, 0x30, 0x97, 0xed, 0xe2, 0x86, 0x56, 0xfc, 0x50, 0x3d, 0x47, 0xc5, 0x1a, 0x2f, 0x2c, + 0x4f, 0x6e, 0xe3, 0xaa, 0x4c, 0x50, 0xbe, 0x8d, 0xfb, 0xcb, 0x00, 0x38, 0x4b, 0x8b, 0xf3, 0x33, + 0xd1, 0x10, 0xf2, 0x0e, 0x86, 0xd7, 0x6a, 0x4d, 0xb8, 0x6d, 0x88, 0x6e, 0xb9, 0x4d, 0xb7, 0x6e, + 0xf3, 0x9a, 0x5d, 0x52, 0x83, 0x75, 0x4b, 0x72, 0xbe, 0xc0, 0xb8, 0x1d, 0xdc, 0x31, 0x48, 0xcf, + 0xda, 0xd3, 0xff, 0xe0, 0xce, 0x8a, 0x6a, 0xb3, 0xf5, 0xe1, 0xe9, 0xb7, 0xa3, 0x22, 0xcc, 0x90, + 0x73, 0x2f, 0x8c, 0xe7, 0xf2, 0x34, 0xff, 0x1e, 0xcf, 0x8b, 0x6c, 0x2e, 0x7e, 0x2a, 0x73, 0xc5, + 0xbd, 0x34, 0x05, 0x3c, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0x31, 0x37, 0xa1, 0xa9, 0x8a, 0x04, + 0x00, 0x00, } diff --git a/go/vt/proto/workflow/workflow.pb.go b/go/vt/proto/workflow/workflow.pb.go index 9d1a9658165..f24d4457792 100644 --- a/go/vt/proto/workflow/workflow.pb.go +++ b/go/vt/proto/workflow/workflow.pb.go @@ -45,7 +45,7 @@ func (x WorkflowState) String() string { return proto.EnumName(WorkflowState_name, int32(x)) } func (WorkflowState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_workflow_35b1cca913e8ce26, []int{0} + return fileDescriptor_workflow_cc5eebeb403313d8, []int{0} } type TaskState int32 @@ -71,7 +71,7 @@ func (x TaskState) String() string { return proto.EnumName(TaskState_name, int32(x)) } func (TaskState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_workflow_35b1cca913e8ce26, []int{1} + return fileDescriptor_workflow_cc5eebeb403313d8, []int{1} } // Workflow is the persisted state of a long-running workflow. @@ -107,7 +107,9 @@ type Workflow struct { StartTime int64 `protobuf:"varint,7,opt,name=start_time,json=startTime" json:"start_time,omitempty"` // end_time is set when the workflow is finished. // This field only makes sense if 'state' is Done. - EndTime int64 `protobuf:"varint,8,opt,name=end_time,json=endTime" json:"end_time,omitempty"` + EndTime int64 `protobuf:"varint,8,opt,name=end_time,json=endTime" json:"end_time,omitempty"` + // create_time is set when the workflow is created. + CreateTime int64 `protobuf:"varint,9,opt,name=create_time,json=createTime" json:"create_time,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -117,7 +119,7 @@ func (m *Workflow) Reset() { *m = Workflow{} } func (m *Workflow) String() string { return proto.CompactTextString(m) } func (*Workflow) ProtoMessage() {} func (*Workflow) Descriptor() ([]byte, []int) { - return fileDescriptor_workflow_35b1cca913e8ce26, []int{0} + return fileDescriptor_workflow_cc5eebeb403313d8, []int{0} } func (m *Workflow) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Workflow.Unmarshal(m, b) @@ -193,6 +195,13 @@ func (m *Workflow) GetEndTime() int64 { return 0 } +func (m *Workflow) GetCreateTime() int64 { + if m != nil { + return m.CreateTime + } + return 0 +} + type WorkflowCheckpoint struct { // code_version is used to detect incompabilities between the version of the // running workflow and the one which wrote the checkpoint. If they don't @@ -214,7 +223,7 @@ func (m *WorkflowCheckpoint) Reset() { *m = WorkflowCheckpoint{} } func (m *WorkflowCheckpoint) String() string { return proto.CompactTextString(m) } func (*WorkflowCheckpoint) ProtoMessage() {} func (*WorkflowCheckpoint) Descriptor() ([]byte, []int) { - return fileDescriptor_workflow_35b1cca913e8ce26, []int{1} + return fileDescriptor_workflow_cc5eebeb403313d8, []int{1} } func (m *WorkflowCheckpoint) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_WorkflowCheckpoint.Unmarshal(m, b) @@ -270,7 +279,7 @@ func (m *Task) Reset() { *m = Task{} } func (m *Task) String() string { return proto.CompactTextString(m) } func (*Task) ProtoMessage() {} func (*Task) Descriptor() ([]byte, []int) { - return fileDescriptor_workflow_35b1cca913e8ce26, []int{2} + return fileDescriptor_workflow_cc5eebeb403313d8, []int{2} } func (m *Task) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Task.Unmarshal(m, b) @@ -329,40 +338,41 @@ func init() { proto.RegisterEnum("workflow.TaskState", TaskState_name, TaskState_value) } -func init() { proto.RegisterFile("workflow.proto", fileDescriptor_workflow_35b1cca913e8ce26) } - -var fileDescriptor_workflow_35b1cca913e8ce26 = []byte{ - // 501 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x6d, 0x8b, 0xd3, 0x40, - 0x10, 0x36, 0x69, 0x73, 0x4d, 0x27, 0xbd, 0x5c, 0x19, 0x0f, 0x8c, 0x05, 0xa5, 0x16, 0xe5, 0x62, - 0xc1, 0x04, 0x2a, 0x88, 0x28, 0x77, 0xe0, 0x2b, 0x7e, 0xba, 0x0f, 0xe9, 0xa1, 0xe0, 0x97, 0xb2, - 0xd7, 0xec, 0xd5, 0xa5, 0xd7, 0xdd, 0x63, 0xb3, 0xe9, 0xd1, 0x1f, 0xe8, 0x5f, 0xf0, 0x37, 0xf8, - 0x33, 0x64, 0x77, 0x9b, 0xb4, 0x51, 0x11, 0xfc, 0x36, 0x33, 0xcf, 0x3c, 0xcf, 0x64, 0xf6, 0x99, - 0x40, 0x78, 0x2b, 0xe4, 0xf2, 0xea, 0x5a, 0xdc, 0x26, 0x37, 0x52, 0x28, 0x81, 0x7e, 0x95, 0x8f, - 0x7e, 0x3a, 0xe0, 0x7f, 0xd9, 0x26, 0x88, 0xd0, 0x2e, 0x4b, 0x96, 0x47, 0xce, 0xd0, 0x89, 0xbb, - 0x99, 0x89, 0xf1, 0x11, 0xf4, 0xae, 0xc8, 0x5c, 0x09, 0xb9, 0x99, 0x71, 0xb2, 0xa2, 0x91, 0x6b, - 0xb0, 0x60, 0x5b, 0x3b, 0x27, 0x2b, 0xaa, 0x69, 0x06, 0x6a, 0x59, 0x9a, 0x8e, 0xf1, 0x19, 0x78, - 0x85, 0x22, 0x8a, 0x46, 0xed, 0xa1, 0x13, 0x87, 0x93, 0x7b, 0x49, 0xfd, 0x05, 0xd5, 0xb4, 0xa9, - 0x86, 0x33, 0xdb, 0xa5, 0x25, 0x72, 0xa2, 0x48, 0xe4, 0x0d, 0x9d, 0xb8, 0x97, 0x99, 0x18, 0x8f, - 0xc1, 0xa3, 0x52, 0x0a, 0x19, 0x1d, 0x18, 0x5d, 0x9b, 0xe0, 0x03, 0x80, 0x42, 0x11, 0xa9, 0x66, - 0x8a, 0xad, 0x68, 0xd4, 0x19, 0x3a, 0x71, 0x2b, 0xeb, 0x9a, 0xca, 0x05, 0x5b, 0x51, 0xbc, 0x0f, - 0x3e, 0xe5, 0xb9, 0x05, 0x7d, 0x03, 0x76, 0x28, 0xcf, 0x35, 0x34, 0xfa, 0xee, 0x02, 0x56, 0xc3, - 0xdf, 0x7d, 0xa3, 0xf3, 0xe5, 0x8d, 0x60, 0x5c, 0xe9, 0x05, 0xe7, 0x22, 0xa7, 0xb3, 0x35, 0x95, - 0x05, 0x13, 0xdc, 0x2c, 0xef, 0x65, 0x81, 0xae, 0x7d, 0xb6, 0x25, 0x3c, 0x05, 0x4f, 0x91, 0x62, - 0x59, 0x44, 0xee, 0xb0, 0x15, 0x07, 0x93, 0x93, 0x3f, 0x97, 0xd9, 0xe9, 0x25, 0x17, 0xba, 0xf3, - 0x03, 0x57, 0x72, 0x93, 0x59, 0x16, 0x7e, 0x04, 0xbf, 0xa0, 0x4a, 0x31, 0xbe, 0x28, 0xa2, 0x96, - 0x51, 0x18, 0xff, 0x53, 0x61, 0xba, 0x6d, 0xb6, 0x22, 0x35, 0x77, 0xf0, 0x09, 0x60, 0x27, 0x8e, - 0x7d, 0x68, 0x2d, 0xe9, 0x66, 0xeb, 0x95, 0x0e, 0xf1, 0x31, 0x78, 0x6b, 0x72, 0x5d, 0x5a, 0x8f, - 0x82, 0x49, 0xb8, 0x1b, 0xa2, 0x69, 0x99, 0x05, 0x5f, 0xb9, 0x2f, 0x9d, 0xc1, 0x6b, 0x38, 0x6c, - 0x0c, 0xf9, 0x8b, 0xd8, 0xf1, 0xbe, 0x58, 0x77, 0x8f, 0x3c, 0xfa, 0xe1, 0x40, 0x5b, 0x0b, 0x62, - 0x08, 0x6e, 0x7d, 0x2c, 0x2e, 0xcb, 0xf1, 0x69, 0xe5, 0xb9, 0x6b, 0x3c, 0xbf, 0xdb, 0x9c, 0xdf, - 0xf0, 0xfb, 0x0c, 0x80, 0x28, 0x25, 0xd9, 0x65, 0xa9, 0x68, 0xf5, 0x28, 0x0f, 0x9b, 0xfd, 0xc9, - 0x9b, 0xba, 0xc1, 0x3e, 0xc4, 0x1e, 0x63, 0x77, 0x1b, 0xed, 0xbd, 0xdb, 0x18, 0x9c, 0xc2, 0xd1, - 0x6f, 0xa4, 0xff, 0x59, 0x6c, 0xfc, 0x02, 0x0e, 0x1b, 0xc7, 0x89, 0x21, 0xc0, 0xb9, 0x50, 0x53, - 0x7d, 0x5c, 0x34, 0xef, 0xdf, 0xc1, 0x00, 0x3a, 0x59, 0xc9, 0x39, 0xe3, 0x8b, 0xbe, 0x83, 0x3e, - 0xb4, 0xdf, 0x0b, 0x4e, 0xfb, 0xee, 0xf8, 0x0c, 0xba, 0xf5, 0x82, 0x88, 0x10, 0xea, 0xa4, 0xc1, - 0x3b, 0x82, 0xc0, 0x38, 0x50, 0x73, 0x7b, 0xe0, 0xeb, 0x82, 0xe5, 0xbf, 0x3d, 0xf9, 0xfa, 0x64, - 0xcd, 0x14, 0x2d, 0x8a, 0x84, 0x89, 0xd4, 0x46, 0xe9, 0x42, 0xa4, 0x6b, 0x95, 0x9a, 0xbf, 0x35, - 0xad, 0x9e, 0xe5, 0xf2, 0xc0, 0xe4, 0xcf, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x42, 0xc0, 0xe7, - 0x77, 0xcf, 0x03, 0x00, 0x00, +func init() { proto.RegisterFile("workflow.proto", fileDescriptor_workflow_cc5eebeb403313d8) } + +var fileDescriptor_workflow_cc5eebeb403313d8 = []byte{ + // 517 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x6f, 0x8b, 0xd3, 0x4e, + 0x10, 0xfe, 0x25, 0x6d, 0xae, 0xe9, 0xa4, 0x97, 0x2b, 0xf3, 0x3b, 0x30, 0x16, 0xd4, 0x5a, 0x94, + 0xab, 0x05, 0x5b, 0xa8, 0x20, 0xa2, 0xdc, 0x81, 0x7f, 0xf1, 0xd5, 0xbd, 0x48, 0x0f, 0x05, 0xdf, + 0x94, 0xbd, 0x66, 0xaf, 0x2e, 0xbd, 0xee, 0x1e, 0x9b, 0x69, 0x8f, 0x7e, 0x04, 0x3f, 0x98, 0x5f, + 0xc1, 0xcf, 0x23, 0xbb, 0xdb, 0xa4, 0x8d, 0x8a, 0xe0, 0xbb, 0x99, 0x79, 0xe6, 0x79, 0x26, 0x3b, + 0xf3, 0x04, 0xe2, 0x5b, 0xa5, 0x17, 0x57, 0xd7, 0xea, 0x76, 0x78, 0xa3, 0x15, 0x29, 0x0c, 0x8b, + 0xbc, 0xf7, 0xcd, 0x87, 0xf0, 0xf3, 0x36, 0x41, 0x84, 0xfa, 0x6a, 0x25, 0xb2, 0xc4, 0xeb, 0x7a, + 0xfd, 0x66, 0x6a, 0x63, 0x7c, 0x08, 0xad, 0x2b, 0x36, 0x23, 0xa5, 0x37, 0x53, 0xc9, 0x96, 0x3c, + 0xf1, 0x2d, 0x16, 0x6d, 0x6b, 0xe7, 0x6c, 0xc9, 0x0d, 0xcd, 0x42, 0x35, 0x47, 0x33, 0x31, 0x3e, + 0x85, 0x20, 0x27, 0x46, 0x3c, 0xa9, 0x77, 0xbd, 0x7e, 0x3c, 0xbe, 0x33, 0x2c, 0xbf, 0xa0, 0x98, + 0x36, 0x31, 0x70, 0xea, 0xba, 0x8c, 0x44, 0xc6, 0x88, 0x25, 0x41, 0xd7, 0xeb, 0xb7, 0x52, 0x1b, + 0xe3, 0x31, 0x04, 0x5c, 0x6b, 0xa5, 0x93, 0x03, 0xab, 0xeb, 0x12, 0xbc, 0x07, 0x90, 0x13, 0xd3, + 0x34, 0x25, 0xb1, 0xe4, 0x49, 0xa3, 0xeb, 0xf5, 0x6b, 0x69, 0xd3, 0x56, 0x2e, 0xc4, 0x92, 0xe3, + 0x5d, 0x08, 0xb9, 0xcc, 0x1c, 0x18, 0x5a, 0xb0, 0xc1, 0x65, 0x66, 0xa1, 0x07, 0x10, 0xcd, 0x34, + 0x67, 0xc4, 0x1d, 0xda, 0xb4, 0x28, 0xb8, 0x92, 0x69, 0xe8, 0x7d, 0xf7, 0x01, 0x8b, 0xaf, 0x7b, + 0xfb, 0x95, 0xcf, 0x16, 0x37, 0x4a, 0x48, 0x32, 0x1b, 0x98, 0xa9, 0x8c, 0x4f, 0xd7, 0x5c, 0xe7, + 0x42, 0x49, 0xbb, 0x9d, 0x20, 0x8d, 0x4c, 0xed, 0x93, 0x2b, 0xe1, 0x29, 0x04, 0xc4, 0xf2, 0x45, + 0x9e, 0xf8, 0xdd, 0x5a, 0x3f, 0x1a, 0x9f, 0xfc, 0xfe, 0xda, 0x9d, 0xde, 0xf0, 0xc2, 0x74, 0xbe, + 0x97, 0xa4, 0x37, 0xa9, 0x63, 0xe1, 0x07, 0x08, 0x73, 0x4e, 0x24, 0xe4, 0x3c, 0x4f, 0x6a, 0x56, + 0x61, 0xf0, 0x57, 0x85, 0xc9, 0xb6, 0xd9, 0x89, 0x94, 0xdc, 0xce, 0x47, 0x80, 0x9d, 0x38, 0xb6, + 0xa1, 0xb6, 0xe0, 0x9b, 0xed, 0x31, 0x4d, 0x88, 0x8f, 0x20, 0x58, 0xb3, 0xeb, 0x95, 0x3b, 0x62, + 0x34, 0x8e, 0x77, 0x43, 0x0c, 0x2d, 0x75, 0xe0, 0x4b, 0xff, 0x85, 0xd7, 0x79, 0x05, 0x87, 0x95, + 0x21, 0x7f, 0x10, 0x3b, 0xde, 0x17, 0x6b, 0xee, 0x91, 0x7b, 0x3f, 0x3c, 0xa8, 0x1b, 0x41, 0x8c, + 0xc1, 0x2f, 0xdd, 0xe4, 0x8b, 0x0c, 0x9f, 0x14, 0xa6, 0xf0, 0xad, 0x29, 0xfe, 0xaf, 0xce, 0xaf, + 0x18, 0xe2, 0x0c, 0x80, 0x11, 0x69, 0x71, 0xb9, 0x22, 0x5e, 0x2c, 0xe5, 0x7e, 0xb5, 0x7f, 0xf8, + 0xba, 0x6c, 0x70, 0x8b, 0xd8, 0x63, 0xec, 0xcc, 0x53, 0xdf, 0x33, 0x4f, 0xe7, 0x14, 0x8e, 0x7e, + 0x21, 0xfd, 0xcb, 0xc3, 0x06, 0xcf, 0xe1, 0xb0, 0xe2, 0x5e, 0x8c, 0x01, 0xce, 0x15, 0x4d, 0x8c, + 0xfb, 0x78, 0xd6, 0xfe, 0x0f, 0x23, 0x68, 0xa4, 0x2b, 0x29, 0x85, 0x9c, 0xb7, 0x3d, 0x0c, 0xa1, + 0xfe, 0x4e, 0x49, 0xde, 0xf6, 0x07, 0x67, 0xd0, 0x2c, 0x1f, 0x88, 0x08, 0xb1, 0x49, 0x2a, 0xbc, + 0x23, 0x88, 0xec, 0x05, 0x4a, 0x6e, 0x0b, 0x42, 0x53, 0x70, 0xfc, 0x37, 0x27, 0x5f, 0x1e, 0xaf, + 0x05, 0xf1, 0x3c, 0x1f, 0x0a, 0x35, 0x72, 0xd1, 0x68, 0xae, 0x46, 0x6b, 0x1a, 0xd9, 0xdf, 0x79, + 0x54, 0xac, 0xe5, 0xf2, 0xc0, 0xe6, 0xcf, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, 0x75, 0x1d, 0xcd, + 0x85, 0xf0, 0x03, 0x00, 0x00, } diff --git a/go/vt/servenv/grpc_server.go b/go/vt/servenv/grpc_server.go index 8bfbcae0fff..e596d1702f8 100644 --- a/go/vt/servenv/grpc_server.go +++ b/go/vt/servenv/grpc_server.go @@ -83,6 +83,10 @@ var ( // The lower bound for window size is 64K and any value smaller than that will be ignored. GRPCInitialWindowSize = flag.Int("grpc_server_initial_window_size", 0, "grpc server initial window size") + // EnforcementPolicy MinTime that sets the keepalive enforcement policy on the server. + // This is the minimum amount of time a client should wait before sending a keepalive ping. + GRPCKeepAliveEnforcementPolicyMinTime = flag.Duration("grpc_server_keepalive_enforcement_policy_min_time", 5*time.Minute, "grpc server minimum keepalive time") + authPlugin Authenticator ) @@ -143,6 +147,11 @@ func createGRPCServer() { opts = append(opts, grpc.InitialWindowSize(int32(*GRPCInitialWindowSize))) } + ep := keepalive.EnforcementPolicy{ + MinTime: *GRPCKeepAliveEnforcementPolicyMinTime, + } + opts = append(opts, grpc.KeepaliveEnforcementPolicy(ep)) + if GRPCMaxConnectionAge != nil { ka := keepalive.ServerParameters{ MaxConnectionAge: *GRPCMaxConnectionAge, diff --git a/go/vt/servenv/pid_file.go b/go/vt/servenv/pid_file.go index ec06a4a0a95..09224fd63c0 100644 --- a/go/vt/servenv/pid_file.go +++ b/go/vt/servenv/pid_file.go @@ -27,17 +27,20 @@ import ( var pidFile = flag.String("pid_file", "", "If set, the process will write its pid to the named file, and delete it on graceful shutdown.") func init() { + pidFileCreated := false + // Create pid file after flags are parsed. onInit(func() { if *pidFile == "" { return } - file, err := os.Create(*pidFile) + file, err := os.OpenFile(*pidFile, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) if err != nil { log.Errorf("Unable to create pid file '%s': %v", *pidFile, err) return } + pidFileCreated = true fmt.Fprintln(file, os.Getpid()) file.Close() }) @@ -47,6 +50,9 @@ func init() { if *pidFile == "" { return } + if !pidFileCreated { + return + } if err := os.Remove(*pidFile); err != nil { log.Errorf("Unable to remove pid file '%s': %v", *pidFile, err) diff --git a/go/vt/sqlparser/analyzer.go b/go/vt/sqlparser/analyzer.go index 79b527e17f5..010d63aafda 100644 --- a/go/vt/sqlparser/analyzer.go +++ b/go/vt/sqlparser/analyzer.go @@ -275,13 +275,14 @@ func ExtractSetValues(sql string) (keyValues map[SetKey]interface{}, scope strin } result := make(map[SetKey]interface{}) for _, expr := range setStmt.Exprs { - scope := SessionStr + scope := ImplicitStr key := expr.Name.Lowered() switch { case strings.HasPrefix(key, "@@global."): scope = GlobalStr key = strings.TrimPrefix(key, "@@global.") case strings.HasPrefix(key, "@@session."): + scope = SessionStr key = strings.TrimPrefix(key, "@@session.") case strings.HasPrefix(key, "@@"): key = strings.TrimPrefix(key, "@@") diff --git a/go/vt/sqlparser/analyzer_test.go b/go/vt/sqlparser/analyzer_test.go index f25b7128de4..68e24d75ca5 100644 --- a/go/vt/sqlparser/analyzer_test.go +++ b/go/vt/sqlparser/analyzer_test.go @@ -265,6 +265,12 @@ func TestNewPlanValue(t *testing.T) { Val: []byte("strval"), }, out: sqltypes.PlanValue{Value: sqltypes.NewVarBinary("strval")}, + }, { + in: &SQLVal{ + Type: BitVal, + Val: []byte("01100001"), + }, + err: "expression is too complex", }, { in: &SQLVal{ Type: HexVal, @@ -323,14 +329,14 @@ func TestNewPlanValue(t *testing.T) { }} for _, tc := range tcases { got, err := NewPlanValue(tc.in) - if err != nil { + if tc.err != "" { if !strings.Contains(err.Error(), tc.err) { t.Errorf("NewPlanValue(%s) error: %v, want '%s'", String(tc.in), err, tc.err) } continue } - if tc.err != "" { - t.Errorf("NewPlanValue(%s) error: nil, want '%s'", String(tc.in), tc.err) + if err != nil { + t.Error(err) continue } if !reflect.DeepEqual(got, tc.out) { @@ -356,107 +362,120 @@ func TestExtractSetValues(t *testing.T) { err: "invalid syntax: 1 + 1", }, { sql: "set transaction_mode='single'", - out: map[SetKey]interface{}{{Key: "transaction_mode", Scope: "session"}: "single"}, + out: map[SetKey]interface{}{{Key: "transaction_mode", Scope: ImplicitStr}: "single"}, }, { sql: "set autocommit=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: int64(1)}, }, { sql: "set autocommit=true", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: int64(1)}, }, { sql: "set autocommit=false", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(0)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: int64(0)}, }, { sql: "set autocommit=on", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: "on"}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: "on"}, }, { sql: "set autocommit=off", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: "off"}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: "off"}, }, { sql: "set @@global.autocommit=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "global"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: GlobalStr}: int64(1)}, }, { sql: "set @@global.autocommit=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "global"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: GlobalStr}: int64(1)}, }, { sql: "set @@session.autocommit=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: SessionStr}: int64(1)}, }, { sql: "set @@session.`autocommit`=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: SessionStr}: int64(1)}, }, { sql: "set @@session.'autocommit'=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: SessionStr}: int64(1)}, }, { sql: "set @@session.\"autocommit\"=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: SessionStr}: int64(1)}, }, { sql: "set @@session.'\"autocommit'=1", - out: map[SetKey]interface{}{{Key: "\"autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "\"autocommit", Scope: SessionStr}: int64(1)}, }, { sql: "set @@session.`autocommit'`=1", - out: map[SetKey]interface{}{{Key: "autocommit'", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit'", Scope: SessionStr}: int64(1)}, }, { sql: "set AUTOCOMMIT=1", - out: map[SetKey]interface{}{{Key: "autocommit", Scope: "session"}: int64(1)}, + out: map[SetKey]interface{}{{Key: "autocommit", Scope: ImplicitStr}: int64(1)}, }, { sql: "SET character_set_results = NULL", - out: map[SetKey]interface{}{{Key: "character_set_results", Scope: "session"}: nil}, + out: map[SetKey]interface{}{{Key: "character_set_results", Scope: ImplicitStr}: nil}, }, { sql: "SET foo = 0x1234", err: "invalid value type: 0x1234", }, { sql: "SET names utf8", - out: map[SetKey]interface{}{{Key: "names", Scope: "session"}: "utf8"}, + out: map[SetKey]interface{}{{Key: "names", Scope: ImplicitStr}: "utf8"}, }, { sql: "SET names ascii collate ascii_bin", - out: map[SetKey]interface{}{{Key: "names", Scope: "session"}: "ascii"}, + out: map[SetKey]interface{}{{Key: "names", Scope: ImplicitStr}: "ascii"}, }, { sql: "SET charset default", - out: map[SetKey]interface{}{{Key: "charset", Scope: "session"}: "default"}, + out: map[SetKey]interface{}{{Key: "charset", Scope: ImplicitStr}: "default"}, }, { sql: "SET character set ascii", - out: map[SetKey]interface{}{{Key: "charset", Scope: "session"}: "ascii"}, + out: map[SetKey]interface{}{{Key: "charset", Scope: ImplicitStr}: "ascii"}, }, { sql: "SET SESSION wait_timeout = 3600", - out: map[SetKey]interface{}{{Key: "wait_timeout", Scope: "session"}: int64(3600)}, - scope: "session", + out: map[SetKey]interface{}{{Key: "wait_timeout", Scope: ImplicitStr}: int64(3600)}, + scope: SessionStr, }, { sql: "SET GLOBAL wait_timeout = 3600", - out: map[SetKey]interface{}{{Key: "wait_timeout", Scope: "session"}: int64(3600)}, - scope: "global", + out: map[SetKey]interface{}{{Key: "wait_timeout", Scope: ImplicitStr}: int64(3600)}, + scope: GlobalStr, }, { sql: "set session transaction isolation level repeatable read", - out: map[SetKey]interface{}{{Key: "tx_isolation", Scope: "session"}: "repeatable read"}, - scope: "session", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: IsolationLevelRepeatableRead}, + scope: SessionStr, }, { sql: "set session transaction isolation level read committed", - out: map[SetKey]interface{}{{Key: "tx_isolation", Scope: "session"}: "read committed"}, - scope: "session", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: IsolationLevelReadCommitted}, + scope: SessionStr, }, { sql: "set session transaction isolation level read uncommitted", - out: map[SetKey]interface{}{{Key: "tx_isolation", Scope: "session"}: "read uncommitted"}, - scope: "session", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: IsolationLevelReadUncommitted}, + scope: SessionStr, }, { sql: "set session transaction isolation level serializable", - out: map[SetKey]interface{}{{Key: "tx_isolation", Scope: "session"}: "serializable"}, - scope: "session", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: IsolationLevelSerializable}, + scope: SessionStr, + }, { + sql: "set transaction isolation level serializable", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: IsolationLevelSerializable}, + }, { + sql: "set transaction read only", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: TxReadOnly}, + }, { + sql: "set transaction read write", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: TxReadWrite}, + }, { + sql: "set session transaction read write", + out: map[SetKey]interface{}{{Key: TransactionStr, Scope: ImplicitStr}: TxReadWrite}, + scope: SessionStr, }, { sql: "set session tx_read_only = 0", - out: map[SetKey]interface{}{{Key: "tx_read_only", Scope: "session"}: int64(0)}, - scope: "session", + out: map[SetKey]interface{}{{Key: "tx_read_only", Scope: ImplicitStr}: int64(0)}, + scope: SessionStr, }, { sql: "set session tx_read_only = 1", - out: map[SetKey]interface{}{{Key: "tx_read_only", Scope: "session"}: int64(1)}, - scope: "session", + out: map[SetKey]interface{}{{Key: "tx_read_only", Scope: ImplicitStr}: int64(1)}, + scope: SessionStr, }, { sql: "set session sql_safe_updates = 0", - out: map[SetKey]interface{}{{Key: "sql_safe_updates", Scope: "session"}: int64(0)}, - scope: "session", + out: map[SetKey]interface{}{{Key: "sql_safe_updates", Scope: ImplicitStr}: int64(0)}, + scope: SessionStr, }, { sql: "set session sql_safe_updates = 1", - out: map[SetKey]interface{}{{Key: "sql_safe_updates", Scope: "session"}: int64(1)}, - scope: "session", + out: map[SetKey]interface{}{{Key: "sql_safe_updates", Scope: ImplicitStr}: int64(1)}, + scope: SessionStr, }} for _, tcase := range testcases { out, _, err := ExtractSetValues(tcase.sql) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index b6947c3d7fb..1cf53209db8 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "strings" + "sync" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" @@ -33,6 +34,41 @@ import ( vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) +// parserPool is a pool for parser objects. +var parserPool = sync.Pool{} + +// zeroParser is a zero-initialized parser to help reinitialize the parser for pooling. +var zeroParser = *(yyNewParser().(*yyParserImpl)) + +// yyParsePooled is a wrapper around yyParse that pools the parser objects. There isn't a +// particularly good reason to use yyParse directly, since it immediately discards its parser. What +// would be ideal down the line is to actually pool the stacks themselves rather than the parser +// objects, as per https://github.com/cznic/goyacc/blob/master/main.go. However, absent an upstream +// change to goyacc, this is the next best option. +// +// N.B: Parser pooling means that you CANNOT take references directly to parse stack variables (e.g. +// $$ = &$4) in sql.y rules. You must instead add an intermediate reference like so: +// showCollationFilterOpt := $4 +// $$ = &Show{Type: string($2), ShowCollationFilterOpt: &showCollationFilterOpt} +func yyParsePooled(yylex yyLexer) int { + // Being very particular about using the base type and not an interface type b/c we depend on + // the implementation to know how to reinitialize the parser. + var parser *yyParserImpl + + i := parserPool.Get() + if i != nil { + parser = i.(*yyParserImpl) + } else { + parser = yyNewParser().(*yyParserImpl) + } + + defer func() { + *parser = zeroParser + parserPool.Put(parser) + }() + return parser.Parse(yylex) +} + // Instructions for creating new types: If a type // needs to satisfy an interface, declare that function // along with that interface. This will help users @@ -51,7 +87,7 @@ import ( // error is ignored and the DDL is returned anyway. func Parse(sql string) (Statement, error) { tokenizer := NewStringTokenizer(sql) - if yyParse(tokenizer) != 0 { + if yyParsePooled(tokenizer) != 0 { if tokenizer.partialDDL != nil { log.Warningf("ignoring error parsing DDL '%s': %v", sql, tokenizer.LastError) tokenizer.ParseTree = tokenizer.partialDDL @@ -69,7 +105,7 @@ func Parse(sql string) (Statement, error) { // partially parsed DDL statements. func ParseStrictDDL(sql string) (Statement, error) { tokenizer := NewStringTokenizer(sql) - if yyParse(tokenizer) != 0 { + if yyParsePooled(tokenizer) != 0 { return nil, tokenizer.LastError } if tokenizer.ParseTree == nil { @@ -104,7 +140,7 @@ func parseNext(tokenizer *Tokenizer, strict bool) (Statement, error) { tokenizer.reset() tokenizer.multi = true - if yyParse(tokenizer) != 0 { + if yyParsePooled(tokenizer) != 0 { if tokenizer.partialDDL != nil && !strict { tokenizer.ParseTree = tokenizer.partialDDL return tokenizer.ParseTree, nil @@ -619,8 +655,9 @@ type Set struct { // Set.Scope or Show.Scope const ( - SessionStr = "session" - GlobalStr = "global" + SessionStr = "session" + GlobalStr = "global" + ImplicitStr = "" ) // Format formats the node. @@ -1219,7 +1256,10 @@ func (ii *IndexInfo) Format(buf *TrackedBuffer) { if ii.Primary { buf.Myprintf("%s", ii.Type) } else { - buf.Myprintf("%s %v", ii.Type, ii.Name) + buf.Myprintf("%s", ii.Type) + if !ii.Name.IsEmpty() { + buf.Myprintf(" %v", ii.Name) + } } } @@ -1360,11 +1400,47 @@ func (c *ConstraintDefinition) walkSubtree(visit Visit) error { return Walk(visit, c.Details) } +// ReferenceAction indicates the action takes by a referential constraint e.g. +// the `CASCADE` in a `FOREIGN KEY .. ON DELETE CASCADE` table definition. +type ReferenceAction int + +// These map to the SQL-defined reference actions. +// See https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html#foreign-keys-referential-actions +const ( + // DefaultAction indicates no action was explicitly specified. + DefaultAction ReferenceAction = iota + Restrict + Cascade + NoAction + SetNull + SetDefault +) + +func (a ReferenceAction) walkSubtree(visit Visit) error { return nil } + +// Format formats the node. +func (a ReferenceAction) Format(buf *TrackedBuffer) { + switch a { + case Restrict: + buf.WriteString("restrict") + case Cascade: + buf.WriteString("cascade") + case NoAction: + buf.WriteString("no action") + case SetNull: + buf.WriteString("set null") + case SetDefault: + buf.WriteString("set default") + } +} + // ForeignKeyDefinition describes a foreign key in a CREATE TABLE statement type ForeignKeyDefinition struct { Source Columns ReferencedTable TableName ReferencedColumns Columns + OnDelete ReferenceAction + OnUpdate ReferenceAction } var _ ConstraintInfo = &ForeignKeyDefinition{} @@ -1372,6 +1448,12 @@ var _ ConstraintInfo = &ForeignKeyDefinition{} // Format formats the node. func (f *ForeignKeyDefinition) Format(buf *TrackedBuffer) { buf.Myprintf("foreign key %v references %v %v", f.Source, f.ReferencedTable, f.ReferencedColumns) + if f.OnDelete != DefaultAction { + buf.Myprintf(" on delete %v", f.OnDelete) + } + if f.OnUpdate != DefaultAction { + buf.Myprintf(" on update %v", f.OnUpdate) + } } func (f *ForeignKeyDefinition) constraintInfo() {} @@ -3329,11 +3411,28 @@ type SetExpr struct { Expr Expr } +// SetExpr.Expr, for SET TRANSACTION ... or START TRANSACTION +const ( + // TransactionStr is the Name for a SET TRANSACTION statement + TransactionStr = "transaction" + + IsolationLevelReadUncommitted = "isolation level read uncommitted" + IsolationLevelReadCommitted = "isolation level read committed" + IsolationLevelRepeatableRead = "isolation level repeatable read" + IsolationLevelSerializable = "isolation level serializable" + + TxReadOnly = "read only" + TxReadWrite = "read write" +) + // Format formats the node. func (node *SetExpr) Format(buf *TrackedBuffer) { // We don't have to backtick set variable names. if node.Name.EqualString("charset") || node.Name.EqualString("names") { buf.Myprintf("%s %v", node.Name.String(), node.Expr) + } else if node.Name.EqualString(TransactionStr) { + sqlVal := node.Expr.(*SQLVal) + buf.Myprintf("%s %s", node.Name.String(), strings.ToLower(string(sqlVal.Val))) } else { buf.Myprintf("%s = %v", node.Name.String(), node.Expr) } diff --git a/go/vt/sqlparser/normalizer.go b/go/vt/sqlparser/normalizer.go index 4f930f4cbb4..a2ac08337ab 100644 --- a/go/vt/sqlparser/normalizer.go +++ b/go/vt/sqlparser/normalizer.go @@ -69,6 +69,10 @@ func (nz *normalizer) WalkStatement(node SQLNode) (bool, error) { nz.convertSQLVal(node) case *ComparisonExpr: nz.convertComparison(node) + case *ColName, TableName: + // Common node types that never contain SQLVals or ListArgs but create a lot of object + // allocations. + return false, nil } return true, nil } @@ -80,6 +84,10 @@ func (nz *normalizer) WalkSelect(node SQLNode) (bool, error) { nz.convertSQLValDedup(node) case *ComparisonExpr: nz.convertComparison(node) + case *ColName, TableName: + // Common node types that never contain SQLVals or ListArgs but create a lot of object + // allocations. + return false, nil } return true, nil } @@ -211,6 +219,10 @@ func GetBindvars(stmt Statement) map[string]struct{} { bindvars := make(map[string]struct{}) _ = Walk(func(node SQLNode) (kontinue bool, err error) { switch node := node.(type) { + case *ColName, TableName: + // Common node types that never contain SQLVals or ListArgs but create a lot of object + // allocations. + return false, nil case *SQLVal: if node.Type == ValArg { bindvars[string(node.Val[1:])] = struct{}{} diff --git a/go/vt/sqlparser/normalizer_test.go b/go/vt/sqlparser/normalizer_test.go index 7514b9a75cb..7aa24814d55 100644 --- a/go/vt/sqlparser/normalizer_test.go +++ b/go/vt/sqlparser/normalizer_test.go @@ -117,6 +117,16 @@ func TestNormalize(t *testing.T) { in: "update a set v1 = 0x1234", outstmt: "update a set v1 = 0x1234", outbv: map[string]*querypb.BindVariable{}, + }, { + // Bin value does not convert + in: "select * from t where v1 = b'11'", + outstmt: "select * from t where v1 = B'11'", + outbv: map[string]*querypb.BindVariable{}, + }, { + // Bin value does not convert for DMLs + in: "update a set v1 = b'11'", + outstmt: "update a set v1 = B'11'", + outbv: map[string]*querypb.BindVariable{}, }, { // Values up to len 256 will reuse. in: fmt.Sprintf("select * from t where v1 = '%256s' and v2 = '%256s'", "a", "a"), @@ -204,3 +214,20 @@ func TestGetBindVars(t *testing.T) { t.Errorf("GetBindVars: %v, want: %v", got, want) } } + +/* +Skipping ColName, TableName: +BenchmarkNormalize-8 1000000 2205 ns/op 821 B/op 27 allocs/op +Prior to skip: +BenchmarkNormalize-8 500000 3620 ns/op 1461 B/op 55 allocs/op +*/ +func BenchmarkNormalize(b *testing.B) { + sql := "select 'abcd', 20, 30.0, eid from a where 1=eid and name='3'" + ast, err := Parse(sql) + if err != nil { + b.Fatal(err) + } + for i := 0; i < b.N; i++ { + Normalize(ast, map[string]*querypb.BindVariable{}, "") + } +} diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 4bf5cc29bc0..c86abe01d98 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -19,7 +19,9 @@ package sqlparser import ( "bytes" "fmt" + "math/rand" "strings" + "sync" "testing" ) @@ -602,6 +604,9 @@ var ( output: "insert /* qualified columns */ into t(a, b) values (1, 2)", }, { input: "insert /* select */ into a select b, c from d", + }, { + input: "insert /* it accepts columns with keyword action */ into a(action, b) values (1, 2)", + output: "insert /* it accepts columns with keyword action */ into a(`action`, b) values (1, 2)", }, { input: "insert /* no cols & paren select */ into a(select * from t)", output: "insert /* no cols & paren select */ into a select * from t", @@ -715,29 +720,23 @@ var ( }, { input: "set /* mixed list */ a = 3, names 'utf8', charset 'ascii', b = 4", }, { - input: "set session transaction isolation level repeatable read", - output: "set session tx_isolation = 'repeatable read'", + input: "set session transaction isolation level repeatable read", + }, { + input: "set transaction isolation level repeatable read", }, { - input: "set global transaction isolation level repeatable read", - output: "set global tx_isolation = 'repeatable read'", + input: "set global transaction isolation level repeatable read", }, { - input: "set transaction isolation level repeatable read", - output: "set tx_isolation = 'repeatable read'", + input: "set transaction isolation level repeatable read", }, { - input: "set transaction isolation level read committed", - output: "set tx_isolation = 'read committed'", + input: "set transaction isolation level read committed", }, { - input: "set transaction isolation level read uncommitted", - output: "set tx_isolation = 'read uncommitted'", + input: "set transaction isolation level read uncommitted", }, { - input: "set transaction isolation level serializable", - output: "set tx_isolation = 'serializable'", + input: "set transaction isolation level serializable", }, { - input: "set transaction read write", - output: "set tx_read_only = 0", + input: "set transaction read write", }, { - input: "set transaction read only", - output: "set tx_read_only = 1", + input: "set transaction read only", }, { input: "set tx_read_only = 1", }, { @@ -1359,6 +1358,36 @@ func TestValid(t *testing.T) { } } +// Ensure there is no corruption from using a pooled yyParserImpl in Parse. +func TestValidParallel(t *testing.T) { + parallelism := 100 + numIters := 1000 + + wg := sync.WaitGroup{} + wg.Add(parallelism) + for i := 0; i < parallelism; i++ { + go func() { + defer wg.Done() + for j := 0; j < numIters; j++ { + tcase := validSQL[rand.Intn(len(validSQL))] + if tcase.output == "" { + tcase.output = tcase.input + } + tree, err := Parse(tcase.input) + if err != nil { + t.Errorf("Parse(%q) err: %v, want nil", tcase.input, err) + continue + } + out := String(tree) + if out != tcase.output { + t.Errorf("Parse(%q) = %q, want: %q", tcase.input, out, tcase.output) + } + } + }() + } + wg.Wait() +} + func TestCaseSensitivity(t *testing.T) { validSQL := []struct { input string @@ -1639,6 +1668,9 @@ func TestConvert(t *testing.T) { }, { input: "/* a comment */", output: "empty statement", + }, { + input: "set transaction isolation level 12345", + output: "syntax error at position 38 near '12345'", }} for _, tcase := range invalidSQL { @@ -1842,6 +1874,7 @@ func TestCreateTable(t *testing.T) { " c int,\n" + " primary key (id, username),\n" + " unique key by_abc (a, b, c),\n" + + " unique key (a, b, c),\n" + " key by_email (email(10), username)\n" + ")", @@ -1853,7 +1886,14 @@ func TestCreateTable(t *testing.T) { " Z int,\n" + " primary key (id, username),\n" + " key by_email (email(10), username),\n" + - " constraint second_ibfk_1 foreign key (k, j) references simple (a, b)\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b),\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on delete restrict,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on delete no action,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on delete cascade on update set default,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on delete set default on update set null,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on delete set null on update restrict,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on update no action,\n" + + " constraint second_ibfk_1 foreign key (k, j) references simple (a, b) on update cascade\n" + ")", // table options @@ -1931,6 +1971,20 @@ func TestCreateTable(t *testing.T) { " unique key by_username2 (username) key_block_size 8,\n" + " unique by_username3 (username) key_block_size 4\n" + ")", + }, { + // test current_timestamp with and without () + input: "create table t (\n" + + " time1 timestamp default current_timestamp,\n" + + " time2 timestamp default current_timestamp(),\n" + + " time3 timestamp default current_timestamp on update current_timestamp,\n" + + " time4 timestamp default current_timestamp() on update current_timestamp()\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default current_timestamp,\n" + + " time2 timestamp default current_timestamp,\n" + + " time3 timestamp default current_timestamp on update current_timestamp,\n" + + " time4 timestamp default current_timestamp on update current_timestamp\n" + + ")", }, } for _, tcase := range testCases { @@ -2140,8 +2194,36 @@ func TestErrors(t *testing.T) { // BenchmarkParse1-4 100000 16334 ns/op // BenchmarkParse2-4 30000 44121 ns/op +// Benchmark run on 9/3/18, comparing pooled parser performance. +// +// benchmark old ns/op new ns/op delta +// BenchmarkNormalize-4 2540 2533 -0.28% +// BenchmarkParse1-4 18269 13330 -27.03% +// BenchmarkParse2-4 46703 41255 -11.67% +// BenchmarkParse2Parallel-4 22246 20707 -6.92% +// BenchmarkParse3-4 4064743 4083135 +0.45% +// +// benchmark old allocs new allocs delta +// BenchmarkNormalize-4 27 27 +0.00% +// BenchmarkParse1-4 75 74 -1.33% +// BenchmarkParse2-4 264 263 -0.38% +// BenchmarkParse2Parallel-4 176 175 -0.57% +// BenchmarkParse3-4 360 361 +0.28% +// +// benchmark old bytes new bytes delta +// BenchmarkNormalize-4 821 821 +0.00% +// BenchmarkParse1-4 22776 2307 -89.87% +// BenchmarkParse2-4 28352 7881 -72.20% +// BenchmarkParse2Parallel-4 25712 5235 -79.64% +// BenchmarkParse3-4 6352082 6336307 -0.25% + +const ( + sql1 = "select 'abcd', 20, 30.0, eid from a where 1=eid and name='3'" + sql2 = "select aaaa, bbb, ccc, ddd, eeee, ffff, gggg, hhhh, iiii from tttt, ttt1, ttt3 where aaaa = bbbb and bbbb = cccc and dddd+1 = eeee group by fff, gggg having hhhh = iiii and iiii = jjjj order by kkkk, llll limit 3, 4" +) + func BenchmarkParse1(b *testing.B) { - sql := "select 'abcd', 20, 30.0, eid from a where 1=eid and name='3'" + sql := sql1 for i := 0; i < b.N; i++ { ast, err := Parse(sql) if err != nil { @@ -2152,7 +2234,7 @@ func BenchmarkParse1(b *testing.B) { } func BenchmarkParse2(b *testing.B) { - sql := "select aaaa, bbb, ccc, ddd, eeee, ffff, gggg, hhhh, iiii from tttt, ttt1, ttt3 where aaaa = bbbb and bbbb = cccc and dddd+1 = eeee group by fff, gggg having hhhh = iiii and iiii = jjjj order by kkkk, llll limit 3, 4" + sql := sql2 for i := 0; i < b.N; i++ { ast, err := Parse(sql) if err != nil { @@ -2162,6 +2244,19 @@ func BenchmarkParse2(b *testing.B) { } } +func BenchmarkParse2Parallel(b *testing.B) { + sql := sql2 + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + ast, err := Parse(sql) + if err != nil { + b.Fatal(err) + } + _ = ast + } + }) +} + var benchQuery string func init() { diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index 11a1b817a07..a3f59678552 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -95,6 +95,7 @@ type yySymType struct { indexColumns []*IndexColumn constraintDefinition *ConstraintDefinition constraintInfo ConstraintInfo + ReferenceAction ReferenceAction partDefs []*PartitionDefinition partDef *PartitionDefinition partSpec *PartitionSpec @@ -213,131 +214,135 @@ const IF = 57451 const UNIQUE = 57452 const PRIMARY = 57453 const COLUMN = 57454 -const CONSTRAINT = 57455 -const SPATIAL = 57456 -const FULLTEXT = 57457 -const FOREIGN = 57458 -const REFERENCES = 57459 -const KEY_BLOCK_SIZE = 57460 -const SHOW = 57461 -const DESCRIBE = 57462 -const EXPLAIN = 57463 -const DATE = 57464 -const ESCAPE = 57465 -const REPAIR = 57466 -const OPTIMIZE = 57467 -const TRUNCATE = 57468 -const MAXVALUE = 57469 -const PARTITION = 57470 -const REORGANIZE = 57471 -const LESS = 57472 -const THAN = 57473 -const PROCEDURE = 57474 -const TRIGGER = 57475 -const VINDEX = 57476 -const VINDEXES = 57477 -const STATUS = 57478 -const VARIABLES = 57479 -const BEGIN = 57480 -const START = 57481 -const TRANSACTION = 57482 -const COMMIT = 57483 -const ROLLBACK = 57484 -const BIT = 57485 -const TINYINT = 57486 -const SMALLINT = 57487 -const MEDIUMINT = 57488 -const INT = 57489 -const INTEGER = 57490 -const BIGINT = 57491 -const INTNUM = 57492 -const REAL = 57493 -const DOUBLE = 57494 -const FLOAT_TYPE = 57495 -const DECIMAL = 57496 -const NUMERIC = 57497 -const TIME = 57498 -const TIMESTAMP = 57499 -const DATETIME = 57500 -const YEAR = 57501 -const CHAR = 57502 -const VARCHAR = 57503 -const BOOL = 57504 -const CHARACTER = 57505 -const VARBINARY = 57506 -const NCHAR = 57507 -const TEXT = 57508 -const TINYTEXT = 57509 -const MEDIUMTEXT = 57510 -const LONGTEXT = 57511 -const BLOB = 57512 -const TINYBLOB = 57513 -const MEDIUMBLOB = 57514 -const LONGBLOB = 57515 -const JSON = 57516 -const ENUM = 57517 -const GEOMETRY = 57518 -const POINT = 57519 -const LINESTRING = 57520 -const POLYGON = 57521 -const GEOMETRYCOLLECTION = 57522 -const MULTIPOINT = 57523 -const MULTILINESTRING = 57524 -const MULTIPOLYGON = 57525 -const NULLX = 57526 -const AUTO_INCREMENT = 57527 -const APPROXNUM = 57528 -const SIGNED = 57529 -const UNSIGNED = 57530 -const ZEROFILL = 57531 -const COLLATION = 57532 -const DATABASES = 57533 -const TABLES = 57534 -const VITESS_KEYSPACES = 57535 -const VITESS_SHARDS = 57536 -const VITESS_TABLETS = 57537 -const VSCHEMA_TABLES = 57538 -const VITESS_TARGET = 57539 -const FULL = 57540 -const PROCESSLIST = 57541 -const COLUMNS = 57542 -const NAMES = 57543 -const CHARSET = 57544 -const GLOBAL = 57545 -const SESSION = 57546 -const ISOLATION = 57547 -const LEVEL = 57548 -const READ = 57549 -const WRITE = 57550 -const ONLY = 57551 -const REPEATABLE = 57552 -const COMMITTED = 57553 -const UNCOMMITTED = 57554 -const SERIALIZABLE = 57555 -const CURRENT_TIMESTAMP = 57556 -const DATABASE = 57557 -const CURRENT_DATE = 57558 -const CURRENT_TIME = 57559 -const LOCALTIME = 57560 -const LOCALTIMESTAMP = 57561 -const UTC_DATE = 57562 -const UTC_TIME = 57563 -const UTC_TIMESTAMP = 57564 -const REPLACE = 57565 -const CONVERT = 57566 -const CAST = 57567 -const SUBSTR = 57568 -const SUBSTRING = 57569 -const GROUP_CONCAT = 57570 -const SEPARATOR = 57571 -const MATCH = 57572 -const AGAINST = 57573 -const BOOLEAN = 57574 -const LANGUAGE = 57575 -const WITH = 57576 -const QUERY = 57577 -const EXPANSION = 57578 -const UNUSED = 57579 +const SPATIAL = 57455 +const FULLTEXT = 57456 +const KEY_BLOCK_SIZE = 57457 +const ACTION = 57458 +const CASCADE = 57459 +const CONSTRAINT = 57460 +const FOREIGN = 57461 +const NO = 57462 +const REFERENCES = 57463 +const RESTRICT = 57464 +const SHOW = 57465 +const DESCRIBE = 57466 +const EXPLAIN = 57467 +const DATE = 57468 +const ESCAPE = 57469 +const REPAIR = 57470 +const OPTIMIZE = 57471 +const TRUNCATE = 57472 +const MAXVALUE = 57473 +const PARTITION = 57474 +const REORGANIZE = 57475 +const LESS = 57476 +const THAN = 57477 +const PROCEDURE = 57478 +const TRIGGER = 57479 +const VINDEX = 57480 +const VINDEXES = 57481 +const STATUS = 57482 +const VARIABLES = 57483 +const BEGIN = 57484 +const START = 57485 +const TRANSACTION = 57486 +const COMMIT = 57487 +const ROLLBACK = 57488 +const BIT = 57489 +const TINYINT = 57490 +const SMALLINT = 57491 +const MEDIUMINT = 57492 +const INT = 57493 +const INTEGER = 57494 +const BIGINT = 57495 +const INTNUM = 57496 +const REAL = 57497 +const DOUBLE = 57498 +const FLOAT_TYPE = 57499 +const DECIMAL = 57500 +const NUMERIC = 57501 +const TIME = 57502 +const TIMESTAMP = 57503 +const DATETIME = 57504 +const YEAR = 57505 +const CHAR = 57506 +const VARCHAR = 57507 +const BOOL = 57508 +const CHARACTER = 57509 +const VARBINARY = 57510 +const NCHAR = 57511 +const TEXT = 57512 +const TINYTEXT = 57513 +const MEDIUMTEXT = 57514 +const LONGTEXT = 57515 +const BLOB = 57516 +const TINYBLOB = 57517 +const MEDIUMBLOB = 57518 +const LONGBLOB = 57519 +const JSON = 57520 +const ENUM = 57521 +const GEOMETRY = 57522 +const POINT = 57523 +const LINESTRING = 57524 +const POLYGON = 57525 +const GEOMETRYCOLLECTION = 57526 +const MULTIPOINT = 57527 +const MULTILINESTRING = 57528 +const MULTIPOLYGON = 57529 +const NULLX = 57530 +const AUTO_INCREMENT = 57531 +const APPROXNUM = 57532 +const SIGNED = 57533 +const UNSIGNED = 57534 +const ZEROFILL = 57535 +const COLLATION = 57536 +const DATABASES = 57537 +const TABLES = 57538 +const VITESS_KEYSPACES = 57539 +const VITESS_SHARDS = 57540 +const VITESS_TABLETS = 57541 +const VSCHEMA_TABLES = 57542 +const VITESS_TARGET = 57543 +const FULL = 57544 +const PROCESSLIST = 57545 +const COLUMNS = 57546 +const NAMES = 57547 +const CHARSET = 57548 +const GLOBAL = 57549 +const SESSION = 57550 +const ISOLATION = 57551 +const LEVEL = 57552 +const READ = 57553 +const WRITE = 57554 +const ONLY = 57555 +const REPEATABLE = 57556 +const COMMITTED = 57557 +const UNCOMMITTED = 57558 +const SERIALIZABLE = 57559 +const CURRENT_TIMESTAMP = 57560 +const DATABASE = 57561 +const CURRENT_DATE = 57562 +const CURRENT_TIME = 57563 +const LOCALTIME = 57564 +const LOCALTIMESTAMP = 57565 +const UTC_DATE = 57566 +const UTC_TIME = 57567 +const UTC_TIMESTAMP = 57568 +const REPLACE = 57569 +const CONVERT = 57570 +const CAST = 57571 +const SUBSTR = 57572 +const SUBSTRING = 57573 +const GROUP_CONCAT = 57574 +const SEPARATOR = 57575 +const MATCH = 57576 +const AGAINST = 57577 +const BOOLEAN = 57578 +const LANGUAGE = 57579 +const WITH = 57580 +const QUERY = 57581 +const EXPANSION = 57582 +const UNUSED = 57583 var yyToknames = [...]string{ "$end", @@ -469,12 +474,16 @@ var yyToknames = [...]string{ "UNIQUE", "PRIMARY", "COLUMN", - "CONSTRAINT", "SPATIAL", "FULLTEXT", + "KEY_BLOCK_SIZE", + "ACTION", + "CASCADE", + "CONSTRAINT", "FOREIGN", + "NO", "REFERENCES", - "KEY_BLOCK_SIZE", + "RESTRICT", "SHOW", "DESCRIBE", "EXPLAIN", @@ -611,1201 +620,1201 @@ var yyExca = [...]int{ 5, 28, -2, 4, -1, 36, - 153, 274, - 154, 274, - -2, 266, - -1, 250, - 111, 601, - -2, 597, - -1, 251, - 111, 602, - -2, 598, - -1, 321, - 81, 764, + 157, 288, + 158, 288, + -2, 280, + -1, 254, + 111, 615, + -2, 611, + -1, 255, + 111, 616, + -2, 612, + -1, 325, + 81, 782, -2, 59, - -1, 322, - 81, 724, + -1, 326, + 81, 740, -2, 60, - -1, 327, - 81, 706, - -2, 563, - -1, 329, - 81, 745, - -2, 565, - -1, 597, + -1, 331, + 81, 722, + -2, 577, + -1, 333, + 81, 761, + -2, 579, + -1, 601, 53, 42, 55, 42, -2, 44, - -1, 733, - 111, 604, - -2, 600, - -1, 945, + -1, 737, + 111, 618, + -2, 614, + -1, 949, 5, 29, - -2, 408, - -1, 970, + -2, 422, + -1, 974, 5, 28, - -2, 538, - -1, 1196, + -2, 552, + -1, 1201, 5, 29, - -2, 539, - -1, 1241, + -2, 553, + -1, 1247, 5, 28, - -2, 541, - -1, 1305, + -2, 555, + -1, 1313, 5, 29, - -2, 542, + -2, 556, } const yyPrivate = 57344 -const yyLast = 11325 +const yyLast = 11326 var yyAct = [...]int{ - 251, 1296, 884, 544, 669, 795, 1252, 1103, 255, 1131, - 831, 813, 1034, 1202, 835, 229, 281, 973, 543, 3, - 1104, 1100, 591, 834, 911, 796, 589, 844, 989, 1077, - 878, 80, 758, 937, 768, 194, 698, 1037, 194, 1025, - 55, 848, 326, 607, 735, 784, 765, 476, 978, 482, - 874, 606, 425, 578, 320, 792, 308, 767, 488, 593, - 253, 496, 307, 238, 194, 194, 80, 919, 228, 317, - 194, 315, 194, 558, 80, 54, 864, 221, 1329, 1316, - 1327, 1303, 1324, 885, 1315, 257, 1302, 1095, 1190, 430, - 306, 59, 1262, 1125, 313, 901, 242, 451, 1139, 1140, - 1141, 189, 185, 186, 187, 997, 1144, 1142, 996, 900, - 826, 998, 1126, 1127, 827, 828, 61, 62, 63, 64, - 65, 222, 223, 224, 225, 608, 227, 609, 226, 191, - 1016, 23, 24, 50, 26, 27, 467, 905, 857, 1215, - 439, 1230, 865, 468, 465, 1179, 899, 1177, 220, 311, - 42, 462, 463, 1326, 1078, 28, 47, 48, 1323, 316, - 1297, 453, 1058, 455, 427, 793, 429, 1253, 1289, 849, - 440, 814, 816, 677, 433, 37, 1260, 183, 668, 52, - 1255, 436, 182, 194, 183, 194, 1080, 858, 988, 452, - 454, 194, 987, 986, 1045, 896, 893, 894, 194, 892, - 428, 1282, 80, 80, 80, 80, 197, 80, 1055, 851, - 184, 532, 533, 188, 1057, 851, 80, 1199, 1082, 1064, - 1086, 953, 1081, 1043, 1079, 903, 906, 931, 707, 1084, - 500, 446, 510, 832, 520, 520, 699, 704, 1083, 30, - 31, 33, 32, 35, 1009, 80, 815, 913, 495, 1254, - 1287, 1085, 1087, 485, 494, 493, 1158, 1148, 1045, 976, - 898, 36, 43, 44, 865, 610, 45, 46, 34, 1097, - 1143, 495, 450, 484, 785, 1261, 1259, 437, 672, 438, - 38, 39, 897, 40, 41, 445, 1301, 1043, 1044, 710, - 711, 851, 447, 1049, 1046, 1039, 1040, 1047, 1042, 1041, - 458, 474, 1014, 850, 472, 473, 194, 1149, 1056, 850, - 1054, 1048, 1291, 194, 194, 194, 700, 1051, 490, 80, - 426, 902, 1307, 426, 912, 80, 1309, 486, 442, 443, - 444, 432, 68, 950, 904, 1221, 494, 493, 530, 1277, - 509, 508, 518, 519, 511, 512, 513, 514, 515, 516, - 517, 510, 1044, 495, 520, 424, 1220, 1049, 1046, 1039, - 1040, 1047, 1042, 1041, 742, 51, 323, 69, 560, 561, - 562, 563, 564, 565, 566, 1048, 493, 1029, 740, 741, - 739, 1038, 494, 493, 1288, 850, 598, 949, 604, 948, - 847, 845, 495, 843, 846, 1028, 849, 854, 311, 495, - 573, 785, 855, 960, 181, 494, 493, 434, 435, 597, - 509, 508, 518, 519, 511, 512, 513, 514, 515, 516, - 517, 510, 495, 52, 520, 194, 725, 727, 728, 1237, - 80, 726, 1017, 738, 1186, 475, 194, 194, 80, 759, - 194, 760, 1218, 194, 282, 49, 999, 194, 1000, 80, - 80, 80, 80, 80, 80, 80, 80, 1061, 938, 928, - 929, 930, 1026, 80, 80, 1245, 1325, 305, 1312, 475, - 194, 509, 508, 518, 519, 511, 512, 513, 514, 515, - 516, 517, 510, 21, 1285, 520, 494, 493, 80, 686, - 1245, 1294, 194, 1099, 49, 1245, 1257, 475, 80, 1278, - 712, 706, 234, 495, 1245, 475, 1245, 1246, 312, 1211, - 1210, 1122, 475, 1266, 684, 1198, 475, 1155, 1154, 618, - 736, 1135, 511, 512, 513, 514, 515, 516, 517, 510, - 674, 675, 520, 1134, 678, 1151, 1152, 681, 705, 1151, - 1150, 233, 80, 733, 513, 514, 515, 516, 517, 510, - 714, 1010, 520, 1005, 494, 493, 943, 475, 1265, 729, - 777, 780, 887, 761, 701, 772, 786, 683, 731, 575, - 475, 495, 682, 194, 23, 673, 194, 194, 194, 194, - 194, 770, 475, 797, 671, 666, 721, 601, 194, 737, - 448, 194, 248, 762, 763, 194, 617, 616, 968, 441, - 194, 194, 969, 1145, 80, 773, 774, 23, 1067, 772, - 56, 781, 852, 782, 974, 789, 975, 80, 1101, 323, - 574, 974, 52, 975, 955, 788, 821, 790, 791, 602, - 820, 600, 600, 799, 800, 1240, 802, 770, 798, 952, - 810, 801, 1194, 23, 575, 575, 457, 457, 457, 457, - 943, 457, 943, 819, 818, 52, 235, 824, 823, 575, - 457, 311, 311, 311, 311, 311, 974, 794, 954, 194, - 839, 1157, 80, 1153, 80, 1001, 311, 825, 194, 49, - 943, 194, 80, 951, 603, 311, 580, 583, 584, 585, - 581, 52, 582, 586, 529, 822, 880, 531, 194, 52, - 194, 194, 708, 1317, 52, 1225, 859, 879, 866, 867, - 868, 456, 1136, 876, 877, 1116, 1004, 979, 980, 720, - 875, 870, 869, 670, 882, 542, 1138, 546, 547, 548, - 549, 550, 551, 552, 553, 554, 1101, 557, 559, 559, - 559, 559, 559, 559, 559, 559, 567, 568, 569, 570, - 733, 1030, 982, 680, 280, 469, 736, 590, 920, 809, - 921, 584, 585, 883, 271, 270, 273, 274, 275, 276, - 985, 807, 907, 272, 277, 908, 808, 927, 805, 984, - 804, 803, 1321, 806, 933, 78, 1314, 713, 239, 240, - 489, 1063, 910, 580, 583, 584, 585, 581, 916, 582, - 586, 732, 1320, 979, 980, 487, 926, 925, 1021, 615, - 477, 970, 449, 1013, 860, 861, 862, 863, 80, 1192, - 325, 194, 478, 1293, 942, 737, 1292, 1238, 431, 959, - 871, 872, 873, 1011, 1006, 80, 1226, 991, 889, 993, - 957, 679, 588, 236, 237, 769, 771, 992, 489, 1002, - 983, 534, 535, 536, 537, 538, 539, 540, 541, 924, - 230, 787, 1271, 231, 56, 1270, 1228, 923, 975, 994, - 470, 697, 491, 1279, 457, 1020, 1216, 1022, 1023, 1024, - 703, 58, 457, 80, 80, 60, 80, 599, 1007, 1008, - 53, 812, 1, 457, 457, 457, 457, 457, 457, 457, - 457, 886, 1033, 895, 323, 1295, 311, 457, 457, 80, - 1027, 1251, 1130, 842, 459, 460, 461, 836, 464, 833, - 67, 423, 66, 194, 1286, 841, 840, 471, 1258, 1214, - 853, 1050, 80, 1015, 856, 1137, 1290, 1018, 1019, 1012, - 623, 621, 622, 620, 625, 624, 619, 1060, 205, 318, - 587, 611, 881, 492, 70, 1053, 325, 325, 325, 325, - 1052, 325, 891, 466, 207, 528, 922, 995, 1071, 1036, - 325, 324, 80, 80, 1102, 1108, 49, 797, 1076, 1070, - 1089, 709, 1088, 797, 481, 1269, 1105, 1227, 958, 555, - 1107, 546, 783, 256, 724, 269, 733, 266, 1096, 498, - 1112, 1110, 80, 268, 80, 80, 267, 715, 732, 967, - 1124, 502, 254, 246, 1111, 310, 571, 1065, 1129, 579, - 312, 312, 312, 312, 312, 1128, 577, 576, 981, 1146, - 1147, 194, 1123, 1133, 977, 590, 309, 817, 1066, 80, - 1189, 1276, 719, 25, 312, 57, 241, 19, 18, 17, - 20, 16, 80, 194, 15, 14, 29, 13, 12, 80, - 11, 10, 9, 940, 8, 80, 7, 941, 194, 6, - 5, 4, 232, 325, 945, 946, 947, 22, 2, 612, - 0, 0, 0, 956, 1167, 1166, 0, 0, 962, 0, - 963, 964, 965, 966, 1168, 734, 0, 0, 743, 744, - 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, - 755, 756, 757, 1175, 0, 1159, 457, 80, 457, 80, - 80, 80, 194, 80, 1193, 1156, 457, 1201, 1161, 80, - 0, 1164, 1204, 1205, 1206, 836, 0, 80, 0, 1209, - 0, 667, 0, 1002, 1207, 0, 0, 1163, 0, 676, - 1213, 0, 0, 311, 0, 0, 0, 80, 80, 80, - 687, 688, 689, 690, 691, 692, 693, 694, 0, 0, - 1223, 0, 0, 1224, 695, 696, 0, 932, 0, 0, - 0, 0, 0, 0, 325, 0, 1035, 0, 0, 0, - 0, 0, 325, 0, 0, 0, 0, 0, 0, 80, - 80, 0, 0, 325, 325, 325, 325, 325, 325, 325, - 325, 1105, 80, 0, 0, 1239, 1241, 325, 325, 1250, - 0, 1256, 0, 0, 0, 0, 80, 1217, 1263, 1219, - 1264, 0, 1069, 0, 0, 0, 0, 971, 972, 1267, - 0, 0, 716, 0, 1075, 0, 80, 0, 1280, 0, - 1229, 0, 498, 0, 1092, 325, 0, 1105, 1284, 0, - 0, 1281, 0, 0, 0, 312, 1172, 1173, 0, 1174, - 0, 0, 1176, 0, 1178, 1299, 0, 0, 244, 0, - 0, 0, 0, 80, 0, 1304, 0, 0, 797, 0, - 194, 1121, 0, 0, 0, 0, 764, 0, 80, 1310, - 1183, 475, 836, 0, 836, 0, 778, 778, 0, 0, - 0, 0, 778, 1318, 1319, 0, 0, 0, 80, 0, - 1212, 0, 0, 0, 0, 0, 0, 0, 457, 778, - 0, 1322, 0, 934, 935, 936, 0, 509, 508, 518, - 519, 511, 512, 513, 514, 515, 516, 517, 510, 0, - 0, 520, 0, 457, 0, 0, 0, 0, 325, 0, - 0, 0, 0, 0, 0, 1069, 0, 0, 0, 0, - 0, 325, 1169, 0, 0, 0, 0, 0, 0, 1171, - 0, 0, 0, 888, 1308, 890, 0, 0, 0, 0, - 1180, 1181, 1182, 909, 0, 1185, 0, 0, 0, 0, - 0, 475, 0, 0, 0, 0, 0, 0, 1195, 1196, - 1197, 0, 1200, 0, 1106, 0, 49, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 325, 0, 325, 836, - 203, 1118, 1119, 1120, 0, 0, 325, 509, 508, 518, - 519, 511, 512, 513, 514, 515, 516, 517, 510, 0, - 0, 520, 0, 0, 215, 504, 0, 507, 1035, 836, - 0, 0, 325, 521, 522, 523, 524, 525, 526, 527, - 0, 505, 506, 503, 509, 508, 518, 519, 511, 512, - 513, 514, 515, 516, 517, 510, 0, 0, 520, 0, - 480, 1236, 508, 518, 519, 511, 512, 513, 514, 515, - 516, 517, 510, 0, 198, 520, 1247, 1248, 1249, 479, - 483, 200, 312, 0, 0, 0, 0, 0, 206, 202, - 0, 0, 0, 0, 0, 192, 501, 0, 219, 0, - 0, 1073, 1074, 1272, 1273, 1274, 1275, 0, 0, 0, - 1188, 0, 0, 0, 1090, 1091, 204, 1093, 1094, 208, - 0, 0, 245, 0, 192, 192, 0, 0, 0, 0, - 192, 545, 192, 0, 0, 0, 0, 0, 0, 0, - 556, 1187, 990, 0, 0, 0, 0, 199, 1300, 0, - 0, 0, 0, 1305, 0, 0, 0, 0, 0, 325, - 0, 0, 0, 0, 0, 1032, 0, 1311, 0, 0, - 0, 457, 0, 0, 209, 201, 0, 210, 211, 212, - 214, 213, 218, 0, 0, 0, 1184, 217, 216, 0, - 1059, 0, 518, 519, 511, 512, 513, 514, 515, 516, - 517, 510, 1332, 1333, 520, 0, 0, 1031, 325, 1106, - 325, 0, 1242, 0, 509, 508, 518, 519, 511, 512, - 513, 514, 515, 516, 517, 510, 0, 0, 520, 0, - 0, 0, 0, 325, 0, 1170, 0, 0, 0, 0, - 0, 1268, 0, 192, 0, 192, 0, 0, 0, 0, - 0, 192, 0, 0, 0, 1106, 325, 49, 192, 509, - 508, 518, 519, 511, 512, 513, 514, 515, 516, 517, - 510, 0, 0, 520, 0, 0, 0, 0, 325, 0, - 1072, 509, 508, 518, 519, 511, 512, 513, 514, 515, - 516, 517, 510, 778, 0, 520, 1109, 990, 0, 778, - 509, 508, 518, 519, 511, 512, 513, 514, 515, 516, - 517, 510, 0, 0, 520, 0, 0, 0, 0, 702, - 0, 0, 0, 0, 0, 0, 325, 0, 325, 1132, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1328, 722, 723, 0, 0, 1231, 1232, 0, 1233, - 1234, 1235, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1160, 0, 0, 192, 0, 0, 0, - 0, 0, 0, 192, 595, 192, 1162, 0, 0, 0, - 939, 0, 0, 1165, 0, 0, 0, 0, 0, 325, - 0, 0, 0, 0, 0, 545, 0, 0, 775, 776, - 509, 508, 518, 519, 511, 512, 513, 514, 515, 516, - 517, 510, 0, 0, 520, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1222, 0, - 0, 1203, 0, 1203, 1203, 1203, 0, 1208, 0, 0, - 0, 0, 0, 325, 0, 0, 0, 0, 0, 830, - 0, 1203, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 325, 325, 325, 0, 192, 0, 0, 0, 0, - 0, 1330, 0, 0, 0, 0, 192, 192, 0, 0, - 192, 0, 0, 192, 0, 0, 0, 685, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1243, 1244, 0, 0, 0, 0, 0, - 192, 0, 0, 0, 640, 0, 1132, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1203, 0, 192, 0, 917, 918, 0, 483, 0, 0, - 0, 685, 0, 0, 0, 0, 0, 0, 0, 0, - 1283, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 245, 778, 0, 0, 1306, 245, 245, - 0, 628, 779, 779, 245, 0, 0, 0, 779, 944, - 0, 0, 1313, 0, 0, 0, 0, 0, 245, 245, - 245, 245, 0, 192, 961, 779, 192, 192, 192, 192, - 192, 0, 1203, 641, 0, 0, 0, 0, 811, 0, - 0, 192, 0, 0, 0, 595, 0, 0, 0, 0, - 192, 192, 0, 0, 654, 655, 656, 657, 658, 659, - 660, 0, 661, 662, 663, 664, 665, 642, 643, 644, - 645, 626, 627, 0, 0, 629, 0, 630, 631, 632, - 633, 634, 635, 636, 637, 638, 639, 646, 647, 648, - 649, 650, 651, 652, 653, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, - 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, - 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, - 914, 915, 1062, 0, 0, 0, 0, 0, 685, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1098, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1113, 1114, 0, 245, 1115, 0, - 0, 1117, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1191, 0, - 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 245, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 685, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 779, - 0, 0, 0, 0, 0, 779, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 192, 0, 0, 0, 0, 0, 1298, - 545, 0, 0, 0, 0, 0, 0, 0, 192, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 595, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 837, 838, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 1003, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 779, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 192, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 837, 838, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 52, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 1068, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 250, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 730, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 250, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 328, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 329, 327, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 193, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 605, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 328, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 329, 327, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 411, 401, 0, - 373, 414, 351, 365, 422, 366, 367, 394, 337, 381, - 131, 363, 0, 354, 332, 360, 333, 352, 375, 99, - 378, 350, 403, 384, 413, 113, 420, 115, 389, 0, - 149, 124, 0, 0, 377, 405, 379, 399, 372, 395, - 342, 388, 415, 364, 392, 416, 0, 0, 0, 79, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, - 391, 410, 362, 393, 331, 390, 0, 335, 338, 421, - 408, 357, 358, 0, 0, 0, 0, 0, 0, 0, - 376, 380, 396, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 355, 0, 387, 0, 0, 0, 339, 336, - 0, 0, 374, 0, 0, 0, 341, 0, 356, 397, - 0, 330, 400, 406, 371, 195, 409, 369, 368, 412, - 137, 0, 0, 152, 104, 103, 142, 112, 404, 353, - 361, 95, 359, 144, 133, 164, 386, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 319, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 328, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 334, 0, 150, 166, 180, 90, - 349, 407, 172, 173, 174, 175, 176, 0, 0, 91, - 329, 327, 322, 321, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 345, 348, 343, 344, 382, 383, 417, - 418, 419, 398, 340, 0, 346, 347, 0, 402, 385, - 81, 0, 114, 177, 139, 101, 167, 131, 0, 0, - 766, 0, 252, 0, 0, 0, 99, 0, 249, 0, - 0, 0, 113, 292, 115, 0, 0, 149, 124, 0, - 0, 0, 0, 283, 284, 0, 0, 0, 0, 0, - 0, 0, 0, 52, 0, 0, 250, 271, 270, 273, - 274, 275, 276, 0, 0, 92, 272, 277, 278, 279, - 0, 0, 247, 264, 0, 291, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 261, 262, 243, 0, 0, - 0, 303, 0, 263, 0, 0, 258, 259, 260, 265, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 195, 0, 0, 301, 0, 137, 0, 0, - 152, 104, 103, 142, 112, 0, 0, 0, 95, 0, - 144, 133, 164, 0, 134, 143, 116, 156, 138, 163, - 196, 171, 154, 170, 82, 153, 162, 93, 146, 84, - 160, 151, 122, 108, 109, 83, 0, 141, 98, 102, - 97, 130, 157, 158, 96, 179, 87, 169, 86, 88, - 168, 129, 155, 161, 123, 120, 85, 159, 121, 119, - 111, 100, 105, 135, 118, 136, 106, 126, 125, 127, - 0, 0, 0, 150, 166, 180, 90, 0, 0, 172, - 173, 174, 175, 176, 0, 0, 91, 128, 89, 107, - 147, 110, 117, 140, 178, 132, 145, 94, 165, 148, - 293, 302, 299, 300, 297, 298, 296, 295, 294, 304, - 285, 286, 287, 288, 290, 0, 289, 81, 0, 114, - 177, 139, 101, 167, 131, 0, 0, 0, 0, 252, - 0, 0, 0, 99, 0, 249, 0, 0, 0, 113, - 292, 115, 0, 0, 149, 124, 0, 0, 0, 0, - 283, 284, 0, 0, 0, 0, 0, 0, 0, 0, - 52, 0, 475, 250, 271, 270, 273, 274, 275, 276, - 0, 0, 92, 272, 277, 278, 279, 0, 0, 247, - 264, 0, 291, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 261, 262, 0, 0, 0, 0, 303, 0, - 263, 0, 0, 258, 259, 260, 265, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, - 0, 0, 301, 0, 137, 0, 0, 152, 104, 103, - 142, 112, 0, 0, 0, 95, 0, 144, 133, 164, - 0, 134, 143, 116, 156, 138, 163, 196, 171, 154, - 170, 82, 153, 162, 93, 146, 84, 160, 151, 122, - 108, 109, 83, 0, 141, 98, 102, 97, 130, 157, - 158, 96, 179, 87, 169, 86, 88, 168, 129, 155, - 161, 123, 120, 85, 159, 121, 119, 111, 100, 105, - 135, 118, 136, 106, 126, 125, 127, 0, 0, 0, - 150, 166, 180, 90, 0, 0, 172, 173, 174, 175, - 176, 0, 0, 91, 128, 89, 107, 147, 110, 117, - 140, 178, 132, 145, 94, 165, 148, 293, 302, 299, - 300, 297, 298, 296, 295, 294, 304, 285, 286, 287, - 288, 290, 0, 289, 81, 0, 114, 177, 139, 101, - 167, 131, 0, 0, 0, 0, 252, 0, 0, 0, - 99, 0, 249, 0, 0, 0, 113, 292, 115, 0, - 0, 149, 124, 0, 0, 0, 0, 283, 284, 0, - 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, - 250, 271, 270, 273, 274, 275, 276, 0, 0, 92, - 272, 277, 278, 279, 0, 0, 247, 264, 0, 291, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, - 262, 243, 0, 0, 0, 303, 0, 263, 0, 0, - 258, 259, 260, 265, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 195, 0, 0, 301, - 0, 137, 0, 0, 152, 104, 103, 142, 112, 0, - 0, 0, 95, 0, 144, 133, 164, 0, 134, 143, - 116, 156, 138, 163, 196, 171, 154, 170, 82, 153, - 162, 93, 146, 84, 160, 151, 122, 108, 109, 83, - 0, 141, 98, 102, 97, 130, 157, 158, 96, 179, - 87, 169, 86, 88, 168, 129, 155, 161, 123, 120, - 85, 159, 121, 119, 111, 100, 105, 135, 118, 136, - 106, 126, 125, 127, 0, 0, 0, 150, 166, 180, - 90, 0, 0, 172, 173, 174, 175, 176, 0, 0, - 91, 128, 89, 107, 147, 110, 117, 140, 178, 132, - 145, 94, 165, 148, 293, 302, 299, 300, 297, 298, - 296, 295, 294, 304, 285, 286, 287, 288, 290, 0, - 289, 81, 0, 114, 177, 139, 101, 167, 131, 0, - 0, 0, 0, 252, 0, 0, 0, 99, 0, 249, - 0, 0, 0, 113, 292, 115, 0, 0, 149, 124, - 0, 0, 0, 0, 283, 284, 0, 0, 0, 0, - 0, 0, 829, 0, 52, 0, 0, 250, 271, 270, - 273, 274, 275, 276, 0, 0, 92, 272, 277, 278, - 279, 0, 0, 247, 264, 0, 291, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 261, 262, 0, 0, - 0, 0, 303, 0, 263, 0, 0, 258, 259, 260, - 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 195, 0, 0, 301, 0, 137, 0, - 0, 152, 104, 103, 142, 112, 0, 0, 0, 95, - 0, 144, 133, 164, 0, 134, 143, 116, 156, 138, - 163, 196, 171, 154, 170, 82, 153, 162, 93, 146, - 84, 160, 151, 122, 108, 109, 83, 0, 141, 98, - 102, 97, 130, 157, 158, 96, 179, 87, 169, 86, - 88, 168, 129, 155, 161, 123, 120, 85, 159, 121, - 119, 111, 100, 105, 135, 118, 136, 106, 126, 125, - 127, 0, 0, 0, 150, 166, 180, 90, 0, 0, - 172, 173, 174, 175, 176, 0, 0, 91, 128, 89, - 107, 147, 110, 117, 140, 178, 132, 145, 94, 165, - 148, 293, 302, 299, 300, 297, 298, 296, 295, 294, - 304, 285, 286, 287, 288, 290, 23, 289, 81, 0, - 114, 177, 139, 101, 167, 0, 0, 0, 131, 0, - 0, 0, 0, 252, 0, 0, 0, 99, 0, 249, - 0, 0, 0, 113, 292, 115, 0, 0, 149, 124, - 0, 0, 0, 0, 283, 284, 0, 0, 0, 0, - 0, 0, 0, 0, 52, 0, 0, 250, 271, 270, - 273, 274, 275, 276, 0, 0, 92, 272, 277, 278, - 279, 0, 0, 247, 264, 0, 291, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 261, 262, 0, 0, - 0, 0, 303, 0, 263, 0, 0, 258, 259, 260, - 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 195, 0, 0, 301, 0, 137, 0, - 0, 152, 104, 103, 142, 112, 0, 0, 0, 95, - 0, 144, 133, 164, 0, 134, 143, 116, 156, 138, - 163, 196, 171, 154, 170, 82, 153, 162, 93, 146, - 84, 160, 151, 122, 108, 109, 83, 0, 141, 98, - 102, 97, 130, 157, 158, 96, 179, 87, 169, 86, - 88, 168, 129, 155, 161, 123, 120, 85, 159, 121, - 119, 111, 100, 105, 135, 118, 136, 106, 126, 125, - 127, 0, 0, 0, 150, 166, 180, 90, 0, 0, - 172, 173, 174, 175, 176, 0, 0, 91, 128, 89, - 107, 147, 110, 117, 140, 178, 132, 145, 94, 165, - 148, 293, 302, 299, 300, 297, 298, 296, 295, 294, - 304, 285, 286, 287, 288, 290, 0, 289, 81, 0, - 114, 177, 139, 101, 167, 131, 0, 0, 0, 0, - 252, 0, 0, 0, 99, 0, 249, 0, 0, 0, - 113, 292, 115, 0, 0, 149, 124, 0, 0, 0, - 0, 283, 284, 0, 0, 0, 0, 0, 0, 0, - 0, 52, 0, 0, 250, 271, 270, 273, 274, 275, - 276, 0, 0, 92, 272, 277, 278, 279, 0, 0, - 247, 264, 0, 291, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 261, 262, 0, 0, 0, 0, 303, - 0, 263, 0, 0, 258, 259, 260, 265, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 195, 0, 0, 301, 0, 137, 0, 0, 152, 104, - 103, 142, 112, 0, 0, 0, 95, 0, 144, 133, - 164, 0, 134, 143, 116, 156, 138, 163, 196, 171, - 154, 170, 82, 153, 162, 93, 146, 84, 160, 151, - 122, 108, 109, 83, 0, 141, 98, 102, 97, 130, - 157, 158, 96, 179, 87, 169, 86, 88, 168, 129, - 155, 161, 123, 120, 85, 159, 121, 119, 111, 100, - 105, 135, 118, 136, 106, 126, 125, 127, 0, 0, - 0, 150, 166, 180, 90, 0, 0, 172, 173, 174, - 175, 176, 0, 0, 91, 128, 89, 107, 147, 110, - 117, 140, 178, 132, 145, 94, 165, 148, 293, 302, - 299, 300, 297, 298, 296, 295, 294, 304, 285, 286, - 287, 288, 290, 131, 289, 81, 0, 114, 177, 139, - 101, 167, 99, 0, 0, 0, 0, 0, 113, 292, - 115, 0, 0, 149, 124, 0, 0, 0, 0, 283, - 284, 0, 0, 0, 0, 0, 0, 0, 0, 52, - 0, 0, 250, 271, 270, 273, 274, 275, 276, 0, - 0, 92, 272, 277, 278, 279, 0, 0, 0, 264, - 0, 291, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 261, 262, 0, 0, 0, 0, 303, 0, 263, - 0, 0, 258, 259, 260, 265, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, - 0, 301, 0, 137, 0, 0, 152, 104, 103, 142, - 112, 0, 0, 0, 95, 0, 144, 133, 164, 1331, - 134, 143, 116, 156, 138, 163, 196, 171, 154, 170, - 82, 153, 162, 93, 146, 84, 160, 151, 122, 108, - 109, 83, 0, 141, 98, 102, 97, 130, 157, 158, - 96, 179, 87, 169, 86, 88, 168, 129, 155, 161, - 123, 120, 85, 159, 121, 119, 111, 100, 105, 135, - 118, 136, 106, 126, 125, 127, 0, 0, 0, 150, - 166, 180, 90, 0, 0, 172, 173, 174, 175, 176, - 0, 0, 91, 128, 89, 107, 147, 110, 117, 140, - 178, 132, 145, 94, 165, 148, 293, 302, 299, 300, - 297, 298, 296, 295, 294, 304, 285, 286, 287, 288, - 290, 131, 289, 81, 0, 114, 177, 139, 101, 167, - 99, 0, 0, 0, 0, 0, 113, 292, 115, 0, - 0, 149, 124, 0, 0, 0, 0, 283, 284, 0, - 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, - 250, 271, 270, 273, 274, 275, 276, 0, 0, 92, - 272, 277, 278, 279, 0, 0, 0, 264, 0, 291, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, - 262, 0, 0, 0, 0, 303, 0, 263, 0, 0, - 258, 259, 260, 265, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 195, 0, 0, 301, - 0, 137, 0, 0, 152, 104, 103, 142, 112, 0, - 0, 0, 95, 0, 144, 133, 164, 0, 134, 143, - 116, 156, 138, 163, 196, 171, 154, 170, 82, 153, - 162, 93, 146, 84, 160, 151, 122, 108, 109, 83, - 0, 141, 98, 102, 97, 130, 157, 158, 96, 179, - 87, 169, 86, 88, 168, 129, 155, 161, 123, 120, - 85, 159, 121, 119, 111, 100, 105, 135, 118, 136, - 106, 126, 125, 127, 0, 0, 0, 150, 166, 180, - 90, 0, 0, 172, 173, 174, 175, 176, 0, 0, - 91, 128, 89, 107, 147, 110, 117, 140, 178, 132, - 145, 94, 165, 148, 293, 302, 299, 300, 297, 298, - 296, 295, 294, 304, 285, 286, 287, 288, 290, 131, - 289, 81, 0, 114, 177, 139, 101, 167, 99, 0, - 0, 0, 0, 0, 113, 0, 115, 0, 0, 149, - 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, - 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 509, 508, 518, 519, 511, 512, 513, - 514, 515, 516, 517, 510, 0, 0, 520, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 195, 0, 0, 0, 0, 137, - 0, 0, 152, 104, 103, 142, 112, 0, 0, 0, - 95, 0, 144, 133, 164, 0, 134, 143, 116, 156, - 138, 163, 196, 171, 154, 170, 82, 153, 162, 93, - 146, 84, 160, 151, 122, 108, 109, 83, 0, 141, - 98, 102, 97, 130, 157, 158, 96, 179, 87, 169, - 86, 88, 168, 129, 155, 161, 123, 120, 85, 159, - 121, 119, 111, 100, 105, 135, 118, 136, 106, 126, - 125, 127, 0, 0, 0, 150, 166, 180, 90, 0, - 0, 172, 173, 174, 175, 176, 0, 0, 91, 128, - 89, 107, 147, 110, 117, 140, 178, 132, 145, 94, - 165, 148, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 131, 0, 0, 0, 497, 0, 0, 0, 81, - 99, 114, 177, 139, 101, 167, 113, 0, 115, 0, - 0, 149, 124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 79, 0, 499, 0, 0, 0, 0, 0, 0, 92, - 0, 0, 0, 0, 494, 493, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 495, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, - 0, 137, 0, 0, 152, 104, 103, 142, 112, 0, - 0, 0, 95, 0, 144, 133, 164, 0, 134, 143, - 116, 156, 138, 163, 196, 171, 154, 170, 82, 153, - 162, 93, 146, 84, 160, 151, 122, 108, 109, 83, - 0, 141, 98, 102, 97, 130, 157, 158, 96, 179, - 87, 169, 86, 88, 168, 129, 155, 161, 123, 120, - 85, 159, 121, 119, 111, 100, 105, 135, 118, 136, - 106, 126, 125, 127, 0, 0, 0, 150, 166, 180, - 90, 0, 0, 172, 173, 174, 175, 176, 0, 0, - 91, 128, 89, 107, 147, 110, 117, 140, 178, 132, - 145, 94, 165, 148, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, - 0, 81, 99, 114, 177, 139, 101, 167, 113, 0, - 115, 0, 0, 149, 124, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 255, 1348, 1304, 548, 673, 1338, 1207, 799, 888, 285, + 1258, 1108, 1136, 817, 1039, 1109, 839, 977, 595, 882, + 233, 1105, 915, 848, 838, 835, 593, 1013, 800, 330, + 460, 80, 762, 993, 772, 198, 941, 702, 198, 1030, + 1042, 852, 1082, 611, 769, 788, 982, 480, 739, 486, + 547, 3, 610, 429, 878, 324, 257, 796, 242, 55, + 492, 597, 500, 923, 198, 198, 80, 321, 319, 54, + 198, 562, 198, 582, 80, 1341, 1325, 1336, 1311, 905, + 1333, 889, 1324, 1310, 1100, 1195, 434, 1268, 1130, 1001, + 310, 830, 1000, 904, 455, 1002, 246, 311, 1131, 1132, + 232, 1144, 1145, 1146, 231, 193, 189, 190, 191, 1149, + 1147, 312, 259, 831, 832, 612, 248, 613, 230, 1021, + 471, 909, 861, 225, 1220, 59, 862, 472, 469, 1236, + 903, 869, 443, 868, 1284, 513, 512, 522, 523, 515, + 516, 517, 518, 519, 520, 521, 514, 1184, 1182, 524, + 61, 62, 63, 64, 65, 224, 1083, 1335, 457, 1332, + 459, 466, 467, 1305, 1063, 797, 1296, 226, 227, 228, + 229, 478, 855, 1259, 853, 187, 1266, 1352, 1356, 900, + 897, 898, 444, 896, 437, 681, 1261, 198, 855, 198, + 456, 458, 1085, 818, 820, 198, 186, 1060, 187, 855, + 672, 430, 198, 1062, 992, 991, 80, 80, 80, 80, + 990, 80, 432, 907, 910, 440, 201, 1014, 188, 1289, + 80, 192, 536, 537, 1087, 1204, 1091, 1069, 1086, 957, + 1084, 836, 935, 711, 504, 1089, 1050, 463, 464, 465, + 450, 468, 1153, 317, 1088, 524, 708, 703, 902, 80, + 475, 430, 1260, 497, 917, 499, 869, 1090, 1092, 1050, + 771, 514, 954, 1294, 524, 1048, 854, 68, 819, 499, + 901, 851, 849, 454, 850, 1267, 1265, 1148, 195, 847, + 853, 1350, 854, 428, 1351, 1163, 1349, 1309, 1048, 489, + 746, 980, 1154, 854, 789, 614, 488, 1061, 1285, 1059, + 714, 715, 69, 1102, 744, 745, 743, 676, 320, 906, + 198, 498, 497, 431, 789, 433, 964, 198, 198, 198, + 1019, 1298, 908, 80, 446, 447, 448, 704, 499, 80, + 1049, 916, 932, 933, 934, 1054, 1051, 1044, 1052, 1047, + 729, 731, 732, 1045, 1046, 730, 1357, 498, 497, 286, + 49, 483, 487, 1049, 476, 477, 494, 1053, 1054, 1051, + 1044, 1052, 1047, 1056, 499, 490, 1045, 1046, 505, 52, + 564, 565, 566, 567, 568, 569, 570, 858, 1315, 742, + 1053, 1227, 859, 498, 497, 1358, 1043, 602, 1226, 185, + 608, 515, 516, 517, 518, 519, 520, 521, 514, 49, + 499, 524, 763, 549, 764, 1292, 1034, 238, 953, 710, + 952, 1033, 560, 316, 513, 512, 522, 523, 515, 516, + 517, 518, 519, 520, 521, 514, 498, 497, 524, 198, + 441, 1022, 442, 1003, 80, 1004, 436, 1317, 449, 1295, + 198, 198, 80, 499, 198, 451, 709, 198, 1243, 1224, + 1014, 198, 309, 80, 80, 80, 80, 80, 80, 80, + 80, 1066, 498, 497, 671, 1031, 942, 80, 80, 1251, + 1334, 479, 680, 21, 198, 1321, 479, 52, 1009, 499, + 690, 1191, 479, 691, 692, 693, 694, 695, 696, 697, + 698, 891, 80, 498, 497, 765, 198, 699, 700, 687, + 1104, 686, 80, 517, 518, 519, 520, 521, 514, 716, + 499, 524, 438, 439, 688, 1251, 1302, 740, 513, 512, + 522, 523, 515, 516, 517, 518, 519, 520, 521, 514, + 677, 237, 524, 675, 737, 670, 284, 1318, 275, 274, + 277, 278, 279, 280, 1251, 1263, 80, 276, 281, 718, + 1251, 479, 1273, 577, 452, 461, 461, 461, 461, 445, + 461, 1272, 601, 1269, 733, 1251, 1252, 78, 735, 461, + 1216, 1215, 1127, 479, 1203, 479, 605, 198, 1160, 1159, + 198, 198, 198, 198, 198, 1156, 1157, 1150, 49, 1156, + 1155, 706, 198, 766, 767, 198, 947, 479, 856, 198, + 978, 776, 329, 533, 198, 198, 535, 824, 80, 604, + 435, 579, 479, 1106, 726, 727, 978, 793, 606, 786, + 604, 80, 584, 587, 588, 589, 585, 774, 586, 590, + 825, 1199, 983, 984, 546, 1326, 550, 551, 552, 553, + 554, 555, 556, 557, 558, 776, 561, 563, 563, 563, + 563, 563, 563, 563, 563, 571, 572, 573, 574, 823, + 822, 717, 828, 827, 814, 23, 594, 549, 781, 784, + 779, 780, 622, 198, 790, 843, 80, 802, 80, 23, + 805, 23, 198, 678, 679, 198, 80, 682, 1072, 884, + 685, 801, 803, 804, 979, 806, 774, 479, 621, 620, + 56, 578, 198, 972, 198, 198, 892, 973, 894, 1246, + 579, 979, 1162, 52, 674, 1158, 913, 705, 1005, 773, + 775, 880, 881, 959, 956, 829, 579, 52, 239, 52, + 1301, 834, 947, 947, 607, 791, 712, 579, 1231, 725, + 947, 737, 329, 329, 329, 329, 1222, 329, 863, 883, + 1141, 1121, 1008, 740, 978, 879, 329, 864, 865, 866, + 867, 874, 924, 873, 925, 816, 1343, 958, 955, 870, + 871, 872, 886, 875, 876, 877, 52, 983, 984, 1339, + 1143, 1106, 1035, 461, 986, 502, 684, 473, 724, 989, + 988, 461, 937, 584, 587, 588, 589, 585, 808, 586, + 590, 807, 461, 461, 461, 461, 461, 461, 461, 461, + 811, 920, 777, 778, 809, 812, 461, 461, 785, 810, + 798, 813, 80, 588, 589, 198, 921, 922, 1330, 487, + 243, 244, 792, 963, 794, 795, 1323, 1068, 493, 80, + 1329, 995, 930, 997, 929, 481, 1026, 974, 826, 619, + 453, 996, 987, 491, 1018, 1006, 1300, 482, 1299, 329, + 1244, 1016, 1010, 1197, 1232, 616, 893, 683, 592, 240, + 241, 493, 234, 998, 928, 1278, 235, 56, 1277, 1234, + 1015, 979, 927, 261, 474, 49, 701, 80, 80, 495, + 80, 948, 1011, 1012, 1025, 1345, 1027, 1028, 1029, 1286, + 550, 1345, 1344, 1221, 707, 58, 965, 60, 603, 53, + 1, 1337, 890, 80, 1032, 1038, 887, 899, 1037, 1303, + 1257, 252, 1135, 846, 837, 911, 67, 198, 912, 316, + 316, 316, 316, 316, 427, 66, 80, 944, 1055, 1293, + 845, 945, 844, 1064, 594, 914, 821, 315, 949, 950, + 951, 1264, 1065, 316, 1219, 857, 1020, 960, 860, 1142, + 1297, 1017, 966, 462, 967, 968, 969, 970, 627, 625, + 329, 626, 624, 629, 628, 1076, 80, 80, 329, 623, + 1107, 1075, 1081, 1110, 931, 209, 1093, 737, 322, 329, + 329, 329, 329, 329, 329, 329, 329, 1094, 1023, 1024, + 591, 615, 885, 329, 329, 496, 80, 1117, 80, 80, + 1115, 70, 1058, 1057, 1129, 895, 470, 211, 532, 1041, + 926, 1101, 999, 328, 1134, 461, 1112, 461, 720, 327, + 1133, 946, 1113, 1138, 1067, 461, 198, 1116, 502, 1139, + 1140, 329, 713, 485, 80, 1276, 1233, 961, 962, 1151, + 1152, 559, 787, 260, 728, 1128, 273, 80, 198, 270, + 272, 271, 719, 971, 80, 506, 258, 250, 314, 575, + 80, 583, 581, 198, 580, 985, 981, 313, 1071, 1194, + 1283, 1103, 768, 723, 25, 801, 936, 57, 1171, 1172, + 245, 801, 782, 782, 19, 18, 1118, 1119, 782, 1173, + 1120, 17, 20, 1122, 16, 15, 14, 1180, 29, 13, + 12, 11, 10, 9, 8, 782, 7, 6, 1080, 5, + 4, 236, 80, 22, 80, 80, 80, 198, 80, 1198, + 1209, 1210, 1211, 2, 80, 0, 0, 1206, 0, 0, + 534, 0, 80, 0, 329, 1212, 975, 976, 1218, 1214, + 1006, 0, 0, 0, 0, 0, 0, 329, 0, 0, + 0, 0, 80, 80, 80, 1126, 1164, 0, 0, 0, + 1070, 0, 0, 0, 316, 0, 0, 1229, 0, 1166, + 1230, 0, 1169, 0, 538, 539, 540, 541, 542, 543, + 544, 545, 1228, 0, 0, 0, 0, 0, 0, 0, + 315, 0, 0, 0, 80, 80, 0, 0, 0, 1110, + 1177, 1178, 329, 1179, 329, 1245, 1181, 80, 1183, 0, + 0, 1196, 329, 0, 0, 0, 1256, 0, 549, 1262, + 0, 0, 80, 0, 0, 0, 0, 461, 1274, 0, + 0, 0, 0, 0, 0, 0, 0, 1174, 329, 1270, + 0, 1271, 80, 1247, 1176, 0, 1110, 0, 1287, 0, + 0, 0, 461, 0, 1217, 1185, 1186, 1187, 1291, 0, + 1190, 0, 0, 0, 0, 0, 0, 0, 0, 1161, + 0, 0, 1307, 1200, 1201, 1202, 327, 1205, 0, 1223, + 80, 1225, 0, 0, 1312, 0, 0, 198, 0, 1288, + 0, 1168, 0, 0, 0, 0, 80, 1319, 0, 0, + 0, 0, 1235, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1111, 1328, 49, 0, 80, 1327, 0, + 0, 0, 0, 1331, 0, 0, 484, 0, 0, 0, + 1123, 1124, 1125, 1342, 0, 0, 0, 1353, 522, 523, + 515, 516, 517, 518, 519, 520, 521, 514, 994, 0, + 524, 0, 0, 0, 0, 0, 1242, 0, 0, 0, + 0, 196, 0, 0, 223, 329, 0, 0, 0, 0, + 0, 1253, 1254, 1255, 0, 0, 0, 0, 0, 0, + 0, 741, 0, 0, 1306, 549, 0, 0, 249, 801, + 196, 196, 0, 0, 0, 0, 196, 0, 196, 1279, + 1280, 1281, 1282, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 316, 1036, 329, 0, 329, 0, 738, 0, + 0, 747, 748, 749, 750, 751, 752, 753, 754, 755, + 756, 757, 758, 759, 760, 761, 0, 0, 0, 329, + 1193, 0, 0, 0, 0, 1308, 0, 0, 0, 0, + 1313, 0, 0, 315, 315, 315, 315, 315, 736, 0, + 0, 0, 329, 0, 0, 1320, 0, 0, 315, 0, + 23, 24, 50, 26, 27, 0, 0, 315, 0, 0, + 0, 0, 0, 0, 329, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 28, 47, 48, 0, 0, 782, + 0, 461, 1114, 994, 0, 782, 1188, 479, 1354, 1355, + 0, 0, 0, 196, 37, 196, 0, 0, 52, 0, + 0, 196, 0, 0, 0, 0, 0, 0, 196, 0, + 1316, 0, 329, 0, 329, 1137, 0, 0, 0, 1111, + 0, 207, 1248, 513, 512, 522, 523, 515, 516, 517, + 518, 519, 520, 521, 514, 0, 0, 524, 0, 0, + 0, 327, 0, 0, 0, 219, 0, 0, 0, 0, + 1165, 0, 1275, 0, 840, 0, 0, 0, 30, 31, + 33, 32, 35, 1167, 0, 0, 1111, 0, 49, 0, + 1170, 0, 0, 0, 0, 0, 329, 0, 0, 0, + 0, 0, 0, 0, 36, 43, 44, 0, 0, 45, + 46, 34, 0, 0, 0, 202, 0, 741, 0, 0, + 0, 0, 204, 38, 39, 0, 40, 41, 0, 210, + 206, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 0, 0, 0, 196, 599, 196, 0, 0, 1208, 0, + 1208, 1208, 1208, 0, 1213, 0, 938, 939, 940, 0, + 329, 208, 0, 0, 212, 736, 0, 0, 1208, 0, + 0, 0, 0, 0, 0, 1340, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 329, 329, + 329, 0, 203, 0, 0, 0, 0, 0, 315, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, + 205, 0, 214, 215, 216, 218, 217, 222, 1192, 0, + 1249, 1250, 221, 220, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1137, 479, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 196, 0, 0, 1208, 0, + 0, 0, 0, 0, 0, 0, 196, 196, 0, 0, + 196, 0, 0, 196, 0, 0, 0, 689, 1290, 0, + 513, 512, 522, 523, 515, 516, 517, 518, 519, 520, + 521, 514, 840, 0, 524, 0, 0, 0, 0, 0, + 196, 513, 512, 522, 523, 515, 516, 517, 518, 519, + 520, 521, 514, 782, 0, 524, 1314, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, + 0, 689, 1322, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1040, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1208, 1078, 1079, 0, 0, 0, 0, + 1189, 0, 0, 0, 0, 0, 0, 1095, 1096, 0, + 1098, 1099, 0, 249, 0, 0, 0, 0, 249, 249, + 0, 0, 783, 783, 249, 0, 0, 0, 783, 1074, + 0, 0, 0, 0, 0, 0, 0, 0, 249, 249, + 249, 249, 0, 196, 0, 783, 196, 196, 196, 196, + 196, 1097, 0, 0, 0, 0, 0, 0, 815, 0, + 0, 196, 0, 0, 0, 599, 0, 0, 0, 0, + 196, 196, 0, 513, 512, 522, 523, 515, 516, 517, + 518, 519, 520, 521, 514, 0, 315, 524, 0, 0, + 0, 0, 0, 0, 508, 0, 511, 0, 0, 840, + 0, 840, 525, 526, 527, 528, 529, 530, 531, 0, + 509, 510, 507, 513, 512, 522, 523, 515, 516, 517, + 518, 519, 520, 521, 514, 0, 0, 524, 0, 1175, + 0, 0, 0, 0, 0, 644, 0, 0, 0, 196, + 0, 0, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 196, 512, 522, 523, 515, 516, 517, 518, 519, + 520, 521, 514, 1074, 0, 524, 0, 0, 196, 0, + 918, 919, 1077, 0, 0, 0, 0, 0, 689, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 249, 0, 513, 512, 522, 523, 515, 516, 517, 518, + 519, 520, 521, 514, 0, 0, 524, 0, 0, 0, + 0, 0, 632, 0, 513, 512, 522, 523, 515, 516, + 517, 518, 519, 520, 521, 514, 0, 840, 524, 0, + 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, + 1237, 1238, 0, 1239, 1240, 1241, 0, 0, 645, 0, + 0, 0, 0, 249, 0, 0, 1040, 840, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 658, + 659, 660, 661, 662, 663, 664, 0, 665, 666, 667, + 668, 669, 646, 647, 648, 649, 630, 631, 0, 0, + 633, 196, 634, 635, 636, 637, 638, 639, 640, 641, + 642, 643, 650, 651, 652, 653, 654, 655, 656, 657, + 943, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 513, 512, 522, 523, 515, 516, 517, 518, 519, 520, + 521, 514, 0, 0, 524, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1346, 196, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 783, + 0, 0, 0, 0, 0, 783, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 599, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 415, 405, 0, 377, 418, 355, 369, 426, 370, 371, + 398, 341, 385, 134, 367, 0, 358, 336, 364, 337, + 356, 379, 101, 382, 354, 407, 388, 417, 115, 424, + 117, 393, 0, 153, 126, 0, 0, 381, 409, 383, + 403, 376, 399, 346, 392, 419, 368, 396, 420, 0, + 0, 0, 79, 0, 841, 842, 0, 0, 0, 0, + 0, 94, 0, 395, 414, 366, 397, 335, 394, 0, + 339, 342, 425, 412, 361, 362, 1007, 0, 0, 0, + 0, 0, 0, 380, 384, 400, 374, 0, 0, 0, + 0, 0, 0, 0, 0, 359, 0, 391, 0, 0, + 0, 343, 340, 783, 0, 378, 0, 0, 0, 345, + 0, 360, 401, 196, 334, 404, 410, 375, 199, 413, + 373, 372, 416, 140, 0, 156, 106, 114, 82, 88, + 0, 105, 132, 145, 149, 408, 357, 365, 97, 363, + 147, 136, 168, 390, 137, 146, 118, 160, 141, 167, + 200, 175, 158, 174, 83, 157, 166, 95, 150, 85, + 164, 155, 124, 110, 111, 84, 0, 144, 100, 104, + 99, 133, 161, 162, 98, 183, 89, 173, 87, 90, + 172, 131, 159, 165, 125, 122, 86, 163, 123, 121, + 113, 102, 107, 138, 120, 139, 108, 128, 127, 129, + 0, 338, 0, 154, 170, 184, 92, 353, 411, 176, + 177, 178, 179, 180, 0, 0, 93, 130, 91, 109, + 151, 112, 119, 143, 182, 135, 148, 96, 169, 152, + 349, 352, 347, 348, 386, 387, 421, 422, 423, 402, + 344, 0, 350, 351, 0, 406, 389, 81, 0, 116, + 181, 142, 103, 171, 415, 405, 0, 377, 418, 355, + 369, 426, 370, 371, 398, 341, 385, 134, 367, 0, + 358, 336, 364, 337, 356, 379, 101, 382, 354, 407, + 388, 417, 115, 424, 117, 393, 0, 153, 126, 0, + 0, 381, 409, 383, 403, 376, 399, 346, 392, 419, + 368, 396, 420, 0, 0, 0, 79, 0, 841, 842, + 0, 0, 0, 0, 0, 94, 0, 395, 414, 366, + 397, 335, 394, 0, 339, 342, 425, 412, 361, 362, + 0, 0, 0, 0, 0, 0, 0, 380, 384, 400, + 374, 0, 0, 0, 0, 0, 0, 0, 0, 359, + 0, 391, 0, 0, 0, 343, 340, 0, 0, 378, + 0, 0, 0, 345, 0, 360, 401, 0, 334, 404, + 410, 375, 199, 413, 373, 372, 416, 140, 0, 156, + 106, 114, 82, 88, 0, 105, 132, 145, 149, 408, + 357, 365, 97, 363, 147, 136, 168, 390, 137, 146, + 118, 160, 141, 167, 200, 175, 158, 174, 83, 157, + 166, 95, 150, 85, 164, 155, 124, 110, 111, 84, + 0, 144, 100, 104, 99, 133, 161, 162, 98, 183, + 89, 173, 87, 90, 172, 131, 159, 165, 125, 122, + 86, 163, 123, 121, 113, 102, 107, 138, 120, 139, + 108, 128, 127, 129, 0, 338, 0, 154, 170, 184, + 92, 353, 411, 176, 177, 178, 179, 180, 0, 0, + 93, 130, 91, 109, 151, 112, 119, 143, 182, 135, + 148, 96, 169, 152, 349, 352, 347, 348, 386, 387, + 421, 422, 423, 402, 344, 0, 350, 351, 0, 406, + 389, 81, 0, 116, 181, 142, 103, 171, 415, 405, + 0, 377, 418, 355, 369, 426, 370, 371, 398, 341, + 385, 134, 367, 0, 358, 336, 364, 337, 356, 379, + 101, 382, 354, 407, 388, 417, 115, 424, 117, 393, + 0, 153, 126, 0, 0, 381, 409, 383, 403, 376, + 399, 346, 392, 419, 368, 396, 420, 52, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 0, 0, 94, + 0, 395, 414, 366, 397, 335, 394, 0, 339, 342, + 425, 412, 361, 362, 0, 0, 0, 0, 0, 0, + 0, 380, 384, 400, 374, 0, 0, 0, 0, 0, + 0, 0, 0, 359, 0, 391, 0, 0, 0, 343, + 340, 0, 0, 378, 0, 0, 0, 345, 0, 360, + 401, 0, 334, 404, 410, 375, 199, 413, 373, 372, + 416, 140, 0, 156, 106, 114, 82, 88, 0, 105, + 132, 145, 149, 408, 357, 365, 97, 363, 147, 136, + 168, 390, 137, 146, 118, 160, 141, 167, 200, 175, + 158, 174, 83, 157, 166, 95, 150, 85, 164, 155, + 124, 110, 111, 84, 0, 144, 100, 104, 99, 133, + 161, 162, 98, 183, 89, 173, 87, 90, 172, 131, + 159, 165, 125, 122, 86, 163, 123, 121, 113, 102, + 107, 138, 120, 139, 108, 128, 127, 129, 0, 338, + 0, 154, 170, 184, 92, 353, 411, 176, 177, 178, + 179, 180, 0, 0, 93, 130, 91, 109, 151, 112, + 119, 143, 182, 135, 148, 96, 169, 152, 349, 352, + 347, 348, 386, 387, 421, 422, 423, 402, 344, 0, + 350, 351, 0, 406, 389, 81, 0, 116, 181, 142, + 103, 171, 415, 405, 0, 377, 418, 355, 369, 426, + 370, 371, 398, 341, 385, 134, 367, 0, 358, 336, + 364, 337, 356, 379, 101, 382, 354, 407, 388, 417, + 115, 424, 117, 393, 0, 153, 126, 0, 0, 381, + 409, 383, 403, 376, 399, 346, 392, 419, 368, 396, + 420, 0, 0, 0, 79, 0, 0, 0, 0, 0, + 0, 0, 0, 94, 0, 395, 414, 366, 397, 335, + 394, 0, 339, 342, 425, 412, 361, 362, 0, 0, + 0, 0, 0, 0, 0, 380, 384, 400, 374, 0, + 0, 0, 0, 0, 0, 1073, 0, 359, 0, 391, + 0, 0, 0, 343, 340, 0, 0, 378, 0, 0, + 0, 345, 0, 360, 401, 0, 334, 404, 410, 375, + 199, 413, 373, 372, 416, 140, 0, 156, 106, 114, + 82, 88, 0, 105, 132, 145, 149, 408, 357, 365, + 97, 363, 147, 136, 168, 390, 137, 146, 118, 160, + 141, 167, 200, 175, 158, 174, 83, 157, 166, 95, + 150, 85, 164, 155, 124, 110, 111, 84, 0, 144, + 100, 104, 99, 133, 161, 162, 98, 183, 89, 173, + 87, 90, 172, 131, 159, 165, 125, 122, 86, 163, + 123, 121, 113, 102, 107, 138, 120, 139, 108, 128, + 127, 129, 0, 338, 0, 154, 170, 184, 92, 353, + 411, 176, 177, 178, 179, 180, 0, 0, 93, 130, + 91, 109, 151, 112, 119, 143, 182, 135, 148, 96, + 169, 152, 349, 352, 347, 348, 386, 387, 421, 422, + 423, 402, 344, 0, 350, 351, 0, 406, 389, 81, + 0, 116, 181, 142, 103, 171, 415, 405, 0, 377, + 418, 355, 369, 426, 370, 371, 398, 341, 385, 134, + 367, 0, 358, 336, 364, 337, 356, 379, 101, 382, + 354, 407, 388, 417, 115, 424, 117, 393, 0, 153, + 126, 0, 0, 381, 409, 383, 403, 376, 399, 346, + 392, 419, 368, 396, 420, 0, 0, 0, 254, 0, + 0, 0, 0, 0, 0, 0, 0, 94, 0, 395, + 414, 366, 397, 335, 394, 0, 339, 342, 425, 412, + 361, 362, 0, 0, 0, 0, 0, 0, 0, 380, + 384, 400, 374, 0, 0, 0, 0, 0, 0, 734, + 0, 359, 0, 391, 0, 0, 0, 343, 340, 0, + 0, 378, 0, 0, 0, 345, 0, 360, 401, 0, + 334, 404, 410, 375, 199, 413, 373, 372, 416, 140, + 0, 156, 106, 114, 82, 88, 0, 105, 132, 145, + 149, 408, 357, 365, 97, 363, 147, 136, 168, 390, + 137, 146, 118, 160, 141, 167, 200, 175, 158, 174, + 83, 157, 166, 95, 150, 85, 164, 155, 124, 110, + 111, 84, 0, 144, 100, 104, 99, 133, 161, 162, + 98, 183, 89, 173, 87, 90, 172, 131, 159, 165, + 125, 122, 86, 163, 123, 121, 113, 102, 107, 138, + 120, 139, 108, 128, 127, 129, 0, 338, 0, 154, + 170, 184, 92, 353, 411, 176, 177, 178, 179, 180, + 0, 0, 93, 130, 91, 109, 151, 112, 119, 143, + 182, 135, 148, 96, 169, 152, 349, 352, 347, 348, + 386, 387, 421, 422, 423, 402, 344, 0, 350, 351, + 0, 406, 389, 81, 0, 116, 181, 142, 103, 171, + 415, 405, 0, 377, 418, 355, 369, 426, 370, 371, + 398, 341, 385, 134, 367, 0, 358, 336, 364, 337, + 356, 379, 101, 382, 354, 407, 388, 417, 115, 424, + 117, 393, 0, 153, 126, 0, 0, 381, 409, 383, + 403, 376, 399, 346, 392, 419, 368, 396, 420, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, - 0, 92, 0, 0, 0, 0, 72, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 76, 0, 71, 0, - 0, 0, 77, 137, 0, 0, 152, 104, 103, 142, - 112, 0, 0, 0, 95, 0, 144, 133, 164, 0, - 134, 143, 116, 156, 138, 163, 73, 171, 154, 170, - 82, 153, 162, 93, 146, 84, 160, 151, 122, 108, - 109, 83, 0, 141, 98, 102, 97, 130, 157, 158, - 96, 179, 87, 169, 86, 88, 168, 129, 155, 161, - 123, 120, 85, 159, 121, 119, 111, 100, 105, 135, - 118, 136, 106, 126, 125, 127, 0, 0, 0, 150, - 166, 180, 90, 0, 0, 172, 173, 174, 175, 176, - 0, 0, 91, 128, 89, 107, 147, 110, 117, 140, - 178, 132, 145, 94, 165, 148, 0, 74, 0, 0, - 0, 0, 0, 0, 0, 131, 0, 0, 0, 594, - 0, 0, 0, 81, 99, 114, 177, 139, 101, 167, - 113, 0, 115, 0, 0, 149, 124, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 193, 0, 596, 0, 0, 0, - 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 195, 0, 0, 0, 0, 137, 0, 0, 152, 104, - 103, 142, 112, 0, 0, 0, 95, 0, 144, 133, - 164, 0, 134, 143, 116, 156, 138, 163, 196, 171, - 154, 170, 82, 153, 162, 93, 146, 84, 160, 151, - 122, 108, 109, 83, 0, 141, 98, 102, 97, 130, - 157, 158, 96, 179, 87, 169, 86, 88, 168, 129, - 155, 161, 123, 120, 85, 159, 121, 119, 111, 100, - 105, 135, 118, 136, 106, 126, 125, 127, 0, 0, - 0, 150, 166, 180, 90, 0, 0, 172, 173, 174, - 175, 176, 0, 0, 91, 128, 89, 107, 147, 110, - 117, 140, 178, 132, 145, 94, 165, 148, 0, 0, - 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 131, 0, 81, 0, 114, 177, 139, - 101, 167, 99, 0, 0, 0, 0, 0, 113, 0, - 115, 0, 0, 149, 124, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, + 0, 94, 0, 395, 414, 366, 397, 335, 394, 0, + 339, 342, 425, 412, 361, 362, 0, 0, 0, 0, + 0, 0, 0, 380, 384, 400, 374, 0, 0, 0, + 0, 0, 0, 0, 0, 359, 0, 391, 0, 0, + 0, 343, 340, 0, 0, 378, 0, 0, 0, 345, + 0, 360, 401, 0, 334, 404, 410, 375, 199, 413, + 373, 372, 416, 140, 0, 156, 106, 114, 82, 88, + 0, 105, 132, 145, 149, 408, 357, 365, 97, 363, + 147, 136, 168, 390, 137, 146, 118, 160, 141, 167, + 200, 175, 158, 174, 83, 157, 166, 95, 150, 85, + 164, 155, 124, 110, 111, 84, 0, 144, 100, 104, + 99, 133, 161, 162, 98, 183, 89, 173, 87, 90, + 172, 131, 159, 165, 125, 122, 86, 163, 123, 121, + 113, 102, 107, 138, 120, 139, 108, 128, 127, 129, + 0, 338, 0, 154, 170, 184, 92, 353, 411, 176, + 177, 178, 179, 180, 0, 0, 93, 130, 91, 109, + 151, 112, 119, 143, 182, 135, 148, 96, 169, 152, + 349, 352, 347, 348, 386, 387, 421, 422, 423, 402, + 344, 0, 350, 351, 0, 406, 389, 81, 0, 116, + 181, 142, 103, 171, 415, 405, 0, 377, 418, 355, + 369, 426, 370, 371, 398, 341, 385, 134, 367, 0, + 358, 336, 364, 337, 356, 379, 101, 382, 354, 407, + 388, 417, 115, 424, 117, 393, 0, 153, 126, 0, + 0, 381, 409, 383, 403, 376, 399, 346, 392, 419, + 368, 396, 420, 0, 0, 0, 254, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 395, 414, 366, + 397, 335, 394, 0, 339, 342, 425, 412, 361, 362, + 0, 0, 0, 0, 0, 0, 0, 380, 384, 400, + 374, 0, 0, 0, 0, 0, 0, 0, 0, 359, + 0, 391, 0, 0, 0, 343, 340, 0, 0, 378, + 0, 0, 0, 345, 0, 360, 401, 0, 334, 404, + 410, 375, 199, 413, 373, 372, 416, 140, 0, 156, + 106, 114, 82, 88, 0, 105, 132, 145, 149, 408, + 357, 365, 97, 363, 147, 136, 168, 390, 137, 146, + 118, 160, 141, 167, 200, 175, 158, 174, 83, 157, + 166, 95, 150, 85, 164, 155, 124, 110, 111, 84, + 0, 144, 100, 104, 99, 133, 161, 162, 98, 183, + 89, 173, 87, 90, 172, 131, 159, 165, 125, 122, + 86, 163, 123, 121, 113, 102, 107, 138, 120, 139, + 108, 128, 127, 129, 0, 338, 0, 154, 170, 184, + 92, 353, 411, 176, 177, 178, 179, 180, 0, 0, + 93, 130, 91, 109, 151, 112, 119, 143, 182, 135, + 148, 96, 169, 152, 349, 352, 347, 348, 386, 387, + 421, 422, 423, 402, 344, 0, 350, 351, 0, 406, + 389, 81, 0, 116, 181, 142, 103, 171, 415, 405, + 0, 377, 418, 355, 369, 426, 370, 371, 398, 341, + 385, 134, 367, 0, 358, 336, 364, 337, 356, 379, + 101, 382, 354, 407, 388, 417, 115, 424, 117, 393, + 0, 153, 126, 0, 0, 381, 409, 383, 403, 376, + 399, 346, 392, 419, 368, 396, 420, 0, 0, 0, + 79, 0, 0, 0, 0, 0, 0, 0, 0, 94, + 0, 395, 414, 366, 397, 335, 394, 0, 339, 342, + 425, 412, 361, 362, 0, 0, 0, 0, 0, 0, + 0, 380, 384, 400, 374, 0, 0, 0, 0, 0, + 0, 0, 0, 359, 0, 391, 0, 0, 0, 343, + 340, 0, 0, 378, 0, 0, 0, 345, 0, 360, + 401, 0, 334, 404, 410, 375, 199, 413, 373, 372, + 416, 140, 0, 156, 106, 114, 82, 88, 0, 105, + 132, 145, 149, 408, 357, 365, 97, 363, 147, 136, + 168, 390, 137, 146, 118, 160, 141, 167, 200, 175, + 158, 174, 83, 157, 166, 95, 150, 85, 164, 155, + 124, 110, 111, 84, 0, 144, 100, 104, 99, 133, + 161, 162, 98, 183, 89, 173, 87, 332, 172, 131, + 159, 165, 125, 122, 86, 163, 123, 121, 113, 102, + 107, 138, 120, 139, 108, 128, 127, 129, 0, 338, + 0, 154, 170, 184, 92, 353, 411, 176, 177, 178, + 179, 180, 0, 0, 93, 333, 331, 109, 151, 112, + 119, 143, 182, 135, 148, 96, 169, 152, 349, 352, + 347, 348, 386, 387, 421, 422, 423, 402, 344, 0, + 350, 351, 0, 406, 389, 81, 0, 116, 181, 142, + 103, 171, 415, 405, 0, 377, 418, 355, 369, 426, + 370, 371, 398, 341, 385, 134, 367, 0, 358, 336, + 364, 337, 356, 379, 101, 382, 354, 407, 388, 417, + 115, 424, 117, 393, 0, 153, 126, 0, 0, 381, + 409, 383, 403, 376, 399, 346, 392, 419, 368, 396, + 420, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 0, 0, 0, 94, 0, 395, 414, 366, 397, 335, + 394, 0, 339, 342, 425, 412, 361, 362, 0, 0, + 0, 0, 0, 0, 0, 380, 384, 400, 374, 0, + 0, 0, 0, 0, 0, 0, 0, 359, 0, 391, + 0, 0, 0, 343, 340, 0, 0, 378, 0, 0, + 0, 345, 0, 360, 401, 0, 334, 404, 410, 375, + 199, 413, 373, 372, 416, 140, 0, 156, 106, 114, + 82, 88, 0, 105, 132, 145, 149, 408, 357, 365, + 97, 363, 147, 136, 168, 390, 137, 146, 118, 160, + 141, 167, 200, 175, 158, 174, 83, 157, 166, 95, + 150, 85, 164, 155, 124, 110, 111, 84, 0, 144, + 100, 104, 99, 133, 161, 162, 98, 183, 89, 173, + 87, 90, 172, 131, 159, 165, 125, 122, 86, 163, + 123, 121, 113, 102, 107, 138, 120, 139, 108, 128, + 127, 129, 0, 338, 0, 154, 170, 184, 92, 353, + 411, 176, 177, 178, 179, 180, 0, 0, 93, 130, + 91, 109, 151, 112, 119, 143, 182, 135, 148, 96, + 169, 152, 349, 352, 347, 348, 386, 387, 421, 422, + 423, 402, 344, 0, 350, 351, 0, 406, 389, 81, + 0, 116, 181, 142, 103, 171, 415, 405, 0, 377, + 418, 355, 369, 426, 370, 371, 398, 341, 385, 134, + 367, 0, 358, 336, 364, 337, 356, 379, 101, 382, + 354, 407, 388, 417, 115, 424, 117, 393, 0, 153, + 126, 0, 0, 381, 409, 383, 403, 376, 399, 346, + 392, 419, 368, 396, 420, 0, 0, 0, 79, 0, + 0, 0, 0, 0, 0, 0, 0, 94, 0, 395, + 414, 366, 397, 335, 394, 0, 339, 342, 425, 412, + 361, 362, 0, 0, 0, 0, 0, 0, 0, 380, + 384, 400, 374, 0, 0, 0, 0, 0, 0, 0, + 0, 359, 0, 391, 0, 0, 0, 343, 340, 0, + 0, 378, 0, 0, 0, 345, 0, 360, 401, 0, + 334, 404, 410, 375, 199, 413, 373, 372, 416, 140, + 0, 156, 106, 114, 82, 88, 0, 105, 132, 145, + 149, 408, 357, 365, 97, 363, 147, 136, 168, 390, + 137, 146, 118, 160, 141, 167, 200, 175, 158, 174, + 83, 157, 609, 95, 150, 85, 164, 155, 124, 110, + 111, 84, 0, 144, 100, 104, 99, 133, 161, 162, + 98, 183, 89, 173, 87, 332, 172, 131, 159, 165, + 125, 122, 86, 163, 123, 121, 113, 102, 107, 138, + 120, 139, 108, 128, 127, 129, 0, 338, 0, 154, + 170, 184, 92, 353, 411, 176, 177, 178, 179, 180, + 0, 0, 93, 333, 331, 109, 151, 112, 119, 143, + 182, 135, 148, 96, 169, 152, 349, 352, 347, 348, + 386, 387, 421, 422, 423, 402, 344, 0, 350, 351, + 0, 406, 389, 81, 0, 116, 181, 142, 103, 171, + 415, 405, 0, 377, 418, 355, 369, 426, 370, 371, + 398, 341, 385, 134, 367, 0, 358, 336, 364, 337, + 356, 379, 101, 382, 354, 407, 388, 417, 115, 424, + 117, 393, 0, 153, 126, 0, 0, 381, 409, 383, + 403, 376, 399, 346, 392, 419, 368, 396, 420, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, - 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 94, 0, 395, 414, 366, 397, 335, 394, 0, + 339, 342, 425, 412, 361, 362, 0, 0, 0, 0, + 0, 0, 0, 380, 384, 400, 374, 0, 0, 0, + 0, 0, 0, 0, 0, 359, 0, 391, 0, 0, + 0, 343, 340, 0, 0, 378, 0, 0, 0, 345, + 0, 360, 401, 0, 334, 404, 410, 375, 199, 413, + 373, 372, 416, 140, 0, 156, 106, 114, 82, 88, + 0, 105, 132, 145, 149, 408, 357, 365, 97, 363, + 147, 136, 168, 390, 137, 146, 118, 160, 141, 167, + 200, 175, 158, 174, 83, 157, 323, 95, 150, 85, + 164, 155, 124, 110, 111, 84, 0, 144, 100, 104, + 99, 133, 161, 162, 98, 183, 89, 173, 87, 332, + 172, 131, 159, 165, 125, 122, 86, 163, 123, 121, + 113, 102, 107, 138, 120, 139, 108, 128, 127, 129, + 0, 338, 0, 154, 170, 184, 92, 353, 411, 176, + 177, 178, 179, 180, 0, 0, 93, 333, 331, 326, + 325, 112, 119, 143, 182, 135, 148, 96, 169, 152, + 349, 352, 347, 348, 386, 387, 421, 422, 423, 402, + 344, 0, 350, 351, 0, 406, 389, 81, 0, 116, + 181, 142, 103, 171, 134, 0, 0, 770, 0, 256, + 0, 0, 0, 101, 0, 253, 0, 0, 0, 115, + 296, 117, 0, 0, 153, 126, 0, 0, 0, 0, + 287, 288, 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 254, 275, 274, 277, 278, 279, 280, + 0, 0, 94, 276, 281, 282, 283, 0, 0, 251, + 268, 0, 295, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 266, 247, 0, 0, 0, 307, 0, + 267, 0, 0, 262, 263, 264, 269, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, + 0, 0, 305, 0, 140, 0, 156, 106, 114, 82, + 88, 0, 105, 132, 145, 149, 0, 0, 0, 97, + 0, 147, 136, 168, 0, 137, 146, 118, 160, 141, + 167, 200, 175, 158, 174, 83, 157, 166, 95, 150, + 85, 164, 155, 124, 110, 111, 84, 0, 144, 100, + 104, 99, 133, 161, 162, 98, 183, 89, 173, 87, + 90, 172, 131, 159, 165, 125, 122, 86, 163, 123, + 121, 113, 102, 107, 138, 120, 139, 108, 128, 127, + 129, 0, 0, 0, 154, 170, 184, 92, 0, 0, + 176, 177, 178, 179, 180, 0, 0, 93, 130, 91, + 109, 151, 112, 119, 143, 182, 135, 148, 96, 169, + 152, 297, 306, 303, 304, 301, 302, 300, 299, 298, + 308, 289, 290, 291, 292, 294, 0, 293, 81, 0, + 116, 181, 142, 103, 171, 134, 0, 0, 0, 0, + 256, 0, 0, 0, 101, 0, 253, 0, 0, 0, + 115, 296, 117, 0, 0, 153, 126, 0, 0, 0, + 0, 287, 288, 0, 0, 0, 0, 0, 0, 0, + 0, 52, 0, 479, 254, 275, 274, 277, 278, 279, + 280, 0, 0, 94, 276, 281, 282, 283, 0, 0, + 251, 268, 0, 295, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 265, 266, 0, 0, 0, 0, 307, + 0, 267, 0, 0, 262, 263, 264, 269, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 199, 0, 0, 305, 0, 140, 0, 156, 106, 114, + 82, 88, 0, 105, 132, 145, 149, 0, 0, 0, + 97, 0, 147, 136, 168, 0, 137, 146, 118, 160, + 141, 167, 200, 175, 158, 174, 83, 157, 166, 95, + 150, 85, 164, 155, 124, 110, 111, 84, 0, 144, + 100, 104, 99, 133, 161, 162, 98, 183, 89, 173, + 87, 90, 172, 131, 159, 165, 125, 122, 86, 163, + 123, 121, 113, 102, 107, 138, 120, 139, 108, 128, + 127, 129, 0, 0, 0, 154, 170, 184, 92, 0, + 0, 176, 177, 178, 179, 180, 0, 0, 93, 130, + 91, 109, 151, 112, 119, 143, 182, 135, 148, 96, + 169, 152, 297, 306, 303, 304, 301, 302, 300, 299, + 298, 308, 289, 290, 291, 292, 294, 0, 293, 81, + 0, 116, 181, 142, 103, 171, 134, 0, 0, 0, + 0, 256, 0, 0, 0, 101, 0, 253, 0, 0, + 0, 115, 296, 117, 0, 0, 153, 126, 0, 0, + 0, 0, 287, 288, 0, 0, 0, 0, 0, 0, + 0, 0, 52, 0, 0, 254, 275, 274, 277, 278, + 279, 280, 0, 0, 94, 276, 281, 282, 283, 0, + 0, 251, 268, 0, 295, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 266, 247, 0, 0, 0, + 307, 0, 267, 0, 0, 262, 263, 264, 269, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 199, 0, 0, 305, 0, 140, 0, 156, 106, + 114, 82, 88, 0, 105, 132, 145, 149, 0, 0, + 0, 97, 0, 147, 136, 168, 0, 137, 146, 118, + 160, 141, 167, 200, 175, 158, 174, 83, 157, 166, + 95, 150, 85, 164, 155, 124, 110, 111, 84, 0, + 144, 100, 104, 99, 133, 161, 162, 98, 183, 89, + 173, 87, 90, 172, 131, 159, 165, 125, 122, 86, + 163, 123, 121, 113, 102, 107, 138, 120, 139, 108, + 128, 127, 129, 0, 0, 0, 154, 170, 184, 92, + 0, 0, 176, 177, 178, 179, 180, 0, 0, 93, + 130, 91, 109, 151, 112, 119, 143, 182, 135, 148, + 96, 169, 152, 297, 306, 303, 304, 301, 302, 300, + 299, 298, 308, 289, 290, 291, 292, 294, 0, 293, + 81, 0, 116, 181, 142, 103, 171, 134, 0, 0, + 0, 0, 256, 0, 0, 0, 101, 0, 253, 0, + 0, 0, 115, 296, 117, 0, 0, 153, 126, 0, + 0, 0, 0, 287, 288, 0, 0, 0, 0, 0, + 0, 833, 0, 52, 0, 0, 254, 275, 274, 277, + 278, 279, 280, 0, 0, 94, 276, 281, 282, 283, + 0, 0, 251, 268, 0, 295, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 265, 266, 0, 0, 0, + 0, 307, 0, 267, 0, 0, 262, 263, 264, 269, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 199, 0, 0, 305, 0, 140, 0, 156, + 106, 114, 82, 88, 0, 105, 132, 145, 149, 0, + 0, 0, 97, 0, 147, 136, 168, 0, 137, 146, + 118, 160, 141, 167, 200, 175, 158, 174, 83, 157, + 166, 95, 150, 85, 164, 155, 124, 110, 111, 84, + 0, 144, 100, 104, 99, 133, 161, 162, 98, 183, + 89, 173, 87, 90, 172, 131, 159, 165, 125, 122, + 86, 163, 123, 121, 113, 102, 107, 138, 120, 139, + 108, 128, 127, 129, 0, 0, 0, 154, 170, 184, + 92, 0, 0, 176, 177, 178, 179, 180, 0, 0, + 93, 130, 91, 109, 151, 112, 119, 143, 182, 135, + 148, 96, 169, 152, 297, 306, 303, 304, 301, 302, + 300, 299, 298, 308, 289, 290, 291, 292, 294, 23, + 293, 81, 0, 116, 181, 142, 103, 171, 0, 0, + 0, 134, 0, 0, 0, 0, 256, 0, 0, 0, + 101, 0, 253, 0, 0, 0, 115, 296, 117, 0, + 0, 153, 126, 0, 0, 0, 0, 287, 288, 0, + 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, + 254, 275, 274, 277, 278, 279, 280, 0, 0, 94, + 276, 281, 282, 283, 0, 0, 251, 268, 0, 295, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 265, + 266, 0, 0, 0, 0, 307, 0, 267, 0, 0, + 262, 263, 264, 269, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 199, 0, 0, 305, + 0, 140, 0, 156, 106, 114, 82, 88, 0, 105, + 132, 145, 149, 0, 0, 0, 97, 0, 147, 136, + 168, 0, 137, 146, 118, 160, 141, 167, 200, 175, + 158, 174, 83, 157, 166, 95, 150, 85, 164, 155, + 124, 110, 111, 84, 0, 144, 100, 104, 99, 133, + 161, 162, 98, 183, 89, 173, 87, 90, 172, 131, + 159, 165, 125, 122, 86, 163, 123, 121, 113, 102, + 107, 138, 120, 139, 108, 128, 127, 129, 0, 0, + 0, 154, 170, 184, 92, 0, 0, 176, 177, 178, + 179, 180, 0, 0, 93, 130, 91, 109, 151, 112, + 119, 143, 182, 135, 148, 96, 169, 152, 297, 306, + 303, 304, 301, 302, 300, 299, 298, 308, 289, 290, + 291, 292, 294, 0, 293, 81, 0, 116, 181, 142, + 103, 171, 134, 0, 0, 0, 0, 256, 0, 0, + 0, 101, 0, 253, 0, 0, 0, 115, 296, 117, + 0, 0, 153, 126, 0, 0, 0, 0, 287, 288, + 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, + 0, 254, 275, 274, 277, 278, 279, 280, 0, 0, + 94, 276, 281, 282, 283, 0, 0, 251, 268, 0, + 295, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 265, 266, 0, 0, 0, 0, 307, 0, 267, 0, + 0, 262, 263, 264, 269, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, + 305, 0, 140, 0, 156, 106, 114, 82, 88, 0, + 105, 132, 145, 149, 0, 0, 0, 97, 0, 147, + 136, 168, 0, 137, 146, 118, 160, 141, 167, 200, + 175, 158, 174, 83, 157, 166, 95, 150, 85, 164, + 155, 124, 110, 111, 84, 0, 144, 100, 104, 99, + 133, 161, 162, 98, 183, 89, 173, 87, 90, 172, + 131, 159, 165, 125, 122, 86, 163, 123, 121, 113, + 102, 107, 138, 120, 139, 108, 128, 127, 129, 0, + 0, 0, 154, 170, 184, 92, 0, 0, 176, 177, + 178, 179, 180, 0, 0, 93, 130, 91, 109, 151, + 112, 119, 143, 182, 135, 148, 96, 169, 152, 297, + 306, 303, 304, 301, 302, 300, 299, 298, 308, 289, + 290, 291, 292, 294, 134, 293, 81, 0, 116, 181, + 142, 103, 171, 101, 0, 0, 0, 0, 0, 115, + 296, 117, 0, 0, 153, 126, 0, 0, 0, 0, + 287, 288, 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 254, 275, 274, 277, 278, 279, 280, + 0, 0, 94, 276, 281, 282, 283, 0, 0, 0, + 268, 0, 295, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 265, 266, 0, 0, 0, 0, 307, 0, + 267, 0, 0, 262, 263, 264, 269, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, + 0, 0, 305, 0, 140, 0, 156, 106, 114, 82, + 88, 0, 105, 132, 145, 149, 0, 0, 0, 97, + 0, 147, 136, 168, 1347, 137, 146, 118, 160, 141, + 167, 200, 175, 158, 174, 83, 157, 166, 95, 150, + 85, 164, 155, 124, 110, 111, 84, 0, 144, 100, + 104, 99, 133, 161, 162, 98, 183, 89, 173, 87, + 90, 172, 131, 159, 165, 125, 122, 86, 163, 123, + 121, 113, 102, 107, 138, 120, 139, 108, 128, 127, + 129, 0, 0, 0, 154, 170, 184, 92, 0, 0, + 176, 177, 178, 179, 180, 0, 0, 93, 130, 91, + 109, 151, 112, 119, 143, 182, 135, 148, 96, 169, + 152, 297, 306, 303, 304, 301, 302, 300, 299, 298, + 308, 289, 290, 291, 292, 294, 134, 293, 81, 0, + 116, 181, 142, 103, 171, 101, 0, 0, 0, 0, + 0, 115, 296, 117, 0, 0, 153, 126, 0, 0, + 0, 0, 287, 288, 0, 0, 0, 0, 0, 0, + 0, 0, 52, 0, 0, 254, 275, 274, 277, 278, + 279, 280, 0, 0, 94, 276, 281, 282, 283, 0, + 0, 0, 268, 0, 295, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 265, 266, 0, 0, 0, 0, + 307, 0, 267, 0, 0, 262, 263, 264, 269, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 199, 0, 0, 305, 0, 140, 0, 156, 106, + 114, 82, 88, 0, 105, 132, 145, 149, 0, 0, + 0, 97, 0, 147, 136, 168, 0, 137, 146, 118, + 160, 141, 167, 200, 175, 158, 174, 83, 157, 166, + 95, 150, 85, 164, 155, 124, 110, 111, 84, 0, + 144, 100, 104, 99, 133, 161, 162, 98, 183, 89, + 173, 87, 90, 172, 131, 159, 165, 125, 122, 86, + 163, 123, 121, 113, 102, 107, 138, 120, 139, 108, + 128, 127, 129, 0, 0, 0, 154, 170, 184, 92, + 0, 0, 176, 177, 178, 179, 180, 0, 0, 93, + 130, 91, 109, 151, 112, 119, 143, 182, 135, 148, + 96, 169, 152, 297, 306, 303, 304, 301, 302, 300, + 299, 298, 308, 289, 290, 291, 292, 294, 134, 293, + 81, 0, 116, 181, 142, 103, 171, 101, 0, 0, + 0, 0, 0, 115, 0, 117, 0, 0, 153, 126, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, + 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 513, 512, 522, 523, 515, 516, 517, 518, + 519, 520, 521, 514, 0, 0, 524, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 199, 0, 0, 0, 0, 140, 0, + 156, 106, 114, 82, 88, 0, 105, 132, 145, 149, + 0, 0, 0, 97, 0, 147, 136, 168, 0, 137, + 146, 118, 160, 141, 167, 200, 175, 158, 174, 83, + 157, 166, 95, 150, 85, 164, 155, 124, 110, 111, + 84, 0, 144, 100, 104, 99, 133, 161, 162, 98, + 183, 89, 173, 87, 90, 172, 131, 159, 165, 125, + 122, 86, 163, 123, 121, 113, 102, 107, 138, 120, + 139, 108, 128, 127, 129, 0, 0, 0, 154, 170, + 184, 92, 0, 0, 176, 177, 178, 179, 180, 0, + 0, 93, 130, 91, 109, 151, 112, 119, 143, 182, + 135, 148, 96, 169, 152, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 134, 0, 0, 0, 501, 0, + 0, 0, 81, 101, 116, 181, 142, 103, 171, 115, + 0, 117, 0, 0, 153, 126, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 79, 0, 503, 0, 0, 0, 0, + 0, 0, 94, 0, 0, 0, 0, 498, 497, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, + 0, 0, 0, 0, 140, 0, 156, 106, 114, 82, + 88, 0, 105, 132, 145, 149, 0, 0, 0, 97, + 0, 147, 136, 168, 0, 137, 146, 118, 160, 141, + 167, 200, 175, 158, 174, 83, 157, 166, 95, 150, + 85, 164, 155, 124, 110, 111, 84, 0, 144, 100, + 104, 99, 133, 161, 162, 98, 183, 89, 173, 87, + 90, 172, 131, 159, 165, 125, 122, 86, 163, 123, + 121, 113, 102, 107, 138, 120, 139, 108, 128, 127, + 129, 0, 0, 0, 154, 170, 184, 92, 0, 0, + 176, 177, 178, 179, 180, 0, 0, 93, 130, 91, + 109, 151, 112, 119, 143, 182, 135, 148, 96, 169, + 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134, 0, 0, 0, 0, 0, 0, 0, 81, 101, + 116, 181, 142, 103, 171, 115, 0, 117, 0, 0, + 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, + 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 75, 76, 0, 71, 0, 0, 0, 77, + 140, 0, 156, 106, 114, 82, 88, 0, 105, 132, + 145, 149, 0, 0, 0, 97, 0, 147, 136, 168, + 0, 137, 146, 118, 160, 141, 167, 73, 175, 158, + 174, 83, 157, 166, 95, 150, 85, 164, 155, 124, + 110, 111, 84, 0, 144, 100, 104, 99, 133, 161, + 162, 98, 183, 89, 173, 87, 90, 172, 131, 159, + 165, 125, 122, 86, 163, 123, 121, 113, 102, 107, + 138, 120, 139, 108, 128, 127, 129, 0, 0, 0, + 154, 170, 184, 92, 0, 0, 176, 177, 178, 179, + 180, 0, 0, 93, 130, 91, 109, 151, 112, 119, + 143, 182, 135, 148, 96, 169, 152, 0, 74, 0, + 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, + 598, 0, 0, 0, 81, 101, 116, 181, 142, 103, + 171, 115, 0, 117, 0, 0, 153, 126, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 197, 0, 600, 0, 0, + 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 199, 0, 0, 0, 0, 140, 0, 156, 106, + 114, 82, 88, 0, 105, 132, 145, 149, 0, 0, + 0, 97, 0, 147, 136, 168, 0, 137, 146, 118, + 160, 141, 167, 200, 175, 158, 174, 83, 157, 166, + 95, 150, 85, 164, 155, 124, 110, 111, 84, 0, + 144, 100, 104, 99, 133, 161, 162, 98, 183, 89, + 173, 87, 90, 172, 131, 159, 165, 125, 122, 86, + 163, 123, 121, 113, 102, 107, 138, 120, 139, 108, + 128, 127, 129, 0, 0, 0, 154, 170, 184, 92, + 0, 0, 176, 177, 178, 179, 180, 0, 0, 93, + 130, 91, 109, 151, 112, 119, 143, 182, 135, 148, + 96, 169, 152, 0, 0, 0, 23, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, + 81, 0, 116, 181, 142, 103, 171, 101, 0, 0, + 0, 0, 0, 115, 0, 117, 0, 0, 153, 126, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 52, 0, 0, 79, 0, 0, + 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 199, 0, 0, 0, 0, 140, 0, + 156, 106, 114, 82, 88, 0, 105, 132, 145, 149, + 0, 0, 0, 97, 0, 147, 136, 168, 0, 137, + 146, 118, 160, 141, 167, 200, 175, 158, 174, 83, + 157, 166, 95, 150, 85, 164, 155, 124, 110, 111, + 84, 0, 144, 100, 104, 99, 133, 161, 162, 98, + 183, 89, 173, 87, 90, 172, 131, 159, 165, 125, + 122, 86, 163, 123, 121, 113, 102, 107, 138, 120, + 139, 108, 128, 127, 129, 0, 0, 0, 154, 170, + 184, 92, 0, 0, 176, 177, 178, 179, 180, 0, + 0, 93, 130, 91, 109, 151, 112, 119, 143, 182, + 135, 148, 96, 169, 152, 0, 0, 0, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134, 0, 81, 0, 116, 181, 142, 103, 171, 101, + 0, 0, 0, 0, 0, 115, 0, 117, 0, 0, + 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 52, 0, 0, 197, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, + 140, 0, 156, 106, 114, 82, 88, 0, 105, 132, + 145, 149, 0, 0, 0, 97, 0, 147, 136, 168, + 0, 137, 146, 118, 160, 141, 167, 200, 175, 158, + 174, 83, 157, 166, 95, 150, 85, 164, 155, 124, + 110, 111, 84, 0, 144, 100, 104, 99, 133, 161, + 162, 98, 183, 89, 173, 87, 90, 172, 131, 159, + 165, 125, 122, 86, 163, 123, 121, 113, 102, 107, + 138, 120, 139, 108, 128, 127, 129, 0, 0, 0, + 154, 170, 184, 92, 0, 0, 176, 177, 178, 179, + 180, 0, 0, 93, 130, 91, 109, 151, 112, 119, + 143, 182, 135, 148, 96, 169, 152, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, + 0, 0, 0, 0, 81, 101, 116, 181, 142, 103, + 171, 115, 0, 117, 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 79, 0, 0, 721, 0, + 0, 722, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, - 0, 0, 0, 137, 0, 0, 152, 104, 103, 142, - 112, 0, 0, 0, 95, 0, 144, 133, 164, 0, - 134, 143, 116, 156, 138, 163, 196, 171, 154, 170, - 82, 153, 162, 93, 146, 84, 160, 151, 122, 108, - 109, 83, 0, 141, 98, 102, 97, 130, 157, 158, - 96, 179, 87, 169, 86, 88, 168, 129, 155, 161, - 123, 120, 85, 159, 121, 119, 111, 100, 105, 135, - 118, 136, 106, 126, 125, 127, 0, 0, 0, 150, - 166, 180, 90, 0, 0, 172, 173, 174, 175, 176, - 0, 0, 91, 128, 89, 107, 147, 110, 117, 140, - 178, 132, 145, 94, 165, 148, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 131, 0, 81, 0, 114, 177, 139, 101, 167, - 99, 0, 0, 0, 0, 0, 113, 0, 115, 0, - 0, 149, 124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, - 193, 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 199, 0, 0, 0, 0, 140, 0, 156, 106, + 114, 82, 88, 0, 105, 132, 145, 149, 0, 0, + 0, 97, 0, 147, 136, 168, 0, 137, 146, 118, + 160, 141, 167, 200, 175, 158, 174, 83, 157, 166, + 95, 150, 85, 164, 155, 124, 110, 111, 84, 0, + 144, 100, 104, 99, 133, 161, 162, 98, 183, 89, + 173, 87, 90, 172, 131, 159, 165, 125, 122, 86, + 163, 123, 121, 113, 102, 107, 138, 120, 139, 108, + 128, 127, 129, 0, 0, 0, 154, 170, 184, 92, + 0, 0, 176, 177, 178, 179, 180, 0, 0, 93, + 130, 91, 109, 151, 112, 119, 143, 182, 135, 148, + 96, 169, 152, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 134, 0, + 81, 0, 116, 181, 142, 103, 171, 101, 0, 618, + 0, 0, 0, 115, 0, 117, 0, 0, 153, 126, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 79, 0, 617, + 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, - 0, 137, 0, 0, 152, 104, 103, 142, 112, 0, - 0, 0, 95, 0, 144, 133, 164, 0, 134, 143, - 116, 156, 138, 163, 196, 171, 154, 170, 82, 153, - 162, 93, 146, 84, 160, 151, 122, 108, 109, 83, - 0, 141, 98, 102, 97, 130, 157, 158, 96, 179, - 87, 169, 86, 88, 168, 129, 155, 161, 123, 120, - 85, 159, 121, 119, 111, 100, 105, 135, 118, 136, - 106, 126, 125, 127, 0, 0, 0, 150, 166, 180, - 90, 0, 0, 172, 173, 174, 175, 176, 0, 0, - 91, 128, 89, 107, 147, 110, 117, 140, 178, 132, - 145, 94, 165, 148, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, - 0, 81, 99, 114, 177, 139, 101, 167, 113, 0, - 115, 0, 0, 149, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 79, 0, 0, 717, 0, 0, 718, 0, - 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 199, 0, 0, 0, 0, 140, 0, + 156, 106, 114, 82, 88, 0, 105, 132, 145, 149, + 0, 0, 0, 97, 0, 147, 136, 168, 0, 137, + 146, 118, 160, 141, 167, 200, 175, 158, 174, 83, + 157, 166, 95, 150, 85, 164, 155, 124, 110, 111, + 84, 0, 144, 100, 104, 99, 133, 161, 162, 98, + 183, 89, 173, 87, 90, 172, 131, 159, 165, 125, + 122, 86, 163, 123, 121, 113, 102, 107, 138, 120, + 139, 108, 128, 127, 129, 0, 0, 0, 154, 170, + 184, 92, 0, 0, 176, 177, 178, 179, 180, 0, + 0, 93, 130, 91, 109, 151, 112, 119, 143, 182, + 135, 148, 96, 169, 152, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 134, 0, 0, 0, 598, 0, + 0, 0, 81, 101, 116, 181, 142, 103, 171, 115, + 0, 117, 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 197, 0, 600, 0, 0, 0, 0, + 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, - 0, 0, 0, 137, 0, 0, 152, 104, 103, 142, - 112, 0, 0, 0, 95, 0, 144, 133, 164, 0, - 134, 143, 116, 156, 138, 163, 196, 171, 154, 170, - 82, 153, 162, 93, 146, 84, 160, 151, 122, 108, - 109, 83, 0, 141, 98, 102, 97, 130, 157, 158, - 96, 179, 87, 169, 86, 88, 168, 129, 155, 161, - 123, 120, 85, 159, 121, 119, 111, 100, 105, 135, - 118, 136, 106, 126, 125, 127, 0, 0, 0, 150, - 166, 180, 90, 0, 0, 172, 173, 174, 175, 176, - 0, 0, 91, 128, 89, 107, 147, 110, 117, 140, - 178, 132, 145, 94, 165, 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 131, 0, 81, 0, 114, 177, 139, 101, 167, - 99, 0, 614, 0, 0, 0, 113, 0, 115, 0, - 0, 149, 124, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 199, + 0, 0, 0, 0, 140, 0, 156, 106, 114, 82, + 88, 0, 105, 132, 145, 149, 0, 0, 0, 97, + 0, 147, 136, 168, 0, 596, 146, 118, 160, 141, + 167, 200, 175, 158, 174, 83, 157, 166, 95, 150, + 85, 164, 155, 124, 110, 111, 84, 0, 144, 100, + 104, 99, 133, 161, 162, 98, 183, 89, 173, 87, + 90, 172, 131, 159, 165, 125, 122, 86, 163, 123, + 121, 113, 102, 107, 138, 120, 139, 108, 128, 127, + 129, 0, 0, 0, 154, 170, 184, 92, 0, 0, + 176, 177, 178, 179, 180, 0, 0, 93, 130, 91, + 109, 151, 112, 119, 143, 182, 135, 148, 96, 169, + 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 134, 0, 0, 0, 0, 0, 0, 0, 81, 101, + 116, 181, 142, 103, 171, 115, 0, 117, 0, 0, + 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 52, 0, 0, 197, + 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 79, 0, 613, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, + 140, 0, 156, 106, 114, 82, 88, 0, 105, 132, + 145, 149, 0, 0, 0, 97, 0, 147, 136, 168, + 0, 137, 146, 118, 160, 141, 167, 200, 175, 158, + 174, 83, 157, 166, 95, 150, 85, 164, 155, 124, + 110, 111, 84, 0, 144, 100, 104, 99, 133, 161, + 162, 98, 183, 89, 173, 87, 90, 172, 131, 159, + 165, 125, 122, 86, 163, 123, 121, 113, 102, 107, + 138, 120, 139, 108, 128, 127, 129, 0, 0, 0, + 154, 170, 184, 92, 0, 0, 176, 177, 178, 179, + 180, 0, 0, 93, 130, 91, 109, 151, 112, 119, + 143, 182, 135, 148, 96, 169, 152, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 134, 0, 0, 0, + 0, 0, 0, 0, 81, 101, 116, 181, 142, 103, + 171, 115, 0, 117, 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, - 0, 137, 0, 0, 152, 104, 103, 142, 112, 0, - 0, 0, 95, 0, 144, 133, 164, 0, 134, 143, - 116, 156, 138, 163, 196, 171, 154, 170, 82, 153, - 162, 93, 146, 84, 160, 151, 122, 108, 109, 83, - 0, 141, 98, 102, 97, 130, 157, 158, 96, 179, - 87, 169, 86, 88, 168, 129, 155, 161, 123, 120, - 85, 159, 121, 119, 111, 100, 105, 135, 118, 136, - 106, 126, 125, 127, 0, 0, 0, 150, 166, 180, - 90, 0, 0, 172, 173, 174, 175, 176, 0, 0, - 91, 128, 89, 107, 147, 110, 117, 140, 178, 132, - 145, 94, 165, 148, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 131, 0, 0, 0, 594, 0, 0, - 0, 81, 99, 114, 177, 139, 101, 167, 113, 0, - 115, 0, 0, 149, 124, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 197, 0, 600, 0, 0, + 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 193, 0, 596, 0, 0, 0, 0, 0, - 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, - 0, 0, 0, 137, 0, 0, 152, 104, 103, 142, - 112, 0, 0, 0, 95, 0, 144, 133, 164, 0, - 592, 143, 116, 156, 138, 163, 196, 171, 154, 170, - 82, 153, 162, 93, 146, 84, 160, 151, 122, 108, - 109, 83, 0, 141, 98, 102, 97, 130, 157, 158, - 96, 179, 87, 169, 86, 88, 168, 129, 155, 161, - 123, 120, 85, 159, 121, 119, 111, 100, 105, 135, - 118, 136, 106, 126, 125, 127, 0, 0, 0, 150, - 166, 180, 90, 0, 0, 172, 173, 174, 175, 176, - 0, 0, 91, 128, 89, 107, 147, 110, 117, 140, - 178, 132, 145, 94, 165, 148, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, - 0, 0, 0, 81, 99, 114, 177, 139, 101, 167, - 113, 0, 115, 0, 0, 149, 124, 0, 0, 0, + 0, 199, 0, 0, 0, 0, 140, 0, 156, 106, + 114, 82, 88, 0, 105, 132, 145, 149, 0, 0, + 0, 97, 0, 147, 136, 168, 0, 137, 146, 118, + 160, 141, 167, 200, 175, 158, 174, 83, 157, 166, + 95, 150, 85, 164, 155, 124, 110, 111, 84, 0, + 144, 100, 104, 99, 133, 161, 162, 98, 183, 89, + 173, 87, 90, 172, 131, 159, 165, 125, 122, 86, + 163, 123, 121, 113, 102, 107, 138, 120, 139, 108, + 128, 127, 129, 0, 0, 0, 154, 170, 184, 92, + 0, 0, 176, 177, 178, 179, 180, 0, 0, 93, + 130, 91, 109, 151, 112, 119, 143, 182, 135, 148, + 96, 169, 152, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 134, 0, 0, 0, 0, 0, 0, 0, + 81, 101, 116, 181, 142, 103, 171, 115, 0, 117, + 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 79, 0, 503, 0, 0, 0, 0, 0, 0, + 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 52, 0, 0, 193, 0, 0, 0, 0, 0, - 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, + 0, 0, 140, 0, 156, 106, 114, 82, 88, 0, + 105, 132, 145, 149, 0, 0, 0, 97, 0, 147, + 136, 168, 0, 137, 146, 118, 160, 141, 167, 200, + 175, 158, 174, 83, 157, 166, 95, 150, 85, 164, + 155, 124, 110, 111, 84, 0, 144, 100, 104, 99, + 133, 161, 162, 98, 183, 89, 173, 87, 90, 172, + 131, 159, 165, 125, 122, 86, 163, 123, 121, 113, + 102, 107, 138, 120, 139, 108, 128, 127, 129, 0, + 0, 0, 154, 170, 184, 92, 0, 0, 176, 177, + 178, 179, 180, 0, 0, 93, 130, 91, 109, 151, + 112, 119, 143, 182, 135, 148, 96, 169, 152, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 134, 81, 0, 116, 181, + 142, 103, 171, 576, 101, 0, 0, 0, 0, 0, + 115, 0, 117, 0, 0, 153, 126, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 195, 0, 0, 0, 0, 137, 0, 0, 152, 104, - 103, 142, 112, 0, 0, 0, 95, 0, 144, 133, - 164, 0, 134, 143, 116, 156, 138, 163, 196, 171, - 154, 170, 82, 153, 162, 93, 146, 84, 160, 151, - 122, 108, 109, 83, 0, 141, 98, 102, 97, 130, - 157, 158, 96, 179, 87, 169, 86, 88, 168, 129, - 155, 161, 123, 120, 85, 159, 121, 119, 111, 100, - 105, 135, 118, 136, 106, 126, 125, 127, 0, 0, - 0, 150, 166, 180, 90, 0, 0, 172, 173, 174, - 175, 176, 0, 0, 91, 128, 89, 107, 147, 110, - 117, 140, 178, 132, 145, 94, 165, 148, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, - 0, 0, 0, 0, 0, 81, 99, 114, 177, 139, - 101, 167, 113, 0, 115, 0, 0, 149, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 193, 0, 596, 0, - 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 199, 0, 0, 0, 0, 140, 0, 156, 106, 114, + 82, 88, 0, 105, 132, 145, 149, 0, 0, 0, + 97, 0, 147, 136, 168, 0, 137, 146, 118, 160, + 141, 167, 200, 175, 158, 174, 83, 157, 166, 95, + 150, 85, 164, 155, 124, 110, 111, 84, 0, 144, + 100, 104, 99, 133, 161, 162, 98, 183, 89, 173, + 87, 90, 172, 131, 159, 165, 125, 122, 86, 163, + 123, 121, 113, 102, 107, 138, 120, 139, 108, 128, + 127, 129, 0, 0, 0, 154, 170, 184, 92, 0, + 0, 176, 177, 178, 179, 180, 0, 0, 93, 130, + 91, 109, 151, 112, 119, 143, 182, 135, 148, 96, + 169, 152, 0, 0, 318, 0, 0, 0, 0, 0, + 0, 134, 0, 0, 0, 0, 0, 0, 0, 81, + 101, 116, 181, 142, 103, 171, 115, 0, 117, 0, + 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 195, 0, 0, 0, 0, 137, 0, 0, - 152, 104, 103, 142, 112, 0, 0, 0, 95, 0, - 144, 133, 164, 0, 134, 143, 116, 156, 138, 163, - 196, 171, 154, 170, 82, 153, 162, 93, 146, 84, - 160, 151, 122, 108, 109, 83, 0, 141, 98, 102, - 97, 130, 157, 158, 96, 179, 87, 169, 86, 88, - 168, 129, 155, 161, 123, 120, 85, 159, 121, 119, - 111, 100, 105, 135, 118, 136, 106, 126, 125, 127, - 0, 0, 0, 150, 166, 180, 90, 0, 0, 172, - 173, 174, 175, 176, 0, 0, 91, 128, 89, 107, - 147, 110, 117, 140, 178, 132, 145, 94, 165, 148, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, - 0, 0, 0, 0, 0, 0, 0, 81, 99, 114, - 177, 139, 101, 167, 113, 0, 115, 0, 0, 149, - 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, - 499, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, + 0, 140, 0, 156, 106, 114, 82, 88, 0, 105, + 132, 145, 149, 0, 0, 0, 97, 0, 147, 136, + 168, 0, 137, 146, 118, 160, 141, 167, 200, 175, + 158, 174, 83, 157, 166, 95, 150, 85, 164, 155, + 124, 110, 111, 84, 0, 144, 100, 104, 99, 133, + 161, 162, 98, 183, 89, 173, 87, 90, 172, 131, + 159, 165, 125, 122, 86, 163, 123, 121, 113, 102, + 107, 138, 120, 139, 108, 128, 127, 129, 0, 0, + 0, 154, 170, 184, 92, 0, 0, 176, 177, 178, + 179, 180, 0, 0, 93, 130, 91, 109, 151, 112, + 119, 143, 182, 135, 148, 96, 169, 152, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 134, 0, 0, + 0, 0, 0, 0, 0, 81, 101, 116, 181, 142, + 103, 171, 115, 0, 117, 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 195, 0, 0, 0, 0, 137, - 0, 0, 152, 104, 103, 142, 112, 0, 0, 0, - 95, 0, 144, 133, 164, 0, 134, 143, 116, 156, - 138, 163, 196, 171, 154, 170, 82, 153, 162, 93, - 146, 84, 160, 151, 122, 108, 109, 83, 0, 141, - 98, 102, 97, 130, 157, 158, 96, 179, 87, 169, - 86, 88, 168, 129, 155, 161, 123, 120, 85, 159, - 121, 119, 111, 100, 105, 135, 118, 136, 106, 126, - 125, 127, 0, 0, 0, 150, 166, 180, 90, 0, - 0, 172, 173, 174, 175, 176, 0, 0, 91, 128, - 89, 107, 147, 110, 117, 140, 178, 132, 145, 94, - 165, 148, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 131, 81, - 0, 114, 177, 139, 101, 167, 572, 99, 0, 0, - 0, 0, 0, 113, 0, 115, 0, 0, 149, 124, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 193, 0, 0, - 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 195, 0, 0, 0, 0, 137, 0, - 0, 152, 104, 103, 142, 112, 0, 0, 0, 95, - 0, 144, 133, 164, 0, 134, 143, 116, 156, 138, - 163, 196, 171, 154, 170, 82, 153, 162, 93, 146, - 84, 160, 151, 122, 108, 109, 83, 0, 141, 98, - 102, 97, 130, 157, 158, 96, 179, 87, 169, 86, - 88, 168, 129, 155, 161, 123, 120, 85, 159, 121, - 119, 111, 100, 105, 135, 118, 136, 106, 126, 125, - 127, 0, 0, 0, 150, 166, 180, 90, 0, 0, - 172, 173, 174, 175, 176, 0, 0, 91, 128, 89, - 107, 147, 110, 117, 140, 178, 132, 145, 94, 165, - 148, 0, 0, 314, 0, 0, 0, 0, 0, 0, - 131, 0, 0, 0, 0, 0, 0, 0, 81, 99, - 114, 177, 139, 101, 167, 113, 0, 115, 0, 0, - 149, 124, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 194, 0, 199, 0, 0, 0, 0, 140, 0, 156, + 106, 114, 82, 88, 0, 105, 132, 145, 149, 0, + 0, 0, 97, 0, 147, 136, 168, 0, 137, 146, + 118, 160, 141, 167, 200, 175, 158, 174, 83, 157, + 166, 95, 150, 85, 164, 155, 124, 110, 111, 84, + 0, 144, 100, 104, 99, 133, 161, 162, 98, 183, + 89, 173, 87, 90, 172, 131, 159, 165, 125, 122, + 86, 163, 123, 121, 113, 102, 107, 138, 120, 139, + 108, 128, 127, 129, 0, 0, 0, 154, 170, 184, + 92, 0, 0, 176, 177, 178, 179, 180, 0, 0, + 93, 130, 91, 109, 151, 112, 119, 143, 182, 135, + 148, 96, 169, 152, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 134, 0, 0, 0, 0, 0, 0, + 0, 81, 101, 116, 181, 142, 103, 171, 115, 0, + 117, 0, 0, 153, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, - 137, 0, 0, 152, 104, 103, 142, 112, 0, 0, - 0, 95, 0, 144, 133, 164, 0, 134, 143, 116, - 156, 138, 163, 196, 171, 154, 170, 82, 153, 162, - 93, 146, 84, 160, 151, 122, 108, 109, 83, 0, - 141, 98, 102, 97, 130, 157, 158, 96, 179, 87, - 169, 86, 88, 168, 129, 155, 161, 123, 120, 85, - 159, 121, 119, 111, 100, 105, 135, 118, 136, 106, - 126, 125, 127, 0, 0, 0, 150, 166, 180, 90, - 0, 0, 172, 173, 174, 175, 176, 0, 0, 91, - 128, 89, 107, 147, 110, 117, 140, 178, 132, 145, - 94, 165, 148, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, - 81, 99, 114, 177, 139, 101, 167, 113, 0, 115, - 0, 0, 149, 124, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 193, 0, 0, 0, 0, 0, 0, 0, 0, - 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 190, 0, 195, 0, 0, - 0, 0, 137, 0, 0, 152, 104, 103, 142, 112, - 0, 0, 0, 95, 0, 144, 133, 164, 0, 134, - 143, 116, 156, 138, 163, 196, 171, 154, 170, 82, - 153, 162, 93, 146, 84, 160, 151, 122, 108, 109, - 83, 0, 141, 98, 102, 97, 130, 157, 158, 96, - 179, 87, 169, 86, 88, 168, 129, 155, 161, 123, - 120, 85, 159, 121, 119, 111, 100, 105, 135, 118, - 136, 106, 126, 125, 127, 0, 0, 0, 150, 166, - 180, 90, 0, 0, 172, 173, 174, 175, 176, 0, - 0, 91, 128, 89, 107, 147, 110, 117, 140, 178, - 132, 145, 94, 165, 148, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, - 0, 0, 81, 99, 114, 177, 139, 101, 167, 113, - 0, 115, 0, 0, 149, 124, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, - 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, - 0, 0, 0, 0, 137, 0, 0, 152, 104, 103, - 142, 112, 0, 0, 0, 95, 0, 144, 133, 164, - 0, 134, 143, 116, 156, 138, 163, 196, 171, 154, - 170, 82, 153, 162, 93, 146, 84, 160, 151, 122, - 108, 109, 83, 0, 141, 98, 102, 97, 130, 157, - 158, 96, 179, 87, 169, 86, 88, 168, 129, 155, - 161, 123, 120, 85, 159, 121, 119, 111, 100, 105, - 135, 118, 136, 106, 126, 125, 127, 0, 0, 0, - 150, 166, 180, 90, 0, 0, 172, 173, 174, 175, - 176, 0, 0, 91, 128, 89, 107, 147, 110, 117, - 140, 178, 132, 145, 94, 165, 148, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, - 0, 0, 0, 0, 81, 99, 114, 177, 139, 101, - 167, 113, 0, 115, 0, 0, 149, 124, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, - 0, 0, 0, 0, 92, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 195, 0, 0, 0, 0, 137, 0, 0, 152, - 104, 103, 142, 112, 0, 0, 0, 95, 0, 144, - 133, 164, 0, 134, 143, 116, 156, 138, 163, 196, - 171, 154, 170, 82, 153, 162, 93, 146, 84, 160, - 151, 122, 108, 109, 83, 0, 141, 98, 102, 97, - 130, 157, 158, 96, 179, 87, 169, 86, 88, 168, - 129, 155, 161, 123, 120, 85, 159, 121, 119, 111, - 100, 105, 135, 118, 136, 106, 126, 125, 127, 0, - 0, 0, 150, 166, 180, 90, 0, 0, 172, 173, - 174, 175, 176, 0, 0, 91, 128, 89, 107, 147, - 110, 117, 140, 178, 132, 145, 94, 165, 148, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, - 0, 0, 0, 0, 0, 0, 81, 99, 114, 177, - 139, 101, 167, 113, 0, 115, 0, 0, 149, 124, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, - 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 195, 0, 0, 0, 0, 137, 0, - 0, 152, 104, 103, 142, 112, 0, 0, 0, 95, - 0, 144, 133, 164, 0, 134, 143, 116, 156, 138, - 163, 196, 171, 154, 170, 82, 153, 162, 93, 146, - 84, 160, 151, 122, 108, 109, 83, 0, 141, 98, - 102, 97, 130, 157, 158, 96, 179, 87, 169, 86, - 88, 168, 129, 155, 161, 123, 120, 85, 159, 121, - 119, 111, 100, 105, 135, 118, 136, 106, 126, 125, - 127, 0, 0, 0, 150, 166, 180, 90, 0, 0, - 172, 173, 174, 175, 176, 0, 0, 91, 128, 89, - 107, 147, 110, 117, 140, 178, 132, 145, 94, 165, - 148, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, - 114, 177, 139, 101, 167, + 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, + 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, + 0, 0, 0, 140, 0, 156, 106, 114, 82, 88, + 0, 105, 132, 145, 149, 0, 0, 0, 97, 0, + 147, 136, 168, 0, 137, 146, 118, 160, 141, 167, + 200, 175, 158, 174, 83, 157, 166, 95, 150, 85, + 164, 155, 124, 110, 111, 84, 0, 144, 100, 104, + 99, 133, 161, 162, 98, 183, 89, 173, 87, 90, + 172, 131, 159, 165, 125, 122, 86, 163, 123, 121, + 113, 102, 107, 138, 120, 139, 108, 128, 127, 129, + 0, 0, 0, 154, 170, 184, 92, 0, 0, 176, + 177, 178, 179, 180, 0, 0, 93, 130, 91, 109, + 151, 112, 119, 143, 182, 135, 148, 96, 169, 152, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, + 0, 0, 0, 0, 0, 0, 0, 81, 101, 116, + 181, 142, 103, 171, 115, 0, 117, 0, 0, 153, + 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 199, 0, 0, 0, 0, 140, + 0, 156, 106, 114, 82, 88, 0, 105, 132, 145, + 149, 0, 0, 0, 97, 0, 147, 136, 168, 0, + 137, 146, 118, 160, 141, 167, 200, 175, 158, 174, + 83, 157, 166, 95, 150, 85, 164, 155, 124, 110, + 111, 84, 0, 144, 100, 104, 99, 133, 161, 162, + 98, 183, 89, 173, 87, 90, 172, 131, 159, 165, + 125, 122, 86, 163, 123, 121, 113, 102, 107, 138, + 120, 139, 108, 128, 127, 129, 0, 0, 0, 154, + 170, 184, 92, 0, 0, 176, 177, 178, 179, 180, + 0, 0, 93, 130, 91, 109, 151, 112, 119, 143, + 182, 135, 148, 96, 169, 152, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 134, 0, 0, 0, 0, + 0, 0, 0, 81, 101, 116, 181, 142, 103, 171, + 115, 0, 117, 0, 0, 153, 126, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 254, 0, 0, 0, 0, 0, + 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 199, 0, 0, 0, 0, 140, 0, 156, 106, 114, + 82, 88, 0, 105, 132, 145, 149, 0, 0, 0, + 97, 0, 147, 136, 168, 0, 137, 146, 118, 160, + 141, 167, 200, 175, 158, 174, 83, 157, 166, 95, + 150, 85, 164, 155, 124, 110, 111, 84, 0, 144, + 100, 104, 99, 133, 161, 162, 98, 183, 89, 173, + 87, 90, 172, 131, 159, 165, 125, 122, 86, 163, + 123, 121, 113, 102, 107, 138, 120, 139, 108, 128, + 127, 129, 0, 0, 0, 154, 170, 184, 92, 0, + 0, 176, 177, 178, 179, 180, 0, 0, 93, 130, + 91, 109, 151, 112, 119, 143, 182, 135, 148, 96, + 169, 152, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, + 0, 116, 181, 142, 103, 171, } var yyPact = [...]int{ - 125, -1000, -180, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 1474, -1000, -190, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 849, 876, -1000, -1000, -1000, -1000, -1000, -1000, 278, - 7715, 59, 89, -19, 10404, 85, 1397, 10848, -1000, -9, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -81, -83, 637, - -1000, -1000, -1000, -1000, -1000, 843, 847, 650, 823, 748, - -1000, 5873, 52, 9287, 10182, 5162, -1000, -1000, 266, 10848, - 78, 10848, -151, 10626, 48, 48, 48, -1000, -1000, -1000, + -1000, 862, 900, -1000, -1000, -1000, -1000, -1000, -1000, 213, + 7652, 73, 97, -15, 10389, 95, 1518, 10841, -1000, -6, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -95, -109, 659, + -1000, -1000, -1000, -1000, -1000, 855, 860, 722, 849, 790, + -1000, 5778, 50, 9252, 10163, 5055, -1000, -1000, 194, 10841, + 90, 10841, -158, 10615, 58, 58, 58, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -1816,22 +1825,22 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 60, 10848, -1000, 10848, 44, 542, 44, 44, 44, - 10848, -1000, 120, -1000, -1000, -1000, -1000, 10848, 533, 782, - 40, 3162, 3162, 3162, 3162, -2, 3162, -73, 703, 858, - -1000, -1000, -1000, -1000, -1000, 3162, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 441, 791, - 6587, 6587, 849, -1000, 637, -1000, -1000, -1000, 769, -1000, - -1000, 253, 861, -1000, 7493, 119, -1000, 6587, 1382, 645, - -1000, -1000, 645, -1000, -1000, 99, -1000, -1000, 7043, 7043, - 7043, 7043, 7043, 7043, 7043, 7043, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 94, 10841, -1000, 10841, 56, + 502, 56, 56, 56, 10841, -1000, 129, -1000, -1000, -1000, + -1000, 10841, 497, 820, 37, 3023, 3023, 3023, 3023, 4, + 3023, -93, 735, 872, -1000, -1000, -1000, -1000, -1000, 3023, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 645, -1000, 6350, 645, 645, 645, 645, 645, 645, 645, - 645, 6587, 645, 645, 645, 645, 645, 645, 645, 645, - 645, 645, 645, 645, 645, 9960, 590, 644, -1000, -1000, - -1000, 820, 8393, 9065, 10848, 576, -1000, 629, 4912, -97, - -1000, -1000, -1000, 184, 8843, -1000, -1000, -1000, 779, -1000, + -1000, -1000, 415, 826, 6504, 6504, 862, -1000, 659, -1000, + -1000, -1000, 817, -1000, -1000, 291, 878, -1000, 7426, 123, + -1000, 6504, 1891, 423, -1000, -1000, 423, -1000, -1000, 110, + -1000, -1000, 6968, 6968, 6968, 6968, 6968, 6968, 6968, 6968, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 423, -1000, 6263, 423, 423, 423, + 423, 423, 423, 423, 423, 6504, 423, 423, 423, 423, + 423, 423, 423, 423, 423, 423, 423, 423, 423, 9937, + 671, 751, -1000, -1000, -1000, 846, 8342, 9026, 10841, 565, + -1000, 679, 4801, -111, -1000, -1000, -1000, 214, 8800, -1000, + -1000, -1000, 819, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -1840,184 +1849,188 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 541, 10848, -1000, 1934, -1000, 528, 3162, - 55, 670, 527, 205, 518, 10848, 10848, 3162, 49, 10848, - 818, 701, 10848, 515, 510, -1000, 4662, -1000, 3162, 3162, - 3162, 3162, 3162, 3162, 3162, 3162, -1000, -1000, -1000, -1000, - -1000, -1000, 3162, 3162, -1000, 860, 225, -1000, -1000, 10848, - 6587, -1000, -1000, -1000, -1000, -1000, -1000, 871, 146, 483, - 117, 647, -1000, 265, 843, 441, 748, 8615, 676, -1000, - -1000, 10848, -1000, 6587, 6587, 358, -1000, 9731, -1000, -1000, - 3662, 160, 7043, 369, 289, 7043, 7043, 7043, 7043, 7043, - 7043, 7043, 7043, 7043, 7043, 7043, 7043, 7043, 7043, 7043, - 382, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 506, - -1000, 637, 706, 706, 128, 128, 128, 128, 128, 128, - 128, 7271, 5399, 441, 526, 183, 6350, 5873, 5873, 6587, - 6587, 11070, 11070, 5873, 827, 197, 183, 11070, -1000, 441, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 5873, 5873, 5873, - 5873, 20, 10848, -1000, 11070, 9287, 9287, 9287, 9287, 9287, - -1000, 739, 738, -1000, 736, 729, 717, 10848, -1000, 514, - 8393, 121, 645, -1000, 9509, -1000, -1000, 20, 577, 9287, - 10848, -1000, -1000, 4412, 629, -97, 622, -1000, -113, -111, - 6110, 127, -1000, -1000, -1000, -1000, 2912, 263, 556, 329, - -67, -1000, -1000, -1000, 652, -1000, 652, 652, 652, 652, - -38, -38, -38, -38, -1000, -1000, -1000, -1000, -1000, 668, - 667, -1000, 652, 652, 652, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 643, 10841, -1000, + 1975, -1000, 478, 3023, 77, 661, 476, 234, 473, 10841, + 10841, 3023, 61, 10841, 844, 734, 10841, 444, 442, -1000, + 4547, -1000, 3023, 3023, 3023, 3023, 3023, 3023, 3023, 3023, + -1000, -1000, -1000, -1000, -1000, -1000, 3023, 3023, -1000, 875, + 236, -1000, -1000, 10841, 6504, -1000, -1000, -1000, -1000, -1000, + -1000, 895, 155, 391, 122, 681, -1000, 276, 855, 415, + 790, 8568, 745, -1000, -1000, 10841, -1000, 6504, 6504, 272, + -1000, 9704, -1000, -1000, 3531, 167, 6968, 315, 215, 6968, + 6968, 6968, 6968, 6968, 6968, 6968, 6968, 6968, 6968, 6968, + 6968, 6968, 6968, 6968, 345, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 438, -1000, 659, 480, 480, 139, 139, + 139, 139, 139, 139, 139, 7200, 5296, 415, 641, 312, + 6263, 5778, 5778, 6504, 6504, 11067, 11067, 5778, 850, 217, + 312, 11067, -1000, 415, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 5778, 5778, 5778, 5778, 16, 10841, -1000, 11067, 9252, + 9252, 9252, 9252, 9252, -1000, 759, 756, -1000, 772, 768, + 779, 10841, -1000, 556, 8342, 143, 423, -1000, 9478, -1000, + -1000, 16, 554, 9252, 10841, -1000, -1000, 4293, 679, -111, + 670, -1000, -136, -116, 6019, 125, -1000, -1000, -1000, -1000, + 2769, 144, 542, 309, -87, -1000, -1000, -1000, 694, -1000, + 694, 694, 694, 694, -53, -53, -53, -53, -1000, -1000, + -1000, -1000, -1000, 709, 707, -1000, 694, 694, 694, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 666, 666, 666, 653, 653, 671, -1000, 10848, -168, - 505, 3162, 815, 3162, -1000, 80, -1000, 10848, -1000, -1000, - 10848, 3162, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 10848, 235, 10848, - 10848, -1000, 183, -1000, 760, 6587, 6587, 4162, 6587, -1000, - -1000, -1000, 791, -1000, 827, 848, -1000, 773, 772, 5873, - -1000, -1000, 160, 304, -1000, -1000, 391, -1000, -1000, -1000, - -1000, 116, 645, -1000, 1619, -1000, -1000, -1000, -1000, 369, - 7043, 7043, 7043, 318, 1619, 1738, 1528, 1399, 128, 446, - 446, 129, 129, 129, 129, 129, 426, 426, -1000, -1000, - -1000, 441, -1000, -1000, -1000, 441, 5873, 625, -1000, -1000, - 6587, -1000, 441, 501, 501, 334, 311, 628, -1000, 110, - 613, 501, 5873, 324, -1000, 6587, 441, -1000, 501, 441, - 501, 501, 568, 645, -1000, 611, -1000, 178, 644, 665, - 700, 751, -1000, -1000, -1000, -1000, 737, -1000, 728, -1000, - -1000, -1000, -1000, -1000, 71, 70, 66, 10626, -1000, 856, - 9287, 604, -1000, -1000, 622, -97, -119, -1000, -1000, -1000, - 183, -1000, 389, 620, 2662, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 662, 496, -1000, 806, 181, 187, 494, 805, - -1000, -1000, -1000, 784, -1000, 234, -76, -1000, -1000, 372, - -38, -38, -1000, -1000, 127, 778, 127, 127, 127, 403, - 403, -1000, -1000, -1000, -1000, 335, -1000, -1000, -1000, 317, - -1000, 699, 10626, 3162, -1000, 3912, -1000, -1000, -1000, -1000, - -1000, -1000, 230, 166, 186, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 17, -1000, 3162, -1000, - 225, -1000, 398, 6587, -1000, -1000, 752, 183, 183, 108, - -1000, -1000, 10848, -1000, -1000, -1000, -1000, 597, -1000, -1000, - -1000, 3412, 5873, -1000, 318, 1619, 1638, -1000, 7043, 7043, - -1000, -1000, 501, 5873, 183, -1000, -1000, -1000, 47, 382, - 47, 7043, 7043, 4162, 7043, 7043, -161, 595, 189, -1000, - 6587, 415, -1000, -1000, -1000, -1000, -1000, 684, 11070, 645, - -1000, 8165, 10626, 849, 11070, 6587, 6587, -1000, -1000, 6587, - 661, -1000, 6587, -1000, -1000, -1000, 645, 645, 645, 456, - -1000, 849, 604, -1000, -1000, -1000, -131, -116, -1000, -1000, - -1000, 2912, -1000, 2912, 10626, 36, -1000, 476, 464, -1000, - -1000, 658, 674, 39, -1000, -1000, -1000, 547, 127, 127, - -1000, 200, -1000, -1000, -1000, 484, -1000, 480, 618, 462, - 10848, -1000, -1000, 616, -1000, 175, -1000, -1000, 10626, -1000, + -1000, -1000, -1000, -1000, -1000, 701, 701, 701, 695, 695, + 719, -1000, 10841, -174, 434, 3023, 843, 3023, -1000, 64, + -1000, 10841, -1000, -1000, 10841, 3023, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 10626, 10848, -1000, -1000, -1000, -1000, -1000, 10626, -1000, - 235, -1000, 183, -1000, 3912, -1000, 856, 9287, -1000, -1000, - 441, -1000, 7043, 1619, 1619, -1000, -1000, 441, 652, 652, - -1000, 652, 653, -1000, 652, -18, 652, -20, 441, 441, - 1245, 1597, -1000, 379, 1552, 645, -158, -1000, 183, 6587, - -1000, 792, 566, 587, -1000, -1000, 5636, 441, 460, 106, - 456, 843, -1000, 183, 183, 183, 10626, 183, 10626, 10626, - 10626, 7937, 10626, 843, -1000, -1000, -1000, -1000, 2662, -1000, - 454, -1000, 652, -1000, -1000, -1000, 10626, -63, 867, -1000, + -1000, 10841, 242, 10841, 10841, -1000, 312, -1000, 773, 6504, + 6504, 4039, 6504, -1000, -1000, -1000, 826, -1000, 850, 863, + -1000, 810, 808, 5778, -1000, -1000, 167, 181, -1000, -1000, + 264, -1000, -1000, -1000, -1000, 121, 423, -1000, 1992, -1000, + -1000, -1000, -1000, 315, 6968, 6968, 6968, 322, 1992, 2108, + 1254, 1929, 139, 405, 405, 158, 158, 158, 158, 158, + 295, 295, -1000, -1000, -1000, 415, -1000, -1000, -1000, 415, + 5778, 678, -1000, -1000, 6504, -1000, 415, 541, 541, 355, + 240, 713, -1000, 118, 712, 541, 5778, 237, -1000, 6504, + 415, -1000, 541, 415, 541, 541, 673, 423, -1000, 699, + -1000, 210, 751, 725, 732, 580, -1000, -1000, -1000, -1000, + 748, -1000, 747, -1000, -1000, -1000, -1000, -1000, 88, 83, + 82, 10615, -1000, 869, 9252, 682, -1000, -1000, 670, -111, + -139, -1000, -1000, -1000, 312, -1000, 376, 663, 2515, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 698, 421, -1000, 834, + 171, 160, 393, 833, -1000, -1000, -1000, 825, -1000, 252, + -91, -1000, -1000, 371, -53, -53, -1000, -1000, 125, 816, + 125, 125, 125, 406, 406, -1000, -1000, -1000, -1000, 351, + -1000, -1000, -1000, 346, -1000, 730, 10615, 3023, -1000, 3785, + -1000, -1000, -1000, -1000, -1000, -1000, 231, 208, 175, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -38, 383, -38, 296, -1000, 275, 3162, 3912, 2912, -1000, - 651, -1000, -1000, -1000, -1000, 810, -1000, 853, 589, -1000, - 1619, -1000, -1000, 84, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 7043, 7043, -1000, 7043, 7043, 7043, 441, - 370, 183, 799, -1000, 645, -1000, -1000, 601, 10626, 10626, - -1000, -1000, 451, -1000, 449, 449, 449, 121, -1000, -1000, - 114, 10626, -1000, 440, 148, -1000, -139, 127, -1000, 127, - 502, 457, -1000, -1000, -1000, 10626, 645, 851, 846, -1000, - -1000, 1345, 1345, 1345, 1345, 248, -1000, -1000, 864, -1000, - 645, -1000, 637, 90, -1000, 10626, -1000, -1000, -1000, -1000, - -1000, 114, -1000, 427, 169, 325, -1000, 34, 246, 798, - -1000, 795, -1000, -1000, -1000, -1000, -1000, 435, 15, -1000, - 6587, 6587, -1000, -1000, -1000, -1000, 441, 37, -171, 11070, - 587, 441, 10626, -1000, -1000, -1000, 262, -1000, -1000, 10848, - -1000, 267, -1000, -1000, 670, 413, -1000, 10626, 183, 582, - -1000, 747, -166, -174, 559, -1000, -1000, -1000, 649, -1000, - -168, -1000, 15, 768, -1000, 743, -1000, 10626, -1000, -1000, - 11, -169, 410, 5, -172, -1000, 645, -175, 6815, -1000, - 1345, 441, -1000, -1000, + 15, -1000, 3023, -1000, 236, -1000, 402, 6504, -1000, -1000, + 798, 312, 312, 116, -1000, -1000, 10841, -1000, -1000, -1000, + -1000, 677, -1000, -1000, -1000, 3277, 5778, -1000, 322, 1992, + 1970, -1000, 6968, 6968, -1000, -1000, 541, 5778, 312, -1000, + -1000, -1000, 49, 345, 49, 6968, 6968, 4039, 6968, 6968, + -168, 685, 223, -1000, 6504, 422, -1000, -1000, -1000, -1000, + -1000, 729, 11067, 423, -1000, 8110, 10615, 862, 11067, 6504, + 6504, -1000, -1000, 6504, 697, -1000, 6504, -1000, -1000, -1000, + 423, 423, 423, 517, -1000, 862, 682, -1000, -1000, -1000, + -140, -134, -1000, -1000, -1000, 2769, -1000, 2769, 10615, 38, + -1000, 393, 393, -1000, -1000, -1000, 696, 728, 42, -1000, + -1000, -1000, 531, 125, 125, -1000, 185, -1000, -1000, -1000, + 534, -1000, 530, 660, 523, 10841, -1000, -1000, 657, -1000, + 204, -1000, -1000, 10615, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 10615, 10841, -1000, -1000, + -1000, -1000, -1000, 10615, -1000, 242, -1000, 312, -1000, 3785, + -1000, 869, 9252, -1000, -1000, 415, -1000, 6968, 1992, 1992, + -1000, -1000, 415, 694, 694, -1000, 694, 695, -1000, 694, + -21, 694, -22, 415, 415, 1461, 1851, -1000, 426, 1719, + 423, -165, -1000, 312, 6504, -1000, 836, 561, 576, -1000, + -1000, 5537, 415, 519, 114, 517, 855, -1000, 312, 312, + 312, 10615, 312, 10615, 10615, 10615, 7878, 10615, 855, -1000, + -1000, -1000, -1000, 2515, -1000, 515, -1000, 694, -1000, -1000, + -1000, 10615, -82, 894, -1000, -1000, -1000, -1000, 692, -1000, + -1000, -1000, -1000, -1000, -1000, -53, 390, -53, 328, -1000, + 321, 3023, 3785, 2769, -1000, 684, -1000, -1000, -1000, -1000, + 838, -1000, 866, 655, -1000, 1992, -1000, -1000, 72, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 6968, 6968, + -1000, 6968, 6968, 6968, 415, 389, 312, 832, -1000, 423, + -1000, -1000, 675, 10615, 10615, -1000, -1000, 510, -1000, 495, + 495, 495, 143, -1000, -1000, 120, 10615, -1000, 489, 148, + -1000, -148, 507, 125, -1000, 125, 505, 496, -1000, -1000, + -1000, 10615, 423, 864, 859, -1000, -1000, 1698, 1698, 1698, + 1698, 43, -1000, -1000, 890, -1000, 423, -1000, 659, 108, + -1000, 10615, -1000, -1000, -1000, -1000, -1000, 120, -1000, 348, + 182, 380, -1000, 28, 255, 830, -1000, 828, 676, -1000, + -1000, -1000, -1000, -1000, 460, 14, -1000, 6504, 6504, -1000, + -1000, -1000, -1000, 415, 34, -178, 11067, 576, 415, 10615, + -1000, -1000, -1000, 318, -1000, -1000, 10841, -1000, 378, -1000, + -1000, 481, 661, 420, -1000, 10615, 312, 572, -1000, 797, + -172, -181, 545, -1000, -1000, -1000, 581, -1000, -1000, -174, + -1000, 14, 806, -1000, 789, -1000, 10615, -1000, -1000, 8, + -175, 414, 5, -179, 727, 423, -182, 714, -1000, 892, + 6736, -1000, -1000, 886, 147, 147, 1698, 415, -1000, -1000, + -1000, 45, 317, -1000, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 1078, 18, 483, 1077, 1072, 1071, 1070, 1069, 1066, - 1064, 1062, 1061, 1060, 1058, 1057, 1056, 1055, 1054, 1051, - 1050, 1049, 1048, 1047, 91, 1046, 1045, 1043, 58, 1042, - 63, 1041, 1040, 33, 57, 46, 34, 1278, 1038, 26, - 62, 56, 1036, 48, 1034, 1028, 71, 1027, 53, 1026, - 1019, 94, 1016, 1015, 11, 17, 1013, 1012, 1011, 1009, - 60, 592, 1007, 1006, 1003, 997, 995, 994, 44, 3, - 7, 16, 20, 993, 85, 8, 992, 45, 989, 988, - 987, 985, 40, 984, 49, 981, 15, 47, 975, 13, - 55, 28, 21, 5, 69, 51, 971, 25, 54, 43, - 967, 966, 404, 965, 964, 36, 963, 24, 140, 331, - 962, 960, 955, 954, 42, 0, 754, 300, 61, 953, - 952, 951, 1490, 67, 59, 22, 950, 77, 711, 32, - 949, 948, 29, 946, 945, 944, 943, 942, 941, 940, - 187, 939, 936, 935, 76, 10, 934, 933, 50, 30, - 930, 929, 928, 39, 52, 926, 925, 41, 924, 922, - 921, 920, 919, 23, 14, 913, 9, 912, 6, 911, - 27, 905, 1, 903, 12, 902, 2, 901, 4, 37, - 892, 890, 444, 301, 887, 885, 73, + 0, 1133, 50, 473, 1123, 1121, 1120, 1119, 1117, 1116, + 1114, 1113, 1112, 1111, 1110, 1109, 1108, 1106, 1105, 1104, + 1102, 1101, 1095, 1094, 125, 1090, 1087, 1084, 60, 1083, + 58, 1080, 1079, 36, 260, 44, 34, 116, 1078, 26, + 97, 111, 1077, 46, 1076, 1075, 68, 1074, 73, 1072, + 1071, 243, 1069, 1068, 13, 17, 1067, 1066, 1065, 1063, + 56, 921, 1062, 1061, 1060, 1059, 1056, 1054, 48, 3, + 11, 9, 15, 1053, 883, 112, 1052, 45, 1051, 1048, + 1046, 1045, 59, 1043, 49, 1042, 20, 47, 1032, 6, + 57, 33, 21, 7, 67, 52, 1023, 28, 55, 43, + 1022, 1020, 389, 1018, 1017, 37, 1016, 22, 132, 436, + 1015, 1013, 1012, 1011, 29, 0, 536, 963, 62, 1005, + 1002, 1001, 1336, 63, 61, 18, 1000, 123, 30, 32, + 988, 985, 42, 979, 974, 973, 972, 971, 969, 968, + 126, 961, 960, 959, 133, 25, 958, 956, 54, 19, + 955, 954, 951, 39, 53, 942, 940, 41, 27, 939, + 935, 934, 926, 924, 24, 16, 923, 12, 922, 10, + 920, 23, 919, 2, 917, 14, 915, 8, 912, 4, + 40, 1, 911, 5, 910, 909, 349, 171, 908, 907, + 71, } var yyR1 = [...]int{ - 0, 180, 181, 181, 1, 1, 1, 1, 1, 1, + 0, 184, 185, 185, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 6, 3, 4, 4, 5, 5, 7, 7, 27, 27, 8, 9, 9, 9, - 184, 184, 46, 46, 90, 90, 10, 10, 10, 10, + 188, 188, 46, 46, 90, 90, 10, 10, 10, 10, 95, 95, 99, 99, 99, 100, 100, 100, 100, 130, - 130, 11, 11, 11, 11, 11, 11, 11, 11, 178, - 178, 177, 176, 176, 175, 175, 174, 16, 159, 161, - 161, 160, 160, 160, 160, 154, 133, 133, 133, 133, + 130, 11, 11, 11, 11, 11, 11, 11, 11, 179, + 179, 178, 177, 177, 176, 176, 175, 16, 160, 162, + 162, 161, 161, 161, 161, 154, 133, 133, 133, 133, 136, 136, 134, 134, 134, 134, 134, 134, 134, 135, 135, 135, 135, 135, 137, 137, 137, 137, 137, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 153, 153, 140, 140, 148, 148, 149, 149, 149, 146, 146, 147, 147, 150, 150, 150, 141, 141, - 141, 141, 141, 141, 141, 143, 143, 151, 151, 144, - 144, 144, 145, 145, 145, 152, 152, 152, 152, 152, - 142, 142, 155, 155, 169, 169, 168, 168, 168, 158, - 158, 165, 165, 165, 165, 165, 157, 157, 167, 167, - 166, 156, 156, 170, 162, 162, 162, 163, 163, 163, - 164, 164, 164, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 179, 179, 179, 179, 179, 179, 179, 179, - 179, 179, 179, 173, 171, 171, 172, 172, 13, 14, - 14, 14, 14, 14, 15, 15, 17, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 141, 141, 141, 141, 141, 141, 143, 143, 143, 151, + 151, 144, 144, 144, 145, 145, 145, 152, 152, 152, + 152, 152, 142, 142, 155, 155, 170, 170, 169, 169, + 169, 159, 159, 166, 166, 166, 166, 166, 157, 157, + 158, 158, 168, 168, 167, 156, 156, 171, 171, 171, + 171, 182, 183, 181, 181, 181, 181, 181, 163, 163, + 163, 164, 164, 164, 165, 165, 165, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 174, 172, 172, + 173, 173, 13, 14, 14, 14, 14, 14, 15, 15, + 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 106, 106, 104, 104, 105, 105, - 105, 107, 107, 107, 131, 131, 131, 19, 19, 21, - 21, 22, 23, 20, 20, 20, 20, 20, 20, 20, - 185, 24, 25, 25, 26, 26, 26, 30, 30, 30, - 28, 28, 29, 29, 35, 35, 34, 34, 36, 36, - 36, 36, 119, 119, 119, 118, 118, 38, 38, 39, - 39, 40, 40, 41, 41, 41, 53, 53, 89, 89, - 91, 91, 42, 42, 42, 42, 43, 43, 44, 44, - 45, 45, 126, 126, 125, 125, 125, 124, 124, 47, - 47, 47, 49, 48, 48, 48, 48, 50, 50, 52, - 52, 51, 51, 54, 54, 54, 54, 55, 55, 37, - 37, 37, 37, 37, 37, 37, 103, 103, 57, 57, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 67, 67, 67, 67, 67, 67, 58, 58, 58, 58, - 58, 58, 58, 33, 33, 68, 68, 68, 74, 69, - 69, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 18, 18, 18, 18, 18, 18, 18, 18, 106, 106, + 104, 104, 105, 105, 105, 107, 107, 107, 131, 131, + 131, 19, 19, 21, 21, 22, 23, 20, 20, 20, + 20, 20, 20, 20, 189, 24, 25, 25, 26, 26, + 26, 30, 30, 30, 28, 28, 29, 29, 35, 35, + 34, 34, 36, 36, 36, 36, 119, 119, 119, 118, + 118, 38, 38, 39, 39, 40, 40, 41, 41, 41, + 53, 53, 89, 89, 91, 91, 42, 42, 42, 42, + 43, 43, 44, 44, 45, 45, 126, 126, 125, 125, + 125, 124, 124, 47, 47, 47, 49, 48, 48, 48, + 48, 50, 50, 52, 52, 51, 51, 54, 54, 54, + 54, 55, 55, 37, 37, 37, 37, 37, 37, 37, + 103, 103, 57, 57, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 67, 67, 67, 67, 67, 67, + 58, 58, 58, 58, 58, 58, 58, 33, 33, 68, + 68, 68, 74, 69, 69, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 65, 65, 65, 63, 63, 63, 63, + 61, 61, 61, 61, 61, 61, 61, 65, 65, 65, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 64, 64, 64, 64, 64, 64, 64, 64, 186, - 186, 66, 66, 66, 66, 31, 31, 31, 31, 31, - 129, 129, 132, 132, 132, 132, 132, 132, 132, 132, - 132, 132, 132, 132, 132, 78, 78, 32, 32, 76, - 76, 77, 79, 79, 75, 75, 75, 60, 60, 60, - 60, 60, 60, 60, 60, 62, 62, 62, 80, 80, - 81, 81, 82, 82, 83, 83, 84, 85, 85, 85, - 86, 86, 86, 86, 87, 87, 87, 59, 59, 59, - 59, 59, 59, 88, 88, 88, 88, 92, 92, 70, - 70, 72, 72, 71, 73, 93, 93, 97, 94, 94, - 98, 98, 98, 96, 96, 96, 121, 121, 121, 101, - 101, 108, 108, 109, 109, 102, 102, 110, 110, 110, - 110, 110, 110, 110, 110, 110, 110, 111, 111, 111, - 112, 112, 113, 113, 113, 120, 120, 116, 116, 117, - 117, 122, 122, 123, 123, 114, 114, 114, 114, 114, + 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, + 64, 64, 64, 190, 190, 66, 66, 66, 66, 31, + 31, 31, 31, 31, 129, 129, 132, 132, 132, 132, + 132, 132, 132, 132, 132, 132, 132, 132, 132, 78, + 78, 32, 32, 76, 76, 77, 79, 79, 75, 75, + 75, 60, 60, 60, 60, 60, 60, 60, 60, 62, + 62, 62, 80, 80, 81, 81, 82, 82, 83, 83, + 84, 85, 85, 85, 86, 86, 86, 86, 87, 87, + 87, 59, 59, 59, 59, 59, 59, 88, 88, 88, + 88, 92, 92, 70, 70, 72, 72, 71, 73, 93, + 93, 97, 94, 94, 98, 98, 98, 96, 96, 96, + 121, 121, 121, 101, 101, 108, 108, 109, 109, 102, + 102, 110, 110, 110, 110, 110, 110, 110, 110, 110, + 110, 111, 111, 111, 112, 112, 113, 113, 113, 120, + 120, 116, 116, 117, 117, 122, 122, 123, 123, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, @@ -2026,8 +2039,8 @@ var yyR1 = [...]int{ 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, - 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, @@ -2037,7 +2050,8 @@ var yyR1 = [...]int{ 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 182, 183, 127, 128, 128, 128, + 115, 115, 115, 115, 115, 115, 115, 115, 186, 187, + 127, 128, 128, 128, } var yyR2 = [...]int{ @@ -2056,52 +2070,53 @@ var yyR2 = [...]int{ 1, 1, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 3, 0, 5, 0, 3, 5, 0, 1, 0, 1, 0, 1, 2, 0, 2, - 2, 2, 2, 2, 2, 0, 3, 0, 1, 0, - 3, 3, 0, 2, 2, 0, 2, 1, 2, 1, - 0, 2, 5, 4, 1, 2, 2, 3, 2, 0, - 1, 2, 3, 3, 2, 2, 1, 1, 1, 3, - 2, 3, 1, 10, 0, 1, 3, 1, 2, 3, - 1, 1, 1, 6, 7, 7, 12, 7, 7, 7, - 4, 5, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 7, 1, 3, 8, 8, 5, 4, - 6, 5, 4, 4, 3, 2, 3, 4, 4, 4, - 4, 4, 4, 4, 4, 3, 3, 3, 3, 4, - 3, 7, 5, 4, 2, 2, 4, 4, 2, 2, - 2, 2, 2, 3, 1, 1, 0, 1, 0, 2, - 2, 0, 2, 2, 0, 1, 1, 2, 1, 1, - 2, 1, 1, 2, 2, 2, 2, 2, 3, 3, - 0, 2, 0, 2, 1, 2, 2, 0, 1, 1, - 0, 1, 0, 1, 0, 1, 1, 3, 1, 2, - 3, 5, 0, 1, 2, 1, 1, 0, 2, 1, - 3, 1, 1, 1, 3, 3, 3, 7, 1, 3, - 1, 3, 4, 4, 4, 3, 2, 4, 0, 1, - 0, 2, 0, 1, 0, 1, 2, 1, 1, 1, - 2, 2, 1, 2, 3, 2, 3, 2, 2, 2, - 1, 1, 3, 0, 5, 5, 5, 0, 2, 1, - 3, 3, 2, 3, 1, 2, 0, 3, 1, 1, - 3, 3, 4, 4, 5, 3, 4, 5, 6, 2, - 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 0, 2, 1, 1, 1, 3, 1, - 3, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 2, 2, 2, 2, 4, 2, 0, 3, 5, 0, + 1, 0, 3, 3, 0, 2, 2, 0, 2, 1, + 2, 1, 0, 2, 5, 4, 1, 2, 2, 3, + 2, 0, 1, 2, 3, 3, 2, 2, 1, 1, + 0, 1, 1, 3, 2, 3, 1, 10, 11, 11, + 12, 3, 3, 1, 1, 2, 2, 2, 0, 1, + 3, 1, 2, 3, 1, 1, 1, 6, 7, 7, + 12, 7, 7, 7, 4, 5, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 7, 1, 3, + 8, 8, 5, 4, 6, 5, 4, 4, 3, 2, + 3, 4, 4, 4, 4, 4, 4, 4, 4, 3, + 3, 3, 3, 4, 3, 7, 5, 4, 2, 2, + 4, 4, 2, 2, 2, 2, 2, 3, 1, 1, + 0, 1, 0, 2, 2, 0, 2, 2, 0, 1, + 1, 2, 1, 1, 2, 1, 1, 2, 2, 2, + 2, 2, 3, 3, 0, 2, 0, 2, 1, 2, + 2, 0, 1, 1, 0, 1, 0, 1, 0, 1, + 1, 3, 1, 2, 3, 5, 0, 1, 2, 1, + 1, 0, 2, 1, 3, 1, 1, 1, 3, 3, + 3, 7, 1, 3, 1, 3, 4, 4, 4, 3, + 2, 4, 0, 1, 0, 2, 0, 1, 0, 1, + 2, 1, 1, 1, 2, 2, 1, 2, 3, 2, + 3, 2, 2, 2, 1, 1, 3, 0, 5, 5, + 5, 0, 2, 1, 3, 3, 2, 3, 1, 2, + 0, 3, 1, 1, 3, 3, 4, 4, 5, 3, + 4, 5, 6, 2, 1, 2, 1, 2, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, + 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, - 1, 1, 1, 4, 5, 6, 4, 4, 6, 6, - 6, 6, 8, 8, 6, 8, 8, 9, 7, 5, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 0, - 2, 4, 4, 4, 4, 0, 3, 4, 7, 3, - 1, 1, 2, 3, 3, 1, 2, 2, 1, 2, - 1, 2, 2, 1, 2, 0, 1, 0, 2, 1, - 2, 4, 0, 2, 1, 3, 5, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 0, 3, - 0, 2, 0, 3, 1, 3, 2, 0, 1, 1, - 0, 2, 4, 4, 0, 2, 4, 2, 1, 3, - 5, 4, 6, 1, 3, 3, 5, 0, 5, 1, - 3, 1, 2, 3, 1, 1, 3, 3, 1, 3, - 3, 3, 3, 1, 2, 1, 1, 1, 1, 1, - 1, 0, 2, 0, 3, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 0, 1, 1, 0, 2, 1, 1, 1, + 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 3, 1, 1, 1, 1, 4, 5, 6, + 4, 4, 6, 6, 6, 6, 8, 8, 6, 8, + 8, 9, 7, 5, 4, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 2, 4, 4, 4, 4, 0, + 3, 4, 7, 3, 1, 1, 2, 3, 3, 1, + 2, 2, 1, 2, 1, 2, 2, 1, 2, 0, + 1, 0, 2, 1, 2, 4, 0, 2, 1, 3, + 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 0, 3, 0, 2, 0, 3, 1, 3, + 2, 0, 1, 1, 0, 2, 4, 4, 0, 2, + 4, 2, 1, 3, 5, 4, 6, 1, 3, 3, + 5, 0, 5, 1, 3, 1, 2, 3, 1, 1, + 3, 3, 1, 3, 3, 3, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 0, 2, 0, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2121,182 +2136,184 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, } var yyChk = [...]int{ - -1000, -180, -1, -2, -6, -7, -8, -9, -10, -11, + -1000, -184, -1, -2, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -17, -18, -19, -21, -22, -23, -20, -3, -4, 6, 7, -27, 9, 10, 30, -16, - 114, 115, 117, 116, 143, 118, 136, 50, 155, 156, - 158, 159, 25, 137, 138, 141, 142, 31, 32, -182, - 8, 240, 54, -181, 255, -82, 15, -26, 5, -24, - -185, -24, -24, -24, -24, -24, -159, -161, 54, 89, - -113, 123, 71, 151, 232, 120, 121, 127, -116, 57, - -115, 248, 155, 166, 160, 187, 179, 177, 180, 219, - 207, 217, 66, 158, 228, 139, 175, 171, 169, 27, - 192, 253, 170, 133, 132, 193, 197, 220, 164, 165, - 222, 191, 135, 33, 250, 35, 147, 223, 195, 190, - 186, 189, 163, 185, 39, 199, 198, 200, 218, 182, - 172, 18, 226, 142, 145, 194, 196, 128, 149, 252, - 224, 168, 134, 146, 141, 227, 159, 221, 230, 38, - 204, 162, 131, 156, 153, 183, 148, 173, 174, 188, - 161, 184, 157, 150, 143, 229, 205, 254, 181, 178, - 154, 152, 210, 211, 212, 213, 214, 251, 225, 176, - 206, -102, 123, 125, 121, 121, 122, 123, 232, 120, - 121, -51, -122, 57, -115, 123, 151, 121, 107, 180, - 114, 208, 122, 33, 149, -131, 121, -104, 152, 207, - 210, 211, 212, 214, 213, 57, 221, 220, 215, -122, - 157, -127, -127, -127, -127, -127, 209, 209, -2, -86, - 17, 16, -5, -3, -182, 6, 20, 21, -30, 40, - 41, -25, -36, 98, -37, -122, -56, 73, -61, 29, - 57, -115, 23, -60, -57, -75, -73, -74, 107, 108, - 109, 96, 97, 104, 74, 110, -65, -63, -64, -66, - 59, 58, 67, 60, 61, 62, 63, 68, 69, 70, - -116, -71, -182, 44, 45, 241, 242, 243, 244, 247, - 245, 76, 34, 231, 239, 238, 237, 235, 236, 233, - 234, 126, 232, 102, 240, -102, -39, -40, -41, -42, - -53, -74, -182, -51, 11, -46, -51, -94, -130, 157, - -98, 221, 220, -117, -96, -116, -114, 219, 180, 218, - 119, 72, 22, 24, 202, 75, 107, 16, 76, 106, - 241, 114, 48, 233, 234, 231, 243, 244, 232, 208, - 29, 10, 25, 137, 21, 100, 116, 79, 80, 140, - 23, 138, 70, 19, 51, 11, 13, 14, 126, 125, - 91, 122, 46, 8, 110, 26, 88, 42, 28, 44, - 89, 17, 235, 236, 31, 247, 144, 102, 49, 36, - 73, 68, 52, 71, 15, 47, 90, 117, 240, 45, - 120, 6, 246, 30, 136, 43, 121, 209, 78, 124, - 69, 5, 127, 32, 9, 50, 53, 237, 238, 239, - 34, 77, 12, -160, 89, -154, 57, -51, 122, -51, - 240, -116, -109, 126, -109, -109, 121, -51, -51, -108, - 126, 57, -108, -108, -108, -51, 111, -51, 57, 30, - 232, 57, 149, 121, 150, 123, -128, -182, -117, -128, - -128, -128, 153, 154, -128, 217, -106, 209, 216, 52, - 12, -128, -127, -127, -183, 56, -87, 19, 31, -37, - -122, -83, -84, -37, -82, -2, -24, 36, -28, 21, - 65, 11, -119, 72, 71, 88, -118, 22, -116, 59, - 111, -37, -58, 91, 73, 89, 90, 75, 93, 92, - 103, 96, 97, 98, 99, 100, 101, 102, 94, 95, - 106, 81, 82, 83, 84, 85, 86, 87, -103, -182, - -74, -182, 112, 113, -61, -61, -61, -61, -61, -61, - -61, -61, -182, -2, -69, -37, -182, -182, -182, -182, - -182, -182, -182, -182, -182, -78, -37, -182, -186, -182, - -186, -186, -186, -186, -186, -186, -186, -182, -182, -182, - -182, -52, 26, -51, 30, 55, -47, -49, -48, -50, - 42, 46, 48, 43, 44, 45, 49, -126, 22, -39, - -182, -125, 145, -124, 22, -122, 59, -51, -46, -184, - 55, 11, 53, 55, -94, 157, -95, -99, 222, 224, - 81, -121, -116, 59, 29, 30, 56, 55, -51, -133, - -136, -138, -137, -139, -134, -135, 177, 178, 107, 181, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 30, 139, 173, 174, 175, 176, 193, 194, 195, 196, - 197, 198, 199, 200, 160, 161, 162, 163, 164, 165, - 166, 168, 169, 170, 171, 172, 57, -128, 123, -178, - 53, 57, 73, 57, -51, -51, -128, 124, -51, 23, - 52, -51, 57, 57, -123, -122, -114, -128, -128, -128, - -128, -128, -128, -128, -128, -128, -128, 11, -105, 11, - 91, -51, -37, 9, 91, 55, 18, 111, 55, -85, - 24, 25, -86, -183, -30, -62, -116, 60, 63, -29, - 43, -51, -37, -37, -67, 68, 73, 69, 70, -118, - 98, -123, -117, -114, -61, -68, -71, -74, 64, 91, - 89, 90, 75, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -129, 57, - 59, 57, -60, -60, -116, -35, 21, -34, -36, -183, - 55, -183, -2, -34, -34, -37, -37, -75, -116, -122, - -75, -34, -28, -76, -77, 77, -75, -183, -34, -35, - -34, -34, -90, 145, -51, -93, -97, -75, -40, -41, - -41, -40, -41, 42, 42, 42, 47, 42, 47, 42, - -48, -122, -183, -54, 50, 125, 51, -182, -124, -90, - 53, -39, -51, -98, -95, 55, 223, 225, 226, 52, - -37, -145, 106, -162, -163, -164, -117, 59, 60, -154, - -155, -156, -165, 130, -170, 128, 131, 127, -157, 133, - 122, 28, 56, -150, 68, 73, -146, 205, -140, 54, - -140, -140, -140, -140, -144, 180, -144, -144, -144, 54, - 54, -140, -140, -140, -148, 54, -148, -148, -149, 54, - -149, -120, 53, -51, -176, 251, -177, 57, -128, 23, - -128, -110, 119, 116, 117, -173, 115, 202, 180, 66, - 29, 15, 241, 145, 254, 57, 146, -51, -51, -128, - -51, -107, 89, 12, -122, -122, 38, -37, -37, -123, - -84, -87, -101, 19, 11, 34, 34, -34, 68, 69, - 70, 111, -182, -68, -61, -61, -61, -33, 140, 72, - -183, -183, -34, 55, -37, -183, -183, -183, 55, 53, - 22, 55, 11, 111, 55, 11, -183, -34, -79, -77, - 79, -37, -183, -183, -183, -183, -183, -59, 30, 34, - -2, -182, -182, -55, 55, 12, 81, -44, -43, 52, - 53, -45, 52, -43, 42, 42, 122, 122, 122, -91, - -116, -55, -39, -55, -99, -100, 227, 224, 230, 57, - 59, 55, -164, 81, 54, 57, 28, -157, -157, 57, - 57, 28, -141, 29, 68, -147, 206, 60, -144, -144, - -145, 30, -145, -145, -145, -153, 59, -153, 60, 60, - 52, -116, -128, -175, -174, -117, -127, -179, 151, 129, - 130, 133, 132, 57, 122, 28, 128, 131, 145, 127, - -179, 151, -111, -112, 124, 22, 122, 28, 145, -128, - -105, 59, -37, 39, 111, -51, -38, 11, 98, -117, - -35, -33, 72, -61, -61, -183, -36, -132, 107, 177, - 139, 175, 171, 191, 182, 204, 173, 205, -129, -132, - -61, -61, -117, -61, -61, 248, -82, 80, -37, 78, - -92, 52, -93, -70, -72, -71, -182, -2, -88, -116, - -91, -82, -97, -37, -37, -37, 54, -37, -182, -182, - -182, -183, 55, -82, -55, 224, 228, 229, -163, -164, - -167, -166, -116, -170, 57, 57, 54, -143, 52, 59, - 60, 61, 68, 231, 67, 56, -145, -145, 57, 107, - 56, 55, 56, 55, 56, 55, -51, 55, 81, -127, - -116, -127, -116, -51, -127, -116, -107, -55, -39, -183, - -61, -183, -140, -140, -140, -149, -140, 165, -140, 165, - -183, -183, -183, 55, 19, -183, 55, 19, -182, -32, - 246, -37, 27, -92, 55, -183, -183, -183, 55, 111, - -183, -86, -89, -116, -89, -89, -89, -125, -116, -86, - 56, 55, -140, -89, -151, 202, 9, -144, 59, -144, - 60, 60, -128, -174, -164, 54, 26, -80, 13, -144, - 57, -61, -61, -61, -61, -61, -183, 59, 28, -72, - 34, -2, -182, -116, -116, 55, 56, -183, -183, -183, - -54, -169, -168, 53, 135, 66, -166, 56, -152, 128, - 28, 127, 231, -145, -145, 56, 56, -89, -182, -81, - 14, 16, -183, -183, -183, -183, -31, 91, 251, 9, - -70, -2, 111, -116, -168, 57, -158, 81, 59, 134, - -142, 66, 28, 28, 56, -171, -172, 145, -37, -69, - -183, 249, 49, 252, -93, -183, -116, 60, -51, 59, - -178, -183, 55, -116, 39, 250, 253, 54, -176, -172, - 34, 39, -89, 147, 251, 56, 148, 252, -182, 253, - -61, 144, -183, -183, + 114, 115, 117, 116, 147, 118, 140, 50, 159, 160, + 162, 163, 25, 141, 142, 145, 146, 31, 32, -186, + 8, 244, 54, -185, 259, -82, 15, -26, 5, -24, + -189, -24, -24, -24, -24, -24, -160, -162, 54, 89, + -113, 123, 71, 155, 236, 120, 121, 127, -116, 57, + -115, 252, 133, 159, 170, 164, 191, 183, 134, 181, + 184, 223, 211, 221, 66, 162, 232, 143, 179, 175, + 173, 27, 196, 257, 174, 136, 131, 197, 201, 224, + 168, 169, 226, 195, 132, 33, 254, 35, 151, 227, + 199, 194, 190, 193, 167, 189, 39, 203, 202, 204, + 222, 186, 137, 176, 18, 230, 146, 149, 198, 200, + 128, 153, 256, 228, 172, 138, 150, 145, 231, 139, + 163, 225, 234, 38, 208, 166, 130, 160, 157, 187, + 152, 177, 178, 192, 165, 188, 161, 154, 147, 233, + 209, 258, 185, 182, 158, 156, 214, 215, 216, 217, + 218, 255, 229, 180, 210, -102, 123, 125, 121, 121, + 122, 123, 236, 120, 121, -51, -122, 57, -115, 123, + 155, 121, 107, 184, 114, 212, 122, 33, 153, -131, + 121, -104, 156, 211, 214, 215, 216, 218, 217, 57, + 225, 224, 219, -122, 161, -127, -127, -127, -127, -127, + 213, 213, -2, -86, 17, 16, -5, -3, -186, 6, + 20, 21, -30, 40, 41, -25, -36, 98, -37, -122, + -56, 73, -61, 29, 57, -115, 23, -60, -57, -75, + -73, -74, 107, 108, 109, 96, 97, 104, 74, 110, + -65, -63, -64, -66, 59, 58, 67, 60, 61, 62, + 63, 68, 69, 70, -116, -71, -186, 44, 45, 245, + 246, 247, 248, 251, 249, 76, 34, 235, 243, 242, + 241, 239, 240, 237, 238, 126, 236, 102, 244, -102, + -39, -40, -41, -42, -53, -74, -186, -51, 11, -46, + -51, -94, -130, 161, -98, 225, 224, -117, -96, -116, + -114, 223, 184, 222, 119, 72, 22, 24, 206, 75, + 107, 16, 76, 106, 245, 114, 48, 237, 238, 235, + 247, 248, 236, 212, 29, 10, 25, 141, 21, 100, + 116, 79, 80, 144, 23, 142, 70, 19, 51, 11, + 13, 14, 126, 125, 91, 122, 46, 8, 110, 26, + 88, 42, 28, 44, 89, 17, 239, 240, 31, 251, + 148, 102, 49, 36, 73, 68, 52, 71, 15, 47, + 90, 117, 244, 45, 120, 6, 250, 30, 140, 43, + 121, 213, 78, 124, 69, 5, 127, 32, 9, 50, + 53, 241, 242, 243, 34, 77, 12, -161, 89, -154, + 57, -51, 122, -51, 244, -116, -109, 126, -109, -109, + 121, -51, -51, -108, 126, 57, -108, -108, -108, -51, + 111, -51, 57, 30, 236, 57, 153, 121, 154, 123, + -128, -186, -117, -128, -128, -128, 157, 158, -128, 221, + -106, 213, 220, 52, 12, -128, -127, -127, -187, 56, + -87, 19, 31, -37, -122, -83, -84, -37, -82, -2, + -24, 36, -28, 21, 65, 11, -119, 72, 71, 88, + -118, 22, -116, 59, 111, -37, -58, 91, 73, 89, + 90, 75, 93, 92, 103, 96, 97, 98, 99, 100, + 101, 102, 94, 95, 106, 81, 82, 83, 84, 85, + 86, 87, -103, -186, -74, -186, 112, 113, -61, -61, + -61, -61, -61, -61, -61, -61, -186, -2, -69, -37, + -186, -186, -186, -186, -186, -186, -186, -186, -186, -78, + -37, -186, -190, -186, -190, -190, -190, -190, -190, -190, + -190, -186, -186, -186, -186, -52, 26, -51, 30, 55, + -47, -49, -48, -50, 42, 46, 48, 43, 44, 45, + 49, -126, 22, -39, -186, -125, 149, -124, 22, -122, + 59, -51, -46, -188, 55, 11, 53, 55, -94, 161, + -95, -99, 226, 228, 81, -121, -116, 59, 29, 30, + 56, 55, -51, -133, -136, -138, -137, -139, -134, -135, + 181, 182, 107, 185, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 30, 143, 177, 178, 179, 180, + 197, 198, 199, 200, 201, 202, 203, 204, 164, 165, + 166, 167, 168, 169, 170, 172, 173, 174, 175, 176, + 57, -128, 123, -179, 53, 57, 73, 57, -51, -51, + -128, 124, -51, 23, 52, -51, 57, 57, -123, -122, + -114, -128, -128, -128, -128, -128, -128, -128, -128, -128, + -128, 11, -105, 11, 91, -51, -37, 9, 91, 55, + 18, 111, 55, -85, 24, 25, -86, -187, -30, -62, + -116, 60, 63, -29, 43, -51, -37, -37, -67, 68, + 73, 69, 70, -118, 98, -123, -117, -114, -61, -68, + -71, -74, 64, 91, 89, 90, 75, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -129, 57, 59, 57, -60, -60, -116, -35, + 21, -34, -36, -187, 55, -187, -2, -34, -34, -37, + -37, -75, -116, -122, -75, -34, -28, -76, -77, 77, + -75, -187, -34, -35, -34, -34, -90, 149, -51, -93, + -97, -75, -40, -41, -41, -40, -41, 42, 42, 42, + 47, 42, 47, 42, -48, -122, -187, -54, 50, 125, + 51, -186, -124, -90, 53, -39, -51, -98, -95, 55, + 227, 229, 230, 52, -37, -145, 106, -163, -164, -165, + -117, 59, 60, -154, -155, -156, -166, 135, -171, 128, + 130, 127, -157, 136, 122, 28, 56, -150, 68, 73, + -146, 209, -140, 54, -140, -140, -140, -140, -144, 184, + -144, -144, -144, 54, 54, -140, -140, -140, -148, 54, + -148, -148, -149, 54, -149, -120, 53, -51, -177, 255, + -178, 57, -128, 23, -128, -110, 119, 116, 117, -174, + 115, 206, 184, 66, 29, 15, 245, 149, 258, 57, + 150, -51, -51, -128, -51, -107, 89, 12, -122, -122, + 38, -37, -37, -123, -84, -87, -101, 19, 11, 34, + 34, -34, 68, 69, 70, 111, -186, -68, -61, -61, + -61, -33, 144, 72, -187, -187, -34, 55, -37, -187, + -187, -187, 55, 53, 22, 55, 11, 111, 55, 11, + -187, -34, -79, -77, 79, -37, -187, -187, -187, -187, + -187, -59, 30, 34, -2, -186, -186, -55, 55, 12, + 81, -44, -43, 52, 53, -45, 52, -43, 42, 42, + 122, 122, 122, -91, -116, -55, -39, -55, -99, -100, + 231, 228, 234, 57, 59, 55, -165, 81, 54, 57, + 28, -157, -157, -158, 57, -158, 28, -141, 29, 68, + -147, 210, 60, -144, -144, -145, 30, -145, -145, -145, + -153, 59, -153, 60, 60, 52, -116, -128, -176, -175, + -117, -127, -180, 155, 129, 135, 136, 131, 57, 122, + 28, 128, 130, 149, 127, -180, 155, -111, -112, 124, + 22, 122, 28, 149, -128, -105, 59, -37, 39, 111, + -51, -38, 11, 98, -117, -35, -33, 72, -61, -61, + -187, -36, -132, 107, 181, 143, 179, 175, 195, 186, + 208, 177, 209, -129, -132, -61, -61, -117, -61, -61, + 252, -82, 80, -37, 78, -92, 52, -93, -70, -72, + -71, -186, -2, -88, -116, -91, -82, -97, -37, -37, + -37, 54, -37, -186, -186, -186, -187, 55, -82, -55, + 228, 232, 233, -164, -165, -168, -167, -116, -171, -158, + -158, 54, -143, 52, 59, 60, 61, 68, 235, 67, + 56, -145, -145, 57, 107, 56, 55, 56, 55, 56, + 55, -51, 55, 81, -127, -116, -127, -116, -51, -127, + -116, -107, -55, -39, -187, -61, -187, -140, -140, -140, + -149, -140, 169, -140, 169, -187, -187, -187, 55, 19, + -187, 55, 19, -186, -32, 250, -37, 27, -92, 55, + -187, -187, -187, 55, 111, -187, -86, -89, -116, -89, + -89, -89, -125, -116, -86, 56, 55, -140, -89, -151, + 206, 9, 54, -144, 59, -144, 60, 60, -128, -175, + -165, 54, 26, -80, 13, -144, 57, -61, -61, -61, + -61, -61, -187, 59, 28, -72, 34, -2, -186, -116, + -116, 55, 56, -187, -187, -187, -54, -170, -169, 53, + 132, 66, -167, 56, -152, 128, 28, 127, 235, 56, + -145, -145, 56, 56, -89, -186, -81, 14, 16, -187, + -187, -187, -187, -31, 91, 255, 9, -70, -2, 111, + -116, -169, 57, -159, 81, 59, 138, -142, 66, 28, + 28, 54, 56, -172, -173, 149, -37, -69, -187, 253, + 49, 256, -93, -187, -116, 60, -51, 59, 56, -179, + -187, 55, -116, 39, 254, 257, 54, -177, -173, 34, + 39, -89, 151, 255, 56, 152, 256, -182, -183, 52, + -186, 257, -183, 52, 10, 9, -61, 148, -181, 139, + 134, 137, 30, -181, -187, -187, 133, 29, 68, } var yyDef = [...]int{ 22, -2, 2, -2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 522, 0, 290, 290, 290, 290, 290, 290, 0, - 592, 575, 0, 0, 0, 0, -2, 278, 279, 0, - 281, 282, 802, 802, 802, 802, 802, 0, 0, 0, - 34, 35, 800, 1, 3, 530, 0, 0, 294, 297, - 292, 0, 575, 0, 0, 0, 61, 62, 0, 0, - 0, 788, 0, 789, 573, 573, 573, 593, 594, 597, - 598, 698, 699, 700, 701, 702, 703, 704, 705, 706, - 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, - 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, - 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, - 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, - 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, - 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, - 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, - 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, - 787, 790, 791, 792, 793, 794, 795, 796, 797, 798, - 799, 0, 0, 576, 0, 571, 0, 571, 571, 571, - 0, 235, 361, 601, 602, 788, 789, 0, 0, 0, - 0, 803, 803, 803, 803, 0, 803, 0, 254, 255, - 258, 259, 260, 261, 262, 803, 275, 276, 267, 277, - 280, 283, 284, 285, 286, 287, 802, 802, 28, 534, - 0, 0, 522, 30, 0, 290, 295, 296, 300, 298, - 299, 291, 0, 308, 312, 0, 369, 0, 374, 376, - -2, -2, 0, 411, 412, 413, 414, 415, 0, 0, - 0, 0, 0, 0, 0, 0, 439, 440, 441, 442, - 507, 508, 509, 510, 511, 512, 513, 514, 378, 379, - 504, 554, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 495, 0, 469, 469, 469, 469, 469, 469, 469, - 469, 0, 0, 0, 0, 0, 0, 319, 321, 322, - 323, 342, 0, 344, 0, 0, 42, 46, 0, 779, - 558, -2, -2, 0, 0, 599, 600, -2, 705, -2, - 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, - 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + 21, 536, 0, 304, 304, 304, 304, 304, 304, 0, + 606, 589, 0, 0, 0, 0, -2, 292, 293, 0, + 295, 296, 820, 820, 820, 820, 820, 0, 0, 0, + 34, 35, 818, 1, 3, 544, 0, 0, 308, 311, + 306, 0, 589, 0, 0, 0, 61, 62, 0, 0, + 0, 806, 0, 807, 587, 587, 587, 607, 608, 611, + 612, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, + 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, + 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, + 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, + 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, + 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, + 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 808, 809, 810, 811, 812, + 813, 814, 815, 816, 817, 0, 0, 590, 0, 585, + 0, 585, 585, 585, 0, 249, 375, 615, 616, 806, + 807, 0, 0, 0, 0, 821, 821, 821, 821, 0, + 821, 0, 268, 269, 272, 273, 274, 275, 276, 821, + 289, 290, 281, 291, 294, 297, 298, 299, 300, 301, + 820, 820, 28, 548, 0, 0, 536, 30, 0, 304, + 309, 310, 314, 312, 313, 305, 0, 322, 326, 0, + 383, 0, 388, 390, -2, -2, 0, 425, 426, 427, + 428, 429, 0, 0, 0, 0, 0, 0, 0, 0, + 453, 454, 455, 456, 521, 522, 523, 524, 525, 526, + 527, 528, 392, 393, 518, 568, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 509, 0, 483, 483, 483, + 483, 483, 483, 483, 483, 0, 0, 0, 0, 0, + 0, 333, 335, 336, 337, 356, 0, 358, 0, 0, + 42, 46, 0, 797, 572, -2, -2, 0, 0, 613, + 614, -2, 721, -2, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, @@ -2304,98 +2321,101 @@ var yyDef = [...]int{ 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, - 695, 696, 697, 0, 0, 81, 0, 79, 0, 803, - 0, 69, 0, 0, 0, 0, 0, 803, 0, 0, - 0, 0, 0, 0, 0, 234, 0, 236, 803, 803, - 803, 803, 803, 803, 803, 803, 245, 804, 805, 246, - 247, 248, 803, 803, 250, 0, 268, 264, 265, 0, - 0, 263, 288, 289, 29, 801, 23, 0, 0, 531, - 0, 523, 524, 527, 530, 28, 297, 0, 302, 301, - 293, 0, 309, 0, 0, 0, 313, 0, 315, 316, - 0, 372, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 396, 397, 398, 399, 400, 401, 402, 375, 0, - 389, 0, 0, 0, 431, 432, 433, 434, 435, 436, - 437, 0, 304, 28, 0, 409, 0, 0, 0, 0, - 0, 0, 0, 0, 300, 0, 496, 0, 461, 0, - 462, 463, 464, 465, 466, 467, 468, 0, 304, 0, - 0, 44, 0, 360, 0, 0, 0, 0, 0, 0, - 349, 0, 0, 352, 0, 0, 0, 0, 343, 0, - 0, 363, 751, 345, 0, 347, 348, -2, 0, 0, - 0, 40, 41, 0, 47, 779, 49, 50, 0, 0, - 0, 162, 566, 567, 568, 564, 194, 0, 0, 145, - 141, 87, 88, 89, 134, 91, 134, 134, 134, 134, - 159, 159, 159, 159, 117, 118, 119, 120, 121, 0, - 0, 104, 134, 134, 134, 108, 124, 125, 126, 127, - 128, 129, 130, 131, 92, 93, 94, 95, 96, 97, - 98, 136, 136, 136, 138, 138, 595, 64, 0, 72, - 0, 803, 0, 803, 77, 0, 210, 0, 229, 572, - 0, 803, 232, 233, 362, 603, 604, 237, 238, 239, - 240, 241, 242, 243, 244, 249, 253, 0, 271, 0, - 0, 257, 256, 535, 0, 0, 0, 0, 0, 526, - 528, 529, 534, 31, 300, 0, 515, 0, 0, 0, - 303, 26, 370, 371, 373, 390, 0, 392, 394, 314, - 310, 0, 505, -2, 380, 381, 405, 406, 407, 0, - 0, 0, 0, 403, 385, 0, 416, 417, 418, 419, - 420, 421, 422, 423, 424, 425, 426, 427, 430, 480, - 481, 0, 428, 429, 438, 0, 0, 305, 306, 408, - 0, 553, 28, 0, 0, 0, 0, 0, 504, 0, - 0, 0, 0, 502, 499, 0, 0, 470, 0, 0, - 0, 0, 0, 0, 359, 367, 555, 0, 320, 338, - 340, 0, 335, 350, 351, 353, 0, 355, 0, 357, - 358, 324, 325, 326, 0, 0, 0, 0, 346, 367, - 0, 367, 43, 559, 48, 0, 0, 53, 54, 560, - 561, 562, 0, 78, 195, 197, 200, 201, 202, 82, - 83, 84, 0, 0, 192, 0, 0, 0, 0, 0, - 186, 187, 80, 148, 146, 0, 143, 142, 90, 0, - 159, 159, 111, 112, 162, 0, 162, 162, 162, 0, - 0, 105, 106, 107, 99, 0, 100, 101, 102, 0, - 103, 0, 0, 803, 66, 0, 70, 71, 67, 574, - 68, 802, 0, 0, 587, 211, 577, 578, 579, 580, - 581, 582, 583, 584, 585, 586, 0, 228, 803, 231, - 268, 252, 0, 0, 269, 270, 0, 532, 533, 0, - 525, 24, 0, 569, 570, 516, 517, 317, 391, 393, - 395, 0, 304, 382, 403, 386, 0, 383, 0, 0, - 377, 443, 0, 0, 410, -2, 446, 447, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 522, 0, 500, - 0, 0, 460, 471, 472, 473, 474, 547, 0, 0, - -2, 0, 0, 522, 0, 0, 0, 332, 339, 0, - 0, 333, 0, 334, 354, 356, 0, 0, 0, 0, - 330, 522, 367, 39, 51, 52, 0, 0, 58, 163, - 164, 0, 198, 0, 0, 0, 181, 0, 0, 184, - 185, 0, 155, 0, 147, 86, 144, 0, 162, 162, - 113, 0, 114, 115, 116, 0, 132, 0, 0, 0, - 0, 596, 65, 73, 74, 0, 203, 802, 0, 212, - 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, - 802, 0, 0, 802, 588, 589, 590, 591, 0, 230, - 271, 272, 273, 536, 0, 25, 367, 0, 311, 506, - 0, 384, 0, 404, 387, 444, 307, 0, 134, 134, - 485, 134, 138, 488, 134, 490, 134, 493, 0, 0, - 0, 0, 505, 0, 0, 0, 497, 459, 503, 0, - 32, 0, 547, 537, 549, 551, 0, 28, 0, 543, - 0, 530, 556, 368, 557, 336, 0, 341, 0, 0, - 0, 344, 0, 530, 38, 55, 56, 57, 196, 199, - 0, 188, 134, 191, 182, 183, 0, 157, 0, 149, - 150, 151, 152, 153, 154, 135, 109, 110, 160, 161, - 159, 0, 159, 0, 139, 0, 803, 0, 0, 204, - 0, 205, 207, 208, 209, 0, 251, 518, 318, 445, - 388, 448, 482, 159, 486, 487, 489, 491, 492, 494, - 450, 449, 451, 0, 0, 454, 0, 0, 0, 0, - 0, 501, 0, 33, 0, 552, -2, 0, 0, 0, - 45, 36, 0, 328, 0, 0, 0, 363, 331, 37, - 173, 0, 190, 0, 165, 158, 0, 162, 133, 162, - 0, 0, 63, 75, 76, 0, 0, 520, 0, 483, - 484, 0, 0, 0, 0, 475, 458, 498, 0, 550, - 0, -2, 0, 545, 544, 0, 337, 364, 365, 366, - 327, 172, 174, 0, 179, 0, 189, 0, 170, 0, - 167, 169, 156, 122, 123, 137, 140, 0, 0, 27, - 0, 0, 452, 453, 455, 456, 0, 0, 0, 0, - 540, 28, 0, 329, 175, 176, 0, 180, 178, 0, - 85, 0, 166, 168, 69, 0, 224, 0, 521, 519, - 457, 0, 0, 0, 548, -2, 546, 177, 0, 171, - 72, 223, 0, 0, 476, 0, 479, 0, 206, 225, - 0, 477, 0, 0, 0, 193, 0, 0, 0, 478, - 0, 0, 226, 227, + 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 0, 0, 81, + 0, 79, 0, 821, 0, 69, 0, 0, 0, 0, + 0, 821, 0, 0, 0, 0, 0, 0, 0, 248, + 0, 250, 821, 821, 821, 821, 821, 821, 821, 821, + 259, 822, 823, 260, 261, 262, 821, 821, 264, 0, + 282, 278, 279, 0, 0, 277, 302, 303, 29, 819, + 23, 0, 0, 545, 0, 537, 538, 541, 544, 28, + 311, 0, 316, 315, 307, 0, 323, 0, 0, 0, + 327, 0, 329, 330, 0, 386, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 410, 411, 412, 413, 414, + 415, 416, 389, 0, 403, 0, 0, 0, 445, 446, + 447, 448, 449, 450, 451, 0, 318, 28, 0, 423, + 0, 0, 0, 0, 0, 0, 0, 0, 314, 0, + 510, 0, 475, 0, 476, 477, 478, 479, 480, 481, + 482, 0, 318, 0, 0, 44, 0, 374, 0, 0, + 0, 0, 0, 0, 363, 0, 0, 366, 0, 0, + 0, 0, 357, 0, 0, 377, 768, 359, 0, 361, + 362, -2, 0, 0, 0, 40, 41, 0, 47, 797, + 49, 50, 0, 0, 0, 164, 580, 581, 582, 578, + 208, 0, 0, 145, 141, 87, 88, 89, 134, 91, + 134, 134, 134, 134, 161, 161, 161, 161, 117, 118, + 119, 120, 121, 0, 0, 104, 134, 134, 134, 108, + 124, 125, 126, 127, 128, 129, 130, 131, 92, 93, + 94, 95, 96, 97, 98, 136, 136, 136, 138, 138, + 609, 64, 0, 72, 0, 821, 0, 821, 77, 0, + 224, 0, 243, 586, 0, 821, 246, 247, 376, 617, + 618, 251, 252, 253, 254, 255, 256, 257, 258, 263, + 267, 0, 285, 0, 0, 271, 270, 549, 0, 0, + 0, 0, 0, 540, 542, 543, 548, 31, 314, 0, + 529, 0, 0, 0, 317, 26, 384, 385, 387, 404, + 0, 406, 408, 328, 324, 0, 519, -2, 394, 395, + 419, 420, 421, 0, 0, 0, 0, 417, 399, 0, + 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 444, 494, 495, 0, 442, 443, 452, 0, + 0, 319, 320, 422, 0, 567, 28, 0, 0, 0, + 0, 0, 518, 0, 0, 0, 0, 516, 513, 0, + 0, 484, 0, 0, 0, 0, 0, 0, 373, 381, + 569, 0, 334, 352, 354, 0, 349, 364, 365, 367, + 0, 369, 0, 371, 372, 338, 339, 340, 0, 0, + 0, 0, 360, 381, 0, 381, 43, 573, 48, 0, + 0, 53, 54, 574, 575, 576, 0, 78, 209, 211, + 214, 215, 216, 82, 83, 84, 0, 0, 196, 0, + 0, 190, 190, 0, 188, 189, 80, 148, 146, 0, + 143, 142, 90, 0, 161, 161, 111, 112, 164, 0, + 164, 164, 164, 0, 0, 105, 106, 107, 99, 0, + 100, 101, 102, 0, 103, 0, 0, 821, 66, 0, + 70, 71, 67, 588, 68, 820, 0, 0, 601, 225, + 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, + 0, 242, 821, 245, 282, 266, 0, 0, 283, 284, + 0, 546, 547, 0, 539, 24, 0, 583, 584, 530, + 531, 331, 405, 407, 409, 0, 318, 396, 417, 400, + 0, 397, 0, 0, 391, 457, 0, 0, 424, -2, + 460, 461, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 536, 0, 514, 0, 0, 474, 485, 486, 487, + 488, 561, 0, 0, -2, 0, 0, 536, 0, 0, + 0, 346, 353, 0, 0, 347, 0, 348, 368, 370, + 0, 0, 0, 0, 344, 536, 381, 39, 51, 52, + 0, 0, 58, 165, 166, 0, 212, 0, 0, 0, + 183, 190, 190, 186, 191, 187, 0, 156, 0, 147, + 86, 144, 0, 164, 164, 113, 0, 114, 115, 116, + 0, 132, 0, 0, 0, 0, 610, 65, 73, 74, + 0, 217, 820, 0, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 820, 0, 0, 820, 602, + 603, 604, 605, 0, 244, 285, 286, 287, 550, 0, + 25, 381, 0, 325, 520, 0, 398, 0, 418, 401, + 458, 321, 0, 134, 134, 499, 134, 138, 502, 134, + 504, 134, 507, 0, 0, 0, 0, 519, 0, 0, + 0, 511, 473, 517, 0, 32, 0, 561, 551, 563, + 565, 0, 28, 0, 557, 0, 544, 570, 382, 571, + 350, 0, 355, 0, 0, 0, 358, 0, 544, 38, + 55, 56, 57, 210, 213, 0, 192, 134, 195, 184, + 185, 0, 159, 0, 149, 150, 151, 152, 153, 155, + 135, 109, 110, 162, 163, 161, 0, 161, 0, 139, + 0, 821, 0, 0, 218, 0, 219, 221, 222, 223, + 0, 265, 532, 332, 459, 402, 462, 496, 161, 500, + 501, 503, 505, 506, 508, 464, 463, 465, 0, 0, + 468, 0, 0, 0, 0, 0, 515, 0, 33, 0, + 566, -2, 0, 0, 0, 45, 36, 0, 342, 0, + 0, 0, 377, 345, 37, 175, 0, 194, 0, 167, + 160, 0, 0, 164, 133, 164, 0, 0, 63, 75, + 76, 0, 0, 534, 0, 497, 498, 0, 0, 0, + 0, 489, 472, 512, 0, 564, 0, -2, 0, 559, + 558, 0, 351, 378, 379, 380, 341, 174, 176, 0, + 181, 0, 193, 0, 172, 0, 169, 171, 157, 154, + 122, 123, 137, 140, 0, 0, 27, 0, 0, 466, + 467, 469, 470, 0, 0, 0, 0, 554, 28, 0, + 343, 177, 178, 0, 182, 180, 0, 85, 0, 168, + 170, 0, 69, 0, 238, 0, 535, 533, 471, 0, + 0, 0, 562, -2, 560, 179, 0, 173, 158, 72, + 237, 0, 0, 490, 0, 493, 0, 220, 239, 0, + 491, 0, 0, 0, 197, 0, 0, 198, 199, 0, + 0, 492, 200, 0, 0, 0, 0, 0, 201, 203, + 204, 0, 0, 202, 240, 241, 205, 206, 207, } var yyTok1 = [...]int{ @@ -2404,7 +2424,7 @@ var yyTok1 = [...]int{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 74, 3, 3, 3, 101, 93, 3, 54, 56, 98, 96, 55, 97, 111, 99, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 255, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 259, 82, 81, 83, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -2438,7 +2458,7 @@ var yyTok2 = [...]int{ 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, } var yyTok3 = [...]int{ 0, @@ -2783,35 +2803,35 @@ yydefault: case 1: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:308 + //line sql.y:313 { setParseTree(yylex, yyDollar[1].statement) } case 2: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:313 + //line sql.y:318 { } case 3: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:314 + //line sql.y:319 { } case 4: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:318 + //line sql.y:323 { yyVAL.statement = yyDollar[1].selStmt } case 22: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:339 + //line sql.y:344 { setParseTree(yylex, nil) } case 23: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:345 + //line sql.y:350 { sel := yyDollar[1].selStmt.(*Select) sel.OrderBy = yyDollar[2].orderBy @@ -2821,55 +2841,55 @@ yydefault: } case 24: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:353 + //line sql.y:358 { yyVAL.selStmt = &Union{Type: yyDollar[2].str, Left: yyDollar[1].selStmt, Right: yyDollar[3].selStmt, OrderBy: yyDollar[4].orderBy, Limit: yyDollar[5].limit, Lock: yyDollar[6].str} } case 25: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:357 + //line sql.y:362 { yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, SelectExprs: SelectExprs{Nextval{Expr: yyDollar[5].expr}}, From: TableExprs{&AliasedTableExpr{Expr: yyDollar[7].tableName}}} } case 26: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:363 + //line sql.y:368 { yyVAL.statement = &Stream{Comments: Comments(yyDollar[2].bytes2), SelectExpr: yyDollar[3].selectExpr, Table: yyDollar[5].tableName} } case 27: yyDollar = yyS[yypt-10 : yypt+1] - //line sql.y:370 + //line sql.y:375 { yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, Distinct: yyDollar[4].str, Hints: yyDollar[5].str, SelectExprs: yyDollar[6].selectExprs, From: yyDollar[7].tableExprs, Where: NewWhere(WhereStr, yyDollar[8].expr), GroupBy: GroupBy(yyDollar[9].exprs), Having: NewWhere(HavingStr, yyDollar[10].expr)} } case 28: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:376 + //line sql.y:381 { yyVAL.selStmt = yyDollar[1].selStmt } case 29: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:380 + //line sql.y:385 { yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} } case 30: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:386 + //line sql.y:391 { yyVAL.selStmt = yyDollar[1].selStmt } case 31: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:390 + //line sql.y:395 { yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} } case 32: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:397 + //line sql.y:402 { // insert_data returns a *Insert pre-filled with Columns & Values ins := yyDollar[6].ins @@ -2883,7 +2903,7 @@ yydefault: } case 33: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:409 + //line sql.y:414 { cols := make(Columns, 0, len(yyDollar[7].updateExprs)) vals := make(ValTuple, 0, len(yyDollar[8].updateExprs)) @@ -2895,174 +2915,174 @@ yydefault: } case 34: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:421 + //line sql.y:426 { yyVAL.str = InsertStr } case 35: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:425 + //line sql.y:430 { yyVAL.str = ReplaceStr } case 36: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:431 + //line sql.y:436 { yyVAL.statement = &Update{Comments: Comments(yyDollar[2].bytes2), TableExprs: yyDollar[3].tableExprs, Exprs: yyDollar[5].updateExprs, Where: NewWhere(WhereStr, yyDollar[6].expr), OrderBy: yyDollar[7].orderBy, Limit: yyDollar[8].limit} } case 37: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:437 + //line sql.y:442 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), TableExprs: TableExprs{&AliasedTableExpr{Expr: yyDollar[4].tableName}}, Partitions: yyDollar[5].partitions, Where: NewWhere(WhereStr, yyDollar[6].expr), OrderBy: yyDollar[7].orderBy, Limit: yyDollar[8].limit} } case 38: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:441 + //line sql.y:446 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[4].tableNames, TableExprs: yyDollar[6].tableExprs, Where: NewWhere(WhereStr, yyDollar[7].expr)} } case 39: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:445 + //line sql.y:450 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[3].tableNames, TableExprs: yyDollar[5].tableExprs, Where: NewWhere(WhereStr, yyDollar[6].expr)} } case 40: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:450 + //line sql.y:455 { } case 41: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:451 + //line sql.y:456 { } case 42: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:455 + //line sql.y:460 { yyVAL.tableNames = TableNames{yyDollar[1].tableName} } case 43: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:459 + //line sql.y:464 { yyVAL.tableNames = append(yyVAL.tableNames, yyDollar[3].tableName) } case 44: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:464 + //line sql.y:469 { yyVAL.partitions = nil } case 45: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:468 + //line sql.y:473 { yyVAL.partitions = yyDollar[3].partitions } case 46: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:474 + //line sql.y:479 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[3].setExprs} } case 47: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:478 + //line sql.y:483 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[4].setExprs} } case 48: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:482 + //line sql.y:487 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[5].setExprs} } case 49: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:486 + //line sql.y:491 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[4].setExprs} } case 50: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:492 + //line sql.y:497 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } case 51: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:496 + //line sql.y:501 { yyVAL.setExprs = append(yyVAL.setExprs, yyDollar[3].setExpr) } case 52: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:502 + //line sql.y:507 { - yyVAL.setExpr = yyDollar[3].setExpr + yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(yyDollar[3].str))} } case 53: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:506 + //line sql.y:511 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("0"))} + yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadWrite))} } case 54: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:510 + //line sql.y:515 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("1"))} + yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadOnly))} } case 55: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:516 + //line sql.y:521 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("repeatable read"))} + yyVAL.str = IsolationLevelRepeatableRead } case 56: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:520 + //line sql.y:525 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read committed"))} + yyVAL.str = IsolationLevelReadCommitted } case 57: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:524 + //line sql.y:529 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read uncommitted"))} + yyVAL.str = IsolationLevelReadUncommitted } case 58: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:528 + //line sql.y:533 { - yyVAL.setExpr = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("serializable"))} + yyVAL.str = IsolationLevelSerializable } case 59: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:534 + //line sql.y:539 { yyVAL.str = SessionStr } case 60: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:538 + //line sql.y:543 { yyVAL.str = GlobalStr } case 61: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:544 + //line sql.y:549 { yyDollar[1].ddl.TableSpec = yyDollar[2].TableSpec yyVAL.statement = yyDollar[1].ddl } case 62: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:549 + //line sql.y:554 { // Create table [name] like [name] yyDollar[1].ddl.OptLike = yyDollar[2].optLike @@ -3070,26 +3090,26 @@ yydefault: } case 63: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:555 + //line sql.y:560 { // Change this to an alter statement yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[7].tableName, NewName: yyDollar[7].tableName} } case 64: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:560 + //line sql.y:565 { yyVAL.statement = &DDL{Action: CreateStr, NewName: yyDollar[3].tableName.ToViewName()} } case 65: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:564 + //line sql.y:569 { yyVAL.statement = &DDL{Action: CreateStr, NewName: yyDollar[5].tableName.ToViewName()} } case 66: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:568 + //line sql.y:573 { yyVAL.statement = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{ Name: yyDollar[3].colIdent, @@ -3099,120 +3119,120 @@ yydefault: } case 67: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:576 + //line sql.y:581 { yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} } case 68: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:580 + //line sql.y:585 { yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} } case 69: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:585 + //line sql.y:590 { yyVAL.colIdent = NewColIdent("") } case 70: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:589 + //line sql.y:594 { yyVAL.colIdent = yyDollar[2].colIdent } case 71: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:595 + //line sql.y:600 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } case 72: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:600 + //line sql.y:605 { var v []VindexParam yyVAL.vindexParams = v } case 73: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:605 + //line sql.y:610 { yyVAL.vindexParams = yyDollar[2].vindexParams } case 74: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:611 + //line sql.y:616 { yyVAL.vindexParams = make([]VindexParam, 0, 4) yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[1].vindexParam) } case 75: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:616 + //line sql.y:621 { yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[3].vindexParam) } case 76: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:622 + //line sql.y:627 { yyVAL.vindexParam = VindexParam{Key: yyDollar[1].colIdent, Val: yyDollar[3].str} } case 77: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:628 + //line sql.y:633 { yyVAL.ddl = &DDL{Action: CreateStr, NewName: yyDollar[4].tableName} setDDL(yylex, yyVAL.ddl) } case 78: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:635 + //line sql.y:640 { yyVAL.TableSpec = yyDollar[2].TableSpec yyVAL.TableSpec.Options = yyDollar[4].str } case 79: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:642 + //line sql.y:647 { yyVAL.optLike = &OptLike{LikeTable: yyDollar[2].tableName} } case 80: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:646 + //line sql.y:651 { yyVAL.optLike = &OptLike{LikeTable: yyDollar[3].tableName} } case 81: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:652 + //line sql.y:657 { yyVAL.TableSpec = &TableSpec{} yyVAL.TableSpec.AddColumn(yyDollar[1].columnDefinition) } case 82: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:657 + //line sql.y:662 { yyVAL.TableSpec.AddColumn(yyDollar[3].columnDefinition) } case 83: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:661 + //line sql.y:666 { yyVAL.TableSpec.AddIndex(yyDollar[3].indexDefinition) } case 84: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:665 + //line sql.y:670 { yyVAL.TableSpec.AddConstraint(yyDollar[3].constraintDefinition) } case 85: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:671 + //line sql.y:676 { yyDollar[2].columnType.NotNull = yyDollar[3].boolVal yyDollar[2].columnType.Default = yyDollar[4].optVal @@ -3224,7 +3244,7 @@ yydefault: } case 86: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:682 + //line sql.y:687 { yyVAL.columnType = yyDollar[1].columnType yyVAL.columnType.Unsigned = yyDollar[2].boolVal @@ -3232,62 +3252,62 @@ yydefault: } case 90: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:693 + //line sql.y:698 { yyVAL.columnType = yyDollar[1].columnType yyVAL.columnType.Length = yyDollar[2].optVal } case 91: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:698 + //line sql.y:703 { yyVAL.columnType = yyDollar[1].columnType } case 92: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:704 + //line sql.y:709 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 93: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:708 + //line sql.y:713 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 94: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:712 + //line sql.y:717 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 95: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:716 + //line sql.y:721 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 96: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:720 + //line sql.y:725 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 97: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:724 + //line sql.y:729 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 98: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:728 + //line sql.y:733 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 99: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:734 + //line sql.y:739 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3295,7 +3315,7 @@ yydefault: } case 100: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:740 + //line sql.y:745 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3303,7 +3323,7 @@ yydefault: } case 101: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:746 + //line sql.y:751 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3311,7 +3331,7 @@ yydefault: } case 102: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:752 + //line sql.y:757 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3319,7 +3339,7 @@ yydefault: } case 103: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:758 + //line sql.y:763 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3327,206 +3347,206 @@ yydefault: } case 104: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:766 + //line sql.y:771 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 105: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:770 + //line sql.y:775 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } case 106: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:774 + //line sql.y:779 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } case 107: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:778 + //line sql.y:783 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } case 108: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:782 + //line sql.y:787 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 109: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:788 + //line sql.y:793 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 110: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:792 + //line sql.y:797 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 111: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:796 + //line sql.y:801 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } case 112: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:800 + //line sql.y:805 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } case 113: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:804 + //line sql.y:809 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 114: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:808 + //line sql.y:813 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 115: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:812 + //line sql.y:817 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 116: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:816 + //line sql.y:821 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 117: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:820 + //line sql.y:825 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 118: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:824 + //line sql.y:829 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 119: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:828 + //line sql.y:833 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 120: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:832 + //line sql.y:837 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 121: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:836 + //line sql.y:841 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 122: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:840 + //line sql.y:845 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 123: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:845 + //line sql.y:850 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 124: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:851 + //line sql.y:856 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 125: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:855 + //line sql.y:860 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 126: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:859 + //line sql.y:864 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 127: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:863 + //line sql.y:868 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 128: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:867 + //line sql.y:872 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 129: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:871 + //line sql.y:876 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 130: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:875 + //line sql.y:880 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 131: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:879 + //line sql.y:884 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 132: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:885 + //line sql.y:890 { yyVAL.strs = make([]string, 0, 4) yyVAL.strs = append(yyVAL.strs, "'"+string(yyDollar[1].bytes)+"'") } case 133: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:890 + //line sql.y:895 { yyVAL.strs = append(yyDollar[1].strs, "'"+string(yyDollar[3].bytes)+"'") } case 134: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:895 + //line sql.y:900 { yyVAL.optVal = nil } case 135: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:899 + //line sql.y:904 { yyVAL.optVal = NewIntVal(yyDollar[2].bytes) } case 136: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:904 + //line sql.y:909 { yyVAL.LengthScaleOption = LengthScaleOption{} } case 137: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:908 + //line sql.y:913 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3535,13 +3555,13 @@ yydefault: } case 138: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:916 + //line sql.y:921 { yyVAL.LengthScaleOption = LengthScaleOption{} } case 139: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:920 + //line sql.y:925 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3549,7 +3569,7 @@ yydefault: } case 140: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:926 + //line sql.y:931 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3558,398 +3578,482 @@ yydefault: } case 141: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:934 + //line sql.y:939 { yyVAL.boolVal = BoolVal(false) } case 142: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:938 + //line sql.y:943 { yyVAL.boolVal = BoolVal(true) } case 143: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:943 + //line sql.y:948 { yyVAL.boolVal = BoolVal(false) } case 144: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:947 + //line sql.y:952 { yyVAL.boolVal = BoolVal(true) } case 145: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:953 + //line sql.y:958 { yyVAL.boolVal = BoolVal(false) } case 146: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:957 + //line sql.y:962 { yyVAL.boolVal = BoolVal(false) } case 147: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:961 + //line sql.y:966 { yyVAL.boolVal = BoolVal(true) } case 148: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:966 + //line sql.y:971 { yyVAL.optVal = nil } case 149: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:970 + //line sql.y:975 { yyVAL.optVal = NewStrVal(yyDollar[2].bytes) } case 150: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:974 + //line sql.y:979 { yyVAL.optVal = NewIntVal(yyDollar[2].bytes) } case 151: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:978 + //line sql.y:983 { yyVAL.optVal = NewFloatVal(yyDollar[2].bytes) } case 152: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:982 + //line sql.y:987 { yyVAL.optVal = NewValArg(yyDollar[2].bytes) } case 153: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:986 + //line sql.y:991 { yyVAL.optVal = NewValArg(yyDollar[2].bytes) } case 154: + yyDollar = yyS[yypt-4 : yypt+1] + //line sql.y:995 + { + yyVAL.optVal = NewValArg(yyDollar[2].bytes) + } + case 155: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:990 + //line sql.y:999 { yyVAL.optVal = NewBitVal(yyDollar[2].bytes) } - case 155: + case 156: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:995 + //line sql.y:1004 { yyVAL.optVal = nil } - case 156: + case 157: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:999 + //line sql.y:1008 { yyVAL.optVal = NewValArg(yyDollar[3].bytes) } - case 157: + case 158: + yyDollar = yyS[yypt-5 : yypt+1] + //line sql.y:1012 + { + yyVAL.optVal = NewValArg(yyDollar[3].bytes) + } + case 159: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1004 + //line sql.y:1017 { yyVAL.boolVal = BoolVal(false) } - case 158: + case 160: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1008 + //line sql.y:1021 { yyVAL.boolVal = BoolVal(true) } - case 159: + case 161: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1013 + //line sql.y:1026 { yyVAL.str = "" } - case 160: + case 162: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1017 + //line sql.y:1030 { yyVAL.str = string(yyDollar[3].bytes) } - case 161: + case 163: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1021 + //line sql.y:1034 { yyVAL.str = string(yyDollar[3].bytes) } - case 162: + case 164: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1026 + //line sql.y:1039 { yyVAL.str = "" } - case 163: + case 165: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1030 + //line sql.y:1043 { yyVAL.str = string(yyDollar[2].bytes) } - case 164: + case 166: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1034 + //line sql.y:1047 { yyVAL.str = string(yyDollar[2].bytes) } - case 165: + case 167: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1039 + //line sql.y:1052 { yyVAL.colKeyOpt = colKeyNone } - case 166: + case 168: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1043 + //line sql.y:1056 { yyVAL.colKeyOpt = colKeyPrimary } - case 167: + case 169: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1047 + //line sql.y:1060 { yyVAL.colKeyOpt = colKey } - case 168: + case 170: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1051 + //line sql.y:1064 { yyVAL.colKeyOpt = colKeyUniqueKey } - case 169: + case 171: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1055 + //line sql.y:1068 { yyVAL.colKeyOpt = colKeyUnique } - case 170: + case 172: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1060 + //line sql.y:1073 { yyVAL.optVal = nil } - case 171: + case 173: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1064 + //line sql.y:1077 { yyVAL.optVal = NewStrVal(yyDollar[2].bytes) } - case 172: + case 174: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1070 + //line sql.y:1083 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns, Options: yyDollar[5].indexOptions} } - case 173: + case 175: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1074 + //line sql.y:1087 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns} } - case 174: + case 176: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1080 + //line sql.y:1093 { yyVAL.indexOptions = []*IndexOption{yyDollar[1].indexOption} } - case 175: + case 177: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1084 + //line sql.y:1097 { yyVAL.indexOptions = append(yyVAL.indexOptions, yyDollar[2].indexOption) } - case 176: + case 178: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1090 + //line sql.y:1103 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Using: string(yyDollar[2].bytes)} } - case 177: + case 179: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1094 + //line sql.y:1107 { // should not be string yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewIntVal(yyDollar[3].bytes)} } - case 178: + case 180: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1099 + //line sql.y:1112 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewStrVal(yyDollar[2].bytes)} } - case 179: + case 181: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1105 + //line sql.y:1118 { yyVAL.str = "" } - case 180: + case 182: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1109 + //line sql.y:1122 { yyVAL.str = string(yyDollar[1].bytes) } - case 181: + case 183: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1115 + //line sql.y:1128 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].bytes), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} } - case 182: + case 184: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1119 + //line sql.y:1132 { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(string(yyDollar[3].bytes)), Spatial: true, Unique: false} + yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Spatial: true, Unique: false} } - case 183: + case 185: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1123 + //line sql.y:1136 { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(string(yyDollar[3].bytes)), Unique: true} + yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Unique: true} } - case 184: + case 186: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1127 + //line sql.y:1140 { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes), Name: NewColIdent(string(yyDollar[2].bytes)), Unique: true} + yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes), Name: NewColIdent(yyDollar[2].str), Unique: true} } - case 185: + case 187: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1131 + //line sql.y:1144 { - yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].str), Name: NewColIdent(string(yyDollar[2].bytes)), Unique: false} + yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].str), Name: NewColIdent(yyDollar[2].str), Unique: false} } - case 186: + case 188: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1137 + //line sql.y:1150 { yyVAL.str = string(yyDollar[1].bytes) } - case 187: + case 189: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1141 + //line sql.y:1154 { yyVAL.str = string(yyDollar[1].bytes) } - case 188: + case 190: + yyDollar = yyS[yypt-0 : yypt+1] + //line sql.y:1159 + { + yyVAL.str = "" + } + case 191: + yyDollar = yyS[yypt-1 : yypt+1] + //line sql.y:1163 + { + yyVAL.str = string(yyDollar[1].bytes) + } + case 192: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1147 + //line sql.y:1169 { yyVAL.indexColumns = []*IndexColumn{yyDollar[1].indexColumn} } - case 189: + case 193: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1151 + //line sql.y:1173 { yyVAL.indexColumns = append(yyVAL.indexColumns, yyDollar[3].indexColumn) } - case 190: + case 194: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1157 + //line sql.y:1179 { yyVAL.indexColumn = &IndexColumn{Column: yyDollar[1].colIdent, Length: yyDollar[2].optVal} } - case 191: + case 195: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1163 + //line sql.y:1185 { yyVAL.constraintDefinition = &ConstraintDefinition{Name: string(yyDollar[2].bytes), Details: yyDollar[3].constraintInfo} } - case 192: + case 196: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1167 + //line sql.y:1189 { yyVAL.constraintDefinition = &ConstraintDefinition{Details: yyDollar[1].constraintInfo} } - case 193: + case 197: yyDollar = yyS[yypt-10 : yypt+1] - //line sql.y:1174 + //line sql.y:1196 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns} } - case 194: + case 198: + yyDollar = yyS[yypt-11 : yypt+1] + //line sql.y:1200 + { + yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction} + } + case 199: + yyDollar = yyS[yypt-11 : yypt+1] + //line sql.y:1204 + { + yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnUpdate: yyDollar[11].ReferenceAction} + } + case 200: + yyDollar = yyS[yypt-12 : yypt+1] + //line sql.y:1208 + { + yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction, OnUpdate: yyDollar[12].ReferenceAction} + } + case 201: + yyDollar = yyS[yypt-3 : yypt+1] + //line sql.y:1214 + { + yyVAL.ReferenceAction = yyDollar[3].ReferenceAction + } + case 202: + yyDollar = yyS[yypt-3 : yypt+1] + //line sql.y:1220 + { + yyVAL.ReferenceAction = yyDollar[3].ReferenceAction + } + case 203: + yyDollar = yyS[yypt-1 : yypt+1] + //line sql.y:1226 + { + yyVAL.ReferenceAction = Restrict + } + case 204: + yyDollar = yyS[yypt-1 : yypt+1] + //line sql.y:1230 + { + yyVAL.ReferenceAction = Cascade + } + case 205: + yyDollar = yyS[yypt-2 : yypt+1] + //line sql.y:1234 + { + yyVAL.ReferenceAction = NoAction + } + case 206: + yyDollar = yyS[yypt-2 : yypt+1] + //line sql.y:1238 + { + yyVAL.ReferenceAction = SetDefault + } + case 207: + yyDollar = yyS[yypt-2 : yypt+1] + //line sql.y:1242 + { + yyVAL.ReferenceAction = SetNull + } + case 208: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1179 + //line sql.y:1247 { yyVAL.str = "" } - case 195: + case 209: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1183 + //line sql.y:1251 { yyVAL.str = " " + string(yyDollar[1].str) } - case 196: + case 210: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1187 + //line sql.y:1255 { yyVAL.str = string(yyDollar[1].str) + ", " + string(yyDollar[3].str) } - case 197: + case 211: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1195 + //line sql.y:1263 { yyVAL.str = yyDollar[1].str } - case 198: + case 212: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1199 + //line sql.y:1267 { yyVAL.str = yyDollar[1].str + " " + yyDollar[2].str } - case 199: + case 213: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1203 + //line sql.y:1271 { yyVAL.str = yyDollar[1].str + "=" + yyDollar[3].str } - case 200: + case 214: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1209 + //line sql.y:1277 { yyVAL.str = yyDollar[1].colIdent.String() } - case 201: + case 215: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1213 + //line sql.y:1281 { yyVAL.str = "'" + string(yyDollar[1].bytes) + "'" } - case 202: + case 216: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1217 + //line sql.y:1285 { yyVAL.str = string(yyDollar[1].bytes) } - case 203: + case 217: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1223 + //line sql.y:1291 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} } - case 204: + case 218: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1227 + //line sql.y:1295 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} } - case 205: + case 219: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1231 + //line sql.y:1299 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} } - case 206: + case 220: yyDollar = yyS[yypt-12 : yypt+1] - //line sql.y:1235 + //line sql.y:1303 { yyVAL.statement = &DDL{ Action: AddColVindexStr, @@ -3962,9 +4066,9 @@ yydefault: VindexCols: yyDollar[9].columns, } } - case 207: + case 221: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1248 + //line sql.y:1316 { yyVAL.statement = &DDL{ Action: DropColVindexStr, @@ -3974,71 +4078,71 @@ yydefault: }, } } - case 208: + case 222: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1258 + //line sql.y:1326 { // Change this to a rename statement yyVAL.statement = &DDL{Action: RenameStr, Table: yyDollar[4].tableName, NewName: yyDollar[7].tableName} } - case 209: + case 223: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1263 + //line sql.y:1331 { // Rename an index can just be an alter yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, NewName: yyDollar[4].tableName} } - case 210: + case 224: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1268 + //line sql.y:1336 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName.ToViewName(), NewName: yyDollar[3].tableName.ToViewName()} } - case 211: + case 225: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1272 + //line sql.y:1340 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, PartitionSpec: yyDollar[5].partSpec} } - case 223: + case 237: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1291 + //line sql.y:1359 { yyVAL.partSpec = &PartitionSpec{Action: ReorganizeStr, Name: yyDollar[3].colIdent, Definitions: yyDollar[6].partDefs} } - case 224: + case 238: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1297 + //line sql.y:1365 { yyVAL.partDefs = []*PartitionDefinition{yyDollar[1].partDef} } - case 225: + case 239: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1301 + //line sql.y:1369 { yyVAL.partDefs = append(yyDollar[1].partDefs, yyDollar[3].partDef) } - case 226: + case 240: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:1307 + //line sql.y:1375 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Limit: yyDollar[7].expr} } - case 227: + case 241: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:1311 + //line sql.y:1379 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Maxvalue: true} } - case 228: + case 242: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1317 + //line sql.y:1385 { yyVAL.statement = &DDL{Action: RenameStr, Table: yyDollar[3].tableName, NewName: yyDollar[5].tableName} } - case 229: + case 243: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1323 + //line sql.y:1391 { var exists bool if yyDollar[3].byt != 0 { @@ -4046,16 +4150,16 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, Table: yyDollar[4].tableName, IfExists: exists} } - case 230: + case 244: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:1331 + //line sql.y:1399 { // Change this to an alter statement yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[5].tableName, NewName: yyDollar[5].tableName} } - case 231: + case 245: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1336 + //line sql.y:1404 { var exists bool if yyDollar[3].byt != 0 { @@ -4063,130 +4167,130 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, Table: yyDollar[4].tableName.ToViewName(), IfExists: exists} } - case 232: + case 246: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1344 + //line sql.y:1412 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 233: + case 247: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1348 + //line sql.y:1416 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 234: + case 248: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1354 + //line sql.y:1422 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[3].tableName} } - case 235: + case 249: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1358 + //line sql.y:1426 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[2].tableName} } - case 236: + case 250: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1363 + //line sql.y:1431 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName, NewName: yyDollar[3].tableName} } - case 237: + case 251: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1369 + //line sql.y:1437 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 238: + case 252: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1373 + //line sql.y:1441 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 239: + case 253: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1377 + //line sql.y:1445 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 240: + case 254: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1382 + //line sql.y:1450 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 241: + case 255: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1386 + //line sql.y:1454 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 242: + case 256: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1390 + //line sql.y:1458 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 243: + case 257: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1394 + //line sql.y:1462 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 244: + case 258: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1398 + //line sql.y:1466 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 245: + case 259: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1402 + //line sql.y:1470 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 246: + case 260: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1406 + //line sql.y:1474 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 247: + case 261: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1410 + //line sql.y:1478 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 248: + case 262: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1414 + //line sql.y:1482 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 249: + case 263: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1418 + //line sql.y:1486 { yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} } - case 250: + case 264: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1422 + //line sql.y:1490 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 251: + case 265: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1426 + //line sql.y:1494 { showTablesOpt := &ShowTablesOpt{Full: yyDollar[2].str, DbName: yyDollar[6].str, Filter: yyDollar[7].showFilter} yyVAL.statement = &Show{Type: string(yyDollar[3].bytes), ShowTablesOpt: showTablesOpt, OnTable: yyDollar[5].tableName} } - case 252: + case 266: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1431 + //line sql.y:1499 { // this is ugly, but I couldn't find a better way for now if yyDollar[3].str == "processlist" { @@ -4196,616 +4300,618 @@ yydefault: yyVAL.statement = &Show{Type: yyDollar[3].str, ShowTablesOpt: showTablesOpt} } } - case 253: + case 267: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1441 + //line sql.y:1509 { yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} } - case 254: + case 268: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1445 + //line sql.y:1513 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 255: + case 269: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1449 + //line sql.y:1517 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 256: + case 270: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1453 + //line sql.y:1521 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), ShowCollationFilterOpt: &yyDollar[4].expr} + // Cannot dereference $4 directly, or else the parser stackcannot be pooled. See yyParsePooled + showCollationFilterOpt := yyDollar[4].expr + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), ShowCollationFilterOpt: &showCollationFilterOpt} } - case 257: + case 271: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1457 + //line sql.y:1527 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), OnTable: yyDollar[4].tableName} } - case 258: + case 272: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1461 + //line sql.y:1531 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 259: + case 273: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1465 + //line sql.y:1535 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 260: + case 274: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1469 + //line sql.y:1539 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 261: + case 275: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1473 + //line sql.y:1543 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 262: + case 276: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1477 + //line sql.y:1547 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 263: + case 277: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1487 + //line sql.y:1557 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 264: + case 278: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1493 + //line sql.y:1563 { yyVAL.str = string(yyDollar[1].bytes) } - case 265: + case 279: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1497 + //line sql.y:1567 { yyVAL.str = string(yyDollar[1].bytes) } - case 266: + case 280: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1503 + //line sql.y:1573 { yyVAL.str = "" } - case 267: + case 281: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1507 + //line sql.y:1577 { yyVAL.str = "full " } - case 268: + case 282: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1513 + //line sql.y:1583 { yyVAL.str = "" } - case 269: + case 283: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1517 + //line sql.y:1587 { yyVAL.str = yyDollar[2].tableIdent.v } - case 270: + case 284: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1521 + //line sql.y:1591 { yyVAL.str = yyDollar[2].tableIdent.v } - case 271: + case 285: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1527 + //line sql.y:1597 { yyVAL.showFilter = nil } - case 272: + case 286: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1531 + //line sql.y:1601 { yyVAL.showFilter = &ShowFilter{Like: string(yyDollar[2].bytes)} } - case 273: + case 287: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1535 + //line sql.y:1605 { yyVAL.showFilter = &ShowFilter{Filter: yyDollar[2].expr} } - case 274: + case 288: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1541 + //line sql.y:1611 { yyVAL.str = "" } - case 275: + case 289: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1545 + //line sql.y:1615 { yyVAL.str = SessionStr } - case 276: + case 290: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1549 + //line sql.y:1619 { yyVAL.str = GlobalStr } - case 277: + case 291: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1555 + //line sql.y:1625 { yyVAL.statement = &Use{DBName: yyDollar[2].tableIdent} } - case 278: + case 292: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1559 + //line sql.y:1629 { yyVAL.statement = &Use{DBName: TableIdent{v: ""}} } - case 279: + case 293: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1565 + //line sql.y:1635 { yyVAL.statement = &Begin{} } - case 280: + case 294: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1569 + //line sql.y:1639 { yyVAL.statement = &Begin{} } - case 281: + case 295: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1575 + //line sql.y:1645 { yyVAL.statement = &Commit{} } - case 282: + case 296: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1581 + //line sql.y:1651 { yyVAL.statement = &Rollback{} } - case 283: + case 297: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1587 + //line sql.y:1657 { yyVAL.statement = &OtherRead{} } - case 284: + case 298: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1591 + //line sql.y:1661 { yyVAL.statement = &OtherRead{} } - case 285: + case 299: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1595 + //line sql.y:1665 { yyVAL.statement = &OtherRead{} } - case 286: + case 300: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1599 + //line sql.y:1669 { yyVAL.statement = &OtherAdmin{} } - case 287: + case 301: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1603 + //line sql.y:1673 { yyVAL.statement = &OtherAdmin{} } - case 288: + case 302: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1607 + //line sql.y:1677 { yyVAL.statement = &OtherAdmin{} } - case 289: + case 303: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1611 + //line sql.y:1681 { yyVAL.statement = &OtherAdmin{} } - case 290: + case 304: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1616 + //line sql.y:1686 { setAllowComments(yylex, true) } - case 291: + case 305: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1620 + //line sql.y:1690 { yyVAL.bytes2 = yyDollar[2].bytes2 setAllowComments(yylex, false) } - case 292: + case 306: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1626 + //line sql.y:1696 { yyVAL.bytes2 = nil } - case 293: + case 307: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1630 + //line sql.y:1700 { yyVAL.bytes2 = append(yyDollar[1].bytes2, yyDollar[2].bytes) } - case 294: + case 308: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1636 + //line sql.y:1706 { yyVAL.str = UnionStr } - case 295: + case 309: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1640 + //line sql.y:1710 { yyVAL.str = UnionAllStr } - case 296: + case 310: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1644 + //line sql.y:1714 { yyVAL.str = UnionDistinctStr } - case 297: + case 311: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1649 + //line sql.y:1719 { yyVAL.str = "" } - case 298: + case 312: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1653 + //line sql.y:1723 { yyVAL.str = SQLNoCacheStr } - case 299: + case 313: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1657 + //line sql.y:1727 { yyVAL.str = SQLCacheStr } - case 300: + case 314: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1662 + //line sql.y:1732 { yyVAL.str = "" } - case 301: + case 315: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1666 + //line sql.y:1736 { yyVAL.str = DistinctStr } - case 302: + case 316: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1671 + //line sql.y:1741 { yyVAL.str = "" } - case 303: + case 317: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1675 + //line sql.y:1745 { yyVAL.str = StraightJoinHint } - case 304: + case 318: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1680 + //line sql.y:1750 { yyVAL.selectExprs = nil } - case 305: + case 319: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1684 + //line sql.y:1754 { yyVAL.selectExprs = yyDollar[1].selectExprs } - case 306: + case 320: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1690 + //line sql.y:1760 { yyVAL.selectExprs = SelectExprs{yyDollar[1].selectExpr} } - case 307: + case 321: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1694 + //line sql.y:1764 { yyVAL.selectExprs = append(yyVAL.selectExprs, yyDollar[3].selectExpr) } - case 308: + case 322: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1700 + //line sql.y:1770 { yyVAL.selectExpr = &StarExpr{} } - case 309: + case 323: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1704 + //line sql.y:1774 { yyVAL.selectExpr = &AliasedExpr{Expr: yyDollar[1].expr, As: yyDollar[2].colIdent} } - case 310: + case 324: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1708 + //line sql.y:1778 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Name: yyDollar[1].tableIdent}} } - case 311: + case 325: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1712 + //line sql.y:1782 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}} } - case 312: + case 326: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1717 + //line sql.y:1787 { yyVAL.colIdent = ColIdent{} } - case 313: + case 327: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1721 + //line sql.y:1791 { yyVAL.colIdent = yyDollar[1].colIdent } - case 314: + case 328: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1725 + //line sql.y:1795 { yyVAL.colIdent = yyDollar[2].colIdent } - case 316: + case 330: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1732 + //line sql.y:1802 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 317: + case 331: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1737 + //line sql.y:1807 { yyVAL.tableExprs = TableExprs{&AliasedTableExpr{Expr: TableName{Name: NewTableIdent("dual")}}} } - case 318: + case 332: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1741 + //line sql.y:1811 { yyVAL.tableExprs = yyDollar[2].tableExprs } - case 319: + case 333: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1747 + //line sql.y:1817 { yyVAL.tableExprs = TableExprs{yyDollar[1].tableExpr} } - case 320: + case 334: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1751 + //line sql.y:1821 { yyVAL.tableExprs = append(yyVAL.tableExprs, yyDollar[3].tableExpr) } - case 323: + case 337: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1761 + //line sql.y:1831 { yyVAL.tableExpr = yyDollar[1].aliasedTableName } - case 324: + case 338: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1765 + //line sql.y:1835 { yyVAL.tableExpr = &AliasedTableExpr{Expr: yyDollar[1].subquery, As: yyDollar[3].tableIdent} } - case 325: + case 339: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1769 + //line sql.y:1839 { yyVAL.tableExpr = &ParenTableExpr{Exprs: yyDollar[2].tableExprs} } - case 326: + case 340: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1775 + //line sql.y:1845 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, As: yyDollar[2].tableIdent, Hints: yyDollar[3].indexHints} } - case 327: + case 341: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:1779 + //line sql.y:1849 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, Partitions: yyDollar[4].partitions, As: yyDollar[6].tableIdent, Hints: yyDollar[7].indexHints} } - case 328: + case 342: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1785 + //line sql.y:1855 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 329: + case 343: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1789 + //line sql.y:1859 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 330: + case 344: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1795 + //line sql.y:1865 { yyVAL.partitions = Partitions{yyDollar[1].colIdent} } - case 331: + case 345: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1799 + //line sql.y:1869 { yyVAL.partitions = append(yyVAL.partitions, yyDollar[3].colIdent) } - case 332: + case 346: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1812 + //line sql.y:1882 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 333: + case 347: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1816 + //line sql.y:1886 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 334: + case 348: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1820 + //line sql.y:1890 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 335: + case 349: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1824 + //line sql.y:1894 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr} } - case 336: + case 350: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1830 + //line sql.y:1900 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 337: + case 351: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:1832 + //line sql.y:1902 { yyVAL.joinCondition = JoinCondition{Using: yyDollar[3].columns} } - case 338: + case 352: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1836 + //line sql.y:1906 { yyVAL.joinCondition = JoinCondition{} } - case 339: + case 353: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1838 + //line sql.y:1908 { yyVAL.joinCondition = yyDollar[1].joinCondition } - case 340: + case 354: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1842 + //line sql.y:1912 { yyVAL.joinCondition = JoinCondition{} } - case 341: + case 355: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1844 + //line sql.y:1914 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 342: + case 356: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1847 + //line sql.y:1917 { yyVAL.empty = struct{}{} } - case 343: + case 357: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1849 + //line sql.y:1919 { yyVAL.empty = struct{}{} } - case 344: + case 358: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1852 + //line sql.y:1922 { yyVAL.tableIdent = NewTableIdent("") } - case 345: + case 359: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1856 + //line sql.y:1926 { yyVAL.tableIdent = yyDollar[1].tableIdent } - case 346: + case 360: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1860 + //line sql.y:1930 { yyVAL.tableIdent = yyDollar[2].tableIdent } - case 348: + case 362: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1867 + //line sql.y:1937 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 349: + case 363: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1873 + //line sql.y:1943 { yyVAL.str = JoinStr } - case 350: + case 364: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1877 + //line sql.y:1947 { yyVAL.str = JoinStr } - case 351: + case 365: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1881 + //line sql.y:1951 { yyVAL.str = JoinStr } - case 352: + case 366: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1887 + //line sql.y:1957 { yyVAL.str = StraightJoinStr } - case 353: + case 367: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1893 + //line sql.y:1963 { yyVAL.str = LeftJoinStr } - case 354: + case 368: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1897 + //line sql.y:1967 { yyVAL.str = LeftJoinStr } - case 355: + case 369: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1901 + //line sql.y:1971 { yyVAL.str = RightJoinStr } - case 356: + case 370: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1905 + //line sql.y:1975 { yyVAL.str = RightJoinStr } - case 357: + case 371: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1911 + //line sql.y:1981 { yyVAL.str = NaturalJoinStr } - case 358: + case 372: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1915 + //line sql.y:1985 { if yyDollar[2].str == LeftJoinStr { yyVAL.str = NaturalLeftJoinStr @@ -4813,459 +4919,459 @@ yydefault: yyVAL.str = NaturalRightJoinStr } } - case 359: + case 373: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1925 + //line sql.y:1995 { yyVAL.tableName = yyDollar[2].tableName } - case 360: + case 374: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1929 + //line sql.y:1999 { yyVAL.tableName = yyDollar[1].tableName } - case 361: + case 375: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1935 + //line sql.y:2005 { yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} } - case 362: + case 376: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1939 + //line sql.y:2009 { yyVAL.tableName = TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent} } - case 363: + case 377: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1944 + //line sql.y:2014 { yyVAL.indexHints = nil } - case 364: + case 378: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1948 + //line sql.y:2018 { yyVAL.indexHints = &IndexHints{Type: UseStr, Indexes: yyDollar[4].columns} } - case 365: + case 379: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1952 + //line sql.y:2022 { yyVAL.indexHints = &IndexHints{Type: IgnoreStr, Indexes: yyDollar[4].columns} } - case 366: + case 380: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:1956 + //line sql.y:2026 { yyVAL.indexHints = &IndexHints{Type: ForceStr, Indexes: yyDollar[4].columns} } - case 367: + case 381: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:1961 + //line sql.y:2031 { yyVAL.expr = nil } - case 368: + case 382: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1965 + //line sql.y:2035 { yyVAL.expr = yyDollar[2].expr } - case 369: + case 383: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1971 + //line sql.y:2041 { yyVAL.expr = yyDollar[1].expr } - case 370: + case 384: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1975 + //line sql.y:2045 { yyVAL.expr = &AndExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 371: + case 385: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1979 + //line sql.y:2049 { yyVAL.expr = &OrExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 372: + case 386: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1983 + //line sql.y:2053 { yyVAL.expr = &NotExpr{Expr: yyDollar[2].expr} } - case 373: + case 387: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:1987 + //line sql.y:2057 { yyVAL.expr = &IsExpr{Operator: yyDollar[3].str, Expr: yyDollar[1].expr} } - case 374: + case 388: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:1991 + //line sql.y:2061 { yyVAL.expr = yyDollar[1].expr } - case 375: + case 389: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:1995 + //line sql.y:2065 { yyVAL.expr = &Default{ColName: yyDollar[2].str} } - case 376: + case 390: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2001 + //line sql.y:2071 { yyVAL.str = "" } - case 377: + case 391: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2005 + //line sql.y:2075 { yyVAL.str = string(yyDollar[2].bytes) } - case 378: + case 392: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2011 + //line sql.y:2081 { yyVAL.boolVal = BoolVal(true) } - case 379: + case 393: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2015 + //line sql.y:2085 { yyVAL.boolVal = BoolVal(false) } - case 380: + case 394: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2021 + //line sql.y:2091 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: yyDollar[2].str, Right: yyDollar[3].expr} } - case 381: + case 395: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2025 + //line sql.y:2095 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: InStr, Right: yyDollar[3].colTuple} } - case 382: + case 396: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2029 + //line sql.y:2099 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotInStr, Right: yyDollar[4].colTuple} } - case 383: + case 397: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2033 + //line sql.y:2103 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: LikeStr, Right: yyDollar[3].expr, Escape: yyDollar[4].expr} } - case 384: + case 398: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2037 + //line sql.y:2107 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotLikeStr, Right: yyDollar[4].expr, Escape: yyDollar[5].expr} } - case 385: + case 399: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2041 + //line sql.y:2111 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: RegexpStr, Right: yyDollar[3].expr} } - case 386: + case 400: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2045 + //line sql.y:2115 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotRegexpStr, Right: yyDollar[4].expr} } - case 387: + case 401: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2049 + //line sql.y:2119 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: BetweenStr, From: yyDollar[3].expr, To: yyDollar[5].expr} } - case 388: + case 402: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2053 + //line sql.y:2123 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: NotBetweenStr, From: yyDollar[4].expr, To: yyDollar[6].expr} } - case 389: + case 403: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2057 + //line sql.y:2127 { yyVAL.expr = &ExistsExpr{Subquery: yyDollar[2].subquery} } - case 390: + case 404: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2063 + //line sql.y:2133 { yyVAL.str = IsNullStr } - case 391: + case 405: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2067 + //line sql.y:2137 { yyVAL.str = IsNotNullStr } - case 392: + case 406: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2071 + //line sql.y:2141 { yyVAL.str = IsTrueStr } - case 393: + case 407: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2075 + //line sql.y:2145 { yyVAL.str = IsNotTrueStr } - case 394: + case 408: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2079 + //line sql.y:2149 { yyVAL.str = IsFalseStr } - case 395: + case 409: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2083 + //line sql.y:2153 { yyVAL.str = IsNotFalseStr } - case 396: + case 410: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2089 + //line sql.y:2159 { yyVAL.str = EqualStr } - case 397: + case 411: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2093 + //line sql.y:2163 { yyVAL.str = LessThanStr } - case 398: + case 412: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2097 + //line sql.y:2167 { yyVAL.str = GreaterThanStr } - case 399: + case 413: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2101 + //line sql.y:2171 { yyVAL.str = LessEqualStr } - case 400: + case 414: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2105 + //line sql.y:2175 { yyVAL.str = GreaterEqualStr } - case 401: + case 415: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2109 + //line sql.y:2179 { yyVAL.str = NotEqualStr } - case 402: + case 416: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2113 + //line sql.y:2183 { yyVAL.str = NullSafeEqualStr } - case 403: + case 417: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2118 + //line sql.y:2188 { yyVAL.expr = nil } - case 404: + case 418: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2122 + //line sql.y:2192 { yyVAL.expr = yyDollar[2].expr } - case 405: + case 419: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2128 + //line sql.y:2198 { yyVAL.colTuple = yyDollar[1].valTuple } - case 406: + case 420: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2132 + //line sql.y:2202 { yyVAL.colTuple = yyDollar[1].subquery } - case 407: + case 421: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2136 + //line sql.y:2206 { yyVAL.colTuple = ListArg(yyDollar[1].bytes) } - case 408: + case 422: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2142 + //line sql.y:2212 { yyVAL.subquery = &Subquery{yyDollar[2].selStmt} } - case 409: + case 423: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2148 + //line sql.y:2218 { yyVAL.exprs = Exprs{yyDollar[1].expr} } - case 410: + case 424: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2152 + //line sql.y:2222 { yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) } - case 411: + case 425: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2158 + //line sql.y:2228 { yyVAL.expr = yyDollar[1].expr } - case 412: + case 426: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2162 + //line sql.y:2232 { yyVAL.expr = yyDollar[1].boolVal } - case 413: + case 427: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2166 + //line sql.y:2236 { yyVAL.expr = yyDollar[1].colName } - case 414: + case 428: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2170 + //line sql.y:2240 { yyVAL.expr = yyDollar[1].expr } - case 415: + case 429: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2174 + //line sql.y:2244 { yyVAL.expr = yyDollar[1].subquery } - case 416: + case 430: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2178 + //line sql.y:2248 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitAndStr, Right: yyDollar[3].expr} } - case 417: + case 431: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2182 + //line sql.y:2252 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitOrStr, Right: yyDollar[3].expr} } - case 418: + case 432: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2186 + //line sql.y:2256 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitXorStr, Right: yyDollar[3].expr} } - case 419: + case 433: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2190 + //line sql.y:2260 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: PlusStr, Right: yyDollar[3].expr} } - case 420: + case 434: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2194 + //line sql.y:2264 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MinusStr, Right: yyDollar[3].expr} } - case 421: + case 435: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2198 + //line sql.y:2268 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MultStr, Right: yyDollar[3].expr} } - case 422: + case 436: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2202 + //line sql.y:2272 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: DivStr, Right: yyDollar[3].expr} } - case 423: + case 437: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2206 + //line sql.y:2276 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: IntDivStr, Right: yyDollar[3].expr} } - case 424: + case 438: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2210 + //line sql.y:2280 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } - case 425: + case 439: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2214 + //line sql.y:2284 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } - case 426: + case 440: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2218 + //line sql.y:2288 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftLeftStr, Right: yyDollar[3].expr} } - case 427: + case 441: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2222 + //line sql.y:2292 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftRightStr, Right: yyDollar[3].expr} } - case 428: + case 442: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2226 + //line sql.y:2296 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONExtractOp, Right: yyDollar[3].expr} } - case 429: + case 443: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2230 + //line sql.y:2300 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONUnquoteExtractOp, Right: yyDollar[3].expr} } - case 430: + case 444: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2234 + //line sql.y:2304 { yyVAL.expr = &CollateExpr{Expr: yyDollar[1].expr, Charset: yyDollar[3].str} } - case 431: + case 445: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2238 + //line sql.y:2308 { yyVAL.expr = &UnaryExpr{Operator: BinaryStr, Expr: yyDollar[2].expr} } - case 432: + case 446: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2242 + //line sql.y:2312 { yyVAL.expr = &UnaryExpr{Operator: UBinaryStr, Expr: yyDollar[2].expr} } - case 433: + case 447: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2246 + //line sql.y:2316 { yyVAL.expr = &UnaryExpr{Operator: Utf8mb4Str, Expr: yyDollar[2].expr} } - case 434: + case 448: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2250 + //line sql.y:2320 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { yyVAL.expr = num @@ -5273,9 +5379,9 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UPlusStr, Expr: yyDollar[2].expr} } } - case 435: + case 449: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2258 + //line sql.y:2328 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { // Handle double negative @@ -5289,21 +5395,21 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UMinusStr, Expr: yyDollar[2].expr} } } - case 436: + case 450: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2272 + //line sql.y:2342 { yyVAL.expr = &UnaryExpr{Operator: TildaStr, Expr: yyDollar[2].expr} } - case 437: + case 451: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2276 + //line sql.y:2346 { yyVAL.expr = &UnaryExpr{Operator: BangStr, Expr: yyDollar[2].expr} } - case 438: + case 452: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2280 + //line sql.y:2350 { // This rule prevents the usage of INTERVAL // as a function. If support is needed for that, @@ -5311,431 +5417,431 @@ yydefault: // will be non-trivial because of grammar conflicts. yyVAL.expr = &IntervalExpr{Expr: yyDollar[2].expr, Unit: yyDollar[3].colIdent.String()} } - case 443: + case 457: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2298 + //line sql.y:2368 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprs} } - case 444: + case 458: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2302 + //line sql.y:2372 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprs} } - case 445: + case 459: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2306 + //line sql.y:2376 { yyVAL.expr = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprs} } - case 446: + case 460: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2316 + //line sql.y:2386 { yyVAL.expr = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprs} } - case 447: + case 461: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2320 + //line sql.y:2390 { yyVAL.expr = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprs} } - case 448: + case 462: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2324 + //line sql.y:2394 { yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } - case 449: + case 463: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2328 + //line sql.y:2398 { yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } - case 450: + case 464: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2332 + //line sql.y:2402 { yyVAL.expr = &ConvertUsingExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].str} } - case 451: + case 465: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2336 + //line sql.y:2406 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } - case 452: + case 466: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2340 + //line sql.y:2410 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 453: + case 467: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2344 + //line sql.y:2414 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 454: + case 468: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2348 + //line sql.y:2418 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } - case 455: + case 469: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2352 + //line sql.y:2422 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 456: + case 470: yyDollar = yyS[yypt-8 : yypt+1] - //line sql.y:2356 + //line sql.y:2426 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 457: + case 471: yyDollar = yyS[yypt-9 : yypt+1] - //line sql.y:2360 + //line sql.y:2430 { yyVAL.expr = &MatchExpr{Columns: yyDollar[3].selectExprs, Expr: yyDollar[7].expr, Option: yyDollar[8].str} } - case 458: + case 472: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:2364 + //line sql.y:2434 { yyVAL.expr = &GroupConcatExpr{Distinct: yyDollar[3].str, Exprs: yyDollar[4].selectExprs, OrderBy: yyDollar[5].orderBy, Separator: yyDollar[6].str} } - case 459: + case 473: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2368 + //line sql.y:2438 { yyVAL.expr = &CaseExpr{Expr: yyDollar[2].expr, Whens: yyDollar[3].whens, Else: yyDollar[4].expr} } - case 460: + case 474: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2372 + //line sql.y:2442 { yyVAL.expr = &ValuesFuncExpr{Name: yyDollar[3].colName} } - case 461: + case 475: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2382 + //line sql.y:2452 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_timestamp")} } - case 462: + case 476: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2386 + //line sql.y:2456 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_timestamp")} } - case 463: + case 477: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2390 + //line sql.y:2460 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_time")} } - case 464: + case 478: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2394 + //line sql.y:2464 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} } - case 465: + case 479: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2399 + //line sql.y:2469 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} } - case 466: + case 480: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2404 + //line sql.y:2474 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} } - case 467: + case 481: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2409 + //line sql.y:2479 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} } - case 468: + case 482: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2414 + //line sql.y:2484 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} } - case 471: + case 485: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2428 + //line sql.y:2498 { yyVAL.expr = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprs} } - case 472: + case 486: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2432 + //line sql.y:2502 { yyVAL.expr = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprs} } - case 473: + case 487: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2436 + //line sql.y:2506 { yyVAL.expr = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprs} } - case 474: + case 488: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2440 + //line sql.y:2510 { yyVAL.expr = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprs} } - case 475: + case 489: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2446 + //line sql.y:2516 { yyVAL.str = "" } - case 476: + case 490: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2450 + //line sql.y:2520 { yyVAL.str = BooleanModeStr } - case 477: + case 491: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2454 + //line sql.y:2524 { yyVAL.str = NaturalLanguageModeStr } - case 478: + case 492: yyDollar = yyS[yypt-7 : yypt+1] - //line sql.y:2458 + //line sql.y:2528 { yyVAL.str = NaturalLanguageModeWithQueryExpansionStr } - case 479: + case 493: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2462 + //line sql.y:2532 { yyVAL.str = QueryExpansionStr } - case 480: + case 494: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2468 + //line sql.y:2538 { yyVAL.str = string(yyDollar[1].bytes) } - case 481: + case 495: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2472 + //line sql.y:2542 { yyVAL.str = string(yyDollar[1].bytes) } - case 482: + case 496: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2478 + //line sql.y:2548 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 483: + case 497: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2482 + //line sql.y:2552 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} } - case 484: + case 498: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2486 + //line sql.y:2556 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: string(yyDollar[3].bytes)} } - case 485: + case 499: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2490 + //line sql.y:2560 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 486: + case 500: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2494 + //line sql.y:2564 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 487: + case 501: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2498 + //line sql.y:2568 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} yyVAL.convertType.Length = yyDollar[2].LengthScaleOption.Length yyVAL.convertType.Scale = yyDollar[2].LengthScaleOption.Scale } - case 488: + case 502: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2504 + //line sql.y:2574 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 489: + case 503: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2508 + //line sql.y:2578 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 490: + case 504: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2512 + //line sql.y:2582 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 491: + case 505: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2516 + //line sql.y:2586 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 492: + case 506: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2520 + //line sql.y:2590 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 493: + case 507: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2524 + //line sql.y:2594 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 494: + case 508: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2528 + //line sql.y:2598 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 495: + case 509: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2533 + //line sql.y:2603 { yyVAL.expr = nil } - case 496: + case 510: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2537 + //line sql.y:2607 { yyVAL.expr = yyDollar[1].expr } - case 497: + case 511: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2542 + //line sql.y:2612 { yyVAL.str = string("") } - case 498: + case 512: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2546 + //line sql.y:2616 { yyVAL.str = " separator '" + string(yyDollar[2].bytes) + "'" } - case 499: + case 513: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2552 + //line sql.y:2622 { yyVAL.whens = []*When{yyDollar[1].when} } - case 500: + case 514: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2556 + //line sql.y:2626 { yyVAL.whens = append(yyDollar[1].whens, yyDollar[2].when) } - case 501: + case 515: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2562 + //line sql.y:2632 { yyVAL.when = &When{Cond: yyDollar[2].expr, Val: yyDollar[4].expr} } - case 502: + case 516: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2567 + //line sql.y:2637 { yyVAL.expr = nil } - case 503: + case 517: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2571 + //line sql.y:2641 { yyVAL.expr = yyDollar[2].expr } - case 504: + case 518: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2577 + //line sql.y:2647 { yyVAL.colName = &ColName{Name: yyDollar[1].colIdent} } - case 505: + case 519: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2581 + //line sql.y:2651 { yyVAL.colName = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} } - case 506: + case 520: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2585 + //line sql.y:2655 { yyVAL.colName = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} } - case 507: + case 521: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2591 + //line sql.y:2661 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 508: + case 522: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2595 + //line sql.y:2665 { yyVAL.expr = NewHexVal(yyDollar[1].bytes) } - case 509: + case 523: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2599 + //line sql.y:2669 { yyVAL.expr = NewBitVal(yyDollar[1].bytes) } - case 510: + case 524: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2603 + //line sql.y:2673 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 511: + case 525: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2607 + //line sql.y:2677 { yyVAL.expr = NewFloatVal(yyDollar[1].bytes) } - case 512: + case 526: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2611 + //line sql.y:2681 { yyVAL.expr = NewHexNum(yyDollar[1].bytes) } - case 513: + case 527: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2615 + //line sql.y:2685 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 514: + case 528: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2619 + //line sql.y:2689 { yyVAL.expr = &NullVal{} } - case 515: + case 529: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2625 + //line sql.y:2695 { // TODO(sougou): Deprecate this construct. if yyDollar[1].colIdent.Lowered() != "value" { @@ -5744,239 +5850,239 @@ yydefault: } yyVAL.expr = NewIntVal([]byte("1")) } - case 516: + case 530: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2634 + //line sql.y:2704 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 517: + case 531: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2638 + //line sql.y:2708 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 518: + case 532: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2643 + //line sql.y:2713 { yyVAL.exprs = nil } - case 519: + case 533: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2647 + //line sql.y:2717 { yyVAL.exprs = yyDollar[3].exprs } - case 520: + case 534: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2652 + //line sql.y:2722 { yyVAL.expr = nil } - case 521: + case 535: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2656 + //line sql.y:2726 { yyVAL.expr = yyDollar[2].expr } - case 522: + case 536: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2661 + //line sql.y:2731 { yyVAL.orderBy = nil } - case 523: + case 537: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2665 + //line sql.y:2735 { yyVAL.orderBy = yyDollar[3].orderBy } - case 524: + case 538: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2671 + //line sql.y:2741 { yyVAL.orderBy = OrderBy{yyDollar[1].order} } - case 525: + case 539: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2675 + //line sql.y:2745 { yyVAL.orderBy = append(yyDollar[1].orderBy, yyDollar[3].order) } - case 526: + case 540: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2681 + //line sql.y:2751 { yyVAL.order = &Order{Expr: yyDollar[1].expr, Direction: yyDollar[2].str} } - case 527: + case 541: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2686 + //line sql.y:2756 { yyVAL.str = AscScr } - case 528: + case 542: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2690 + //line sql.y:2760 { yyVAL.str = AscScr } - case 529: + case 543: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2694 + //line sql.y:2764 { yyVAL.str = DescScr } - case 530: + case 544: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2699 + //line sql.y:2769 { yyVAL.limit = nil } - case 531: + case 545: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2703 + //line sql.y:2773 { yyVAL.limit = &Limit{Rowcount: yyDollar[2].expr} } - case 532: + case 546: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2707 + //line sql.y:2777 { yyVAL.limit = &Limit{Offset: yyDollar[2].expr, Rowcount: yyDollar[4].expr} } - case 533: + case 547: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2711 + //line sql.y:2781 { yyVAL.limit = &Limit{Offset: yyDollar[4].expr, Rowcount: yyDollar[2].expr} } - case 534: + case 548: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2716 + //line sql.y:2786 { yyVAL.str = "" } - case 535: + case 549: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2720 + //line sql.y:2790 { yyVAL.str = ForUpdateStr } - case 536: + case 550: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2724 + //line sql.y:2794 { yyVAL.str = ShareModeStr } - case 537: + case 551: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2737 + //line sql.y:2807 { yyVAL.ins = &Insert{Rows: yyDollar[2].values} } - case 538: + case 552: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2741 + //line sql.y:2811 { yyVAL.ins = &Insert{Rows: yyDollar[1].selStmt} } - case 539: + case 553: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2745 + //line sql.y:2815 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Rows: yyDollar[2].selStmt} } - case 540: + case 554: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2750 + //line sql.y:2820 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].values} } - case 541: + case 555: yyDollar = yyS[yypt-4 : yypt+1] - //line sql.y:2754 + //line sql.y:2824 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[4].selStmt} } - case 542: + case 556: yyDollar = yyS[yypt-6 : yypt+1] - //line sql.y:2758 + //line sql.y:2828 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].selStmt} } - case 543: + case 557: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2765 + //line sql.y:2835 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 544: + case 558: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2769 + //line sql.y:2839 { yyVAL.columns = Columns{yyDollar[3].colIdent} } - case 545: + case 559: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2773 + //line sql.y:2843 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 546: + case 560: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2777 + //line sql.y:2847 { yyVAL.columns = append(yyVAL.columns, yyDollar[5].colIdent) } - case 547: + case 561: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2782 + //line sql.y:2852 { yyVAL.updateExprs = nil } - case 548: + case 562: yyDollar = yyS[yypt-5 : yypt+1] - //line sql.y:2786 + //line sql.y:2856 { yyVAL.updateExprs = yyDollar[5].updateExprs } - case 549: + case 563: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2792 + //line sql.y:2862 { yyVAL.values = Values{yyDollar[1].valTuple} } - case 550: + case 564: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2796 + //line sql.y:2866 { yyVAL.values = append(yyDollar[1].values, yyDollar[3].valTuple) } - case 551: + case 565: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2802 + //line sql.y:2872 { yyVAL.valTuple = yyDollar[1].valTuple } - case 552: + case 566: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2806 + //line sql.y:2876 { yyVAL.valTuple = ValTuple{} } - case 553: + case 567: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2812 + //line sql.y:2882 { yyVAL.valTuple = ValTuple(yyDollar[2].exprs) } - case 554: + case 568: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2818 + //line sql.y:2888 { if len(yyDollar[1].valTuple) == 1 { yyVAL.expr = &ParenExpr{yyDollar[1].valTuple[0]} @@ -5984,306 +6090,306 @@ yydefault: yyVAL.expr = yyDollar[1].valTuple } } - case 555: + case 569: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2828 + //line sql.y:2898 { yyVAL.updateExprs = UpdateExprs{yyDollar[1].updateExpr} } - case 556: + case 570: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2832 + //line sql.y:2902 { yyVAL.updateExprs = append(yyDollar[1].updateExprs, yyDollar[3].updateExpr) } - case 557: + case 571: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2838 + //line sql.y:2908 { yyVAL.updateExpr = &UpdateExpr{Name: yyDollar[1].colName, Expr: yyDollar[3].expr} } - case 558: + case 572: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2844 + //line sql.y:2914 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } - case 559: + case 573: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2848 + //line sql.y:2918 { yyVAL.setExprs = append(yyDollar[1].setExprs, yyDollar[3].setExpr) } - case 560: + case 574: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2854 + //line sql.y:2924 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("on"))} } - case 561: + case 575: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2858 + //line sql.y:2928 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: yyDollar[3].expr} } - case 562: + case 576: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2862 + //line sql.y:2932 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(string(yyDollar[1].bytes)), Expr: yyDollar[2].expr} } - case 564: + case 578: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2869 + //line sql.y:2939 { yyVAL.bytes = []byte("charset") } - case 566: + case 580: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2876 + //line sql.y:2946 { yyVAL.expr = NewStrVal([]byte(yyDollar[1].colIdent.String())) } - case 567: + case 581: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2880 + //line sql.y:2950 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 568: + case 582: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2884 + //line sql.y:2954 { yyVAL.expr = &Default{} } - case 571: + case 585: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2893 + //line sql.y:2963 { yyVAL.byt = 0 } - case 572: + case 586: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2895 + //line sql.y:2965 { yyVAL.byt = 1 } - case 573: + case 587: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2898 + //line sql.y:2968 { yyVAL.empty = struct{}{} } - case 574: + case 588: yyDollar = yyS[yypt-3 : yypt+1] - //line sql.y:2900 + //line sql.y:2970 { yyVAL.empty = struct{}{} } - case 575: + case 589: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2903 + //line sql.y:2973 { yyVAL.str = "" } - case 576: + case 590: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2905 + //line sql.y:2975 { yyVAL.str = IgnoreStr } - case 577: + case 591: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2909 + //line sql.y:2979 { yyVAL.empty = struct{}{} } - case 578: + case 592: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2911 + //line sql.y:2981 { yyVAL.empty = struct{}{} } - case 579: + case 593: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2913 + //line sql.y:2983 { yyVAL.empty = struct{}{} } - case 580: + case 594: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2915 + //line sql.y:2985 { yyVAL.empty = struct{}{} } - case 581: + case 595: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2917 + //line sql.y:2987 { yyVAL.empty = struct{}{} } - case 582: + case 596: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2919 + //line sql.y:2989 { yyVAL.empty = struct{}{} } - case 583: + case 597: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2921 + //line sql.y:2991 { yyVAL.empty = struct{}{} } - case 584: + case 598: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2923 + //line sql.y:2993 { yyVAL.empty = struct{}{} } - case 585: + case 599: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2925 + //line sql.y:2995 { yyVAL.empty = struct{}{} } - case 586: + case 600: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2927 + //line sql.y:2997 { yyVAL.empty = struct{}{} } - case 587: + case 601: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2930 + //line sql.y:3000 { yyVAL.empty = struct{}{} } - case 588: + case 602: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2932 + //line sql.y:3002 { yyVAL.empty = struct{}{} } - case 589: + case 603: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2934 + //line sql.y:3004 { yyVAL.empty = struct{}{} } - case 590: + case 604: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2938 + //line sql.y:3008 { yyVAL.empty = struct{}{} } - case 591: + case 605: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2940 + //line sql.y:3010 { yyVAL.empty = struct{}{} } - case 592: + case 606: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2943 + //line sql.y:3013 { yyVAL.empty = struct{}{} } - case 593: + case 607: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2945 + //line sql.y:3015 { yyVAL.empty = struct{}{} } - case 594: + case 608: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2947 + //line sql.y:3017 { yyVAL.empty = struct{}{} } - case 595: + case 609: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:2950 + //line sql.y:3020 { yyVAL.colIdent = ColIdent{} } - case 596: + case 610: yyDollar = yyS[yypt-2 : yypt+1] - //line sql.y:2952 + //line sql.y:3022 { yyVAL.colIdent = yyDollar[2].colIdent } - case 597: + case 611: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2956 + //line sql.y:3026 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 598: + case 612: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2960 + //line sql.y:3030 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 600: + case 614: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2967 + //line sql.y:3037 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 601: + case 615: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2973 + //line sql.y:3043 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 602: + case 616: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2977 + //line sql.y:3047 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 604: + case 618: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:2984 + //line sql.y:3054 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 800: + case 818: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3205 + //line sql.y:3279 { if incNesting(yylex) { yylex.Error("max nesting level reached") return 1 } } - case 801: + case 819: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3214 + //line sql.y:3288 { decNesting(yylex) } - case 802: + case 820: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:3219 + //line sql.y:3293 { forceEOF(yylex) } - case 803: + case 821: yyDollar = yyS[yypt-0 : yypt+1] - //line sql.y:3224 + //line sql.y:3298 { forceEOF(yylex) } - case 804: + case 822: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3228 + //line sql.y:3302 { forceEOF(yylex) } - case 805: + case 823: yyDollar = yyS[yypt-1 : yypt+1] - //line sql.y:3232 + //line sql.y:3306 { forceEOF(yylex) } diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index a35f703680e..9914eb5b808 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -106,6 +106,7 @@ func forceEOF(yylex interface{}) { indexColumns []*IndexColumn constraintDefinition *ConstraintDefinition constraintInfo ConstraintInfo + ReferenceAction ReferenceAction partDefs []*PartitionDefinition partDef *PartitionDefinition partSpec *PartitionSpec @@ -156,7 +157,8 @@ func forceEOF(yylex interface{}) { // DDL Tokens %token CREATE ALTER DROP RENAME ANALYZE ADD -%token SCHEMA TABLE INDEX VIEW TO IGNORE IF UNIQUE PRIMARY COLUMN CONSTRAINT SPATIAL FULLTEXT FOREIGN REFERENCES KEY_BLOCK_SIZE +%token SCHEMA TABLE INDEX VIEW TO IGNORE IF UNIQUE PRIMARY COLUMN SPATIAL FULLTEXT KEY_BLOCK_SIZE +%token ACTION CASCADE CONSTRAINT FOREIGN NO REFERENCES RESTRICT %token SHOW DESCRIBE EXPLAIN DATE ESCAPE REPAIR OPTIMIZE TRUNCATE %token MAXVALUE PARTITION REORGANIZE LESS THAN PROCEDURE TRIGGER %token VINDEX VINDEXES @@ -252,7 +254,8 @@ func forceEOF(yylex interface{}) { %type set_list transaction_chars %type charset_or_character_set %type update_expression -%type set_expression transaction_char isolation_level +%type set_expression transaction_char +%type isolation_level %type for_from %type ignore_opt default_opt %type full_opt from_database_opt tables_or_processlist @@ -281,6 +284,7 @@ func forceEOF(yylex interface{}) { %type index_definition %type constraint_definition %type index_or_key +%type name_opt %type equal_opt %type table_spec table_column_list %type create_like @@ -298,6 +302,7 @@ func forceEOF(yylex interface{}) { %type vindex_param_list vindex_params_opt %type vindex_type vindex_type_opt %type alter_object_type +%type fk_reference_action fk_on_delete fk_on_update %start any_command @@ -500,33 +505,33 @@ transaction_chars: transaction_char: ISOLATION LEVEL isolation_level { - $$ = $3 + $$ = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte($3))} } | READ WRITE { - $$ = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("0"))} + $$ = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadWrite))} } | READ ONLY { - $$ = &SetExpr{Name: NewColIdent("tx_read_only"), Expr: NewIntVal([]byte("1"))} + $$ = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadOnly))} } isolation_level: REPEATABLE READ { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("repeatable read"))} + $$ = IsolationLevelRepeatableRead } | READ COMMITTED { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read committed"))} + $$ = IsolationLevelReadCommitted } | READ UNCOMMITTED { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("read uncommitted"))} + $$ = IsolationLevelReadUncommitted } | SERIALIZABLE { - $$ = &SetExpr{Name: NewColIdent("tx_isolation"), Expr: NewStrVal([]byte("serializable"))} + $$ = IsolationLevelSerializable } set_session_or_global: @@ -986,6 +991,10 @@ column_default_opt: { $$ = NewValArg($2) } +| DEFAULT CURRENT_TIMESTAMP '(' ')' + { + $$ = NewValArg($2) + } | DEFAULT BIT_LITERAL { $$ = NewBitVal($2) @@ -999,6 +1008,10 @@ on_update_opt: { $$ = NewValArg($3) } +| ON UPDATE CURRENT_TIMESTAMP '(' ')' +{ + $$ = NewValArg($3) +} auto_increment_opt: { @@ -1115,21 +1128,21 @@ index_info: { $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} } -| SPATIAL index_or_key ID +| SPATIAL index_or_key name_opt { - $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent(string($3)), Spatial: true, Unique: false} + $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent($3), Spatial: true, Unique: false} } -| UNIQUE index_or_key ID +| UNIQUE index_or_key name_opt { - $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent(string($3)), Unique: true} + $$ = &IndexInfo{Type: string($1) + " " + string($2), Name: NewColIdent($3), Unique: true} } -| UNIQUE ID +| UNIQUE name_opt { - $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: true} + $$ = &IndexInfo{Type: string($1), Name: NewColIdent($2), Unique: true} } -| index_or_key ID +| index_or_key name_opt { - $$ = &IndexInfo{Type: string($1), Name: NewColIdent(string($2)), Unique: false} + $$ = &IndexInfo{Type: string($1), Name: NewColIdent($2), Unique: false} } index_or_key: @@ -1142,6 +1155,15 @@ index_or_key: $$ = string($1) } +name_opt: + { + $$ = "" + } +| ID + { + $$ = string($1) + } + index_column_list: index_column { @@ -1174,6 +1196,52 @@ constraint_info: { $$ = &ForeignKeyDefinition{Source: $4, ReferencedTable: $7, ReferencedColumns: $9} } +| FOREIGN KEY '(' column_list ')' REFERENCES table_name '(' column_list ')' fk_on_delete + { + $$ = &ForeignKeyDefinition{Source: $4, ReferencedTable: $7, ReferencedColumns: $9, OnDelete: $11} + } +| FOREIGN KEY '(' column_list ')' REFERENCES table_name '(' column_list ')' fk_on_update + { + $$ = &ForeignKeyDefinition{Source: $4, ReferencedTable: $7, ReferencedColumns: $9, OnUpdate: $11} + } +| FOREIGN KEY '(' column_list ')' REFERENCES table_name '(' column_list ')' fk_on_delete fk_on_update + { + $$ = &ForeignKeyDefinition{Source: $4, ReferencedTable: $7, ReferencedColumns: $9, OnDelete: $11, OnUpdate: $12} + } + +fk_on_delete: + ON DELETE fk_reference_action + { + $$ = $3 + } + +fk_on_update: + ON UPDATE fk_reference_action + { + $$ = $3 + } + +fk_reference_action: + RESTRICT + { + $$ = Restrict + } +| CASCADE + { + $$ = Cascade + } +| NO ACTION + { + $$ = NoAction + } +| SET DEFAULT + { + $$ = SetDefault + } +| SET NULL + { + $$ = SetNull + } table_option_list: { @@ -1451,7 +1519,9 @@ show_statement: } | SHOW COLLATION WHERE expression { - $$ = &Show{Type: string($2), ShowCollationFilterOpt: &$4} + // Cannot dereference $4 directly, or else the parser stackcannot be pooled. See yyParsePooled + showCollationFilterOpt := $4 + $$ = &Show{Type: string($2), ShowCollationFilterOpt: &showCollationFilterOpt} } | SHOW VINDEXES ON table_name { @@ -3098,11 +3168,13 @@ reserved_keyword: */ non_reserved_keyword: AGAINST +| ACTION | BEGIN | BIGINT | BIT | BLOB | BOOL +| CASCADE | CHAR | CHARACTER | CHARSET @@ -3146,6 +3218,7 @@ non_reserved_keyword: | MULTIPOLYGON | NAMES | NCHAR +| NO | NUMERIC | OFFSET | ONLY @@ -3162,6 +3235,7 @@ non_reserved_keyword: | REORGANIZE | REPAIR | REPEATABLE +| RESTRICT | ROLLBACK | SESSION | SERIALIZABLE diff --git a/go/vt/sqlparser/token.go b/go/vt/sqlparser/token.go index 344e68f16ea..47be2aa9668 100644 --- a/go/vt/sqlparser/token.go +++ b/go/vt/sqlparser/token.go @@ -85,6 +85,7 @@ func NewTokenizer(r io.Reader) *Tokenizer { // in identifiers. See the docs for each grammar to determine which one to put it into. var keywords = map[string]int{ "accessible": UNUSED, + "action": ACTION, "add": ADD, "against": AGAINST, "all": ALL, @@ -109,7 +110,7 @@ var keywords = map[string]int{ "both": UNUSED, "by": BY, "call": UNUSED, - "cascade": UNUSED, + "cascade": CASCADE, "case": CASE, "cast": CAST, "change": UNUSED, @@ -264,6 +265,7 @@ var keywords = map[string]int{ "natural": NATURAL, "nchar": NCHAR, "next": NEXT, + "no": NO, "not": NOT, "no_write_to_binlog": UNUSED, "null": NULL, @@ -304,7 +306,7 @@ var keywords = map[string]int{ "replace": REPLACE, "require": UNUSED, "resignal": UNUSED, - "restrict": UNUSED, + "restrict": RESTRICT, "return": UNUSED, "revoke": UNUSED, "right": RIGHT, diff --git a/go/vt/topo/errors.go b/go/vt/topo/errors.go index f66d3b6465d..a0bf8ad8dde 100644 --- a/go/vt/topo/errors.go +++ b/go/vt/topo/errors.go @@ -31,6 +31,7 @@ const ( BadVersion PartialResult NoUpdateNeeded + NoImplementation ) // Error represents a topo error. @@ -59,6 +60,8 @@ func NewError(code ErrorCode, node string) error { message = fmt.Sprintf("partial result: %s", node) case NoUpdateNeeded: message = fmt.Sprintf("no update needed: %s", node) + case NoImplementation: + message = fmt.Sprintf("no such topology implementation %s", node) default: message = fmt.Sprintf("unknown code: %s", node) } diff --git a/go/vt/topo/server.go b/go/vt/topo/server.go index 4f4702e3ce3..3f6fc48a605 100644 --- a/go/vt/topo/server.go +++ b/go/vt/topo/server.go @@ -199,7 +199,7 @@ func NewWithFactory(factory Factory, serverAddress, root string) (*Server, error func OpenServer(implementation, serverAddress, root string) (*Server, error) { factory, ok := factories[implementation] if !ok { - return nil, NewError(NoNode, implementation) + return nil, NewError(NoImplementation, implementation) } return NewWithFactory(factory, serverAddress, root) } @@ -207,6 +207,9 @@ func OpenServer(implementation, serverAddress, root string) (*Server, error) { // Open returns a Server using the command line parameter flags // for implementation, address and root. It log.Exits out if an error occurs. func Open() *Server { + if *topoGlobalServerAddress == "" { + log.Exitf("topo_global_server_address must be configured") + } ts, err := OpenServer(*topoImplementation, *topoGlobalServerAddress, *topoGlobalRoot) if err != nil { log.Exitf("Failed to open topo server (%v,%v,%v): %v", *topoImplementation, *topoGlobalServerAddress, *topoGlobalRoot, err) diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index 93f0a3fa9e6..0e6c79d254a 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -624,22 +624,14 @@ func (itmc *internalTabletManagerClient) GetSlaves(ctx context.Context, tablet * return nil, fmt.Errorf("not implemented in vtcombo") } -func (itmc *internalTabletManagerClient) WaitBlpPosition(ctx context.Context, tablet *topodatapb.Tablet, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error { - return fmt.Errorf("not implemented in vtcombo") -} - -func (itmc *internalTabletManagerClient) StopBlp(ctx context.Context, tablet *topodatapb.Tablet) ([]*tabletmanagerdatapb.BlpPosition, error) { +func (itmc *internalTabletManagerClient) VReplicationExec(ctx context.Context, tablet *topodatapb.Tablet, query string) (*querypb.QueryResult, error) { return nil, fmt.Errorf("not implemented in vtcombo") } -func (itmc *internalTabletManagerClient) StartBlp(ctx context.Context, tablet *topodatapb.Tablet) error { +func (itmc *internalTabletManagerClient) VReplicationWaitForPos(ctx context.Context, tablet *topodatapb.Tablet, id int, pos string) error { return fmt.Errorf("not implemented in vtcombo") } -func (itmc *internalTabletManagerClient) RunBlpUntil(ctx context.Context, tablet *topodatapb.Tablet, positions []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) { - return "", fmt.Errorf("not implemented in vtcombo") -} - func (itmc *internalTabletManagerClient) ResetReplication(ctx context.Context, tablet *topodatapb.Tablet) error { return fmt.Errorf("not implemented in vtcombo") } diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 1bc17348828..9fc6b7d7d99 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -215,6 +215,9 @@ var commands = []commandGroup{ {"ExecuteFetchAsDba", commandExecuteFetchAsDba, "[-max_rows=10000] [-disable_binlogs] [-json] ", "Runs the given SQL command as a DBA on the remote tablet."}, + {"VReplicationExec", commandVReplicationExec, + "[-json] ", + "Runs the given VReplication command on the remote tablet."}, }, }, { @@ -1085,6 +1088,33 @@ func commandExecuteFetchAsDba(ctx context.Context, wr *wrangler.Wrangler, subFla return nil } +func commandVReplicationExec(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + json := subFlags.Bool("json", false, "Output JSON instead of human-readable table") + + if err := subFlags.Parse(args); err != nil { + return err + } + if subFlags.NArg() != 2 { + return fmt.Errorf("the and arguments are required for the VReplicationExec command") + } + + alias, err := topoproto.ParseTabletAlias(subFlags.Arg(0)) + if err != nil { + return err + } + query := subFlags.Arg(1) + qrproto, err := wr.VReplicationExec(ctx, alias, query) + if err != nil { + return err + } + qr := sqltypes.Proto3ToResult(qrproto) + if *json { + return printJSON(wr.Logger(), qr) + } + printQueryResult(loggerWriter{wr.Logger()}, qr) + return nil +} + func commandExecuteHook(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { if err := subFlags.Parse(args); err != nil { return err diff --git a/go/vt/vtctld/workflow.go b/go/vt/vtctld/workflow.go index f3eb93d0a25..07f61049e15 100644 --- a/go/vt/vtctld/workflow.go +++ b/go/vt/vtctld/workflow.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/vt/vtctl" "vitess.io/vitess/go/vt/workflow" "vitess.io/vitess/go/vt/workflow/resharding" + "vitess.io/vitess/go/vt/workflow/reshardingworkflowgen" "vitess.io/vitess/go/vt/workflow/topovalidator" ) @@ -59,6 +60,9 @@ func initWorkflowManager(ts *topo.Server) { // Register the Horizontal Resharding workflow. resharding.Register() + // Register workflow that generates Horizontal Resharding workflows. + reshardingworkflowgen.Register() + // Unregister the blacklisted workflows. for _, name := range workflowManagerDisable { workflow.Unregister(name) diff --git a/go/vt/vtexplain/vtexplain.go b/go/vt/vtexplain/vtexplain.go index ad063ba346f..8f118ec2f44 100644 --- a/go/vt/vtexplain/vtexplain.go +++ b/go/vt/vtexplain/vtexplain.go @@ -63,6 +63,10 @@ type Options struct { // StrictDDL is used in unit tests only to verify that the schema // is parsed properly. StrictDDL bool + + // Target is used to override the "database" target in the + // vtgate session to simulate `USE ` + Target string } // TabletQuery defines a query that was sent to a given tablet and how it was diff --git a/go/vt/vtexplain/vtexplain_flaky_test.go b/go/vt/vtexplain/vtexplain_flaky_test.go index fee1836aab9..190bd949894 100644 --- a/go/vt/vtexplain/vtexplain_flaky_test.go +++ b/go/vt/vtexplain/vtexplain_flaky_test.go @@ -144,6 +144,16 @@ func TestOptions(t *testing.T) { testExplain("options", opts, t) } +func TestTarget(t *testing.T) { + opts := &Options{ + ReplicationMode: "ROW", + NumShards: 4, + Normalize: false, + Target: "ks_sharded/40-80", + } + + testExplain("target", opts, t) +} func TestComments(t *testing.T) { testExplain("comments", defaultTestOpts(), t) diff --git a/go/vt/vtexplain/vtexplain_vtgate.go b/go/vt/vtexplain/vtexplain_vtgate.go index f2e914ccf84..4e90acf00f2 100644 --- a/go/vt/vtexplain/vtexplain_vtgate.go +++ b/go/vt/vtexplain/vtexplain_vtgate.go @@ -46,7 +46,7 @@ var ( healthCheck *discovery.FakeHealthCheck vtgateSession = &vtgatepb.Session{ - TargetString: "@master", + TargetString: "", Autocommit: true, } ) @@ -62,6 +62,8 @@ func initVtgateExecutor(vSchemaStr string, opts *Options) error { return err } + vtgateSession.TargetString = opts.Target + streamSize := 10 queryPlanCacheSize := int64(10) vtgateExecutor = vtgate.NewExecutor(context.Background(), explainTopo, vtexplainCell, "", resolver, opts.Normalize, streamSize, queryPlanCacheSize, false /* legacyAutocommit */) diff --git a/go/vt/vtgate/engine/insert.go b/go/vt/vtgate/engine/insert.go index 6a6e2d4f014..80696fcc2d5 100644 --- a/go/vt/vtgate/engine/insert.go +++ b/go/vt/vtgate/engine/insert.go @@ -451,9 +451,6 @@ func (ins *Insert) processPrimary(vcursor VCursor, vindexKeys [][]sqltypes.Value func (ins *Insert) processOwned(vcursor VCursor, vindexColumnsKeys [][]sqltypes.Value, colVindex *vindexes.ColumnVindex, bv map[string]*querypb.BindVariable, ksids [][]byte) error { for rowNum, rowColumnKeys := range vindexColumnsKeys { for colIdx, vindexKey := range rowColumnKeys { - if vindexKey.IsNull() { - return fmt.Errorf("value must be supplied for column %v", colVindex.Columns[colIdx]) - } col := colVindex.Columns[colIdx] bv[insertVarName(col, rowNum)] = sqltypes.ValueBindVariable(vindexKey) } @@ -476,9 +473,6 @@ func (ins *Insert) processOwnedIgnore(vcursor VCursor, vindexColumnsKeys [][]sql createKsids = append(createKsids, ksids[rowNum]) for colIdx, vindexKey := range rowColumnKeys { - if vindexKey.IsNull() { - return fmt.Errorf("value must be supplied for column %v", colVindex.Columns) - } rowKeys = append(rowKeys, vindexKey) col := colVindex.Columns[colIdx] bv[insertVarName(col, rowNum)] = sqltypes.ValueBindVariable(vindexKey) diff --git a/go/vt/vtgate/engine/insert_test.go b/go/vt/vtgate/engine/insert_test.go index 2ebf3f63e3a..5353588c73d 100644 --- a/go/vt/vtgate/engine/insert_test.go +++ b/go/vt/vtgate/engine/insert_test.go @@ -560,7 +560,7 @@ func TestInsertShardedOwned(t *testing.T) { }) } -func TestInsertShardedOwnedFail(t *testing.T) { +func TestInsertShardedOwnedWithNull(t *testing.T) { invschema := &vschemapb.SrvVSchema{ Keyspaces: map[string]*vschemapb.Keyspace{ "sharded": { @@ -626,11 +626,20 @@ func TestInsertShardedOwnedFail(t *testing.T) { } vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, + shards: []string{"-20", "20-"}, + shardForKsid: []string{"20-", "-20", "20-"}, } - // No reverse map available for lookup. So, it will fail. _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) - expectError(t, "Execute", err, "execInsertSharded: getInsertShardedRoute: value must be supplied for column c3") + if err != nil { + t.Fatal(err) + } + vc.ExpectLog(t, []string{ + `Execute insert into lkp1(from, toc) values(:from0, :toc0) from0: toc0: type:VARBINARY ` + + `value:"\026k@\264J\272K\326" true`, + `ResolveDestinations sharded [value:"0" ] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, + `ExecuteMultiShard sharded.20-: prefix mid1 suffix /* vtgate:: keyspace_id:166b40b44aba4bd6 */ ` + + `{_c30: _id0: type:INT64 value:"1" } true true`, + }) } func TestInsertShardedIgnoreOwned(t *testing.T) { @@ -824,7 +833,7 @@ func TestInsertShardedIgnoreOwned(t *testing.T) { }) } -func TestInsertShardedIgnoreOwnedFail(t *testing.T) { +func TestInsertShardedIgnoreOwnedWithNull(t *testing.T) { invschema := &vschemapb.SrvVSchema{ Keyspaces: map[string]*vschemapb.Keyspace{ "sharded": { @@ -889,11 +898,35 @@ func TestInsertShardedIgnoreOwnedFail(t *testing.T) { Suffix: " suffix", } + ksid0 := sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "to", + "varbinary", + ), + "\x00", + ) + //noresult := &sqltypes.Result{} vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, + shards: []string{"-20", "20-"}, + shardForKsid: []string{"-20", "20-"}, + results: []*sqltypes.Result{ + ksid0, + ksid0, + ksid0, + }, } _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) - expectError(t, "Execute", err, "execInsertSharded: getInsertShardedRoute: value must be supplied for column [c3]") + if err != nil { + t.Fatal(err) + } + vc.ExpectLog(t, []string{ + `Execute insert ignore into lkp1(from, toc) values(:from0, :toc0) from0: toc0: type:VARBINARY ` + + `value:"\026k@\264J\272K\326" true`, + `Execute select from from lkp1 where from = :from and toc = :toc from: toc: type:VARBINARY value:"\026k@\264J\272K\326" true`, + `ResolveDestinations sharded [value:"0" ] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, + `ExecuteMultiShard sharded.-20: prefix mid1 suffix /* vtgate:: keyspace_id:166b40b44aba4bd6 */ ` + + `{_c30: _id0: type:INT64 value:"1" } true true`, + }) } func TestInsertShardedUnownedVerify(t *testing.T) { diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 16cb9c0b0db..0ff13d4c5e9 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -608,6 +608,13 @@ func (e *Executor) handleSet(ctx context.Context, safeSession *SafeSession, sql return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid transaction_mode: %s", val) } safeSession.TransactionMode = vtgatepb.TransactionMode(out) + case sqlparser.TransactionStr: + // Parser ensures it's well-formed. + + // TODO: This is a NOP, modeled off of tx_isolation and tx_read_only. It's incredibly + // dangerous that it's a NOP, but fixing that is left to. Note that vtqueryservice needs + // to be updated as well: + // https://github.com/vitessio/vitess/issues/4127 case "tx_isolation": val, ok := v.(string) if !ok { @@ -615,7 +622,7 @@ func (e *Executor) handleSet(ctx context.Context, safeSession *SafeSession, sql } switch val { case "repeatable read", "read committed", "read uncommitted", "serializable": - // no op + // TODO (4127): This is a dangerous NOP. default: return nil, fmt.Errorf("unexpected value for tx_isolation: %v", val) } @@ -626,7 +633,7 @@ func (e *Executor) handleSet(ctx context.Context, safeSession *SafeSession, sql } switch val { case 0, 1: - // no op + // TODO (4127): This is a dangerous NOP. default: return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected value for tx_read_only: %d", val) } diff --git a/go/vt/vtgate/executor_framework_test.go b/go/vt/vtgate/executor_framework_test.go index 8ac7813cead..36f4909ee00 100644 --- a/go/vt/vtgate/executor_framework_test.go +++ b/go/vt/vtgate/executor_framework_test.go @@ -17,6 +17,7 @@ limitations under the License. package vtgate import ( + "bytes" "fmt" "reflect" "strconv" @@ -482,8 +483,9 @@ func testQueryLog(t *testing.T, logChan chan interface{}, method, stmtType, sql return nil } - log := streamlog.GetFormatter(QueryLogger)(nil, logStats) - fields := strings.Split(log, "\t") + var log bytes.Buffer + streamlog.GetFormatter(QueryLogger)(&log, nil, logStats) + fields := strings.Split(log.String(), "\t") // fields[0] is the method if method != fields[0] { diff --git a/go/vt/vtgate/logstats.go b/go/vt/vtgate/logstats.go index 10eb416a3df..84042878be8 100644 --- a/go/vt/vtgate/logstats.go +++ b/go/vt/vtgate/logstats.go @@ -17,9 +17,9 @@ limitations under the License. package vtgate import ( - "bytes" "fmt" "html/template" + "io" "net/url" "time" @@ -94,55 +94,6 @@ func (stats *LogStats) TotalTime() time.Duration { return stats.EndTime.Sub(stats.StartTime) } -// FmtBindVariables returns the map of bind variables as JSON. For -// values that are strings or byte slices it only reports their type -// and length. -func (stats *LogStats) FmtBindVariables(full bool) string { - if *streamlog.RedactDebugUIQueries { - return "\"[REDACTED]\"" - } - - var out map[string]*querypb.BindVariable - if full { - out = stats.BindVariables - } else { - // NOTE(szopa): I am getting rid of potentially large bind - // variables. - out = make(map[string]*querypb.BindVariable) - for k, v := range stats.BindVariables { - if sqltypes.IsIntegral(v.Type) || sqltypes.IsFloat(v.Type) { - out[k] = v - } else if v.Type == querypb.Type_TUPLE { - out[k] = sqltypes.StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) - } else { - out[k] = sqltypes.StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) - } - } - } - - if *streamlog.QueryLogFormat == streamlog.QueryLogFormatJSON { - var buf bytes.Buffer - buf.WriteString("{") - first := true - for k, v := range out { - if !first { - buf.WriteString(", ") - } else { - first = false - } - if sqltypes.IsIntegral(v.Type) || sqltypes.IsFloat(v.Type) { - fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) - } else { - fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) - } - } - buf.WriteString("}") - return buf.String() - } - - return fmt.Sprintf("%v", out) -} - // ContextHTML returns the HTML version of the context that was used, or "". // This is a method on LogStats instead of a field so that it doesn't need // to be passed by value everywhere. @@ -167,10 +118,18 @@ func (stats *LogStats) RemoteAddrUsername() (string, string) { return ci.RemoteAddr(), ci.Username() } -// Format returns a tab separated list of logged fields. -func (stats *LogStats) Format(params url.Values) string { - _, fullBindParams := params["full"] - formattedBindVars := stats.FmtBindVariables(fullBindParams) +// Logf formats the log record to the given writer, either as +// tab-separated list of logged fields or as JSON. +func (stats *LogStats) Logf(w io.Writer, params url.Values) error { + formattedBindVars := "\"[REDACTED]\"" + if !*streamlog.RedactDebugUIQueries { + _, fullBindParams := params["full"] + formattedBindVars = sqltypes.FormatBindVariables( + stats.BindVariables, + fullBindParams, + *streamlog.QueryLogFormat == streamlog.QueryLogFormatJSON, + ) + } // TODO: remove username here we fully enforce immediate caller id remoteAddr, username := stats.RemoteAddrUsername() @@ -183,7 +142,8 @@ func (stats *LogStats) Format(params url.Values) string { fmtString = "{\"Method\": %q, \"RemoteAddr\": %q, \"Username\": %q, \"ImmediateCaller\": %q, \"Effective Caller\": %q, \"Start\": \"%v\", \"End\": \"%v\", \"TotalTime\": %.6f, \"PlanTime\": %v, \"ExecuteTime\": %v, \"CommitTime\": %v, \"StmtType\": %q, \"SQL\": %q, \"BindVars\": %v, \"ShardQueries\": %v, \"RowsAffected\": %v, \"Error\": %q}\n" } - return fmt.Sprintf( + _, err := fmt.Fprintf( + w, fmtString, stats.Method, remoteAddr, @@ -203,4 +163,5 @@ func (stats *LogStats) Format(params url.Values) string { stats.RowsAffected, stats.ErrorStr(), ) + return err } diff --git a/go/vt/vtgate/logstats_test.go b/go/vt/vtgate/logstats_test.go index e35303db0bf..01f5430e6d8 100644 --- a/go/vt/vtgate/logstats_test.go +++ b/go/vt/vtgate/logstats_test.go @@ -17,6 +17,7 @@ limitations under the License. package vtgate import ( + "bytes" "encoding/json" "errors" "net/url" @@ -33,6 +34,12 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" ) +func testFormat(stats *LogStats, params url.Values) string { + var b bytes.Buffer + stats.Logf(&b, params) + return b.String() +} + func TestLogStatsFormat(t *testing.T) { logStats := NewLogStats(context.Background(), "test", "sql1", map[string]*querypb.BindVariable{"intVal": sqltypes.Int64BindVariable(1)}) logStats.StartTime = time.Date(2017, time.January, 1, 1, 2, 3, 0, time.UTC) @@ -41,7 +48,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = false *streamlog.QueryLogFormat = "text" - got := logStats.Format(url.Values(params)) + got := testFormat(logStats, url.Values(params)) want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[intVal:type:INT64 value:\"1\" ]\t0\t0\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) @@ -49,7 +56,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = true *streamlog.QueryLogFormat = "text" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\t\"[REDACTED]\"\t0\t0\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) @@ -57,7 +64,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = false *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) var parsed map[string]interface{} err := json.Unmarshal([]byte(got), &parsed) if err != nil { @@ -74,7 +81,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = true *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) err = json.Unmarshal([]byte(got), &parsed) if err != nil { t.Errorf("logstats format: error unmarshaling json: %v -- got:\n%v", err, got) @@ -95,14 +102,14 @@ func TestLogStatsFormat(t *testing.T) { logStats.BindVariables = map[string]*querypb.BindVariable{"strVal": sqltypes.StringBindVariable("abc")} *streamlog.QueryLogFormat = "text" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t0.000000\t0.000000\t0.000000\t\t\"sql1\"\tmap[strVal:type:VARCHAR value:\"abc\" ]\t0\t0\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) err = json.Unmarshal([]byte(got), &parsed) if err != nil { t.Errorf("logstats format: error unmarshaling json: %v -- got:\n%v", err, got) @@ -119,52 +126,6 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.QueryLogFormat = "text" } -func TestLogStatsFormatBindVariables(t *testing.T) { - tupleBindVar, err := sqltypes.BuildBindVariable([]int64{1, 2}) - if err != nil { - t.Fatalf("failed to create a tuple bind var: %v", err) - } - - logStats := NewLogStats(context.Background(), "test", "sql1", map[string]*querypb.BindVariable{ - "key_1": sqltypes.StringBindVariable("val_1"), - "key_2": sqltypes.Int64BindVariable(789), - "key_3": sqltypes.BytesBindVariable([]byte("val_3")), - "key_4": tupleBindVar, - }) - - formattedStr := logStats.FmtBindVariables(true) - if !strings.Contains(formattedStr, "key_1") || - !strings.Contains(formattedStr, "val_1") { - t.Fatalf("bind variable 'key_1': 'val_1' is not formatted") - } - if !strings.Contains(formattedStr, "key_2") || - !strings.Contains(formattedStr, "789") { - t.Fatalf("bind variable 'key_2': '789' is not formatted") - } - if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "val_3") { - t.Fatalf("bind variable 'key_3': 'val_3' is not formatted") - } - if !strings.Contains(formattedStr, "key_4") || - !strings.Contains(formattedStr, "values: values:") { - t.Fatalf("bind variable 'key_4': (1, 2) is not formatted") - } - - formattedStr = logStats.FmtBindVariables(false) - if !strings.Contains(formattedStr, "key_1") { - t.Fatalf("bind variable 'key_1' is not formatted") - } - if !strings.Contains(formattedStr, "key_2") || - !strings.Contains(formattedStr, "789") { - t.Fatalf("bind variable 'key_2': '789' is not formatted") - } - if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "5 bytes") { - t.Fatalf("bind variable 'key_3' is not formatted") - } - if !strings.Contains(formattedStr, "key_4") || !strings.Contains(formattedStr, "2 items") { - t.Fatalf("bind variable 'key_4' is not formatted") - } -} - func TestLogStatsContextHTML(t *testing.T) { html := "HtmlContext" callInfo := &fakecallinfo.FakeCallInfo{ diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go index cc0571821fe..69bf468fee8 100644 --- a/go/vt/vtgate/planbuilder/from.go +++ b/go/vt/vtgate/planbuilder/from.go @@ -276,10 +276,8 @@ func (pb *primitiveBuilder) join(rpb *primitiveBuilder, ajoin *sqlparser.JoinTab } // Both l & r routes point to the same shard. - if lRoute.ERoute.Opcode == engine.SelectEqualUnique && rRoute.ERoute.Opcode == engine.SelectEqualUnique { - if valEqual(lRoute.condition, rRoute.condition) { - return pb.mergeRoutes(rpb, ajoin) - } + if lRoute.isSameShardedRoute(rRoute) == nil { + return pb.mergeRoutes(rpb, ajoin) } } diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index e0544368b5a..92ed6126188 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -622,14 +622,7 @@ func (rb *route) SubqueryCanMerge(pb *primitiveBuilder, inner *route) error { default: return errors.New("unsupported: scatter subquery") } - - if rb.ERoute.Opcode != engine.SelectEqualUnique { - return errors.New("unsupported: subquery does not depend on scatter outer query") - } - if !valEqual(rb.condition, inner.condition) { - return errors.New("unsupported: subquery and parent route to different shards") - } - return nil + return rb.isSameShardedRoute(inner) } // UnionCanMerge returns nil if the supplied route that represents @@ -654,12 +647,21 @@ func (rb *route) UnionCanMerge(right *route) error { } return errIntermixingUnsupported } + return rb.isSameShardedRoute(right) +} +// isSameShardedRoute returns nil if the supplied route has +// the same single shard target as the current route. If not, it +// returns an appropriate error. +func (rb *route) isSameShardedRoute(right *route) error { if rb.ERoute.Opcode != engine.SelectEqualUnique || right.ERoute.Opcode != engine.SelectEqualUnique { - return errors.New("unsupported: UNION on multi-shard queries") + return errors.New("unsupported: UNION or subquery containing multi-shard queries") + } + if rb.ERoute.Vindex != right.ERoute.Vindex { + return errors.New("unsupported: UNION or subquery on different shards: vindexes are different") } if !valEqual(rb.condition, right.condition) { - return errors.New("unsupported: UNION queries with different target shards") + return errors.New("unsupported: UNION or subquery on different shards: vindex values are different") } return nil } diff --git a/go/vt/vtgate/plugin_mysql_server.go b/go/vt/vtgate/plugin_mysql_server.go index 194f04a428b..37628f9cb3c 100644 --- a/go/vt/vtgate/plugin_mysql_server.go +++ b/go/vt/vtgate/plugin_mysql_server.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/callerid" + "vitess.io/vitess/go/vt/callinfo" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vttls" @@ -105,6 +106,8 @@ func (vh *vtgateHandler) ComQuery(c *mysql.Conn, query string, callback func(*sq ctx = context.Background() } + ctx = callinfo.MysqlCallInfo(ctx, c) + // Fill in the ImmediateCallerID with the UserData returned by // the AuthServer plugin for that user. If nothing was // returned, use the User. This lets the plugin map a MySQL diff --git a/go/vt/vtgate/vindexes/lookup_hash_test.go b/go/vt/vtgate/vindexes/lookup_hash_test.go index ee8606704af..7cd9692d3e2 100644 --- a/go/vt/vtgate/vindexes/lookup_hash_test.go +++ b/go/vt/vtgate/vindexes/lookup_hash_test.go @@ -154,6 +154,39 @@ func TestLookupHashMapAbsent(t *testing.T) { } } +func TestLookupHashMapNull(t *testing.T) { + lookuphash := createLookup(t, "lookup_hash", false) + vc := &vcursor{numRows: 1} + + got, err := lookuphash.Map(vc, []sqltypes.Value{sqltypes.NULL}) + if err != nil { + t.Error(err) + } + want := []key.Destination{ + key.DestinationKeyspaceIDs([][]byte{ + []byte("\x16k@\xb4J\xbaK\xd6"), + }), + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Map(): %#v, want %+v", got, want) + } + + // writeOnly true should return full keyranges. + lookuphash = createLookup(t, "lookup_hash", true) + got, err = lookuphash.Map(vc, []sqltypes.Value{sqltypes.NULL}) + if err != nil { + t.Error(err) + } + want = []key.Destination{ + key.DestinationKeyRange{ + KeyRange: &topodatapb.KeyRange{}, + }, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Map(): %#v, want %+v", got, want) + } +} + func TestLookupHashVerify(t *testing.T) { lookuphash := createLookup(t, "lookup_hash", false) vc := &vcursor{numRows: 1} @@ -216,6 +249,15 @@ func TestLookupHashCreate(t *testing.T) { t.Errorf("vc.queries length: %v, want %v", got, want) } + vc.queries = nil + err = lookuphash.(Lookup).Create(vc, [][]sqltypes.Value{{sqltypes.NULL}}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}, false /* ignoreMode */) + if err != nil { + t.Error(err) + } + if got, want := len(vc.queries), 1; got != want { + t.Errorf("vc.queries length: %v, want %v", got, want) + } + err = lookuphash.(Lookup).Create(vc, [][]sqltypes.Value{{sqltypes.NewInt64(1)}}, [][]byte{[]byte("bogus")}, false /* ignoreMode */) want := "lookup.Create.vunhash: invalid keyspace id: 626f677573" if err == nil || err.Error() != want { @@ -235,6 +277,15 @@ func TestLookupHashDelete(t *testing.T) { t.Errorf("vc.queries length: %v, want %v", got, want) } + vc.queries = nil + err = lookuphash.(Lookup).Delete(vc, [][]sqltypes.Value{{sqltypes.NULL}}, []byte("\x16k@\xb4J\xbaK\xd6")) + if err != nil { + t.Error(err) + } + if got, want := len(vc.queries), 1; got != want { + t.Errorf("vc.queries length: %v, want %v", got, want) + } + err = lookuphash.(Lookup).Delete(vc, [][]sqltypes.Value{{sqltypes.NewInt64(1)}}, []byte("bogus")) want := "lookup.Delete.vunhash: invalid keyspace id: 626f677573" if err == nil || err.Error() != want { @@ -253,4 +304,13 @@ func TestLookupHashUpdate(t *testing.T) { if got, want := len(vc.queries), 2; got != want { t.Errorf("vc.queries length: %v, want %v", got, want) } + + vc.queries = nil + err = lookuphash.(Lookup).Update(vc, []sqltypes.Value{sqltypes.NULL}, []byte("\x16k@\xb4J\xbaK\xd6"), []sqltypes.Value{sqltypes.NewInt64(2)}) + if err != nil { + t.Error(err) + } + if got, want := len(vc.queries), 2; got != want { + t.Errorf("vc.queries length: %v, want %v", got, want) + } } diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go index bba94948cfc..7619b77d405 100644 --- a/go/vt/vtgate/vindexes/vschema.go +++ b/go/vt/vtgate/vindexes/vschema.go @@ -17,6 +17,7 @@ limitations under the License. package vindexes import ( + "encoding/hex" "encoding/json" "fmt" "io/ioutil" @@ -203,7 +204,13 @@ func buildTables(source *vschemapb.SrvVSchema, vschema *VSchema) error { if table.Type == "sequence" { t.IsSequence = true } - if keyspace.Sharded && len(table.ColumnVindexes) == 0 { + if table.Pinned != "" { + decoded, err := hex.DecodeString(table.Pinned) + if err != nil { + return fmt.Errorf("could not decode the keyspace id for pin: %v", err) + } + t.Pinned = decoded + } else if keyspace.Sharded && len(table.ColumnVindexes) == 0 { return fmt.Errorf("missing primary col vindex for table: %s", tname) } diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go index 2d075b0733d..133922bd058 100644 --- a/go/vt/vtgate/vindexes/vschema_test.go +++ b/go/vt/vtgate/vindexes/vschema_test.go @@ -237,6 +237,61 @@ func TestVSchemaColumnsFail(t *testing.T) { } } +func TestVSchemaPinned(t *testing.T) { + good := vschemapb.SrvVSchema{ + Keyspaces: map[string]*vschemapb.Keyspace{ + "sharded": { + Sharded: true, + Tables: map[string]*vschemapb.Table{ + "t1": { + Pinned: "80", + }, + }, + }, + }, + } + got, err := BuildVSchema(&good) + if err != nil { + t.Error(err) + } + ks := &Keyspace{ + Name: "sharded", + Sharded: true, + } + t1 := &Table{ + Name: sqlparser.NewTableIdent("t1"), + Keyspace: ks, + Pinned: []byte{0x80}, + } + dual := &Table{ + Name: sqlparser.NewTableIdent("dual"), + Keyspace: ks, + Pinned: []byte{0}, + } + want := &VSchema{ + uniqueTables: map[string]*Table{ + "t1": t1, + "dual": dual, + }, + uniqueVindexes: map[string]Vindex{}, + Keyspaces: map[string]*KeyspaceSchema{ + "sharded": { + Keyspace: ks, + Tables: map[string]*Table{ + "t1": t1, + "dual": dual, + }, + Vindexes: map[string]Vindex{}, + }, + }, + } + if !reflect.DeepEqual(got, want) { + gotjson, _ := json.Marshal(got) + wantjson, _ := json.Marshal(want) + t.Errorf("BuildVSchema:\n%s, want\n%s", gotjson, wantjson) + } +} + func TestShardedVSchemaOwned(t *testing.T) { good := vschemapb.SrvVSchema{ Keyspaces: map[string]*vschemapb.Keyspace{ diff --git a/go/vt/vttablet/agentrpctest/test_agent_rpc.go b/go/vt/vttablet/agentrpctest/test_agent_rpc.go index 997cadbd950..0bfa22d1e79 100644 --- a/go/vt/vttablet/agentrpctest/test_agent_rpc.go +++ b/go/vt/vttablet/agentrpctest/test_agent_rpc.go @@ -75,6 +75,7 @@ func NewFakeRPCAgent(t *testing.T) tabletmanager.RPCAgent { var protoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem() func compare(t *testing.T, name string, got, want interface{}) { + t.Helper() typ := reflect.TypeOf(got) if reflect.TypeOf(got) != reflect.TypeOf(want) { goto fail @@ -105,12 +106,14 @@ fail: } func compareBool(t *testing.T, name string, got bool) { + t.Helper() if !got { t.Errorf("Unexpected %v: got false expected true", name) } } func compareError(t *testing.T, name string, err error, got, want interface{}) { + t.Helper() if err != nil { t.Errorf("%v failed: %v", name, err) } else { @@ -127,6 +130,7 @@ func logStuff(logger logutil.Logger, count int) { } func compareLoggedStuff(t *testing.T, name string, stream logutil.EventStream, count int) error { + t.Helper() for i := 0; i < count; i++ { le, err := stream.Recv() if err != nil { @@ -148,6 +152,7 @@ func compareLoggedStuff(t *testing.T, name string, stream logutil.EventStream, c } func expectHandleRPCPanic(t *testing.T, name string, verbose bool, err error) { + t.Helper() expected := fmt.Sprintf("HandleRPCPanic caught panic during %v with verbose %v", name, verbose) if err == nil || !strings.Contains(err.Error(), expected) { t.Fatalf("Expected a panic error with '%v' but got: %v", expected, err) @@ -825,96 +830,48 @@ func agentRPCTestGetSlavesPanic(ctx context.Context, t *testing.T, client tmclie expectHandleRPCPanic(t, "GetSlaves", false /*verbose*/, err) } -var testBlpPosition = &tabletmanagerdatapb.BlpPosition{ - Uid: 73, - Position: "testReplicationPosition", -} -var testWaitBlpPositionWaitTime = time.Hour -var testWaitBlpPositionCalled = false - -func (fra *fakeRPCAgent) WaitBlpPosition(ctx context.Context, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error { - if fra.panics { - panic(fmt.Errorf("test-triggered panic")) - } - compare(fra.t, "WaitBlpPosition blpPosition", blpPosition, testBlpPosition) - compare(fra.t, "WaitBlpPosition waitTime", waitTime, testWaitBlpPositionWaitTime) - testWaitBlpPositionCalled = true - return nil -} - -func agentRPCTestWaitBlpPosition(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - err := client.WaitBlpPosition(ctx, tablet, testBlpPosition, testWaitBlpPositionWaitTime) - compareError(t, "WaitBlpPosition", err, true, testWaitBlpPositionCalled) -} - -func agentRPCTestWaitBlpPositionPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - err := client.WaitBlpPosition(ctx, tablet, testBlpPosition, testWaitBlpPositionWaitTime) - expectHandleRPCPanic(t, "WaitBlpPosition", true /*verbose*/, err) -} - -var testBlpPositionList = []*tabletmanagerdatapb.BlpPosition{ - { - Uid: 12, - Position: "testBlpPosition", - }, -} +var testVRQuery = "query" -func (fra *fakeRPCAgent) StopBlp(ctx context.Context) ([]*tabletmanagerdatapb.BlpPosition, error) { +func (fra *fakeRPCAgent) VReplicationExec(ctx context.Context, query string) (*querypb.QueryResult, error) { if fra.panics { panic(fmt.Errorf("test-triggered panic")) } - return testBlpPositionList, nil + compare(fra.t, "VReplicationExec query", query, testVRQuery) + return testExecuteFetchResult, nil } -func agentRPCTestStopBlp(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - bpl, err := client.StopBlp(ctx, tablet) - compareError(t, "StopBlp", err, bpl, testBlpPositionList) +func agentRPCTestVReplicationExec(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + rp, err := client.VReplicationExec(ctx, tablet, testVRQuery) + compareError(t, "VReplicationExec", err, rp, testExecuteFetchResult) } -func agentRPCTestStopBlpPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - _, err := client.StopBlp(ctx, tablet) - expectHandleRPCPanic(t, "StopBlp", true /*verbose*/, err) +func agentRPCTestVReplicationExecPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + _, err := client.VReplicationExec(ctx, tablet, testVRQuery) + expectHandleRPCPanic(t, "VReplicationExec", true /*verbose*/, err) } -var testStartBlpCalled = false +var ( + wfpid = 3 + wfppos = "" +) -func (fra *fakeRPCAgent) StartBlp(ctx context.Context) error { +func (fra *fakeRPCAgent) VReplicationWaitForPos(ctx context.Context, id int, pos string) error { if fra.panics { panic(fmt.Errorf("test-triggered panic")) } - testStartBlpCalled = true + compare(fra.t, "VReplicationWaitForPos id", id, wfpid) + compare(fra.t, "VReplicationWaitForPos pos", pos, wfppos) return nil } -func agentRPCTestStartBlp(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - err := client.StartBlp(ctx, tablet) - compareError(t, "StartBlp", err, true, testStartBlpCalled) +func agentRPCTestVReplicationWaitForPos(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + err := client.VReplicationWaitForPos(ctx, tablet, wfpid, wfppos) + compareError(t, "VReplicationWaitForPos", err, true, true) } -func agentRPCTestStartBlpPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - err := client.StartBlp(ctx, tablet) - expectHandleRPCPanic(t, "StartBlp", true /*verbose*/, err) -} - -var testRunBlpUntilWaitTime = 3 * time.Minute - -func (fra *fakeRPCAgent) RunBlpUntil(ctx context.Context, bpl []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) { - if fra.panics { - panic(fmt.Errorf("test-triggered panic")) - } - compare(fra.t, "RunBlpUntil bpl", bpl, testBlpPositionList) - compare(fra.t, "RunBlpUntil waitTime", waitTime, testRunBlpUntilWaitTime) - return testReplicationPosition, nil -} - -func agentRPCTestRunBlpUntil(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - rp, err := client.RunBlpUntil(ctx, tablet, testBlpPositionList, testRunBlpUntilWaitTime) - compareError(t, "RunBlpUntil", err, rp, testReplicationPosition) -} - -func agentRPCTestRunBlpUntilPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - _, err := client.RunBlpUntil(ctx, tablet, testBlpPositionList, testRunBlpUntilWaitTime) - expectHandleRPCPanic(t, "RunBlpUntil", true /*verbose*/, err) +func agentRPCTestVReplicationWaitForPosPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + err := client.VReplicationWaitForPos(ctx, tablet, wfpid, wfppos) + expectHandleRPCPanic(t, "VReplicationWaitForPos", true /*verbose*/, err) } // @@ -1271,10 +1228,10 @@ func Run(t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.T agentRPCTestStartSlave(ctx, t, client, tablet) agentRPCTestTabletExternallyReparented(ctx, t, client, tablet) agentRPCTestGetSlaves(ctx, t, client, tablet) - agentRPCTestWaitBlpPosition(ctx, t, client, tablet) - agentRPCTestStopBlp(ctx, t, client, tablet) - agentRPCTestStartBlp(ctx, t, client, tablet) - agentRPCTestRunBlpUntil(ctx, t, client, tablet) + + // VReplication methods + agentRPCTestVReplicationExec(ctx, t, client, tablet) + agentRPCTestVReplicationWaitForPos(ctx, t, client, tablet) // Reparenting related functions agentRPCTestResetReplication(ctx, t, client, tablet) @@ -1324,10 +1281,10 @@ func Run(t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.T agentRPCTestStartSlavePanic(ctx, t, client, tablet) agentRPCTestTabletExternallyReparentedPanic(ctx, t, client, tablet) agentRPCTestGetSlavesPanic(ctx, t, client, tablet) - agentRPCTestWaitBlpPositionPanic(ctx, t, client, tablet) - agentRPCTestStopBlpPanic(ctx, t, client, tablet) - agentRPCTestStartBlpPanic(ctx, t, client, tablet) - agentRPCTestRunBlpUntilPanic(ctx, t, client, tablet) + + // VReplication methods + agentRPCTestVReplicationExecPanic(ctx, t, client, tablet) + agentRPCTestVReplicationWaitForPosPanic(ctx, t, client, tablet) // Reparenting related functions agentRPCTestResetReplicationPanic(ctx, t, client, tablet) diff --git a/go/vt/vttablet/endtoend/queries_test.go b/go/vt/vttablet/endtoend/queries_test.go index f321de17dab..56021b831da 100644 --- a/go/vt/vttablet/endtoend/queries_test.go +++ b/go/vt/vttablet/endtoend/queries_test.go @@ -1679,7 +1679,7 @@ func TestQueries(t *testing.T) { Query: "insert into vitess_misc(id, b, d, dt, t) select 2, b, d, dt, t from vitess_misc", Rewritten: []string{ "select 2, b, d, dt, t from vitess_misc limit 10001", - "insert into vitess_misc(id, b, d, dt, t) values (2, '\x01', '2012-01-01', '2012-01-01 15:45:45', '15:45:45') /* _stream vitess_misc (id ) (2 )", + "insert into vitess_misc(id, b, d, dt, t) values (2, b'00000001', '2012-01-01', '2012-01-01 15:45:45', '15:45:45') /* _stream vitess_misc (id ) (2 )", }, }, framework.TestQuery("commit"), @@ -1798,8 +1798,11 @@ func TestQueries(t *testing.T) { } func TestBitDefault(t *testing.T) { + // Default values for bit fields that are PKs are not supported + // Does not make sense to use a bit field as PK client := framework.NewClient() + expectedError := "bit default value: Execute failed: could not create default row for insert without row values: cannot convert value BIT(\"\\x05\") to AST (CallerID: dev)" testCases := []framework.Testable{ &framework.MultiCase{ Name: "bit default value", @@ -1824,8 +1827,9 @@ func TestBitDefault(t *testing.T) { }, } for _, tcase := range testCases { - if err := tcase.Test("", client); err != nil { - t.Error(err) + err := tcase.Test("", client) + if err == nil || err.Error() != expectedError { + t.Errorf("TestBitDefault result: \n%q\nexpecting\n%q", err.Error(), expectedError) } } } diff --git a/go/vt/vttablet/faketmclient/fake_client.go b/go/vt/vttablet/faketmclient/fake_client.go index 8d87c6fe2fc..77b528d9930 100644 --- a/go/vt/vttablet/faketmclient/fake_client.go +++ b/go/vt/vttablet/faketmclient/fake_client.go @@ -27,6 +27,7 @@ import ( "golang.org/x/net/context" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -195,34 +196,21 @@ func (client *FakeTabletManagerClient) GetSlaves(ctx context.Context, tablet *to return nil, nil } -// WaitBlpPosition is part of the tmclient.TabletManagerClient interface. -func (client *FakeTabletManagerClient) WaitBlpPosition(ctx context.Context, tablet *topodatapb.Tablet, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error { - return nil -} - -// StopBlp is part of the tmclient.TabletManagerClient interface. -func (client *FakeTabletManagerClient) StopBlp(ctx context.Context, tablet *topodatapb.Tablet) ([]*tabletmanagerdatapb.BlpPosition, error) { - // TODO(aaijazi): this works because all tests so far only need to rely on Uid 0. - // Ideally, this should turn into a full mock, where the caller can configure the exact - // return value. - bpl := []*tabletmanagerdatapb.BlpPosition{ - { - Uid: uint32(0), - }, - } - return bpl, nil +// VReplicationExec is part of the tmclient.TabletManagerClient interface. +func (client *FakeTabletManagerClient) VReplicationExec(ctx context.Context, tablet *topodatapb.Tablet, query string) (*querypb.QueryResult, error) { + // This result satisfies 'select pos from _vt.vreplication...' called from split clone unit tests in go/vt/worker. + result := sqltypes.MakeTestResult( + sqltypes.MakeTestFields("pos", "varchar"), + "MariaDB/1-1-1", + ) + return sqltypes.ResultToProto3(result), nil } -// StartBlp is part of the tmclient.TabletManagerClient interface. -func (client *FakeTabletManagerClient) StartBlp(ctx context.Context, tablet *topodatapb.Tablet) error { +// VReplicationWaitForPos is part of the tmclient.TabletManagerClient interface. +func (client *FakeTabletManagerClient) VReplicationWaitForPos(ctx context.Context, tablet *topodatapb.Tablet, id int, pos string) error { return nil } -// RunBlpUntil is part of the tmclient.TabletManagerClient interface. -func (client *FakeTabletManagerClient) RunBlpUntil(ctx context.Context, tablet *topodatapb.Tablet, positions []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) { - return "", nil -} - // // Reparenting related functions // diff --git a/go/vt/vttablet/grpctmclient/client.go b/go/vt/vttablet/grpctmclient/client.go index 1a78ed58b79..0a0232c51b0 100644 --- a/go/vt/vttablet/grpctmclient/client.go +++ b/go/vt/vttablet/grpctmclient/client.go @@ -22,9 +22,9 @@ import ( "sync" "time" + "golang.org/x/net/context" "google.golang.org/grpc" - "golang.org/x/net/context" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/vt/grpcclient" "vitess.io/vitess/go/vt/hook" @@ -524,60 +524,31 @@ func (client *Client) GetSlaves(ctx context.Context, tablet *topodatapb.Tablet) return response.Addrs, nil } -// WaitBlpPosition is part of the tmclient.TabletManagerClient interface. -func (client *Client) WaitBlpPosition(ctx context.Context, tablet *topodatapb.Tablet, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error { - cc, c, err := client.dial(tablet) - if err != nil { - return err - } - defer cc.Close() - _, err = c.WaitBlpPosition(ctx, &tabletmanagerdatapb.WaitBlpPositionRequest{ - BlpPosition: blpPosition, - WaitTimeout: int64(waitTime), - }) - return err -} - -// StopBlp is part of the tmclient.TabletManagerClient interface. -func (client *Client) StopBlp(ctx context.Context, tablet *topodatapb.Tablet) ([]*tabletmanagerdatapb.BlpPosition, error) { +// VReplicationExec is part of the tmclient.TabletManagerClient interface. +func (client *Client) VReplicationExec(ctx context.Context, tablet *topodatapb.Tablet, query string) (*querypb.QueryResult, error) { cc, c, err := client.dial(tablet) if err != nil { return nil, err } defer cc.Close() - response, err := c.StopBlp(ctx, &tabletmanagerdatapb.StopBlpRequest{}) + response, err := c.VReplicationExec(ctx, &tabletmanagerdatapb.VReplicationExecRequest{Query: query}) if err != nil { return nil, err } - return response.BlpPositions, nil + return response.Result, nil } -// StartBlp is part of the tmclient.TabletManagerClient interface. -func (client *Client) StartBlp(ctx context.Context, tablet *topodatapb.Tablet) error { +// VReplicationWaitForPos is part of the tmclient.TabletManagerClient interface. +func (client *Client) VReplicationWaitForPos(ctx context.Context, tablet *topodatapb.Tablet, id int, pos string) error { cc, c, err := client.dial(tablet) if err != nil { return err } defer cc.Close() - _, err = c.StartBlp(ctx, &tabletmanagerdatapb.StartBlpRequest{}) - return err -} - -// RunBlpUntil is part of the tmclient.TabletManagerClient interface. -func (client *Client) RunBlpUntil(ctx context.Context, tablet *topodatapb.Tablet, positions []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) { - cc, c, err := client.dial(tablet) - if err != nil { - return "", err - } - defer cc.Close() - response, err := c.RunBlpUntil(ctx, &tabletmanagerdatapb.RunBlpUntilRequest{ - BlpPositions: positions, - WaitTimeout: int64(waitTime), - }) - if err != nil { - return "", err + if _, err = c.VReplicationWaitForPos(ctx, &tabletmanagerdatapb.VReplicationWaitForPosRequest{Id: int64(id), Position: pos}); err != nil { + return err } - return response.Position, nil + return nil } // diff --git a/go/vt/vttablet/grpctmserver/server.go b/go/vt/vttablet/grpctmserver/server.go index 03d5afc5ece..7054c37b721 100644 --- a/go/vt/vttablet/grpctmserver/server.go +++ b/go/vt/vttablet/grpctmserver/server.go @@ -287,40 +287,19 @@ func (s *server) GetSlaves(ctx context.Context, request *tabletmanagerdatapb.Get return response, err } -func (s *server) WaitBlpPosition(ctx context.Context, request *tabletmanagerdatapb.WaitBlpPositionRequest) (response *tabletmanagerdatapb.WaitBlpPositionResponse, err error) { - defer s.agent.HandleRPCPanic(ctx, "WaitBlpPosition", request, response, true /*verbose*/, &err) +func (s *server) VReplicationExec(ctx context.Context, request *tabletmanagerdatapb.VReplicationExecRequest) (response *tabletmanagerdatapb.VReplicationExecResponse, err error) { + defer s.agent.HandleRPCPanic(ctx, "VReplicationExec", request, response, true /*verbose*/, &err) ctx = callinfo.GRPCCallInfo(ctx) - response = &tabletmanagerdatapb.WaitBlpPositionResponse{} - return response, s.agent.WaitBlpPosition(ctx, request.BlpPosition, time.Duration(request.WaitTimeout)) -} - -func (s *server) StopBlp(ctx context.Context, request *tabletmanagerdatapb.StopBlpRequest) (response *tabletmanagerdatapb.StopBlpResponse, err error) { - defer s.agent.HandleRPCPanic(ctx, "StopBlp", request, response, true /*verbose*/, &err) - ctx = callinfo.GRPCCallInfo(ctx) - response = &tabletmanagerdatapb.StopBlpResponse{} - positions, err := s.agent.StopBlp(ctx) - if err == nil { - response.BlpPositions = positions - } + response = &tabletmanagerdatapb.VReplicationExecResponse{} + response.Result, err = s.agent.VReplicationExec(ctx, request.Query) return response, err } -func (s *server) StartBlp(ctx context.Context, request *tabletmanagerdatapb.StartBlpRequest) (response *tabletmanagerdatapb.StartBlpResponse, err error) { - defer s.agent.HandleRPCPanic(ctx, "StartBlp", request, response, true /*verbose*/, &err) - ctx = callinfo.GRPCCallInfo(ctx) - response = &tabletmanagerdatapb.StartBlpResponse{} - return response, s.agent.StartBlp(ctx) -} - -func (s *server) RunBlpUntil(ctx context.Context, request *tabletmanagerdatapb.RunBlpUntilRequest) (response *tabletmanagerdatapb.RunBlpUntilResponse, err error) { - defer s.agent.HandleRPCPanic(ctx, "RunBlpUntil", request, response, true /*verbose*/, &err) +func (s *server) VReplicationWaitForPos(ctx context.Context, request *tabletmanagerdatapb.VReplicationWaitForPosRequest) (response *tabletmanagerdatapb.VReplicationWaitForPosResponse, err error) { + defer s.agent.HandleRPCPanic(ctx, "VReplicationWaitForPos", request, response, true /*verbose*/, &err) ctx = callinfo.GRPCCallInfo(ctx) - response = &tabletmanagerdatapb.RunBlpUntilResponse{} - position, err := s.agent.RunBlpUntil(ctx, request.BlpPositions, time.Duration(request.WaitTimeout)) - if err == nil { - response.Position = position - } - return response, err + err = s.agent.VReplicationWaitForPos(ctx, int(request.Id), request.Position) + return &tabletmanagerdatapb.VReplicationWaitForPosResponse{}, err } // diff --git a/go/vt/vttablet/sysloglogger/sysloglogger.go b/go/vt/vttablet/sysloglogger/sysloglogger.go index 60f2f97d4d7..328c327f621 100644 --- a/go/vt/vttablet/sysloglogger/sysloglogger.go +++ b/go/vt/vttablet/sysloglogger/sysloglogger.go @@ -18,6 +18,7 @@ limitations under the License. package sysloglogger import ( + "bytes" "flag" "log/syslog" @@ -73,7 +74,12 @@ func run() { log.Errorf("Unexpected value in query logs: %#v (expecting value of type %T)", out, &tabletenv.LogStats{}) continue } - if err := writer.Info(stats.Format(formatParams)); err != nil { + var b bytes.Buffer + if err := stats.Logf(&b, formatParams); err != nil { + log.Errorf("Error formatting logStats: %v", err) + continue + } + if err := writer.Info(b.String()); err != nil { log.Errorf("Error writing to syslog: %v", err) continue } diff --git a/go/vt/vttablet/tabletmanager/action_agent.go b/go/vt/vttablet/tabletmanager/action_agent.go index 4abe92269ef..9bda98cc001 100644 --- a/go/vt/vttablet/tabletmanager/action_agent.go +++ b/go/vt/vttablet/tabletmanager/action_agent.go @@ -62,6 +62,7 @@ import ( "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tabletserver" "vitess.io/vitess/go/vt/vttablet/tabletservermock" @@ -90,7 +91,7 @@ type ActionAgent struct { Cnf *mysqlctl.Mycnf MysqlDaemon mysqlctl.MysqlDaemon DBConfigs *dbconfigs.DBConfigs - BinlogPlayerMap *BinlogPlayerMap + VREngine *vreplication.Engine // exportStats is set only for production tablet. exportStats bool @@ -253,13 +254,12 @@ func NewActionAgent( agent.statsTabletType = stats.NewString("TabletType") agent.statsTabletTypeCount = stats.NewCountersWithSingleLabel("TabletTypeCount", "Number of times the tablet changed to the labeled type", "type") - // Start the binlog player services, not playing at start. - agent.BinlogPlayerMap = NewBinlogPlayerMap(ts, mysqld, func() binlogplayer.VtClient { - return binlogplayer.NewDbClient(agent.DBConfigs.FilteredWithDB()) + // The db name will get set by the Start function called below, before + // VREngine gets to invoke the FilteredWithDB call. + agent.VREngine = vreplication.NewEngine(ts, tabletAlias.Cell, mysqld, func() binlogplayer.DBClient { + return binlogplayer.NewDBClient(agent.DBConfigs.FilteredWithDB()) }) - // Stop all binlog players upon entering lameduck. - servenv.OnTerm(agent.BinlogPlayerMap.StopAllPlayersAndReset) - RegisterBinlogPlayerMap(agent.BinlogPlayerMap) + servenv.OnTerm(agent.VREngine.Close) var mysqlHost string var mysqlPort int32 @@ -341,7 +341,7 @@ func NewTestActionAgent(batchCtx context.Context, ts *topo.Server, tabletAlias * Cnf: nil, MysqlDaemon: mysqlDaemon, DBConfigs: &dbconfigs.DBConfigs{}, - BinlogPlayerMap: nil, + VREngine: vreplication.NewEngine(ts, tabletAlias.Cell, mysqlDaemon, binlogplayer.NewFakeDBClient), History: history.New(historyLength), _healthy: fmt.Errorf("healthcheck not run yet"), } @@ -380,7 +380,7 @@ func NewComboActionAgent(batchCtx context.Context, ts *topo.Server, tabletAlias Cnf: nil, MysqlDaemon: mysqlDaemon, DBConfigs: dbcfgs, - BinlogPlayerMap: nil, + VREngine: vreplication.NewEngine(nil, "", nil, nil), gotMysqlPort: true, History: history.New(historyLength), _healthy: fmt.Errorf("healthcheck not run yet"), @@ -637,6 +637,7 @@ func (agent *ActionAgent) Start(ctx context.Context, mysqlHost string, mysqlPort statsShard := stats.NewString("TabletShard") statsKeyRangeStart := stats.NewString("TabletKeyRangeStart") statsKeyRangeEnd := stats.NewString("TabletKeyRangeEnd") + statsAlias := stats.NewString("TabletAlias") statsKeyspace.Set(agent.initialTablet.Keyspace) statsShard.Set(agent.initialTablet.Shard) @@ -644,6 +645,7 @@ func (agent *ActionAgent) Start(ctx context.Context, mysqlHost string, mysqlPort statsKeyRangeStart.Set(hex.EncodeToString(agent.initialTablet.KeyRange.Start)) statsKeyRangeEnd.Set(hex.EncodeToString(agent.initialTablet.KeyRange.End)) } + statsAlias.Set(topoproto.TabletAliasString(agent.initialTablet.Alias)) } // Initialize the current tablet to match our current running @@ -684,9 +686,7 @@ func (agent *ActionAgent) Stop() { if agent.UpdateStream != nil { agent.UpdateStream.Disable() } - if agent.BinlogPlayerMap != nil { - agent.BinlogPlayerMap.StopAllPlayersAndReset() - } + agent.VREngine.Close() if agent.MysqlDaemon != nil { agent.MysqlDaemon.Close() } diff --git a/go/vt/vttablet/tabletmanager/binlog_players.go b/go/vt/vttablet/tabletmanager/binlog_players.go deleted file mode 100644 index 2baa2e69163..00000000000 --- a/go/vt/vttablet/tabletmanager/binlog_players.go +++ /dev/null @@ -1,782 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 tabletmanager - -// This file handles the binlog players launched on masters for filtered -// replication - -import ( - "flag" - "fmt" - "html/template" - "math/rand" // not crypto-safe is OK here - "sort" - "strings" - "sync" - "time" - - "golang.org/x/net/context" - - "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/stats" - "vitess.io/vitess/go/tb" - "vitess.io/vitess/go/vt/binlog/binlogplayer" - "vitess.io/vitess/go/vt/concurrency" - "vitess.io/vitess/go/vt/discovery" - "vitess.io/vitess/go/vt/key" - "vitess.io/vitess/go/vt/log" - "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/topo/topoproto" - - tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" - topodatapb "vitess.io/vitess/go/vt/proto/topodata" -) - -var ( - retryDelay = flag.Duration("binlog_player_retry_delay", 5*time.Second, "delay before retrying a failed binlog connection") - - healthCheckTopologyRefresh = flag.Duration("binlog_player_healthcheck_topology_refresh", 30*time.Second, "refresh interval for re-reading the topology") - healthcheckRetryDelay = flag.Duration("binlog_player_healthcheck_retry_delay", 5*time.Second, "delay before retrying a failed healthcheck") - healthCheckTimeout = flag.Duration("binlog_player_healthcheck_timeout", time.Minute, "the health check timeout period") - sourceTabletTypeStr = flag.String("binlog_player_tablet_type", "REPLICA", "comma separated list of tablet types used as a source") -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -// BinlogPlayerController controls one player. -type BinlogPlayerController struct { - // Configuration parameters (set at construction, immutable). - ts *topo.Server - vtClientFactory func() binlogplayer.VtClient - mysqld mysqlctl.MysqlDaemon - - // Information about us (set at construction, immutable). - cell string - keyRange *topodatapb.KeyRange - dbName string - - // Information about the source (set at construction, immutable). - sourceShard *topodatapb.Shard_SourceShard - - // binlogPlayerStats has the stats for the players we're going to use - // (pointer is set at construction, immutable, values are thread-safe). - binlogPlayerStats *binlogplayer.Stats - - // healthCheck handles the connections to the sources (set at - // construction, immutable). - healthCheck discovery.HealthCheck - - // tabletStatsCache stores the values healthCheck is returning, as its listener. - // (set at construction, immutable). - tabletStatsCache *discovery.TabletStatsCache - - // shardReplicationWatcher watches the addresses of the sources, and - // feeds the HealthCheck (set at construction, immutable). - shardReplicationWatcher *discovery.TopologyWatcher - - // playerMutex is used to protect the next fields in this structure. - // They will change depending on our state. - playerMutex sync.Mutex - - // ctx is the context to cancel to stop the playback. - ctx context.Context - cancel context.CancelFunc - - // done is the channel to wait for to be sure the player is done. - done chan struct{} - - // stopPosition contains the stopping point for this player, if any. - stopPosition string - - // information about the individual tablet we're replicating from. - sourceTablet *topodatapb.TabletAlias - - // last error we've seen by the player. - lastError error -} - -// newBinlogPlayerController instantiates a new BinlogPlayerController. -// Use Start() and Stop() to start and stop it. -// Once stopped, you should call Close() to stop and free resources e.g. the -// healthcheck instance. -func newBinlogPlayerController(ts *topo.Server, vtClientFactory func() binlogplayer.VtClient, mysqld mysqlctl.MysqlDaemon, cell string, keyRange *topodatapb.KeyRange, sourceShard *topodatapb.Shard_SourceShard, dbName string) *BinlogPlayerController { - healthCheck := discovery.NewHealthCheck(*healthcheckRetryDelay, *healthCheckTimeout) - return &BinlogPlayerController{ - ts: ts, - vtClientFactory: vtClientFactory, - mysqld: mysqld, - cell: cell, - keyRange: keyRange, - dbName: dbName, - sourceShard: sourceShard, - binlogPlayerStats: binlogplayer.NewStats(), - // Note: healthCheck and shardReplicationWatcher remain active independent - // of whether the BinlogPlayerController is Start()'d or Stop()'d. - // Use Close() after Stop() to finally close them and free their resources. - healthCheck: healthCheck, - tabletStatsCache: discovery.NewTabletStatsCache(healthCheck, ts, cell), - shardReplicationWatcher: discovery.NewShardReplicationWatcher(ts, healthCheck, cell, sourceShard.Keyspace, sourceShard.Shard, *healthCheckTopologyRefresh, discovery.DefaultTopoReadConcurrency), - } -} - -func (bpc *BinlogPlayerController) String() string { - return "BinlogPlayerController(" + topoproto.SourceShardString(bpc.sourceShard) + ")" -} - -// Start will start the player in the background and run forever. -func (bpc *BinlogPlayerController) Start(ctx context.Context) { - bpc.playerMutex.Lock() - defer bpc.playerMutex.Unlock() - if bpc.ctx != nil { - log.Warningf("%v: already started", bpc) - return - } - log.Infof("%v: starting binlog player", bpc) - bpc.ctx, bpc.cancel = context.WithCancel(ctx) - bpc.done = make(chan struct{}, 1) - bpc.stopPosition = "" // run forever - go bpc.Loop() -} - -// StartUntil will start the Player until we reach the given position. -func (bpc *BinlogPlayerController) StartUntil(ctx context.Context, stopPos string) error { - bpc.playerMutex.Lock() - defer bpc.playerMutex.Unlock() - if bpc.ctx != nil { - return fmt.Errorf("%v: already started", bpc) - } - log.Infof("%v: starting binlog player until %v", bpc, stopPos) - bpc.ctx, bpc.cancel = context.WithCancel(ctx) - bpc.done = make(chan struct{}, 1) - bpc.stopPosition = stopPos - go bpc.Loop() - return nil -} - -// reset will clear the internal data structures. -func (bpc *BinlogPlayerController) reset() { - bpc.playerMutex.Lock() - defer bpc.playerMutex.Unlock() - bpc.ctx = nil - bpc.cancel = nil - bpc.done = nil - bpc.sourceTablet = nil - bpc.lastError = nil -} - -// WaitForStop will wait until the player is stopped. Use this after StartUntil. -func (bpc *BinlogPlayerController) WaitForStop(waitTimeout time.Duration) error { - // take the lock, check the data, get what we need, release the lock. - bpc.playerMutex.Lock() - if bpc.ctx == nil { - bpc.playerMutex.Unlock() - log.Warningf("%v: not started", bpc) - return fmt.Errorf("WaitForStop called but player not started") - } - done := bpc.done - bpc.playerMutex.Unlock() - - // start waiting - tmr := time.NewTimer(waitTimeout) - defer tmr.Stop() - select { - case <-done: - bpc.reset() - return nil - case <-tmr.C: - bpc.Stop() - return fmt.Errorf("WaitForStop timeout, stopping current player") - } -} - -// Stop will ask the controller to stop playing, and wait until it is stopped. -func (bpc *BinlogPlayerController) Stop() { - bpc.playerMutex.Lock() - if bpc.ctx == nil { - bpc.playerMutex.Unlock() - log.Warningf("%v: not started", bpc) - return - } - log.Infof("%v: stopping binlog player", bpc) - bpc.cancel() - done := bpc.done - bpc.playerMutex.Unlock() - - select { - case <-done: - bpc.reset() - } -} - -// Close will stop and free any long running resources e.g. the healthcheck. -// Returns an error if BinlogPlayerController is not stopped (i.e. Start() was -// called but not Stop().) -func (bpc *BinlogPlayerController) Close() error { - bpc.playerMutex.Lock() - defer bpc.playerMutex.Unlock() - - if bpc.ctx != nil { - return fmt.Errorf("%v: cannot Close() a BinlogPlayerController which was not Stop()'d before", bpc) - } - - bpc.shardReplicationWatcher.Stop() - bpc.healthCheck.Close() - return nil -} - -// Loop runs the main player loop: try to play, and in case of error, -// sleep for 5 seconds and try again. -func (bpc *BinlogPlayerController) Loop() { - for { - err := bpc.Iteration() - if err == nil { - // this happens when we get interrupted - break - } - log.Warningf("%v: %v", bpc, err) - - // clear the source, remember the error - bpc.playerMutex.Lock() - bpc.sourceTablet = nil - bpc.lastError = err - bpc.playerMutex.Unlock() - - // sleep for a bit before retrying to connect - time.Sleep(*retryDelay) - } - - log.Infof("%v: exited main binlog player loop", bpc) - close(bpc.done) -} - -// Iteration is a single iteration for the player: get the current status, -// try to play, and plays until interrupted, or until an error occurs. -func (bpc *BinlogPlayerController) Iteration() (err error) { - defer func() { - if x := recover(); x != nil { - log.Errorf("%v: caught panic: %v\n%s", bpc, x, tb.Stack(4)) - err = fmt.Errorf("panic: %v", x) - } - }() - - // Check if the context is still good. - select { - case <-bpc.ctx.Done(): - if bpc.ctx.Err() == context.Canceled { - // We were stopped. Break out of Loop(). - return nil - } - return fmt.Errorf("giving up since the context is done: %v", bpc.ctx.Err()) - default: - } - - // Apply any special settings necessary for playback of binlogs. - // We do it on every iteration to be sure, in case MySQL was restarted. - if err := bpc.mysqld.EnableBinlogPlayback(); err != nil { - // We failed to apply the required settings, so we shouldn't keep going. - return err - } - - // create the db connection, connect it - vtClient := bpc.vtClientFactory() - if err := vtClient.Connect(); err != nil { - return fmt.Errorf("can't connect to database: %v", err) - } - defer vtClient.Close() - - // Read the start position - startPosition, flags, err := binlogplayer.ReadStartPosition(vtClient, bpc.sourceShard.Uid) - if err != nil { - return fmt.Errorf("can't read startPosition: %v", err) - } - - // if we shouldn't start, we just error out and try again later - if strings.Index(flags, binlogplayer.BlpFlagDontStart) != -1 { - return fmt.Errorf("not starting because flag '%v' is set", binlogplayer.BlpFlagDontStart) - } - - sourceTabletTypes, err := topoproto.ParseTabletTypes(*sourceTabletTypeStr) - if err != nil { - return fmt.Errorf("failed to parse list of source tablet types: %v", *sourceTabletTypeStr) - } - - // wait for any of required the tablets (useful for the first run at least, fast for next runs) - if err := bpc.tabletStatsCache.WaitForAnyTablet(bpc.ctx, bpc.cell, bpc.sourceShard.Keyspace, bpc.sourceShard.Shard, sourceTabletTypes); err != nil { - return fmt.Errorf("error waiting for tablets for %v %v %v: %v", bpc.cell, bpc.sourceShard.String(), sourceTabletTypes, err) - } - - // Find the server list from the health check. - // Note: We cannot use tsc.GetHealthyTabletStats() here because it does - // not return non-serving tablets. We must include non-serving tablets because - // REPLICA source tablets may not be serving anymore because their traffic was - // already migrated to the destination shards. - var tablet *topodatapb.Tablet - for _, sourceTabletType := range sourceTabletTypes { - addrs := discovery.RemoveUnhealthyTablets(bpc.tabletStatsCache.GetTabletStats(bpc.sourceShard.Keyspace, bpc.sourceShard.Shard, sourceTabletType)) - if len(addrs) > 0 { - newServerIndex := rand.Intn(len(addrs)) - tablet = addrs[newServerIndex].Tablet - break - } - } - if tablet == nil { - return fmt.Errorf("can't find any healthy source tablet for %v %v %v", bpc.cell, bpc.sourceShard.String(), sourceTabletTypes) - } - - // save our current server - bpc.playerMutex.Lock() - bpc.sourceTablet = tablet.Alias - bpc.lastError = nil - bpc.playerMutex.Unlock() - - // check which kind of replication we're doing, tables or keyrange - if len(bpc.sourceShard.Tables) > 0 { - // tables, first resolve wildcards - tables, err := mysqlctl.ResolveTables(bpc.mysqld, bpc.dbName, bpc.sourceShard.Tables) - if err != nil { - return fmt.Errorf("failed to resolve table names: %v", err) - } - - // tables, just get them - player, err := binlogplayer.NewBinlogPlayerTables(vtClient, tablet, tables, bpc.sourceShard.Uid, startPosition, bpc.stopPosition, bpc.binlogPlayerStats) - if err != nil { - return fmt.Errorf("NewBinlogPlayerTables failed: %v", err) - } - return player.ApplyBinlogEvents(bpc.ctx) - } - // the data we have to replicate is the intersection of the - // source keyrange and our keyrange - overlap, err := key.KeyRangesOverlap(bpc.sourceShard.KeyRange, bpc.keyRange) - if err != nil { - return fmt.Errorf("Source shard %v doesn't overlap destination shard %v", bpc.sourceShard.KeyRange, bpc.keyRange) - } - - player, err := binlogplayer.NewBinlogPlayerKeyRange(vtClient, tablet, overlap, bpc.sourceShard.Uid, startPosition, bpc.stopPosition, bpc.binlogPlayerStats) - if err != nil { - return fmt.Errorf("NewBinlogPlayerKeyRange failed: %v", err) - } - return player.ApplyBinlogEvents(bpc.ctx) -} - -// BlpPosition returns the current position for a controller, as read from the database. -func (bpc *BinlogPlayerController) BlpPosition(vtClient binlogplayer.VtClient) (*tabletmanagerdatapb.BlpPosition, string, error) { - pos, flags, err := binlogplayer.ReadStartPosition(vtClient, bpc.sourceShard.Uid) - if err != nil { - return nil, "", err - } - return &tabletmanagerdatapb.BlpPosition{ - Uid: bpc.sourceShard.Uid, - Position: pos, - }, flags, nil -} - -// BinlogPlayerMap controls all the players. -// It can be stopped and restarted. -type BinlogPlayerMap struct { - // Immutable, set at construction time. - ts *topo.Server - vtClientFactory func() binlogplayer.VtClient - mysqld mysqlctl.MysqlDaemon - - // This mutex protects the map and the state. - mu sync.Mutex - players map[uint32]*BinlogPlayerController - state int64 -} - -const ( - // BpmStateRunning indicates BinlogPlayerMap is running. - BpmStateRunning int64 = iota - // BpmStateStopped indicates BinlogPlayerMap has stopped. - BpmStateStopped -) - -// NewBinlogPlayerMap creates a new map of players. -func NewBinlogPlayerMap(ts *topo.Server, mysqld mysqlctl.MysqlDaemon, vtClientFactory func() binlogplayer.VtClient) *BinlogPlayerMap { - return &BinlogPlayerMap{ - ts: ts, - vtClientFactory: vtClientFactory, - mysqld: mysqld, - players: make(map[uint32]*BinlogPlayerController), - state: BpmStateRunning, - } -} - -// RegisterBinlogPlayerMap registers the varz for the players. -func RegisterBinlogPlayerMap(blm *BinlogPlayerMap) { - stats.NewGaugeFunc("BinlogPlayerMapSize", "Binlog player map size", func() int64 { - blm.mu.Lock() - defer blm.mu.Unlock() - return int64(len(blm.players)) - }) - stats.NewGaugeFunc( - "BinlogPlayerSecondsBehindMaster", - "Binlog player seconds behind master", - func() int64 { - blm.mu.Lock() - defer blm.mu.Unlock() - return blm.maxSecondsBehindMasterUNGUARDED() - }) - stats.NewCountersFuncWithMultiLabels( - "BinlogPlayerSecondsBehindMasterMap", - "Binlog player seconds behind master per player", - // CAUTION: Always keep this label as "counts" because the Google - // internal monitoring may depend on this specific value. - []string{"counts"}, - func() map[string]int64 { - blm.mu.Lock() - result := make(map[string]int64, len(blm.players)) - for i, bpc := range blm.players { - sbm := bpc.binlogPlayerStats.SecondsBehindMaster.Get() - result[fmt.Sprintf("%v", i)] = sbm - } - blm.mu.Unlock() - return result - }) - stats.Publish("BinlogPlayerSourceShardNameMap", stats.StringMapFunc(func() map[string]string { - blm.mu.Lock() - result := make(map[string]string, len(blm.players)) - for i, bpc := range blm.players { - name := bpc.sourceShard.Keyspace + "/" + bpc.sourceShard.Shard - result[fmt.Sprintf("%v", i)] = name - } - blm.mu.Unlock() - return result - })) - stats.Publish("BinlogPlayerSourceTabletAliasMap", stats.StringMapFunc(func() map[string]string { - blm.mu.Lock() - result := make(map[string]string, len(blm.players)) - for i, bpc := range blm.players { - bpc.playerMutex.Lock() - result[fmt.Sprintf("%v", i)] = bpc.sourceTablet.String() - bpc.playerMutex.Unlock() - } - blm.mu.Unlock() - return result - })) -} - -func (blm *BinlogPlayerMap) isRunningFilteredReplication() bool { - blm.mu.Lock() - defer blm.mu.Unlock() - return len(blm.players) != 0 -} - -// maxSecondsBehindMasterUNGUARDED returns the maximum of the secondsBehindMaster -// value of all binlog players i.e. the highest seen filtered replication lag. -// NOTE: Caller must own a lock on blm.mu. -func (blm *BinlogPlayerMap) maxSecondsBehindMasterUNGUARDED() int64 { - sbm := int64(0) - for _, bpc := range blm.players { - psbm := bpc.binlogPlayerStats.SecondsBehindMaster.Get() - if psbm > sbm { - sbm = psbm - } - } - return sbm -} - -// addPlayer adds a new player to the map. It assumes we have the lock. -func (blm *BinlogPlayerMap) addPlayer(ctx context.Context, cell string, keyRange *topodatapb.KeyRange, sourceShard *topodatapb.Shard_SourceShard, dbName string) { - bpc, ok := blm.players[sourceShard.Uid] - if ok { - log.Infof("Already playing logs for %v", sourceShard) - return - } - - bpc = newBinlogPlayerController(blm.ts, blm.vtClientFactory, blm.mysqld, cell, keyRange, sourceShard, dbName) - blm.players[sourceShard.Uid] = bpc - if blm.state == BpmStateRunning { - bpc.Start(ctx) - } -} - -// StopAllPlayersAndReset stops all the binlog players, and reset the map of players. -func (blm *BinlogPlayerMap) StopAllPlayersAndReset() { - hadPlayers := false - blm.mu.Lock() - for _, bpc := range blm.players { - if blm.state == BpmStateRunning { - bpc.Stop() - } - if err := bpc.Close(); err != nil { - log.Error(err) - } - hadPlayers = true - } - blm.players = make(map[uint32]*BinlogPlayerController) - blm.mu.Unlock() - - if hadPlayers { - // We're done streaming, so turn off special playback settings. - blm.mysqld.DisableBinlogPlayback() - } -} - -// RefreshMap reads the right data from topo.Server and makes sure -// we're playing the right logs. -func (blm *BinlogPlayerMap) RefreshMap(ctx context.Context, tablet *topodatapb.Tablet, shardInfo *topo.ShardInfo) { - log.Infof("Refreshing map of binlog players") - if shardInfo == nil { - log.Warningf("Could not read shardInfo, not changing anything") - return - } - - blm.mu.Lock() - - // get the existing sources and build a map of sources to remove - toRemove := make(map[uint32]bool) - hadPlayers := false - for source := range blm.players { - toRemove[source] = true - hadPlayers = true - } - - // for each source, add it if not there, and delete from toRemove - for _, sourceShard := range shardInfo.SourceShards { - blm.addPlayer(ctx, tablet.Alias.Cell, tablet.KeyRange, sourceShard, topoproto.TabletDbName(tablet)) - delete(toRemove, sourceShard.Uid) - } - hasPlayers := len(shardInfo.SourceShards) > 0 - - // remove all entries from toRemove - for source := range toRemove { - blm.players[source].Stop() - if err := blm.players[source].Close(); err != nil { - log.Error(err) - } - delete(blm.players, source) - } - - blm.mu.Unlock() - - if hadPlayers && !hasPlayers { - // We're done streaming, so turn off special playback settings. - blm.mysqld.DisableBinlogPlayback() - } -} - -// Stop stops the current players, but does not remove them from the map. -// Call 'Start' to restart the playback. -func (blm *BinlogPlayerMap) Stop() { - blm.mu.Lock() - defer blm.mu.Unlock() - if blm.state == BpmStateStopped { - log.Warningf("BinlogPlayerMap already stopped") - return - } - log.Infof("Stopping map of binlog players") - for _, bpc := range blm.players { - bpc.Stop() - } - blm.state = BpmStateStopped -} - -// Start restarts the current players. -func (blm *BinlogPlayerMap) Start(ctx context.Context) { - blm.mu.Lock() - defer blm.mu.Unlock() - if blm.state == BpmStateRunning { - log.Warningf("BinlogPlayerMap already started") - return - } - log.Infof("Starting map of binlog players") - for _, bpc := range blm.players { - bpc.Start(ctx) - } - blm.state = BpmStateRunning -} - -// BlpPositionList returns the current position of all the players. -func (blm *BinlogPlayerMap) BlpPositionList() ([]*tabletmanagerdatapb.BlpPosition, error) { - // create a db connection for this purpose - vtClient := blm.vtClientFactory() - if err := vtClient.Connect(); err != nil { - return nil, fmt.Errorf("can't connect to database: %v", err) - } - defer vtClient.Close() - - var result []*tabletmanagerdatapb.BlpPosition - blm.mu.Lock() - defer blm.mu.Unlock() - for _, bpc := range blm.players { - blp, _, err := bpc.BlpPosition(vtClient) - if err != nil { - return nil, fmt.Errorf("can't read current position for %v: %v", bpc, err) - } - - result = append(result, blp) - } - return result, nil -} - -// RunUntil will run all the players until they reach the given position. -// Holds the map lock during that exercise, shouldn't take long at all. -func (blm *BinlogPlayerMap) RunUntil(ctx context.Context, blpPositionList []*tabletmanagerdatapb.BlpPosition, waitTimeout time.Duration) error { - // lock and check state - blm.mu.Lock() - defer blm.mu.Unlock() - if blm.state != BpmStateStopped { - return fmt.Errorf("RunUntil: player not stopped: %v", blm.state) - } - log.Infof("Starting map of binlog players until position") - - // We may not start all players, but this is OK - startedPlayers := make([]*BinlogPlayerController, len(blpPositionList)) - for i, blpPosition := range blpPositionList { - bpc, ok := blm.players[blpPosition.Uid] - if !ok { - return fmt.Errorf("no binlog player for Uid %v", blpPosition.Uid) - } - if err := bpc.StartUntil(ctx, blpPosition.Position); err != nil { - return err - } - startedPlayers[i] = bpc - } - - // Wait for all started players to be stopped, or timeout. - wg := sync.WaitGroup{} - rec := concurrency.AllErrorRecorder{} - for _, bpc := range startedPlayers { - wg.Add(1) - go func(bpc *BinlogPlayerController) { - if err := bpc.WaitForStop(waitTimeout); err != nil { - rec.RecordError(err) - } - wg.Done() - }(bpc) - } - wg.Wait() - - return rec.Error() -} - -// The following structures are used for status display - -// BinlogPlayerControllerStatus is the status of an individual controller. -type BinlogPlayerControllerStatus struct { - // configuration values - Index uint32 - SourceShard *topodatapb.Shard_SourceShard - StopPosition string - - // stats and current values - LastPosition mysql.Position - SecondsBehindMaster int64 - Counts map[string]int64 - Rates map[string][]float64 - State string - SourceTablet *topodatapb.TabletAlias - LastError string -} - -// SourceShardAsHTML returns the SourceShard as HTML -func (bpcs *BinlogPlayerControllerStatus) SourceShardAsHTML() template.HTML { - return topoproto.SourceShardAsHTML(bpcs.SourceShard) -} - -// SourceTabletAlias returns the string version of the SourceTablet alias, if set -func (bpcs *BinlogPlayerControllerStatus) SourceTabletAlias() string { - if bpcs.SourceTablet != nil { - return topoproto.TabletAliasString(bpcs.SourceTablet) - } - return "" -} - -// BinlogPlayerControllerStatusList is the list of statuses. -type BinlogPlayerControllerStatusList []*BinlogPlayerControllerStatus - -// Len is part of sort.Interface. -func (bpcsl BinlogPlayerControllerStatusList) Len() int { - return len(bpcsl) -} - -// Less is part of sort.Interface. -func (bpcsl BinlogPlayerControllerStatusList) Less(i, j int) bool { - return bpcsl[i].Index < bpcsl[j].Index -} - -// Swap is part of sort.Interface. -func (bpcsl BinlogPlayerControllerStatusList) Swap(i, j int) { - bpcsl[i], bpcsl[j] = bpcsl[j], bpcsl[i] -} - -// BinlogPlayerMapStatus is the complete player status. -type BinlogPlayerMapStatus struct { - State string - Controllers BinlogPlayerControllerStatusList -} - -// Status returns the BinlogPlayerMapStatus for the BinlogPlayerMap. -// It is used to display the complete status in the webinterface. -func (blm *BinlogPlayerMap) Status() *BinlogPlayerMapStatus { - // Create the result, take care of the stopped state. - result := &BinlogPlayerMapStatus{} - blm.mu.Lock() - defer blm.mu.Unlock() - - // fill in state - if blm.state == BpmStateStopped { - result.State = "Stopped" - } else { - result.State = "Running" - } - - // fill in controllers - result.Controllers = make([]*BinlogPlayerControllerStatus, 0, len(blm.players)) - - for i, bpc := range blm.players { - bpcs := &BinlogPlayerControllerStatus{ - Index: i, - SourceShard: bpc.sourceShard, - StopPosition: bpc.stopPosition, - LastPosition: bpc.binlogPlayerStats.GetLastPosition(), - SecondsBehindMaster: bpc.binlogPlayerStats.SecondsBehindMaster.Get(), - Counts: bpc.binlogPlayerStats.Timings.Counts(), - Rates: bpc.binlogPlayerStats.Rates.Get(), - } - bpc.playerMutex.Lock() - if bpc.ctx == nil { - bpcs.State = "Stopped" - } else { - bpcs.State = "Running" - } - bpcs.SourceTablet = bpc.sourceTablet - if bpc.lastError != nil { - bpcs.LastError = bpc.lastError.Error() - } - bpc.playerMutex.Unlock() - result.Controllers = append(result.Controllers, bpcs) - } - sort.Sort(result.Controllers) - - return result -} - -// StatusSummary returns aggregated health information e.g. -// the maximum replication delay across all binlog players. -// It is used by the QueryService.StreamHealth RPC. -func (blm *BinlogPlayerMap) StatusSummary() (maxSecondsBehindMaster int64, binlogPlayersCount int32) { - blm.mu.Lock() - defer blm.mu.Unlock() - maxSecondsBehindMaster = blm.maxSecondsBehindMasterUNGUARDED() - binlogPlayersCount = int32(len(blm.players)) - return -} diff --git a/go/vt/vttablet/tabletmanager/binlog_players_test.go b/go/vt/vttablet/tabletmanager/binlog_players_test.go deleted file mode 100644 index d160bbb9500..00000000000 --- a/go/vt/vttablet/tabletmanager/binlog_players_test.go +++ /dev/null @@ -1,791 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 tabletmanager - -import ( - "flag" - "fmt" - "strings" - "sync" - "testing" - "time" - - "golang.org/x/net/context" - - "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/vt/binlog/binlogplayer" - "vitess.io/vitess/go/vt/grpcclient" - "vitess.io/vitess/go/vt/key" - "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" - "vitess.io/vitess/go/vt/mysqlctl/tmutils" - "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/topo/memorytopo" - "vitess.io/vitess/go/vt/vttablet/queryservice" - "vitess.io/vitess/go/vt/vttablet/queryservice/fakes" - "vitess.io/vitess/go/vt/vttablet/tabletconn" - - 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" -) - -// The tests in this file test the BinlogPlayerMap object. -// -// The BinlogPlayerMap object is configured using the SourceShards of a Shard -// object. So we have to create the right topology entries for that. -// -// BinlogPlayerMap will create BinlogPlayerController objects -// to talk to the source remote tablets. They will use the topology to -// find valid tablets, so we have to update the Tablets. -// -// We fake the communication between the BinlogPlayerController objects and -// the remote tablets by registering our own binlogplayer.Client. -// -// BinlogPlayerController objects will then play the received events -// through a binlogplayer.VtClient. Again, we mock that one to record -// what is being sent to it and make sure it's correct. - -// fakeBinlogClient implements binlogplayer.Client -type fakeBinlogClient struct { - t *testing.T - expectedDialUID uint32 - - expectedTables string - tablesChannel chan *binlogdatapb.BinlogTransaction - - expectedKeyRange string - keyRangeChannel chan *binlogdatapb.BinlogTransaction -} - -func newFakeBinlogClient(t *testing.T, expectedDialUID uint32) *fakeBinlogClient { - return &fakeBinlogClient{ - t: t, - expectedDialUID: expectedDialUID, - - tablesChannel: make(chan *binlogdatapb.BinlogTransaction), - keyRangeChannel: make(chan *binlogdatapb.BinlogTransaction), - } -} - -// Dial is part of the binlogplayer.Client interface -func (fbc *fakeBinlogClient) Dial(tablet *topodatapb.Tablet) error { - if fbc.expectedDialUID != tablet.Alias.Uid { - fbc.t.Errorf("fakeBinlogClient.Dial expected uid %v got %v", fbc.expectedDialUID, tablet.Alias.Uid) - } - return nil -} - -// Close is part of the binlogplayer.Client interface -func (fbc *fakeBinlogClient) Close() { -} - -type testStreamEventAdapter struct { - c chan *binlogdatapb.BinlogTransaction - ctx context.Context -} - -func (t *testStreamEventAdapter) Recv() (*binlogdatapb.BinlogTransaction, error) { - select { - case bt := <-t.c: - return bt, nil - case <-t.ctx.Done(): - return nil, t.ctx.Err() - } -} - -// StreamTables is part of the binlogplayer.Client interface -func (fbc *fakeBinlogClient) StreamTables(ctx context.Context, position string, tables []string, charset *binlogdatapb.Charset) (binlogplayer.BinlogTransactionStream, error) { - actualTables := strings.Join(tables, ",") - if actualTables != fbc.expectedTables { - return nil, fmt.Errorf("Got wrong tables %v, expected %v", actualTables, fbc.expectedTables) - } - return &testStreamEventAdapter{c: fbc.tablesChannel, ctx: ctx}, nil -} - -// StreamKeyRange is part of the binlogplayer.Client interface -func (fbc *fakeBinlogClient) StreamKeyRange(ctx context.Context, position string, keyRange *topodatapb.KeyRange, charset *binlogdatapb.Charset) (binlogplayer.BinlogTransactionStream, error) { - actualKeyRange := key.KeyRangeString(keyRange) - if actualKeyRange != fbc.expectedKeyRange { - return nil, fmt.Errorf("Got wrong keyrange %v, expected %v", actualKeyRange, fbc.expectedKeyRange) - } - return &testStreamEventAdapter{c: fbc.keyRangeChannel, ctx: ctx}, nil -} - -// fakeTabletConn implement TabletConn interface. We only care about the -// health check part. -type fakeTabletConn struct { - queryservice.QueryService - tablet *topodatapb.Tablet -} - -// StreamHealth is part of queryservice.QueryService. -func (ftc *fakeTabletConn) StreamHealth(ctx context.Context, callback func(*querypb.StreamHealthResponse) error) error { - callback(&querypb.StreamHealthResponse{ - Serving: true, - Target: &querypb.Target{ - Keyspace: ftc.tablet.Keyspace, - Shard: ftc.tablet.Shard, - TabletType: ftc.tablet.Type, - }, - RealtimeStats: &querypb.RealtimeStats{}, - }) - return nil -} - -// createSourceTablet is a helper method to create the source tablet -// in the given keyspace/shard. -func createSourceTablet(t *testing.T, name string, ts *topo.Server, keyspace, shard string) { - vshard, kr, err := topo.ValidateShardName(shard) - if err != nil { - t.Fatalf("ValidateShardName(%v) failed: %v", shard, err) - } - - ctx := context.Background() - tablet := &topodatapb.Tablet{ - Alias: &topodatapb.TabletAlias{ - Cell: "cell1", - Uid: 100, - }, - Keyspace: keyspace, - Shard: vshard, - Type: topodatapb.TabletType_REPLICA, - KeyRange: kr, - PortMap: map[string]int32{ - "vt": 80, - }, - } - if err := ts.CreateTablet(ctx, tablet); err != nil { - t.Fatalf("CreateTablet failed: %v", err) - } - - // register a tablet conn dialer that will return the instance - // we want - tabletconn.RegisterDialer(name, func(tablet *topodatapb.Tablet, failFast grpcclient.FailFast) (queryservice.QueryService, error) { - return &fakeTabletConn{ - QueryService: fakes.ErrorQueryService, - tablet: tablet, - }, nil - }) - flag.Set("tablet_protocol", name) -} - -// checkBlpPositionList will ask the BinlogPlayerMap for its BlpPositionList, -// and check it contains one entry with the right data. -func checkBlpPositionList(t *testing.T, bpm *BinlogPlayerMap, vtClientSyncChannel chan *binlogplayer.VtClientMock) { - // ask for BlpPositionList, make sure we got what we expect - go func() { - vtcm := binlogplayer.NewVtClientMock() - vtcm.AddResult(&sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("MariaDB/0-1-1235"), - sqltypes.NewVarBinary(""), - }, - }, - }) - vtClientSyncChannel <- vtcm - }() - bpl, err := bpm.BlpPositionList() - if err != nil { - t.Errorf("BlpPositionList failed: %v", err) - return - } - if len(bpl) != 1 || - bpl[0].Uid != 1 || - bpl[0].Position != "MariaDB/0-1-1235" { - t.Errorf("unexpected BlpPositionList: %v", bpl) - } -} - -// mockedThrottlerSettings is the mocked out query result when filtered -// replication reads the throttler settings from the DB. -var mockedThrottlerSettings = &sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("9223372036854775807"), // max_tps - sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag - }, - }, -} - -func TestBinlogPlayerMapHorizontalSplit(t *testing.T) { - ts := memorytopo.NewServer("cell1") - ctx := context.Background() - - // create the keyspace, a full set of covering shards, - // and a new split destination shard. - if err := ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{ - ShardingColumnType: topodatapb.KeyspaceIdType_UINT64, - ShardingColumnName: "sharding_key", - }); err != nil { - t.Fatalf("CreateKeyspace failed: %v", err) - } - for _, shard := range []string{"-80", "80-", "40-60"} { - if err := ts.CreateShard(ctx, "ks", shard); err != nil { - t.Fatalf("CreateShard failed: %v", err) - } - } - - // create one replica remote tablet in source shard, we will - // use it as a source for filtered replication. - createSourceTablet(t, "test_horizontal", ts, "ks", "-80") - - // register a binlog player factory that will return the instances - // we want - clientSyncChannel := make(chan *fakeBinlogClient) - binlogplayer.RegisterClientFactory("test_horizontal", func() binlogplayer.Client { - return <-clientSyncChannel - }) - flag.Set("binlog_player_protocol", "test_horizontal") - - // create the BinlogPlayerMap on the local tablet - // (note that local tablet is never in the topology, we don't - // need it there at all) - mysqlDaemon := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} - vtClientSyncChannel := make(chan *binlogplayer.VtClientMock) - bpm := NewBinlogPlayerMap(ts, mysqlDaemon, func() binlogplayer.VtClient { - return <-vtClientSyncChannel - }) - - tablet := &topodatapb.Tablet{ - Alias: &topodatapb.TabletAlias{ - Cell: "cell1", - Uid: 1, - }, - KeyRange: &topodatapb.KeyRange{ - Start: []byte{0x40}, - End: []byte{0x60}, - }, - Keyspace: "ks", - Shard: "40-60", - } - - si, err := ts.GetShard(ctx, "ks", "40-60") - if err != nil { - t.Fatalf("GetShard failed: %v", err) - } - - // no source shard for the shard, not adding players - bpm.RefreshMap(ctx, tablet, si) - if bpm.isRunningFilteredReplication() { - t.Errorf("isRunningFilteredReplication should be false") - } - if mysqlDaemon.BinlogPlayerEnabled { - t.Errorf("mysqlDaemon.BinlogPlayerEnabled should be false") - } - - // now add the source in shard - si, err = ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { - si.SourceShards = []*topodatapb.Shard_SourceShard{ - { - Uid: 1, - Keyspace: "ks", - Shard: "-80", - KeyRange: &topodatapb.KeyRange{ - End: []byte{0x80}, - }, - }, - } - return nil - }) - if err != nil { - t.Fatalf("UpdateShardFields failed: %v", err) - } - - // now we have a source, adding players - bpm.RefreshMap(ctx, tablet, si) - if !bpm.isRunningFilteredReplication() { - t.Errorf("isRunningFilteredReplication should be true") - } - - // write a mocked vtClientMock that will be used to read the - // start position at first. Note this also synchronizes the player, - // so we can then check mysqlDaemon.BinlogPlayerEnabled. - vtClientMock := binlogplayer.NewVtClientMock() - vtClientMock.AddResult(&sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("MariaDB/0-1-1234"), - sqltypes.NewVarBinary(""), - }, - }, - }) - - // Mock out the throttler settings result. - vtClientMock.AddResult(mockedThrottlerSettings) - - vtClientSyncChannel <- vtClientMock - if !mysqlDaemon.BinlogPlayerEnabled { - t.Errorf("mysqlDaemon.BinlogPlayerEnabled should be true") - } - - // the client will then try to connect to the remote tablet. - // give it what it needs. - fbc := newFakeBinlogClient(t, 100) - fbc.expectedKeyRange = "40-60" - clientSyncChannel <- fbc - - // now we can feed an event through the fake connection - vtClientMock.CommitChannel = make(chan []string) - fbc.keyRangeChannel <- &binlogdatapb.BinlogTransaction{ - Statements: []*binlogdatapb.BinlogTransaction_Statement{ - { - Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, - Sql: []byte("INSERT INTO tablet VALUES(1)"), - }, - }, - EventToken: &querypb.EventToken{ - Timestamp: 72, - Position: "MariaDB/0-1-1235", - }, - } - - // and make sure it results in a committed statement - sql := <-vtClientMock.CommitChannel - if len(sql) != 6 || - sql[0] != "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[1] != "SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[2] != "BEGIN" || - sql[3] != "INSERT INTO tablet VALUES(1)" || - !strings.HasPrefix(sql[4], "UPDATE _vt.blp_checkpoint SET pos='MariaDB/0-1-1235', time_updated=") || - !strings.HasSuffix(sql[4], ", transaction_timestamp=72 WHERE source_shard_uid=1") || - sql[5] != "COMMIT" { - t.Errorf("Got wrong SQL: %#v", sql) - } - - // ask for status, make sure we got what we expect - s := bpm.Status() - if s.State != "Running" || - len(s.Controllers) != 1 || - s.Controllers[0].Index != 1 || - s.Controllers[0].State != "Running" || - s.Controllers[0].SourceShard.Keyspace != "ks" || - s.Controllers[0].SourceShard.Shard != "-80" || - s.Controllers[0].LastError != "" { - t.Errorf("unexpected state: %v", s) - } - - // check BlpPositionList API from BinlogPlayerMap - checkBlpPositionList(t, bpm, vtClientSyncChannel) - - // now stop the binlog player map, by removing the source shard. - // this will stop the player, which will cancel its context, - // and exit the fake streaming connection. - si.SourceShards = nil - bpm.RefreshMap(ctx, tablet, si) - if bpm.isRunningFilteredReplication() { - t.Errorf("isRunningFilteredReplication should be false") - } - s = bpm.Status() - if s.State != "Running" || - len(s.Controllers) != 0 { - t.Errorf("unexpected state: %v", s) - } - - // now just stop the map - bpm.Stop() - s = bpm.Status() - if s.State != "Stopped" || - len(s.Controllers) != 0 { - t.Errorf("unexpected state: %v", s) - } -} - -func TestBinlogPlayerMapHorizontalSplitStopStartUntil(t *testing.T) { - ts := memorytopo.NewServer("cell1") - ctx := context.Background() - - // create the keyspace, a full set of covering shards, - // and a new split destination shard. - if err := ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{ - ShardingColumnType: topodatapb.KeyspaceIdType_UINT64, - ShardingColumnName: "sharding_key", - }); err != nil { - t.Fatalf("CreateKeyspace failed: %v", err) - } - for _, shard := range []string{"-80", "80-", "40-60"} { - if err := ts.CreateShard(ctx, "ks", shard); err != nil { - t.Fatalf("CreateShard failed: %v", err) - } - } - - // create one replica remote tablet in source shard, we will - // use it as a source for filtered replication. - createSourceTablet(t, "test_horizontal_until", ts, "ks", "-80") - - // register a binlog player factory that will return the instances - // we want - clientSyncChannel := make(chan *fakeBinlogClient) - binlogplayer.RegisterClientFactory("test_horizontal_until", func() binlogplayer.Client { - return <-clientSyncChannel - }) - flag.Set("binlog_player_protocol", "test_horizontal_until") - - // create the BinlogPlayerMap on the local tablet - // (note that local tablet is never in the topology, we don't - // need it there at all) - mysqlDaemon := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} - vtClientSyncChannel := make(chan *binlogplayer.VtClientMock) - bpm := NewBinlogPlayerMap(ts, mysqlDaemon, func() binlogplayer.VtClient { - return <-vtClientSyncChannel - }) - - tablet := &topodatapb.Tablet{ - Alias: &topodatapb.TabletAlias{ - Cell: "cell1", - Uid: 1, - }, - KeyRange: &topodatapb.KeyRange{ - Start: []byte{0x40}, - End: []byte{0x60}, - }, - Keyspace: "ks", - Shard: "40-60", - } - - si, err := ts.UpdateShardFields(ctx, "ks", "40-60", func(si *topo.ShardInfo) error { - si.SourceShards = []*topodatapb.Shard_SourceShard{ - { - Uid: 1, - Keyspace: "ks", - Shard: "-80", - KeyRange: &topodatapb.KeyRange{ - End: []byte{0x80}, - }, - }, - } - return nil - }) - if err != nil { - t.Fatalf("UpdateShardFields failed: %v", err) - } - - // now we have a source, adding players - bpm.RefreshMap(ctx, tablet, si) - if !bpm.isRunningFilteredReplication() { - t.Errorf("isRunningFilteredReplication should be true") - } - - // write a mocked vtClientMock that will be used to read the - // start position at first. Note this also synchronizes the player, - // so we can then check mysqlDaemon.BinlogPlayerEnabled. - startPos := &sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("MariaDB/0-1-1234"), - sqltypes.NewVarBinary(""), - }, - }, - } - vtClientMock := binlogplayer.NewVtClientMock() - vtClientMock.AddResult(startPos) - - // Mock out the throttler settings result. - vtClientMock.AddResult(mockedThrottlerSettings) - // Mock two more results since the BinlogPlayer will be stopped and then - // restarted again with the RunUntil() call. - vtClientMock.AddResult(startPos) - vtClientMock.AddResult(mockedThrottlerSettings) - - vtClientSyncChannel <- vtClientMock - if !mysqlDaemon.BinlogPlayerEnabled { - t.Errorf("mysqlDaemon.BinlogPlayerEnabled should be true") - } - - // the client will then try to connect to the remote tablet. - // give it what it needs. - fbc := newFakeBinlogClient(t, 100) - fbc.expectedKeyRange = "40-60" - clientSyncChannel <- fbc - - // now stop the map - bpm.Stop() - s := bpm.Status() - if s.State != "Stopped" || - len(s.Controllers) != 1 || - s.Controllers[0].State != "Stopped" { - t.Errorf("unexpected state: %v", s) - } - - // in the background, start a function that will do what's needed - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - // the client will first try to read the current position again - vtClientSyncChannel <- vtClientMock - - // the client will then try to connect to the remote tablet. - // give it what it needs. - fbc := newFakeBinlogClient(t, 100) - fbc.expectedKeyRange = "40-60" - clientSyncChannel <- fbc - - // feed an event through the fake connection - vtClientMock.CommitChannel = make(chan []string) - fbc.keyRangeChannel <- &binlogdatapb.BinlogTransaction{ - Statements: []*binlogdatapb.BinlogTransaction_Statement{ - { - Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, - Sql: []byte("INSERT INTO tablet VALUES(1)"), - }, - }, - EventToken: &querypb.EventToken{ - Timestamp: 72, - Position: "MariaDB/0-1-1235", - }, - } - - // and make sure it results in a committed statement - sql := <-vtClientMock.CommitChannel - if len(sql) != 8 || - sql[0] != "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[1] != "SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[2] != "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[3] != "SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[4] != "BEGIN" || - sql[5] != "INSERT INTO tablet VALUES(1)" || - !strings.HasPrefix(sql[6], "UPDATE _vt.blp_checkpoint SET pos='MariaDB/0-1-1235', time_updated=") || - !strings.HasSuffix(sql[6], ", transaction_timestamp=72 WHERE source_shard_uid=1") || - sql[7] != "COMMIT" { - t.Errorf("Got wrong SQL: %#v", sql) - } - wg.Done() - }() - - // now restart the map until we get the right BlpPosition - mysqlDaemon.BinlogPlayerEnabled = false - ctx1, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - if err := bpm.RunUntil(ctx1, []*tabletmanagerdatapb.BlpPosition{ - { - Uid: 1, - Position: "MariaDB/0-1-1235", - }, - }, 5*time.Second); err != nil { - t.Fatalf("RunUntil failed: %v", err) - } - - // make sure the background function is done - wg.Wait() - - // ask for status, make sure we got what we expect - s = bpm.Status() - if s.State != "Stopped" || - len(s.Controllers) != 1 || - s.Controllers[0].Index != 1 || - s.Controllers[0].State != "Stopped" || - s.Controllers[0].LastError != "" { - t.Errorf("unexpected state: %v", s) - } - - // check BlpPositionList API from BinlogPlayerMap - checkBlpPositionList(t, bpm, vtClientSyncChannel) -} - -func TestBinlogPlayerMapVerticalSplit(t *testing.T) { - ts := memorytopo.NewServer("cell1") - ctx := context.Background() - - // create the keyspaces, with one shard each - if err := ts.CreateKeyspace(ctx, "source", &topodatapb.Keyspace{}); err != nil { - t.Fatalf("CreateKeyspace failed: %v", err) - } - if err := ts.CreateKeyspace(ctx, "destination", &topodatapb.Keyspace{}); err != nil { - t.Fatalf("CreateKeyspace failed: %v", err) - } - for _, keyspace := range []string{"source", "destination"} { - if err := ts.CreateShard(ctx, keyspace, "0"); err != nil { - t.Fatalf("CreateShard failed: %v", err) - } - } - - // create one replica remote tablet in source keyspace, we will - // use it as a source for filtered replication. - createSourceTablet(t, "test_vertical", ts, "source", "0") - - // register a binlog player factory that will return the instances - // we want - clientSyncChannel := make(chan *fakeBinlogClient) - binlogplayer.RegisterClientFactory("test_vertical", func() binlogplayer.Client { - return <-clientSyncChannel - }) - flag.Set("binlog_player_protocol", "test_vertical") - - // create the BinlogPlayerMap on the local tablet - // (note that local tablet is never in the topology, we don't - // need it there at all) - // The schema will be used to resolve the table wildcards. - mysqlDaemon := &fakemysqldaemon.FakeMysqlDaemon{ - MysqlPort: 3306, - Schema: &tabletmanagerdatapb.SchemaDefinition{ - DatabaseSchema: "", - TableDefinitions: []*tabletmanagerdatapb.TableDefinition{ - { - Name: "table1", - Columns: []string{"id", "msg", "keyspace_id"}, - PrimaryKeyColumns: []string{"id"}, - Type: tmutils.TableBaseTable, - }, - { - Name: "funtables_one", - Columns: []string{"id", "msg", "keyspace_id"}, - PrimaryKeyColumns: []string{"id"}, - Type: tmutils.TableBaseTable, - }, - { - Name: "excluded_table", - Columns: []string{"id", "msg", "keyspace_id"}, - PrimaryKeyColumns: []string{"id"}, - Type: tmutils.TableBaseTable, - }, - }, - }, - } - vtClientSyncChannel := make(chan *binlogplayer.VtClientMock) - bpm := NewBinlogPlayerMap(ts, mysqlDaemon, func() binlogplayer.VtClient { - return <-vtClientSyncChannel - }) - - tablet := &topodatapb.Tablet{ - Alias: &topodatapb.TabletAlias{ - Cell: "cell1", - Uid: 1, - }, - Keyspace: "destination", - Shard: "0", - } - - si, err := ts.UpdateShardFields(ctx, "destination", "0", func(si *topo.ShardInfo) error { - si.SourceShards = []*topodatapb.Shard_SourceShard{ - { - Uid: 1, - Keyspace: "source", - Shard: "0", - Tables: []string{ - "table1", - "/funtables_/", - }, - }, - } - return nil - }) - if err != nil { - t.Fatalf("UpdateShardFields failed: %v", err) - } - - // now we have a source, adding players - bpm.RefreshMap(ctx, tablet, si) - if !bpm.isRunningFilteredReplication() { - t.Errorf("isRunningFilteredReplication should be true") - } - - // write a mocked vtClientMock that will be used to read the - // start position at first. Note this also synchronizes the player, - // so we can then check mysqlDaemon.BinlogPlayerEnabled. - vtClientMock := binlogplayer.NewVtClientMock() - vtClientMock.AddResult(&sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("MariaDB/0-1-1234"), - sqltypes.NewVarBinary(""), - }, - }, - }) - - // Mock out the throttler settings result. - vtClientMock.AddResult(mockedThrottlerSettings) - - vtClientSyncChannel <- vtClientMock - if !mysqlDaemon.BinlogPlayerEnabled { - t.Errorf("mysqlDaemon.BinlogPlayerEnabled should be true") - } - // the client will then try to connect to the remote tablet. - // give it what it needs. - fbc := newFakeBinlogClient(t, 100) - fbc.expectedTables = "table1,funtables_one" - clientSyncChannel <- fbc - - // now we can feed an event through the fake connection - vtClientMock.CommitChannel = make(chan []string) - fbc.tablesChannel <- &binlogdatapb.BinlogTransaction{ - Statements: []*binlogdatapb.BinlogTransaction_Statement{ - { - Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, - Sql: []byte("INSERT INTO tablet VALUES(1)"), - }, - }, - EventToken: &querypb.EventToken{ - Timestamp: 72, - Position: "MariaDB/0-1-1235", - }, - } - - // and make sure it results in a committed statement - sql := <-vtClientMock.CommitChannel - if len(sql) != 6 || - sql[0] != "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[1] != "SELECT max_tps, max_replication_lag FROM _vt.blp_checkpoint WHERE source_shard_uid=1" || - sql[2] != "BEGIN" || - sql[3] != "INSERT INTO tablet VALUES(1)" || - !strings.HasPrefix(sql[4], "UPDATE _vt.blp_checkpoint SET pos='MariaDB/0-1-1235', time_updated=") || - !strings.HasSuffix(sql[4], ", transaction_timestamp=72 WHERE source_shard_uid=1") || - sql[5] != "COMMIT" { - t.Errorf("Got wrong SQL: %#v", sql) - } - - // ask for status, make sure we got what we expect - s := bpm.Status() - if s.State != "Running" || - len(s.Controllers) != 1 || - s.Controllers[0].Index != 1 || - s.Controllers[0].State != "Running" || - s.Controllers[0].SourceShard.Keyspace != "source" || - s.Controllers[0].SourceShard.Shard != "0" || - s.Controllers[0].LastError != "" { - t.Errorf("unexpected state: %v %v", s, s.Controllers[0]) - } - - // check BlpPositionList API from BinlogPlayerMap - checkBlpPositionList(t, bpm, vtClientSyncChannel) - - // now stop the binlog player map. - // this will stop the player, which will cancel its context, - // and exit the fake streaming connection. - bpm.Stop() - s = bpm.Status() - if s.State != "Stopped" || - len(s.Controllers) != 1 || - s.Controllers[0].State != "Stopped" { - t.Errorf("unexpected state: %v", s) - } -} diff --git a/go/vt/vttablet/tabletmanager/healthcheck.go b/go/vt/vttablet/tabletmanager/healthcheck.go index 77606b999eb..cf187767741 100644 --- a/go/vt/vttablet/tabletmanager/healthcheck.go +++ b/go/vt/vttablet/tabletmanager/healthcheck.go @@ -283,6 +283,16 @@ func (agent *ActionAgent) runHealthCheckLocked() { agent.UpdateStream.Disable() } + // All master tablets have to run the VReplication engine. + // There is no guarantee that VREngine was succesfully started when tabletmanager + // came up. This is because the mysql could have been in read-only mode, etc. + // So, start the engine if it's not already running. + if tablet.Type == topodatapb.TabletType_MASTER && !agent.VREngine.IsOpen() { + if err := agent.VREngine.Open(agent.batchCtx); err == nil { + log.Info("VReplication engine successfully started") + } + } + // save the health record record.Time = time.Now() record.Error = healthErr diff --git a/go/vt/vttablet/tabletmanager/healthcheck_test.go b/go/vt/vttablet/tabletmanager/healthcheck_test.go index 0bc72a59df0..2084bd283a7 100644 --- a/go/vt/vttablet/tabletmanager/healthcheck_test.go +++ b/go/vt/vttablet/tabletmanager/healthcheck_test.go @@ -18,7 +18,6 @@ package tabletmanager import ( "errors" - "flag" "fmt" "html/template" "reflect" @@ -28,8 +27,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/health" "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" "vitess.io/vitess/go/vt/topo" @@ -128,7 +125,7 @@ func (fhc *fakeHealthCheck) HTMLName() template.HTML { return template.HTML("fakeHealthCheck") } -func createTestAgent(ctx context.Context, t *testing.T, preStart func(*ActionAgent)) (*ActionAgent, chan<- *binlogplayer.VtClientMock) { +func createTestAgent(ctx context.Context, t *testing.T, preStart func(*ActionAgent)) *ActionAgent { ts := memorytopo.NewServer("cell1") if err := ts.CreateKeyspace(ctx, "test_keyspace", &topodatapb.Keyspace{}); err != nil { @@ -157,14 +154,9 @@ func createTestAgent(ctx context.Context, t *testing.T, preStart func(*ActionAge mysqlDaemon := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} agent := NewTestActionAgent(ctx, ts, tabletAlias, port, 0, mysqlDaemon, preStart) - vtClientMocksChannel := make(chan *binlogplayer.VtClientMock, 1) - agent.BinlogPlayerMap = NewBinlogPlayerMap(ts, mysqlDaemon, func() binlogplayer.VtClient { - return <-vtClientMocksChannel - }) - agent.HealthReporter = &fakeHealthCheck{} - return agent, vtClientMocksChannel + return agent } // TestHealthCheckControlsQueryService verifies that a tablet going healthy @@ -177,7 +169,7 @@ func TestHealthCheckControlsQueryService(t *testing.T) { }() ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) /// Consume the first health broadcast triggered by ActionAgent.Start(): // (REPLICA, NOT_SERVING) goes to (REPLICA, SERVING). And we @@ -285,7 +277,7 @@ func TestHealthCheckControlsQueryService(t *testing.T) { func TestErrSlaveNotRunningIsHealthy(t *testing.T) { *unhealthyThreshold = 10 * time.Minute ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) /// Consume the first health broadcast triggered by ActionAgent.Start(): // (REPLICA, NOT_SERVING) goes to (REPLICA, SERVING). And we @@ -338,7 +330,7 @@ func TestErrSlaveNotRunningIsHealthy(t *testing.T) { // query service, it should not go healthy. func TestQueryServiceNotStarting(t *testing.T) { ctx := context.Background() - agent, _ := createTestAgent(ctx, t, func(a *ActionAgent) { + agent := createTestAgent(ctx, t, func(a *ActionAgent) { // The SetServingType that will fail is part of Start() // so we have to do this here. a.QueryServiceControl.(*tabletservermock.Controller).SetServingTypeError = fmt.Errorf("test cannot start query service") @@ -394,7 +386,7 @@ func TestQueryServiceNotStarting(t *testing.T) { // service is shut down, the tablet goes unhealthy func TestQueryServiceStopped(t *testing.T) { ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) /// Consume the first health broadcast triggered by ActionAgent.Start(): // (REPLICA, NOT_SERVING) goes to (REPLICA, SERVING). And we @@ -492,7 +484,7 @@ func TestQueryServiceStopped(t *testing.T) { // query service in a tablet. func TestTabletControl(t *testing.T) { ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) /// Consume the first health broadcast triggered by ActionAgent.Start(): // (REPLICA, NOT_SERVING) goes to (REPLICA, SERVING). And we @@ -687,12 +679,8 @@ func TestTabletControl(t *testing.T) { // of the QueryService state or the tablet type will result into a broadcast // of a StreamHealthResponse message. func TestStateChangeImmediateHealthBroadcast(t *testing.T) { - // BinlogPlayer will fail in the second retry because we don't fully mock - // it. Retry faster to make it fail faster. - flag.Set("binlog_player_retry_delay", "100ms") - ctx := context.Background() - agent, vtClientMocksChannel := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) /// Consume the first health broadcast triggered by ActionAgent.Start(): // (REPLICA, NOT_SERVING) goes to (REPLICA, SERVING). And we @@ -786,21 +774,6 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { t.Fatalf("UpdateShardFields failed: %v", err) } - // Mock out the BinlogPlayer client. Tell the BinlogPlayer not to start. - vtClientMock := binlogplayer.NewVtClientMock() - vtClientMock.AddResult(&sqltypes.Result{ - Fields: nil, - RowsAffected: 1, - InsertID: 0, - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary("MariaDB/0-1-1234"), - sqltypes.NewVarBinary("DontStart"), - }, - }, - }) - vtClientMocksChannel <- vtClientMock - // Refresh the tablet state, as vtworker would do. // Since we change the QueryService state, we'll also trigger a health broadcast. agent.HealthReporter.(*fakeHealthCheck).reportReplicationDelay = 21 * time.Second @@ -814,11 +787,7 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { // (MASTER, SERVING) to (MASTER, NOT_SERVING). // Since we didn't run healthcheck again yet, the broadcast data contains the // cached replication lag of 20 instead of 21. - if bd, err := expectBroadcastData(agent.QueryServiceControl, false, "", 20); err == nil { - if bd.RealtimeStats.BinlogPlayersCount != 1 { - t.Fatalf("filtered replication must be enabled: %v", bd) - } - } else { + if _, err := expectBroadcastData(agent.QueryServiceControl, false, "", 20); err != nil { t.Fatal(err) } if err := expectStateChange(agent.QueryServiceControl, false, topodatapb.TabletType_MASTER); err != nil { @@ -841,11 +810,7 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { if got := agent.QueryServiceControl.(*tabletservermock.Controller).CurrentTarget.TabletType; got != topodatapb.TabletType_MASTER { t.Errorf("invalid tabletserver target: got = %v, want = %v", got, topodatapb.TabletType_MASTER) } - if bd, err := expectBroadcastData(agent.QueryServiceControl, false, "", 22); err == nil { - if bd.RealtimeStats.BinlogPlayersCount != 1 { - t.Fatalf("filtered replication must be still running: %v", bd) - } - } else { + if _, err := expectBroadcastData(agent.QueryServiceControl, false, "", 22); err != nil { t.Fatal(err) } // NOTE: No state change here since nothing has changed. @@ -871,11 +836,7 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { } // Since we didn't run healthcheck again yet, the broadcast data contains the // cached replication lag of 22 instead of 23. - if bd, err := expectBroadcastData(agent.QueryServiceControl, true, "", 22); err == nil { - if bd.RealtimeStats.BinlogPlayersCount != 0 { - t.Fatalf("filtered replication must be disabled now: %v", bd) - } - } else { + if _, err := expectBroadcastData(agent.QueryServiceControl, true, "", 22); err != nil { t.Fatal(err) } if err := expectStateChange(agent.QueryServiceControl, true, topodatapb.TabletType_MASTER); err != nil { @@ -894,7 +855,7 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { // return an error func TestOldHealthCheck(t *testing.T) { ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) *healthCheckInterval = 20 * time.Second agent._healthy = nil diff --git a/go/vt/vttablet/tabletmanager/init_tablet_test.go b/go/vt/vttablet/tabletmanager/init_tablet_test.go index 1fe63b9f358..d9083ab86ef 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet_test.go +++ b/go/vt/vttablet/tabletmanager/init_tablet_test.go @@ -29,6 +29,7 @@ import ( "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -48,14 +49,13 @@ func TestInitTabletFixesReplicationData(t *testing.T) { gRPCPort := int32(3456) mysqlDaemon := fakemysqldaemon.NewFakeMysqlDaemon(nil) agent := &ActionAgent{ - TopoServer: ts, - TabletAlias: tabletAlias, - MysqlDaemon: mysqlDaemon, - DBConfigs: &dbconfigs.DBConfigs{}, - BinlogPlayerMap: nil, - batchCtx: ctx, - History: history.New(historyLength), - _healthy: fmt.Errorf("healthcheck not run yet"), + TopoServer: ts, + TabletAlias: tabletAlias, + MysqlDaemon: mysqlDaemon, + DBConfigs: &dbconfigs.DBConfigs{}, + batchCtx: ctx, + History: history.New(historyLength), + _healthy: fmt.Errorf("healthcheck not run yet"), } // 1. Initialize the tablet as REPLICA. @@ -114,14 +114,13 @@ func TestInitTabletDoesNotUpdateReplicationDataForTabletInWrongShard(t *testing. gRPCPort := int32(3456) mysqlDaemon := fakemysqldaemon.NewFakeMysqlDaemon(nil) agent := &ActionAgent{ - TopoServer: ts, - TabletAlias: tabletAlias, - MysqlDaemon: mysqlDaemon, - DBConfigs: &dbconfigs.DBConfigs{}, - BinlogPlayerMap: nil, - batchCtx: ctx, - History: history.New(historyLength), - _healthy: fmt.Errorf("healthcheck not run yet"), + TopoServer: ts, + TabletAlias: tabletAlias, + MysqlDaemon: mysqlDaemon, + DBConfigs: &dbconfigs.DBConfigs{}, + batchCtx: ctx, + History: history.New(historyLength), + _healthy: fmt.Errorf("healthcheck not run yet"), } // 1. Initialize the tablet as REPLICA. @@ -176,14 +175,14 @@ func TestInitTablet(t *testing.T) { gRPCPort := int32(3456) mysqlDaemon := fakemysqldaemon.NewFakeMysqlDaemon(nil) agent := &ActionAgent{ - TopoServer: ts, - TabletAlias: tabletAlias, - MysqlDaemon: mysqlDaemon, - DBConfigs: &dbconfigs.DBConfigs{}, - BinlogPlayerMap: nil, - batchCtx: ctx, - History: history.New(historyLength), - _healthy: fmt.Errorf("healthcheck not run yet"), + TopoServer: ts, + TabletAlias: tabletAlias, + MysqlDaemon: mysqlDaemon, + DBConfigs: &dbconfigs.DBConfigs{}, + VREngine: vreplication.NewEngine(nil, "", nil, nil), + batchCtx: ctx, + History: history.New(historyLength), + _healthy: fmt.Errorf("healthcheck not run yet"), } // 1. Initialize the tablet as REPLICA. diff --git a/go/vt/vttablet/tabletmanager/rpc_actions.go b/go/vt/vttablet/tabletmanager/rpc_actions.go index 2ac5da8548a..ba0413969a4 100644 --- a/go/vt/vttablet/tabletmanager/rpc_actions.go +++ b/go/vt/vttablet/tabletmanager/rpc_actions.go @@ -62,6 +62,12 @@ func (agent *ActionAgent) ChangeType(ctx context.Context, tabletType topodatapb. } defer agent.unlock() + // We don't want to allow multiple callers to claim a tablet as drained. There is a race that could happen during + // horizontal resharding where two vtworkers will try to DRAIN the same tablet. This check prevents that race from + // causing errors. + if tabletType == topodatapb.TabletType_DRAINED && agent.Tablet().Type == topodatapb.TabletType_DRAINED { + return fmt.Errorf("Tablet: %v, is already drained", agent.TabletAlias) + } // change our type in the topology _, err := topotools.ChangeType(ctx, agent.TopoServer, agent.TabletAlias, tabletType) if err != nil { diff --git a/go/vt/vttablet/tabletmanager/rpc_agent.go b/go/vt/vttablet/tabletmanager/rpc_agent.go index 81c211ddf4e..04f956afdfd 100644 --- a/go/vt/vttablet/tabletmanager/rpc_agent.go +++ b/go/vt/vttablet/tabletmanager/rpc_agent.go @@ -20,6 +20,7 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -87,13 +88,9 @@ type RPCAgent interface { GetSlaves(ctx context.Context) ([]string, error) - WaitBlpPosition(ctx context.Context, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error - - StopBlp(ctx context.Context) ([]*tabletmanagerdatapb.BlpPosition, error) - - StartBlp(ctx context.Context) error - - RunBlpUntil(ctx context.Context, bpl []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) + // VReplication API + VReplicationExec(ctx context.Context, query string) (*querypb.QueryResult, error) + VReplicationWaitForPos(ctx context.Context, id int, pos string) error // Reparenting related functions diff --git a/go/vt/vttablet/tabletmanager/rpc_binlog_players.go b/go/vt/vttablet/tabletmanager/rpc_binlog_players.go deleted file mode 100644 index 124070599b0..00000000000 --- a/go/vt/vttablet/tabletmanager/rpc_binlog_players.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 tabletmanager - -import ( - "fmt" - "time" - - "golang.org/x/net/context" - - "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/vt/binlog/binlogplayer" - "vitess.io/vitess/go/vt/mysqlctl" - - tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" -) - -// WaitBlpPosition waits until a specific filtered replication position is -// reached. -func (agent *ActionAgent) WaitBlpPosition(ctx context.Context, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error { - if err := agent.lock(ctx); err != nil { - return err - } - defer agent.unlock() - - waitCtx, cancel := context.WithTimeout(ctx, waitTime) - defer cancel() - return mysqlctl.WaitBlpPosition(waitCtx, agent.MysqlDaemon, binlogplayer.QueryBlpCheckpoint(blpPosition.Uid), blpPosition.Position) -} - -// StopBlp stops the binlog players, and return their positions. -func (agent *ActionAgent) StopBlp(ctx context.Context) ([]*tabletmanagerdatapb.BlpPosition, error) { - if err := agent.lock(ctx); err != nil { - return nil, err - } - defer agent.unlock() - - if agent.BinlogPlayerMap == nil { - return nil, fmt.Errorf("No BinlogPlayerMap configured") - } - agent.BinlogPlayerMap.Stop() - return agent.BinlogPlayerMap.BlpPositionList() -} - -// StartBlp starts the binlog players -func (agent *ActionAgent) StartBlp(ctx context.Context) error { - if err := agent.lock(ctx); err != nil { - return err - } - defer agent.unlock() - - if agent.BinlogPlayerMap == nil { - return fmt.Errorf("No BinlogPlayerMap configured") - } - agent.BinlogPlayerMap.Start(agent.batchCtx) - return nil -} - -// RunBlpUntil runs the binlog player server until the position is reached, -// and returns the current mysql master replication position. -func (agent *ActionAgent) RunBlpUntil(ctx context.Context, bpl []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) { - if err := agent.lock(ctx); err != nil { - return "", err - } - defer agent.unlock() - - if agent.BinlogPlayerMap == nil { - return "", fmt.Errorf("No BinlogPlayerMap configured") - } - if err := agent.BinlogPlayerMap.RunUntil(ctx, bpl, waitTime); err != nil { - return "", err - } - pos, err := agent.MysqlDaemon.MasterPosition() - if err != nil { - return "", err - } - return mysql.EncodePosition(pos), nil -} diff --git a/go/vt/vttablet/tabletmanager/rpc_external_reparent_test.go b/go/vt/vttablet/tabletmanager/rpc_external_reparent_test.go index 3de383bd83c..05cf42110b6 100644 --- a/go/vt/vttablet/tabletmanager/rpc_external_reparent_test.go +++ b/go/vt/vttablet/tabletmanager/rpc_external_reparent_test.go @@ -23,7 +23,7 @@ import ( func TestTabletExternallyReparentedAlwaysUpdatesTimestamp(t *testing.T) { ctx := context.Background() - agent, _ := createTestAgent(ctx, t, nil) + agent := createTestAgent(ctx, t, nil) // Initial call sets the timestamp. if err := agent.TabletExternallyReparented(ctx, "unused_id"); err != nil { diff --git a/go/vt/vttablet/tabletmanager/state_change.go b/go/vt/vttablet/tabletmanager/state_change.go index 51f7732ea8e..3f615067e68 100644 --- a/go/vt/vttablet/tabletmanager/state_change.go +++ b/go/vt/vttablet/tabletmanager/state_change.go @@ -33,6 +33,7 @@ import ( "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vttablet/tabletmanager/events" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tabletserver/rules" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -108,9 +109,7 @@ func (agent *ActionAgent) broadcastHealth() { stats := &querypb.RealtimeStats{ SecondsBehindMaster: uint32(replicationDelay.Seconds()), } - if agent.BinlogPlayerMap != nil { - stats.SecondsBehindMasterFilteredReplication, stats.BinlogPlayersCount = agent.BinlogPlayerMap.StatusSummary() - } + stats.SecondsBehindMasterFilteredReplication, stats.BinlogPlayersCount = vreplication.StatusSummary() stats.Qps = tabletenv.QPSRates.TotalRate() if healthError != nil { stats.HealthError = healthError.Error() @@ -305,13 +304,15 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl agent.statsTabletTypeCount.Add(s, 1) } - // See if we need to start or stop any binlog player. - if agent.BinlogPlayerMap != nil { - if newTablet.Type == topodatapb.TabletType_MASTER { - agent.BinlogPlayerMap.RefreshMap(agent.batchCtx, newTablet, shardInfo) + // See if we need to start or stop vreplication. + if newTablet.Type == topodatapb.TabletType_MASTER { + if err := agent.VREngine.Open(agent.batchCtx); err != nil { + log.Errorf("Could not start VReplication engine: %v. Will keep retrying at health check intervals.", err) } else { - agent.BinlogPlayerMap.StopAllPlayersAndReset() + log.Info("VReplication engine started") } + } else { + agent.VREngine.Close() } // Broadcast health changes to vtgate immediately. diff --git a/go/vt/vttablet/tabletmanager/vreplication.go b/go/vt/vttablet/tabletmanager/vreplication.go new file mode 100644 index 00000000000..091b5ea1ec8 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication.go @@ -0,0 +1,39 @@ +/* +Copyright 2018 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 tabletmanager + +import ( + "golang.org/x/net/context" + + "vitess.io/vitess/go/sqltypes" + + querypb "vitess.io/vitess/go/vt/proto/query" +) + +// VReplicationExec executes a vreplication command. +func (agent *ActionAgent) VReplicationExec(ctx context.Context, query string) (*querypb.QueryResult, error) { + qr, err := agent.VREngine.Exec(query) + if err != nil { + return nil, err + } + return sqltypes.ResultToProto3(qr), nil +} + +// VReplicationWaitForPos waits for the specified position. +func (agent *ActionAgent) VReplicationWaitForPos(ctx context.Context, id int, pos string) error { + return agent.VREngine.WaitForPos(ctx, id, pos) +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller.go b/go/vt/vttablet/tabletmanager/vreplication/controller.go new file mode 100644 index 00000000000..cf5f8f98f89 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/controller.go @@ -0,0 +1,187 @@ +/* +Copyright 2018 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 vreplication + +import ( + "flag" + "fmt" + "strconv" + "time" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + + "vitess.io/vitess/go/sync2" + "vitess.io/vitess/go/tb" + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/mysqlctl" + "vitess.io/vitess/go/vt/topo" + + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" +) + +var retryDelay = flag.Duration("vreplication_retry_delay", 5*time.Second, "delay before retrying a failed binlog connection") + +// controller is created by Engine. Members are initialized upfront. +// There is no mutex within a controller becaust its members are +// either read-only or self-synchronized. +type controller struct { + dbClientFactory func() binlogplayer.DBClient + mysqld mysqlctl.MysqlDaemon + blpStats *binlogplayer.Stats + + id uint32 + source binlogdatapb.BinlogSource + stopPos string + tabletPicker *tabletPicker + + cancel context.CancelFunc + done chan struct{} + + // The following fields are updated after start. So, they need synchronization. + sourceTablet sync2.AtomicString +} + +// newController creates a new controller. Unless a stream is explicitly 'Stopped', +// this function launches a goroutine to perform continuous vreplication. +func newController(ctx context.Context, params map[string]string, dbClientFactory func() binlogplayer.DBClient, mysqld mysqlctl.MysqlDaemon, ts *topo.Server, cell, tabletTypesStr string, blpStats *binlogplayer.Stats) (*controller, error) { + if blpStats == nil { + blpStats = binlogplayer.NewStats() + } + ct := &controller{ + dbClientFactory: dbClientFactory, + mysqld: mysqld, + blpStats: blpStats, + done: make(chan struct{}), + } + + // id + id, err := strconv.Atoi(params["id"]) + if err != nil { + return nil, err + } + ct.id = uint32(id) + + // Nothing to do if replication is stopped. + if params["state"] == binlogplayer.BlpStopped { + ct.cancel = func() {} + close(ct.done) + return ct, nil + } + + // source, stopPos + if err := proto.UnmarshalText(params["source"], &ct.source); err != nil { + return nil, err + } + ct.stopPos = params["stop_pos"] + + // tabletPicker + if v, ok := params["cell"]; ok { + cell = v + } + if v, ok := params["tablet_types"]; ok { + tabletTypesStr = v + } + tp, err := newTabletPicker(ts, cell, ct.source.Keyspace, ct.source.Shard, tabletTypesStr) + if err != nil { + return nil, err + } + ct.tabletPicker = tp + + // cancel + ctx, ct.cancel = context.WithCancel(ctx) + + go ct.run(ctx) + + return ct, nil +} + +func (ct *controller) run(ctx context.Context) { + defer func() { + log.Infof("stream %v: stopped", ct.id) + ct.tabletPicker.Close() + close(ct.done) + }() + + for { + err := ct.runBlp(ctx) + if err == nil { + return + } + // Sometimes, canceled contexts get wrapped as errors. + select { + case <-ctx.Done(): + return + default: + } + log.Warningf("stream %v: %v, retrying after %v", ct.id, err, *retryDelay) + time.Sleep(*retryDelay) + } +} + +func (ct *controller) runBlp(ctx context.Context) (err error) { + defer func() { + ct.sourceTablet.Set("") + if x := recover(); x != nil { + log.Errorf("stream %v: caught panic: %v\n%s", ct.id, x, tb.Stack(4)) + err = fmt.Errorf("panic: %v", x) + } + }() + + select { + case <-ctx.Done(): + return nil + default: + } + + // Call this for youtube-specific customization. + // This should be done every time, in case mysql was restarted. + if err := ct.mysqld.EnableBinlogPlayback(); err != nil { + return err + } + + dbClient := ct.dbClientFactory() + if err := dbClient.Connect(); err != nil { + return fmt.Errorf("can't connect to database: %v", err) + } + defer dbClient.Close() + + tablet, err := ct.tabletPicker.Pick(ctx) + if err != nil { + return err + } + ct.sourceTablet.Set(tablet.Alias.String()) + + if len(ct.source.Tables) > 0 { + // Table names can have search patterns. Resolve them against the schema. + tables, err := mysqlctl.ResolveTables(ct.mysqld, dbClient.DBName(), ct.source.Tables) + if err != nil { + return fmt.Errorf("failed to resolve table names: %v", err) + } + + player := binlogplayer.NewBinlogPlayerTables(dbClient, tablet, tables, ct.id, ct.blpStats) + return player.ApplyBinlogEvents(ctx) + } + player := binlogplayer.NewBinlogPlayerKeyRange(dbClient, tablet, ct.source.KeyRange, ct.id, ct.blpStats) + return player.ApplyBinlogEvents(ctx) +} + +func (ct *controller) Stop() { + ct.cancel() + <-ct.done +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller_test.go b/go/vt/vttablet/tabletmanager/vreplication/controller_test.go new file mode 100644 index 00000000000..bfd84b53ece --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/controller_test.go @@ -0,0 +1,333 @@ +/* +Copyright 2018 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 vreplication + +import ( + "errors" + "testing" + "time" + + "golang.org/x/net/context" + + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" + "vitess.io/vitess/go/vt/mysqlctl/tmutils" + + tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +var ( + testSettingsResponse = &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NULL, // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + testDMLResponse = &sqltypes.Result{RowsAffected: 1} + testPos = "MariaDB/0-1-1083" +) + +func TestControllerKeyRange(t *testing.T) { + ts := createTopo() + fbc := newFakeBinlogClient() + wantTablet := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" key_range: `, + } + + dbClient := binlogplayer.NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + ct, err := newController(context.Background(), params, dbClientFactory, mysqld, ts, testCell, "replica", nil) + if err != nil { + t.Fatal(err) + } + defer func() { + dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='context canceled' where id=1", testDMLResponse, nil) + ct.Stop() + }() + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, nil, &topodatapb.KeyRange{End: []byte{0x80}}) +} + +func TestControllerTables(t *testing.T) { + ts := createTopo() + wantTablet := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + fbc := newFakeBinlogClient() + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" tables:"table1" tables:"/funtables_/" `, + } + + dbClient := binlogplayer.NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{ + MysqlPort: 3306, + Schema: &tabletmanagerdatapb.SchemaDefinition{ + DatabaseSchema: "", + TableDefinitions: []*tabletmanagerdatapb.TableDefinition{ + { + Name: "table1", + Columns: []string{"id", "msg", "keyspace_id"}, + PrimaryKeyColumns: []string{"id"}, + Type: tmutils.TableBaseTable, + }, + { + Name: "funtables_one", + Columns: []string{"id", "msg", "keyspace_id"}, + PrimaryKeyColumns: []string{"id"}, + Type: tmutils.TableBaseTable, + }, + { + Name: "excluded_table", + Columns: []string{"id", "msg", "keyspace_id"}, + PrimaryKeyColumns: []string{"id"}, + Type: tmutils.TableBaseTable, + }, + }, + }, + } + + ct, err := newController(context.Background(), params, dbClientFactory, mysqld, ts, testCell, "replica", nil) + if err != nil { + t.Fatal(err) + } + defer func() { + dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='context canceled' where id=1", testDMLResponse, nil) + ct.Stop() + }() + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, []string{"table1", "funtables_one"}, nil) +} + +func TestControllerBadID(t *testing.T) { + params := map[string]string{ + "id": "bad", + } + _, err := newController(context.Background(), params, nil, nil, nil, "", "", nil) + want := `strconv.Atoi: parsing "bad": invalid syntax` + if err == nil || err.Error() != want { + t.Errorf("newController err: %v, want %v", err, want) + } +} + +func TestControllerStopped(t *testing.T) { + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpStopped, + } + + ct, err := newController(context.Background(), params, nil, nil, nil, "", "", nil) + if err != nil { + t.Fatal(err) + } + defer ct.Stop() + + select { + case <-ct.done: + default: + t.Errorf("context should be closed, but is not: %v", ct) + } +} + +func TestControllerOverrides(t *testing.T) { + ts := createTopo() + fbc := newFakeBinlogClient() + wantTablet := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" key_range: `, + "cell": testCell, + "tablet_types": "replica", + } + + dbClient := binlogplayer.NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + ct, err := newController(context.Background(), params, dbClientFactory, mysqld, ts, testCell, "rdonly", nil) + if err != nil { + t.Fatal(err) + } + defer func() { + dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='context canceled' where id=1", testDMLResponse, nil) + ct.Stop() + }() + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, nil, &topodatapb.KeyRange{End: []byte{0x80}}) +} + +func TestControllerCanceledContext(t *testing.T) { + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" key_range: `, + } + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + ct, err := newController(ctx, params, nil, nil, ts, testCell, "rdonly", nil) + if err != nil { + t.Fatal(err) + } + defer ct.Stop() + + select { + case <-ct.done: + case <-time.After(1 * time.Second): + t.Errorf("context should be closed, but is not: %v", ct) + } +} + +func TestControllerRetry(t *testing.T) { + savedDelay := *retryDelay + defer func() { *retryDelay = savedDelay }() + *retryDelay = 10 * time.Millisecond + + ts := createTopo() + _ = newFakeBinlogClient() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" key_range: `, + "cell": testCell, + "tablet_types": "replica", + } + + dbClient := binlogplayer.NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", nil, errors.New("(expected error)")) + dbClient.ExpectRequest("update _vt.vreplication set state='Error', message='error (expected error) in selecting vreplication settings select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + ct, err := newController(context.Background(), params, dbClientFactory, mysqld, ts, testCell, "rdonly", nil) + if err != nil { + t.Fatal(err) + } + defer ct.Stop() + + dbClient.Wait() +} + +func TestControllerStopPosition(t *testing.T) { + ts := createTopo() + fbc := newFakeBinlogClient() + wantTablet := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + params := map[string]string{ + "id": "1", + "state": binlogplayer.BlpRunning, + "source": `keyspace:"ks" shard:"0" key_range: `, + } + + dbClient := binlogplayer.NewMockDBClient(t) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + withStop := &sqltypes.Result{ + Fields: nil, + RowsAffected: 1, + InsertID: 0, + Rows: [][]sqltypes.Value{ + { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), // pos + sqltypes.NewVarBinary("MariaDB/0-1-1235"), // stop_pos + sqltypes.NewVarBinary("9223372036854775807"), // max_tps + sqltypes.NewVarBinary("9223372036854775807"), // max_replication_lag + }, + }, + } + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", withStop, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='Reached stopping position, done playing logs' where id=1", testDMLResponse, nil) + + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + ct, err := newController(context.Background(), params, dbClientFactory, mysqld, ts, testCell, "replica", nil) + if err != nil { + t.Fatal(err) + } + defer func() { + dbClient.ExpectRequest("update _vt.vreplication set state='Stopped', message='context canceled' where id=1", testDMLResponse, nil) + ct.Stop() + }() + + // Also confirm that replication stopped. + select { + case <-ct.done: + case <-time.After(1 * time.Second): + t.Errorf("context should be closed, but is not: %v", ct) + } + + dbClient.Wait() + expectFBCRequest(t, fbc, wantTablet, testPos, nil, &topodatapb.KeyRange{End: []byte{0x80}}) +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine.go b/go/vt/vttablet/tabletmanager/vreplication/engine.go new file mode 100644 index 00000000000..abf1b0b9efd --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/engine.go @@ -0,0 +1,359 @@ +/* +Copyright 2018 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 vreplication + +import ( + "errors" + "flag" + "fmt" + "sync" + "time" + + "golang.org/x/net/context" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/mysqlctl" + "vitess.io/vitess/go/vt/topo" +) + +var tabletTypesStr = flag.String("vreplication_tablet_type", "REPLICA", "comma separated list of tablet types used as a source") + +// waitRetryTime can be changed to a smaller value for tests. +// A VReplication stream can be created by sending an insert statement +// to the Engine. Such a stream can also be updated or deleted. The fields +// of the table are described in binlogplayer.binlog_player.go. Changing +// values in a vreplication row will cause the Engine to accordingly react. +// For example, setting the state to 'Stopped' will cause that stream to +// stop replicating. +var waitRetryTime = 1 * time.Second + +// Engine is the engine for handling vreplication. +type Engine struct { + // mu synchronizes isOpen, controllers and wg. + mu sync.Mutex + isOpen bool + controllers map[int]*controller + // wg is used by in-flight functions that can run for long periods. + wg sync.WaitGroup + mustCreate bool + + // ctx is the root context for all controllers. + ctx context.Context + // cancel will cancel the root context, thereby all controllers. + cancel context.CancelFunc + + ts *topo.Server + cell string + mysqld mysqlctl.MysqlDaemon + dbClientFactory func() binlogplayer.DBClient +} + +// NewEngine creates a new Engine. +// A nil ts means that the Engine is disabled. +func NewEngine(ts *topo.Server, cell string, mysqld mysqlctl.MysqlDaemon, dbClientFactory func() binlogplayer.DBClient) *Engine { + vre := &Engine{ + controllers: make(map[int]*controller), + ts: ts, + cell: cell, + mysqld: mysqld, + dbClientFactory: dbClientFactory, + } + return vre +} + +// Open starts the Engine service. +func (vre *Engine) Open(ctx context.Context) error { + vre.mu.Lock() + defer vre.mu.Unlock() + if vre.ts == nil { + log.Info("ts is nil: disabling vreplication engine") + return nil + } + if vre.isOpen { + return nil + } + + vre.ctx, vre.cancel = context.WithCancel(ctx) + vre.isOpen = true + if err := vre.initAll(); err != nil { + go vre.Close() + return err + } + vre.updateStats() + return nil +} + +func (vre *Engine) initAll() error { + dbClient := vre.dbClientFactory() + if err := dbClient.Connect(); err != nil { + return err + } + defer dbClient.Close() + + rows, err := readAllRows(dbClient) + if err != nil { + // Handle Table not found. + if merr, ok := err.(*mysql.SQLError); ok && merr.Num == 1146 { + vre.mustCreate = true + log.Info("_vt.vreplication table not found. Will create it later if needed") + return nil + } + return err + } + for _, row := range rows { + ct, err := newController(vre.ctx, row, vre.dbClientFactory, vre.mysqld, vre.ts, vre.cell, *tabletTypesStr, nil) + if err != nil { + return err + } + vre.controllers[int(ct.id)] = ct + } + return nil +} + +// IsOpen returns true if Engine is open. +func (vre *Engine) IsOpen() bool { + vre.mu.Lock() + defer vre.mu.Unlock() + return vre.isOpen +} + +// Close closes the Engine service. +func (vre *Engine) Close() { + vre.mu.Lock() + defer vre.mu.Unlock() + if !vre.isOpen { + return + } + + vre.cancel() + // We still have to wait for all controllers to stop. + for _, ct := range vre.controllers { + ct.Stop() + } + vre.controllers = make(map[int]*controller) + + // Wait for long-running functions to exit. + vre.wg.Wait() + + vre.mysqld.DisableBinlogPlayback() + vre.isOpen = false + + vre.updateStats() +} + +// Exec executes the query and the related actions. +// Example insert statement: +// insert into _vt.vreplication +// (workflow, source, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, state) +// values ('Resharding', 'keyspace:"ks" shard:"0" tables:"a" tables:"b" ', 'MariaDB/0-1-1083', 9223372036854775807, 9223372036854775807, 481823, 0, 'Running')` +// Example update statement: +// update _vt.vreplication set state='Stopped', message='testing stop' where id=1 +// Example delete: delete from _vt.vreplication where id=1 +// Example select: select * from _vt.vreplication +func (vre *Engine) Exec(query string) (*sqltypes.Result, error) { + vre.mu.Lock() + defer vre.mu.Unlock() + if !vre.isOpen { + return nil, errors.New("vreplication engine is closed") + } + defer vre.updateStats() + + plan, err := getPlan(query) + if err != nil { + return nil, err + } + dbClient := vre.dbClientFactory() + if err := dbClient.Connect(); err != nil { + return nil, err + } + defer dbClient.Close() + + if vre.mustCreate { + for _, query := range binlogplayer.CreateVReplicationTable() { + if _, err := dbClient.ExecuteFetch(query, 0); err != nil { + return nil, err + } + } + vre.mustCreate = false + } + + switch plan.opcode { + case insertQuery: + qr, err := dbClient.ExecuteFetch(plan.query, 1) + if err != nil { + return nil, err + } + if qr.InsertID == 0 { + return nil, fmt.Errorf("insert failed to generate an id") + } + params, err := readRow(dbClient, int(qr.InsertID)) + if err != nil { + return nil, err + } + // Create a controller for the newly created row. + ct, err := newController(vre.ctx, params, vre.dbClientFactory, vre.mysqld, vre.ts, vre.cell, *tabletTypesStr, nil) + if err != nil { + return nil, err + } + vre.controllers[int(qr.InsertID)] = ct + return qr, nil + case updateQuery: + var blpStats *binlogplayer.Stats + if ct := vre.controllers[plan.id]; ct != nil { + // Stop the current controller. + ct.Stop() + blpStats = ct.blpStats + } + qr, err := dbClient.ExecuteFetch(plan.query, 1) + if err != nil { + return nil, err + } + params, err := readRow(dbClient, plan.id) + if err != nil { + return nil, err + } + // Create a new controller in place of the old one. + // For continuity, the new controller inherits the previous stats. + ct, err := newController(vre.ctx, params, vre.dbClientFactory, vre.mysqld, vre.ts, vre.cell, *tabletTypesStr, blpStats) + if err != nil { + return nil, err + } + vre.controllers[plan.id] = ct + return qr, nil + case deleteQuery: + // Stop and delete the current controller. + if ct := vre.controllers[plan.id]; ct != nil { + ct.Stop() + delete(vre.controllers, plan.id) + } + return dbClient.ExecuteFetch(plan.query, 1) + case selectQuery: + // select queries are passed through. + return dbClient.ExecuteFetch(plan.query, 10000) + } + panic("unreachable") +} + +// WaitForPos waits for the replication to reach the specified position. +func (vre *Engine) WaitForPos(ctx context.Context, id int, pos string) error { + mPos, err := mysql.DecodePosition(pos) + if err != nil { + return err + } + + vre.mu.Lock() + if !vre.isOpen { + vre.mu.Unlock() + return errors.New("vreplication engine is closed") + } + // Ensure that the engine won't be closed while this is running. + vre.wg.Add(1) + vre.mu.Unlock() + defer vre.wg.Done() + + dbClient := vre.dbClientFactory() + if err := dbClient.Connect(); err != nil { + return err + } + defer dbClient.Close() + + for { + qr, err := dbClient.ExecuteFetch(binlogplayer.ReadVReplicationPos(uint32(id)), 10) + switch { + case err != nil: + return err + case len(qr.Rows) == 0: + return fmt.Errorf("vreplication stream %d not found", id) + case len(qr.Rows) > 1 || len(qr.Rows[0]) != 1: + return fmt.Errorf("unexpected result: %v", qr) + } + current, err := mysql.DecodePosition(qr.Rows[0][0].ToString()) + if err != nil { + return err + } + + if current.AtLeast(mPos) { + return nil + } + + select { + case <-ctx.Done(): + return ctx.Err() + case <-vre.ctx.Done(): + return fmt.Errorf("vreplication is closing: %v", vre.ctx.Err()) + case <-time.After(waitRetryTime): + } + } +} + +// UpdateStats must be called with lock held. +func (vre *Engine) updateStats() { + globalStats.mu.Lock() + defer globalStats.mu.Unlock() + + globalStats.isOpen = vre.isOpen + globalStats.controllers = make(map[int]*controller, len(vre.controllers)) + for id, ct := range vre.controllers { + globalStats.controllers[id] = ct + } +} + +func readAllRows(dbClient binlogplayer.DBClient) ([]map[string]string, error) { + qr, err := dbClient.ExecuteFetch("select * from _vt.vreplication", 10000) + if err != nil { + return nil, err + } + maps := make([]map[string]string, len(qr.Rows)) + for i := range qr.Rows { + mrow, err := rowToMap(qr, i) + if err != nil { + return nil, err + } + maps[i] = mrow + } + return maps, nil +} + +func readRow(dbClient binlogplayer.DBClient, id int) (map[string]string, error) { + qr, err := dbClient.ExecuteFetch(fmt.Sprintf("select * from _vt.vreplication where id = %d", id), 10) + if err != nil { + return nil, err + } + if len(qr.Rows) != 1 { + return nil, fmt.Errorf("unexpected number of rows: %v", qr) + } + if len(qr.Fields) != len(qr.Rows[0]) { + return nil, fmt.Errorf("fields don't match rows: %v", qr) + } + return rowToMap(qr, 0) +} + +// rowToMap converts a row into a map for easier processing. +func rowToMap(qr *sqltypes.Result, rownum int) (map[string]string, error) { + row := qr.Rows[rownum] + m := make(map[string]string, len(row)) + for i, fld := range qr.Fields { + if row[i].IsNull() { + continue + } + m[fld.Name] = row[i].ToString() + } + return m, nil +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine_test.go b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go new file mode 100644 index 00000000000..d10f91ff177 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go @@ -0,0 +1,427 @@ +/* +Copyright 2018 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 vreplication + +import ( + "reflect" + "testing" + "time" + + "golang.org/x/net/context" + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +func TestEngineOpen(t *testing.T) { + defer func() { globalStats = &vrStats{} }() + + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + _ = newFakeBinlogClient() + dbClient := binlogplayer.NewMockDBClient(t) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + // Test Insert + + vre := NewEngine(ts, testCell, mysqld, dbClientFactory) + if vre.IsOpen() { + t.Errorf("IsOpen: %v, want false", vre.IsOpen()) + } + + dbClient.ExpectRequest("select * from _vt.vreplication", sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source", + "int64|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: `, + ), nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + defer vre.Close() + if !vre.IsOpen() { + t.Errorf("IsOpen: %v, want true", vre.IsOpen()) + } + + // Verify stats + if !reflect.DeepEqual(globalStats.controllers, vre.controllers) { + t.Errorf("stats are mismatched: %v, wnat %v", globalStats.controllers, vre.controllers) + } + + ct := vre.controllers[1] + if ct == nil || ct.id != 1 { + t.Errorf("ct: %v, id should be 1", ct) + } +} + +func TestEngineExec(t *testing.T) { + defer func() { globalStats = &vrStats{} }() + + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + _ = newFakeBinlogClient() + dbClient := binlogplayer.NewMockDBClient(t) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + // Test Insert + + vre := NewEngine(ts, testCell, mysqld, dbClientFactory) + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + defer vre.Close() + + dbClient.ExpectRequest("insert into _vt.vreplication values (null)", &sqltypes.Result{InsertID: 1}, nil) + dbClient.ExpectRequest("select * from _vt.vreplication where id = 1", sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source", + "int64|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: `, + ), nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + qr, err := vre.Exec("insert into _vt.vreplication values(null)") + if err != nil { + t.Fatal(err) + } + wantqr := &sqltypes.Result{InsertID: 1} + if !reflect.DeepEqual(qr, wantqr) { + t.Errorf("Exec: %v, want %v", qr, wantqr) + } + dbClient.Wait() + + ct := vre.controllers[1] + if ct == nil || ct.id != 1 { + t.Errorf("ct: %v, id should be 1", ct) + } + + // Verify stats + if !reflect.DeepEqual(globalStats.controllers, vre.controllers) { + t.Errorf("stats are mismatched: %v, wnat %v", globalStats.controllers, vre.controllers) + } + + // Test Update + + savedBlp := ct.blpStats + + dbClient.ExpectRequest("update _vt.vreplication set pos = 'MariaDB/0-1-1084', state = 'Running' where id = 1", testDMLResponse, nil) + dbClient.ExpectRequest("select * from _vt.vreplication where id = 1", sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source", + "int64|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: `, + ), nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + qr, err = vre.Exec("update _vt.vreplication set pos = 'MariaDB/0-1-1084', state = 'Running' where id = 1") + if err != nil { + t.Fatal(err) + } + wantqr = &sqltypes.Result{RowsAffected: 1} + if !reflect.DeepEqual(qr, wantqr) { + t.Errorf("Exec: %v, want %v", qr, wantqr) + } + dbClient.Wait() + + ct = vre.controllers[1] + + // Verify that the new controller has reused the previous blpStats. + if ct.blpStats != savedBlp { + t.Errorf("BlpStats: %v and %v, must be same", ct.blpStats, savedBlp) + } + + // Verify stats + if !reflect.DeepEqual(globalStats.controllers, vre.controllers) { + t.Errorf("stats are mismatched: %v, wnat %v", globalStats.controllers, vre.controllers) + } + + // Test Delete + + delQuery := "delete from _vt.vreplication where id = 1" + dbClient.ExpectRequest(delQuery, testDMLResponse, nil) + + qr, err = vre.Exec(delQuery) + if err != nil { + t.Fatal(err) + } + wantqr = &sqltypes.Result{RowsAffected: 1} + if !reflect.DeepEqual(qr, wantqr) { + t.Errorf("Exec: %v, want %v", qr, wantqr) + } + dbClient.Wait() + + ct = vre.controllers[1] + if ct != nil { + t.Errorf("ct: %v, want nil", ct) + } + + // Verify stats + if !reflect.DeepEqual(globalStats.controllers, vre.controllers) { + t.Errorf("stats are mismatched: %v, want %v", globalStats.controllers, vre.controllers) + } +} + +func TestEngineBadInsert(t *testing.T) { + defer func() { globalStats = &vrStats{} }() + + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + _ = newFakeBinlogClient() + + dbClient := binlogplayer.NewMockDBClient(t) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + vre := NewEngine(ts, testCell, mysqld, dbClientFactory) + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + defer vre.Close() + + dbClient.ExpectRequest("insert into _vt.vreplication values (null)", &sqltypes.Result{}, nil) + _, err := vre.Exec("insert into _vt.vreplication values(null)") + want := "insert failed to generate an id" + if err == nil || err.Error() != want { + t.Errorf("vre.Exec err: %v, want %v", err, want) + } + + // Verify stats + if !reflect.DeepEqual(globalStats.controllers, vre.controllers) { + t.Errorf("stats are mismatched: %v, wnat %v", globalStats.controllers, vre.controllers) + } +} + +func TestEngineSelect(t *testing.T) { + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + _ = newFakeBinlogClient() + dbClient := binlogplayer.NewMockDBClient(t) + + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + vre := NewEngine(ts, testCell, mysqld, dbClientFactory) + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + defer vre.Close() + + wantQuery := "select * from _vt.vreplication where workflow = 'x'" + wantResult := sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source|pos", + "int64|varchar|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: |MariaDB/0-1-1083`, + ) + dbClient.ExpectRequest(wantQuery, wantResult, nil) + qr, err := vre.Exec(wantQuery) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(qr, wantResult) { + t.Errorf("Exec: %v, want %v", qr, wantResult) + } +} + +func TestWaitForPos(t *testing.T) { + savedRetryTime := waitRetryTime + defer func() { waitRetryTime = savedRetryTime }() + waitRetryTime = 10 * time.Millisecond + + dbClient := binlogplayer.NewMockDBClient(t) + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + vre := NewEngine(createTopo(), testCell, mysqld, dbClientFactory) + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/0-1-1083"), + }}}, nil) + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/0-1-1084"), + }}}, nil) + start := time.Now() + if err := vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084"); err != nil { + t.Fatal(err) + } + if duration := time.Since(start); duration < 10*time.Microsecond { + t.Errorf("duration: %v, want < 10ms", duration) + } +} + +func TestWaitForPosError(t *testing.T) { + dbClient := binlogplayer.NewMockDBClient(t) + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + vre := NewEngine(createTopo(), testCell, mysqld, dbClientFactory) + + err := vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084") + want := `vreplication engine is closed` + if err == nil || err.Error() != want { + t.Errorf("WaitForPos: %v, want %v", err, want) + } + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + + err = vre.WaitForPos(context.Background(), 1, "BadFlavor/0-1-1084") + want = `parse error: unknown GTIDSet flavor "BadFlavor"` + if err == nil || err.Error() != want { + t.Errorf("WaitForPos: %v, want %v", err, want) + } + + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{}}}, nil) + err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084") + want = "unexpected result: &{[] 0 0 [[]] }" + if err == nil || err.Error() != want { + t.Errorf("WaitForPos: %v, want %v", err, want) + } + + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/0-1-1083"), + }, { + sqltypes.NewVarBinary("MariaDB/0-1-1083"), + }}}, nil) + err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084") + want = `unexpected result: &{[] 0 0 [[VARBINARY("MariaDB/0-1-1083")] [VARBINARY("MariaDB/0-1-1083")]] }` + if err == nil || err.Error() != want { + t.Errorf("WaitForPos: %v, want %v", err, want) + } +} + +func TestWaitForPosCancel(t *testing.T) { + dbClient := binlogplayer.NewMockDBClient(t) + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + vre := NewEngine(createTopo(), testCell, mysqld, dbClientFactory) + + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/0-1-1083"), + }}}, nil) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + err := vre.WaitForPos(ctx, 1, "MariaDB/0-1-1084") + if err == nil || err != context.Canceled { + t.Errorf("WaitForPos: %v, want %v", err, context.Canceled) + } + dbClient.Wait() + + go func() { + time.Sleep(5 * time.Millisecond) + vre.Close() + }() + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/0-1-1083"), + }}}, nil) + err = vre.WaitForPos(context.Background(), 1, "MariaDB/0-1-1084") + want := "vreplication is closing: context canceled" + if err == nil || err.Error() != want { + t.Errorf("WaitForPos: %v, want %v", err, want) + } +} + +func TestCreateDBAndTable(t *testing.T) { + defer func() { globalStats = &vrStats{} }() + + ts := createTopo() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + _ = newFakeBinlogClient() + dbClient := binlogplayer.NewMockDBClient(t) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + mysqld := &fakemysqldaemon.FakeMysqlDaemon{MysqlPort: 3306} + + // Test Insert + + vre := NewEngine(ts, testCell, mysqld, dbClientFactory) + + notFound := mysql.SQLError{Num: 1146, Message: "not found"} + dbClient.ExpectRequest("select * from _vt.vreplication", nil, ¬Found) + if err := vre.Open(context.Background()); err != nil { + t.Fatal(err) + } + defer vre.Close() + + dbClient.ExpectRequest("CREATE DATABASE IF NOT EXISTS _vt", &sqltypes.Result{}, nil) + dbClient.ExpectRequest("DROP TABLE IF EXISTS _vt.blp_checkpoint", &sqltypes.Result{}, nil) + dbClient.ExpectRequestRE("CREATE TABLE IF NOT EXISTS _vt.vreplication.*", &sqltypes.Result{}, nil) + dbClient.ExpectRequest("insert into _vt.vreplication values (null)", &sqltypes.Result{InsertID: 1}, nil) + dbClient.ExpectRequest("select * from _vt.vreplication where id = 1", sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "id|state|source", + "int64|varchar|varchar", + ), + `1|Running|keyspace:"ks" shard:"0" key_range: `, + ), nil) + dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) + dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag from _vt.vreplication where id=1", testSettingsResponse, nil) + dbClient.ExpectRequest("begin", nil, nil) + dbClient.ExpectRequest("insert into t values(1)", testDMLResponse, nil) + dbClient.ExpectRequestRE("update _vt.vreplication set pos='MariaDB/0-1-1235', time_updated=.*", testDMLResponse, nil) + dbClient.ExpectRequest("commit", nil, nil) + + qr, err := vre.Exec("insert into _vt.vreplication values(null)") + if err != nil { + t.Fatal(err) + } + wantqr := &sqltypes.Result{InsertID: 1} + if !reflect.DeepEqual(qr, wantqr) { + t.Errorf("Exec: %v, want %v", qr, wantqr) + } + dbClient.Wait() +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go new file mode 100644 index 00000000000..559f285e1ff --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go @@ -0,0 +1,234 @@ +/* +Copyright 2018 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 vreplication + +import ( + "flag" + "reflect" + "testing" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/grpcclient" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/vttablet/queryservice" + "vitess.io/vitess/go/vt/vttablet/queryservice/fakes" + "vitess.io/vitess/go/vt/vttablet/tabletconn" + + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + querypb "vitess.io/vitess/go/vt/proto/query" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +const ( + testCell = "cell" + testKeyspace = "ks" + testShard = "0" +) + +// This file provides support functions for tests. +// It's capable of creating a single unsharded keyspace +// and allows you to add various tablet types. + +//-------------------------------------- +// Topos and tablets + +func createTopo() *topo.Server { + ts := memorytopo.NewServer(testCell) + ctx := context.Background() + if err := ts.CreateKeyspace(ctx, testKeyspace, &topodatapb.Keyspace{}); err != nil { + panic(err) + } + if err := ts.CreateShard(ctx, testKeyspace, testShard); err != nil { + panic(err) + } + return ts +} + +func addTablet(ts *topo.Server, id int, shard string, tabletType topodatapb.TabletType, serving, healthy bool) *topodatapb.Tablet { + t := newTablet(id, shard, tabletType, serving, healthy) + if err := ts.CreateTablet(context.Background(), t); err != nil { + panic(err) + } + return t +} + +func newTablet(id int, shard string, tabletType topodatapb.TabletType, serving, healthy bool) *topodatapb.Tablet { + stag := "not_serving" + if serving { + stag = "serving" + } + htag := "not_healthy" + if healthy { + htag = "healthy" + } + _, kr, err := topo.ValidateShardName(shard) + if err != nil { + panic(err) + } + return &topodatapb.Tablet{ + Alias: &topodatapb.TabletAlias{ + Cell: testCell, + Uid: uint32(id), + }, + Keyspace: testKeyspace, + Shard: testShard, + KeyRange: kr, + Type: tabletType, + Tags: map[string]string{ + "serving": stag, + "healthy": htag, + }, + PortMap: map[string]int32{ + "test": int32(id), + }, + } +} + +// fakeTabletConn implement TabletConn interface. We only care about the +// health check part. The state reported by the tablet will depend +// on the Tag values "serving" and "healthy". +type fakeTabletConn struct { + queryservice.QueryService + tablet *topodatapb.Tablet +} + +// StreamHealth is part of queryservice.QueryService. +func (ftc *fakeTabletConn) StreamHealth(ctx context.Context, callback func(*querypb.StreamHealthResponse) error) error { + serving := true + if s, ok := ftc.tablet.Tags["serving"]; ok { + serving = (s == "serving") + } + var herr string + if s, ok := ftc.tablet.Tags["healthy"]; ok && s != "healthy" { + herr = "err" + } + callback(&querypb.StreamHealthResponse{ + Serving: serving, + Target: &querypb.Target{ + Keyspace: ftc.tablet.Keyspace, + Shard: ftc.tablet.Shard, + TabletType: ftc.tablet.Type, + }, + RealtimeStats: &querypb.RealtimeStats{HealthError: herr}, + }) + return nil +} + +//-------------------------------------- +// Binlog Client to TabletManager + +// fakeBinlogClient satisfies binlogplayer.Client. +// Not to be used concurrently. +type fakeBinlogClient struct { + lastTablet *topodatapb.Tablet + lastPos string + lastTables []string + lastKeyRange *topodatapb.KeyRange + lastCharset *binlogdatapb.Charset +} + +func newFakeBinlogClient() *fakeBinlogClient { + globalFBC = &fakeBinlogClient{} + return globalFBC +} + +func (fbc *fakeBinlogClient) Dial(tablet *topodatapb.Tablet) error { + fbc.lastTablet = tablet + return nil +} + +func (fbc *fakeBinlogClient) Close() { +} + +func (fbc *fakeBinlogClient) StreamTables(ctx context.Context, position string, tables []string, charset *binlogdatapb.Charset) (binlogplayer.BinlogTransactionStream, error) { + fbc.lastPos = position + fbc.lastTables = tables + fbc.lastCharset = charset + return &btStream{ctx: ctx}, nil +} + +func (fbc *fakeBinlogClient) StreamKeyRange(ctx context.Context, position string, keyRange *topodatapb.KeyRange, charset *binlogdatapb.Charset) (binlogplayer.BinlogTransactionStream, error) { + fbc.lastPos = position + fbc.lastKeyRange = keyRange + fbc.lastCharset = charset + return &btStream{ctx: ctx}, nil +} + +// btStream satisfies binlogplayer.BinlogTransactionStream +type btStream struct { + ctx context.Context + sent bool +} + +func (t *btStream) Recv() (*binlogdatapb.BinlogTransaction, error) { + if !t.sent { + t.sent = true + return &binlogdatapb.BinlogTransaction{ + Statements: []*binlogdatapb.BinlogTransaction_Statement{ + { + Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, + Sql: []byte("insert into t values(1)"), + }, + }, + EventToken: &querypb.EventToken{ + Timestamp: 72, + Position: "MariaDB/0-1-1235", + }, + }, nil + } + <-t.ctx.Done() + return nil, t.ctx.Err() +} + +func expectFBCRequest(t *testing.T, fbc *fakeBinlogClient, tablet *topodatapb.Tablet, pos string, tables []string, kr *topodatapb.KeyRange) { + t.Helper() + if !proto.Equal(tablet, fbc.lastTablet) { + t.Errorf("Request tablet: %v, want %v", fbc.lastTablet, tablet) + } + if pos != fbc.lastPos { + t.Errorf("Request pos: %v, want %v", fbc.lastPos, pos) + } + if !reflect.DeepEqual(tables, fbc.lastTables) { + t.Errorf("Request tables: %v, want %v", fbc.lastTables, tables) + } + if !proto.Equal(kr, fbc.lastKeyRange) { + t.Errorf("Request KeyRange: %v, want %v", fbc.lastKeyRange, kr) + } +} + +//-------------------------------------- +// init + +// globalFBC is set by newFakeBinlogClient, which is then returned by the client factory below. +var globalFBC *fakeBinlogClient + +func init() { + tabletconn.RegisterDialer("test", func(tablet *topodatapb.Tablet, failFast grpcclient.FailFast) (queryservice.QueryService, error) { + return &fakeTabletConn{ + QueryService: fakes.ErrorQueryService, + tablet: tablet, + }, nil + }) + flag.Set("tablet_protocol", "test") + + binlogplayer.RegisterClientFactory("test", func() binlogplayer.Client { return globalFBC }) + flag.Set("binlog_player_protocol", "test") +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/planbuilder.go b/go/vt/vttablet/tabletmanager/vreplication/planbuilder.go new file mode 100644 index 00000000000..22713df9478 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/planbuilder.go @@ -0,0 +1,189 @@ +/* +Copyright 2018 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 vreplication + +import ( + "fmt" + "strconv" + + "vitess.io/vitess/go/vt/sqlparser" +) + +// plan is the plan for vreplication control statements. +type plan struct { + opcode int + query string + id int +} + +const ( + insertQuery = iota + updateQuery + deleteQuery + selectQuery +) + +// getPlan parses the input query and returns an appropriate plan. +func getPlan(query string) (*plan, error) { + stmt, err := sqlparser.Parse(query) + if err != nil { + return nil, err + } + switch stmt := stmt.(type) { + case *sqlparser.Insert: + return buildInsertPlan(stmt) + case *sqlparser.Update: + return buildUpdatePlan(stmt) + case *sqlparser.Delete: + return buildDeletePlan(stmt) + case *sqlparser.Select: + return buildSelectPlan(stmt) + default: + return nil, fmt.Errorf("unsupported construct: %s", sqlparser.String(stmt)) + } +} + +func buildInsertPlan(ins *sqlparser.Insert) (*plan, error) { + if ins.Action != sqlparser.InsertStr { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + if ins.Ignore != "" { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + if sqlparser.String(ins.Table) != "_vt.vreplication" { + return nil, fmt.Errorf("invalid table name: %v", sqlparser.String(ins.Table)) + } + if ins.Partitions != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + if ins.OnDup != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + rows, ok := ins.Rows.(sqlparser.Values) + if !ok { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + if len(rows) != 1 { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(ins)) + } + row := rows[0] + idPos := 0 + if len(ins.Columns) != 0 { + if len(ins.Columns) != len(row) { + return nil, fmt.Errorf("malformed statement: %v", sqlparser.String(ins)) + } + idPos = -1 + for i, col := range ins.Columns { + if col.EqualString("id") { + idPos = i + break + } + } + } + if idPos >= 0 { + if _, ok := row[idPos].(*sqlparser.NullVal); !ok { + return nil, fmt.Errorf("id should not have a value: %v", sqlparser.String(ins)) + } + } + return &plan{ + opcode: insertQuery, + query: sqlparser.String(ins), + }, nil +} + +func buildUpdatePlan(upd *sqlparser.Update) (*plan, error) { + if sqlparser.String(upd.TableExprs) != "_vt.vreplication" { + return nil, fmt.Errorf("invalid table name: %v", sqlparser.String(upd.TableExprs)) + } + if upd.OrderBy != nil || upd.Limit != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(upd)) + } + for _, expr := range upd.Exprs { + if expr.Name.Name.EqualString("id") { + return nil, fmt.Errorf("id cannot be changed: %v", sqlparser.String(expr)) + } + } + + id, err := extractID(upd.Where) + if err != nil { + return nil, err + } + + return &plan{ + opcode: updateQuery, + query: sqlparser.String(upd), + id: id, + }, nil +} + +func buildDeletePlan(del *sqlparser.Delete) (*plan, error) { + if del.Targets != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del)) + } + if sqlparser.String(del.TableExprs) != "_vt.vreplication" { + return nil, fmt.Errorf("invalid table name: %v", sqlparser.String(del.TableExprs)) + } + if del.Partitions != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del)) + } + if del.OrderBy != nil || del.Limit != nil { + return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del)) + } + + id, err := extractID(del.Where) + if err != nil { + return nil, err + } + + return &plan{ + opcode: deleteQuery, + query: sqlparser.String(del), + id: id, + }, nil +} + +func buildSelectPlan(sel *sqlparser.Select) (*plan, error) { + if sqlparser.String(sel.From) != "_vt.vreplication" { + return nil, fmt.Errorf("invalid table name: %v", sqlparser.String(sel.From)) + } + return &plan{ + opcode: selectQuery, + query: sqlparser.String(sel), + }, nil +} + +func extractID(where *sqlparser.Where) (int, error) { + if where == nil { + return 0, fmt.Errorf("invalid where clause:%v", sqlparser.String(where)) + } + comp, ok := where.Expr.(*sqlparser.ComparisonExpr) + if !ok { + return 0, fmt.Errorf("invalid where clause:%v", sqlparser.String(where)) + } + if sqlparser.String(comp.Left) != "id" { + return 0, fmt.Errorf("invalid where clause:%v", sqlparser.String(where)) + } + if comp.Operator != sqlparser.EqualStr { + return 0, fmt.Errorf("invalid where clause:%v", sqlparser.String(where)) + } + + id, err := strconv.Atoi(sqlparser.String(comp.Right)) + if err != nil { + return 0, fmt.Errorf("invalid where clause:%v", sqlparser.String(where)) + } + return id, nil +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/planbuilder_test.go b/go/vt/vttablet/tabletmanager/vreplication/planbuilder_test.go new file mode 100644 index 00000000000..af89c949c65 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/planbuilder_test.go @@ -0,0 +1,189 @@ +/* +Copyright 2018 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 vreplication + +import ( + "reflect" + "testing" +) + +func TestPlanBuilder(t *testing.T) { + tcases := []struct { + in string + plan *plan + err string + }{{ + // Insert + in: "insert into _vt.vreplication values(null)", + plan: &plan{ + opcode: insertQuery, + query: "insert into _vt.vreplication values (null)", + }, + }, { + in: "insert into _vt.vreplication(id) values(null)", + plan: &plan{ + opcode: insertQuery, + query: "insert into _vt.vreplication(id) values (null)", + }, + }, { + in: "insert into _vt.vreplication(workflow, id) values('', null)", + plan: &plan{ + opcode: insertQuery, + query: "insert into _vt.vreplication(workflow, id) values ('', null)", + }, + }, { + in: "replace into _vt.vreplication values(null)", + err: "unsupported construct: replace into _vt.vreplication values (null)", + }, { + in: "insert ignore into _vt.vreplication values(null)", + err: "unsupported construct: insert ignore into _vt.vreplication values (null)", + }, { + in: "insert into other values(null)", + err: "invalid table name: other", + }, { + in: "insert into _vt.vreplication partition(a) values(null)", + err: "unsupported construct: insert into _vt.vreplication partition (a) values (null)", + }, { + in: "insert into _vt.vreplication values(null) on duplicate key update id=3", + err: "unsupported construct: insert into _vt.vreplication values (null) on duplicate key update id = 3", + }, { + in: "insert into _vt.vreplication select * from a", + err: "unsupported construct: insert into _vt.vreplication select * from a", + }, { + in: "insert into _vt.vreplication values(null), (null)", + err: "unsupported construct: insert into _vt.vreplication values (null), (null)", + }, { + in: "insert into _vt.vreplication(a, b, c) values(null)", + err: "malformed statement: insert into _vt.vreplication(a, b, c) values (null)", + }, { + in: "insert into _vt.vreplication(workflow, id) values('aa', 1)", + err: "id should not have a value: insert into _vt.vreplication(workflow, id) values ('aa', 1)", + }, { + in: "insert into _vt.vreplication values(1)", + err: "id should not have a value: insert into _vt.vreplication values (1)", + + // Update + }, { + in: "update _vt.vreplication set state='Running' where id = 1", + plan: &plan{ + opcode: updateQuery, + query: "update _vt.vreplication set state = 'Running' where id = 1", + id: 1, + }, + }, { + in: "update a set state='Running' where id = 1", + err: "invalid table name: a", + }, { + in: "update _vt.vreplication set state='Running' where id = 1 order by id", + err: "unsupported construct: update _vt.vreplication set state = 'Running' where id = 1 order by id asc", + }, { + in: "update _vt.vreplication set state='Running' where id = 1 limit 1", + err: "unsupported construct: update _vt.vreplication set state = 'Running' where id = 1 limit 1", + }, { + in: "update _vt.vreplication set state='Running', id = 2 where id = 1", + err: "id cannot be changed: id = 2", + }, { + in: "update _vt.vreplication set state='Running'", + err: "invalid where clause:", + }, { + in: "update _vt.vreplication set state='Running' where a = 1 and id = 2", + err: "invalid where clause: where a = 1 and id = 2", + }, { + in: "update _vt.vreplication set state='Running' where a = 1", + err: "invalid where clause: where a = 1", + }, { + in: "update _vt.vreplication set state='Running' where id > 1", + err: "invalid where clause: where id > 1", + }, { + in: "update _vt.vreplication set state='Running' where id = 1.1", + err: "invalid where clause: where id = 1.1", + + // Delete + }, { + in: "delete from _vt.vreplication where id = 1", + plan: &plan{ + opcode: deleteQuery, + query: "delete from _vt.vreplication where id = 1", + id: 1, + }, + }, { + in: "delete from a where id = 1", + err: "invalid table name: a", + }, { + in: "delete a, b from a where id = 1", + err: "unsupported construct: delete a, b from a where id = 1", + }, { + in: "delete from _vt.vreplication where id = 1 order by id", + err: "unsupported construct: delete from _vt.vreplication where id = 1 order by id asc", + }, { + in: "delete from _vt.vreplication where id = 1 limit 1", + err: "unsupported construct: delete from _vt.vreplication where id = 1 limit 1", + }, { + in: "delete from _vt.vreplication partition (a) where id = 1 limit 1", + err: "unsupported construct: delete from _vt.vreplication partition (a) where id = 1 limit 1", + }, { + in: "delete from _vt.vreplication", + err: "invalid where clause:", + }, { + in: "delete from _vt.vreplication where a = 1 and id = 2", + err: "invalid where clause: where a = 1 and id = 2", + }, { + in: "delete from _vt.vreplication where a = 1", + err: "invalid where clause: where a = 1", + }, { + in: "delete from _vt.vreplication where id > 1", + err: "invalid where clause: where id > 1", + }, { + in: "delete from _vt.vreplication where id = 1.1", + err: "invalid where clause: where id = 1.1", + + // Select + }, { + in: "select * from _vt.vreplication where id = 1", + plan: &plan{ + opcode: selectQuery, + query: "select * from _vt.vreplication where id = 1", + }, + }, { + in: "select * from a", + err: "invalid table name: a", + + // Parser + }, { + in: "bad query", + err: "syntax error at position 4 near 'bad'", + }, { + in: "set a = 1", + err: "unsupported construct: set a = 1", + }} + for _, tcase := range tcases { + pl, err := getPlan(tcase.in) + if err != nil { + if err.Error() != tcase.err { + t.Errorf("getPlan(%v) error:\n%v, want\n%v", tcase.in, err, tcase.err) + } + continue + } + if tcase.err != "" { + t.Errorf("getPlan(%v) error:\n%v, want\n%v", tcase.in, err, tcase.err) + continue + } + if !reflect.DeepEqual(pl, tcase.plan) { + t.Errorf("getPlan(%v):\n%+v, want\n%+v", tcase.in, pl, tcase.plan) + } + } +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats.go b/go/vt/vttablet/tabletmanager/vreplication/stats.go new file mode 100644 index 00000000000..81079ffa796 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/stats.go @@ -0,0 +1,197 @@ +/* +Copyright 2018 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 vreplication + +import ( + "fmt" + "sort" + "sync" + + "vitess.io/vitess/go/stats" + "vitess.io/vitess/go/vt/servenv" +) + +var ( + globalStats = &vrStats{} +) + +func init() { + globalStats.register() +} + +// StatusSummary returns the summary status of vreplication. +func StatusSummary() (maxSecondsBehindMaster int64, binlogPlayersCount int32) { + return globalStats.maxSecondsBehindMaster(), int32(globalStats.numControllers()) +} + +// AddStatusPart adds the vreplication status to the status page. +func AddStatusPart() { + servenv.AddStatusPart("VReplication", vreplicationTemplate, func() interface{} { + return globalStats.status() + }) +} + +// vrStats exports the stats for Engine. It's a separate structure to +// prevent deadlocks with the mutex in Engine. The Engine pushes changes +// to this struct whenever there is a relevant change. +// This is a singleton. +type vrStats struct { + mu sync.Mutex + isOpen bool + controllers map[int]*controller +} + +func (st *vrStats) register() { + stats.NewGaugeFunc("VReplicationStreamCount", "Number of vreplication streams", st.numControllers) + stats.NewGaugeFunc("VReplicationSecondsBehindMasterMax", "Max vreplication seconds behind master", st.maxSecondsBehindMaster) + stats.NewCountersFuncWithMultiLabels( + "VReplicationSecondsBehindMaster", + "vreplication seconds behind master per stream", + // CAUTION: Always keep this label as "counts" because the Google + // internal monitoring depends on this specific value. + []string{"counts"}, + func() map[string]int64 { + st.mu.Lock() + defer st.mu.Unlock() + result := make(map[string]int64, len(st.controllers)) + for _, ct := range st.controllers { + result[fmt.Sprintf("%v", ct.id)] = ct.blpStats.SecondsBehindMaster.Get() + } + return result + }) + stats.Publish("VReplicationSource", stats.StringMapFunc(func() map[string]string { + st.mu.Lock() + defer st.mu.Unlock() + result := make(map[string]string, len(st.controllers)) + for _, ct := range st.controllers { + result[fmt.Sprintf("%v", ct.id)] = ct.source.Keyspace + "/" + ct.source.Shard + } + return result + })) + stats.Publish("VReplicationSourceTablet", stats.StringMapFunc(func() map[string]string { + st.mu.Lock() + defer st.mu.Unlock() + result := make(map[string]string, len(st.controllers)) + for _, ct := range st.controllers { + result[fmt.Sprintf("%v", ct.id)] = ct.sourceTablet.Get() + } + return result + })) +} + +func (st *vrStats) numControllers() int64 { + st.mu.Lock() + defer st.mu.Unlock() + return int64(len(st.controllers)) +} + +func (st *vrStats) maxSecondsBehindMaster() int64 { + st.mu.Lock() + defer st.mu.Unlock() + max := int64(0) + for _, ct := range st.controllers { + if cur := ct.blpStats.SecondsBehindMaster.Get(); cur > max { + max = cur + } + } + return max +} + +func (st *vrStats) status() *EngineStatus { + st.mu.Lock() + defer st.mu.Unlock() + + status := &EngineStatus{} + status.IsOpen = st.isOpen + + status.Controllers = make([]*ControllerStatus, len(st.controllers)) + i := 0 + for _, ct := range st.controllers { + state := "Running" + select { + case <-ct.done: + state = "Stopped" + default: + } + status.Controllers[i] = &ControllerStatus{ + Index: ct.id, + Source: ct.source.String(), + StopPosition: ct.stopPos, + LastPosition: ct.blpStats.LastPosition().String(), + SecondsBehindMaster: ct.blpStats.SecondsBehindMaster.Get(), + Counts: ct.blpStats.Timings.Counts(), + Rates: ct.blpStats.Rates.Get(), + State: state, + SourceTablet: ct.sourceTablet.Get(), + LastMessage: ct.blpStats.LastMessage.Get(), + } + i++ + } + sort.Slice(status.Controllers, func(i, j int) bool { return status.Controllers[i].Index < status.Controllers[j].Index }) + return status +} + +// EngineStatus contains a renderable status of the Engine. +type EngineStatus struct { + IsOpen bool + Controllers []*ControllerStatus +} + +// ControllerStatus contains a renderable status of a controller. +type ControllerStatus struct { + Index uint32 + Source string + SourceShard string + StopPosition string + LastPosition string + SecondsBehindMaster int64 + Counts map[string]int64 + Rates map[string][]float64 + State string + SourceTablet string + LastMessage string +} + +var vreplicationTemplate = ` +{{if .IsOpen}}VReplication state: Open
+ + + + + + + + + + + + + + {{range .Controllers}} + + + + + + + + + + + {{end}} +
IndexSourceSource TabletStateStop PositionLast PositionSeconds Behind MasterCountsRatesLast Message
{{.Index}}{{.Source}}{{.SourceTablet}}{{.State}}{{.StopPosition}}{{.LastPosition}}{{.SecondsBehindMaster}}{{range $key, $value := .Counts}}{{$key}}: {{$value}}
{{end}}
{{range $key, $values := .Rates}}{{$key}}: {{range $values}}{{.}} {{end}}
{{end}}
{{.LastMessage}}
{{else}}VReplication is closed.{{end}} +` diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats_test.go b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go new file mode 100644 index 00000000000..7c1c9975400 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go @@ -0,0 +1,115 @@ +/* +Copyright 2018 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 vreplication + +import ( + "bytes" + "html/template" + "testing" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/vt/binlog/binlogplayer" + "vitess.io/vitess/go/vt/proto/binlogdata" +) + +var wantOut = ` +VReplication state: Open
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexSourceSource TabletStateStop PositionLast PositionSeconds Behind MasterCountsRatesLast Message
1keyspace:"ks" shard:"0" src1RunningMariaDB/1-2-41-2-32All: 0
Test Message
2keyspace:"ks" shard:"1" src2StoppedMariaDB/1-2-51-2-32All: 0
Test Message
+` + +func TestStatusHtml(t *testing.T) { + pos, err := mysql.DecodePosition("MariaDB/1-2-3") + if err != nil { + t.Fatal(err) + } + + blpStats := binlogplayer.NewStats() + blpStats.SetLastPosition(pos) + blpStats.SecondsBehindMaster.Set(2) + blpStats.LastMessage.Set("Test Message") + + testStats := &vrStats{} + testStats.isOpen = true + testStats.controllers = map[int]*controller{ + 1: { + id: 1, + source: binlogdata.BinlogSource{ + Keyspace: "ks", + Shard: "0", + }, + stopPos: "MariaDB/1-2-4", + blpStats: blpStats, + done: make(chan struct{}), + }, + 2: { + id: 2, + source: binlogdata.BinlogSource{ + Keyspace: "ks", + Shard: "1", + }, + stopPos: "MariaDB/1-2-5", + blpStats: blpStats, + done: make(chan struct{}), + }, + } + testStats.controllers[1].sourceTablet.Set("src1") + testStats.controllers[2].sourceTablet.Set("src2") + close(testStats.controllers[2].done) + + tpl := template.Must(template.New("test").Parse(vreplicationTemplate)) + buf := bytes.NewBuffer(nil) + tpl.Execute(buf, testStats.status()) + if buf.String() != wantOut { + t.Errorf("output: %v, want %v", buf, wantOut) + } +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/tablet_picker.go b/go/vt/vttablet/tabletmanager/vreplication/tablet_picker.go new file mode 100644 index 00000000000..e0ac82471c4 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/tablet_picker.go @@ -0,0 +1,103 @@ +/* +Copyright 2018 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 vreplication + +import ( + "flag" + "fmt" + "math/rand" + "time" + + "golang.org/x/net/context" + + "vitess.io/vitess/go/vt/discovery" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topo/topoproto" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +var ( + healthCheckTopologyRefresh = flag.Duration("vreplication_healthcheck_topology_refresh", 30*time.Second, "refresh interval for re-reading the topology") + healthcheckRetryDelay = flag.Duration("vreplication_healthcheck_retry_delay", 5*time.Second, "delay before retrying a failed healthcheck") + healthCheckTimeout = flag.Duration("vreplication_healthcheck_timeout", time.Minute, "the health check timeout period") +) + +type tabletPicker struct { + ts *topo.Server + cell string + keyspace string + shard string + tabletTypes []topodatapb.TabletType + + healthCheck discovery.HealthCheck + watcher *discovery.TopologyWatcher + statsCache *discovery.TabletStatsCache +} + +func newTabletPicker(ts *topo.Server, cell, keyspace, shard, tabletTypesStr string) (*tabletPicker, error) { + tabletTypes, err := topoproto.ParseTabletTypes(tabletTypesStr) + if err != nil { + return nil, fmt.Errorf("failed to parse list of tablet types: %v", tabletTypesStr) + } + + // These have to be initialized in the following sequence (watcher must be last). + healthCheck := discovery.NewHealthCheck(*healthcheckRetryDelay, *healthCheckTimeout) + statsCache := discovery.NewTabletStatsCache(healthCheck, ts, cell) + watcher := discovery.NewShardReplicationWatcher(ts, healthCheck, cell, keyspace, shard, *healthCheckTopologyRefresh, discovery.DefaultTopoReadConcurrency) + + return &tabletPicker{ + ts: ts, + cell: cell, + keyspace: keyspace, + shard: shard, + tabletTypes: tabletTypes, + healthCheck: healthCheck, + watcher: watcher, + statsCache: statsCache, + }, nil +} + +func (tp *tabletPicker) Pick(ctx context.Context) (*topodatapb.Tablet, error) { + // wait for any of required the tablets (useful for the first run at least, fast for next runs) + if err := tp.statsCache.WaitForAnyTablet(ctx, tp.cell, tp.keyspace, tp.shard, tp.tabletTypes); err != nil { + return nil, fmt.Errorf("error waiting for tablets for %v %v %v: %v", tp.cell, tp.keyspace, tp.shard, err) + } + + // Find the server list from the health check. + // Note: We cannot use statsCache.GetHealthyTabletStats() here because it does + // not return non-serving tablets. We must include non-serving tablets because + // some tablets may not be serving if their traffic was already migrated to the + // destination shards. + for _, tabletType := range tp.tabletTypes { + addrs := discovery.RemoveUnhealthyTablets(tp.statsCache.GetTabletStats(tp.keyspace, tp.shard, tabletType)) + if len(addrs) > 0 { + return addrs[rand.Intn(len(addrs))].Tablet, nil + } + } + return nil, fmt.Errorf("can't find any healthy source tablet for %v %v %v", tp.keyspace, tp.shard, tp.tabletTypes) +} + +func (tp *tabletPicker) Close() { + tp.watcher.Stop() + tp.healthCheck.Close() +} + +func init() { + // TODO(sougou): consolidate this call to be once per process. + rand.Seed(time.Now().UnixNano()) +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/tablet_picker_test.go b/go/vt/vttablet/tabletmanager/vreplication/tablet_picker_test.go new file mode 100644 index 00000000000..3bbec75cb5e --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/tablet_picker_test.go @@ -0,0 +1,126 @@ +/* +Copyright 2018 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 vreplication + +import ( + "testing" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +func TestPickSimple(t *testing.T) { + ts := createTopo() + defer ts.Close() + want := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + + tp, err := newTabletPicker(ts, testCell, testKeyspace, testShard, "replica") + if err != nil { + t.Fatal(err) + } + defer tp.Close() + + tablet, err := tp.Pick(context.Background()) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(want, tablet) { + t.Errorf("Pick: %v, want %v", tablet, want) + } +} + +func TestPickFromTwoHealthy(t *testing.T) { + ts := createTopo() + defer ts.Close() + want1 := addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, true, true) + want2 := addTablet(ts, 101, "0", topodatapb.TabletType_RDONLY, true, true) + + tp, err := newTabletPicker(ts, testCell, testKeyspace, testShard, "replica,rdonly") + if err != nil { + t.Fatal(err) + } + defer tp.Close() + + tablet, err := tp.Pick(context.Background()) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(tablet, want1) { + t.Errorf("Pick:\n%v, want\n%v", tablet, want1) + } + + tp, err = newTabletPicker(ts, testCell, testKeyspace, testShard, "rdonly,replica") + if err != nil { + t.Fatal(err) + } + defer tp.Close() + + tablet, err = tp.Pick(context.Background()) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(tablet, want2) { + t.Errorf("Pick:\n%v, want\n%v", tablet, want2) + } +} + +func TestPickFromSomeUnhealthy(t *testing.T) { + ts := createTopo() + defer ts.Close() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, false, false) + want := addTablet(ts, 101, "0", topodatapb.TabletType_RDONLY, false, true) + + tp, err := newTabletPicker(ts, testCell, testKeyspace, testShard, "replica,rdonly") + if err != nil { + t.Fatal(err) + } + defer tp.Close() + + tablet, err := tp.Pick(context.Background()) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(tablet, want) { + t.Errorf("Pick:\n%v, want\n%v", tablet, want) + } +} + +func TestPickError(t *testing.T) { + ts := createTopo() + defer ts.Close() + _ = addTablet(ts, 100, "0", topodatapb.TabletType_REPLICA, false, false) + + _, err := newTabletPicker(ts, testCell, testKeyspace, testShard, "badtype") + want := "failed to parse list of tablet types: badtype" + if err == nil || err.Error() != want { + t.Errorf("newTabletPicker err: %v, want %v", err, want) + } + + tp, err := newTabletPicker(ts, testCell, testKeyspace, testShard, "replica,rdonly") + if err != nil { + t.Fatal(err) + } + defer tp.Close() + + _, err = tp.Pick(context.Background()) + want = "can't find any healthy source tablet for ks 0 [REPLICA RDONLY]" + if err == nil || err.Error() != want { + t.Errorf("Pick err: %v, want %v", err, want) + } +} diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index dfe4006a5a8..735f95ab2fe 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -126,6 +126,9 @@ type QueryEngine struct { plans *cache.LRUCache queryRuleSources *rules.Map + queryStatsMu sync.RWMutex + queryStats map[string]*QueryStats + // Pools conns *connpool.Pool streamConns *connpool.Pool @@ -182,6 +185,7 @@ func NewQueryEngine(checker connpool.MySQLChecker, se *schema.Engine, config tab plans: cache.NewLRUCache(int64(config.QueryPlanCacheSize)), queryRuleSources: rules.NewMap(), queryPoolWaiterCap: sync2.NewAtomicInt64(int64(config.QueryPoolWaiterCap)), + queryStats: make(map[string]*QueryStats), } qe.conns = connpool.New( @@ -478,53 +482,88 @@ func (qe *QueryEngine) QueryPlanCacheCap() int { return int(qe.plans.Capacity()) } +// QueryStats tracks query stats for export per planName/tableName +type QueryStats struct { + mu sync.Mutex + queryCount int64 + time time.Duration + mysqlTime time.Duration + rowCount int64 + errorCount int64 +} + +// AddStats adds the given stats for the planName.tableName +func (qe *QueryEngine) AddStats(planName, tableName string, queryCount int64, duration, mysqlTime time.Duration, rowCount, errorCount int64) { + key := tableName + "." + planName + + qe.queryStatsMu.RLock() + stats, ok := qe.queryStats[key] + qe.queryStatsMu.RUnlock() + + if !ok { + // Check again with the write lock held and + // create a new record only if none exists + qe.queryStatsMu.Lock() + if stats, ok = qe.queryStats[key]; !ok { + stats = &QueryStats{} + qe.queryStats[key] = stats + } + qe.queryStatsMu.Unlock() + } + + stats.mu.Lock() + stats.queryCount += queryCount + stats.time += duration + stats.mysqlTime += mysqlTime + stats.rowCount += rowCount + stats.errorCount += errorCount + stats.mu.Unlock() +} + func (qe *QueryEngine) getQueryCount() map[string]int64 { - f := func(plan *TabletPlan) int64 { - queryCount, _, _, _, _ := plan.Stats() - return queryCount + qstats := make(map[string]int64) + qe.queryStatsMu.RLock() + defer qe.queryStatsMu.RUnlock() + for k, qs := range qe.queryStats { + qs.mu.Lock() + qstats[k] = qs.queryCount + qs.mu.Unlock() } - return qe.getQueryStats(f) + return qstats } func (qe *QueryEngine) getQueryTime() map[string]int64 { - f := func(plan *TabletPlan) int64 { - _, time, _, _, _ := plan.Stats() - return int64(time) + qstats := make(map[string]int64) + qe.queryStatsMu.RLock() + defer qe.queryStatsMu.RUnlock() + for k, qs := range qe.queryStats { + qs.mu.Lock() + qstats[k] = int64(qs.time) + qs.mu.Unlock() } - return qe.getQueryStats(f) + return qstats } func (qe *QueryEngine) getQueryRowCount() map[string]int64 { - f := func(plan *TabletPlan) int64 { - _, _, _, rowCount, _ := plan.Stats() - return rowCount + qstats := make(map[string]int64) + qe.queryStatsMu.RLock() + defer qe.queryStatsMu.RUnlock() + for k, qs := range qe.queryStats { + qs.mu.Lock() + qstats[k] = qs.rowCount + qs.mu.Unlock() } - return qe.getQueryStats(f) + return qstats } func (qe *QueryEngine) getQueryErrorCount() map[string]int64 { - f := func(plan *TabletPlan) int64 { - _, _, _, _, errorCount := plan.Stats() - return errorCount - } - return qe.getQueryStats(f) -} - -type queryStatsFunc func(*TabletPlan) int64 - -func (qe *QueryEngine) getQueryStats(f queryStatsFunc) map[string]int64 { - keys := qe.plans.Keys() qstats := make(map[string]int64) - for _, v := range keys { - if plan := qe.peekQuery(v); plan != nil { - table := plan.TableName() - if table.IsEmpty() { - table = sqlparser.NewTableIdent("Join") - } - planType := plan.PlanID.String() - data := f(plan) - qstats[table.String()+"."+planType] += data - } + qe.queryStatsMu.RLock() + defer qe.queryStatsMu.RUnlock() + for k, qs := range qe.queryStats { + qs.mu.Lock() + qstats[k] = qs.errorCount + qs.mu.Unlock() } return qstats } @@ -589,6 +628,7 @@ func (qe *QueryEngine) handleHTTPQueryStats(response http.ResponseWriter, reques pqstats.Table = plan.TableName().String() pqstats.Plan = plan.PlanID pqstats.QueryCount, pqstats.Time, pqstats.MysqlTime, pqstats.RowCount, pqstats.ErrorCount = plan.Stats() + qstats = append(qstats, pqstats) } } diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index d983972d42d..e3c89ef4656 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -79,11 +79,19 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { tabletenv.QueryStats.Add(planName, duration) tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "Execute", int64(duration)) + mysqlTime := qre.logStats.MysqlResponseTime + tableName := qre.plan.TableName().String() + if tableName == "" { + tableName = "Join" + } + if reply == nil { - qre.plan.AddStats(1, duration, qre.logStats.MysqlResponseTime, 0, 1) + qre.tsv.qe.AddStats(planName, tableName, 1, duration, mysqlTime, 0, 1) + qre.plan.AddStats(1, duration, mysqlTime, 0, 1) return } - qre.plan.AddStats(1, duration, qre.logStats.MysqlResponseTime, int64(reply.RowsAffected), 0) + qre.tsv.qe.AddStats(planName, tableName, 1, duration, mysqlTime, int64(reply.RowsAffected), 0) + qre.plan.AddStats(1, duration, mysqlTime, int64(reply.RowsAffected), 0) qre.logStats.RowsAffected = int(reply.RowsAffected) qre.logStats.Rows = reply.Rows tabletenv.ResultStats.Add(int64(len(reply.Rows))) diff --git a/go/vt/vttablet/tabletserver/tabletenv/logstats.go b/go/vt/vttablet/tabletserver/tabletenv/logstats.go index 8f2000a3458..d95cf046135 100644 --- a/go/vt/vttablet/tabletserver/tabletenv/logstats.go +++ b/go/vt/vttablet/tabletserver/tabletenv/logstats.go @@ -17,9 +17,9 @@ limitations under the License. package tabletenv import ( - "bytes" "fmt" "html/template" + "io" "net/url" "strings" "time" @@ -133,58 +133,6 @@ func (stats *LogStats) SizeOfResponse() int { return size } -// FmtBindVariables returns the map of bind variables as a string or a json -// string depending on the streamlog.QueryLogFormat value. If RedactDebugUIQueries -// is true then this returns the string "[REDACTED]" -// -// For values that are strings or byte slices it only reports their type -// and length unless full is true. -func (stats *LogStats) FmtBindVariables(full bool) string { - if *streamlog.RedactDebugUIQueries { - return "\"[REDACTED]\"" - } - - var out map[string]*querypb.BindVariable - if full { - out = stats.BindVariables - } else { - // NOTE(szopa): I am getting rid of potentially large bind - // variables. - out = make(map[string]*querypb.BindVariable) - for k, v := range stats.BindVariables { - if sqltypes.IsIntegral(v.Type) || sqltypes.IsFloat(v.Type) { - out[k] = v - } else if v.Type == querypb.Type_TUPLE { - out[k] = sqltypes.StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) - } else { - out[k] = sqltypes.StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) - } - } - } - - if *streamlog.QueryLogFormat == streamlog.QueryLogFormatJSON { - var buf bytes.Buffer - buf.WriteString("{") - first := true - for k, v := range out { - if !first { - buf.WriteString(", ") - } else { - first = false - } - if sqltypes.IsIntegral(v.Type) || sqltypes.IsFloat(v.Type) { - fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) - } else { - fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) - } - } - buf.WriteString("}") - return buf.String() - } - - return fmt.Sprintf("%v", out) -} - // FmtQuerySources returns a comma separated list of query // sources. If there were no query sources, it returns the string // "none". @@ -229,15 +177,22 @@ func (stats *LogStats) RemoteAddrUsername() (string, string) { return ci.RemoteAddr(), ci.Username() } -// Format returns a tab separated list of logged fields. -func (stats *LogStats) Format(params url.Values) string { +// Logf formats the log record to the given writer, either as +// tab-separated list of logged fields or as JSON. +func (stats *LogStats) Logf(w io.Writer, params url.Values) error { rewrittenSQL := "[REDACTED]" + formattedBindVars := "\"[REDACTED]\"" + if !*streamlog.RedactDebugUIQueries { rewrittenSQL = stats.RewrittenSQL() - } - _, fullBindParams := params["full"] - formattedBindVars := stats.FmtBindVariables(fullBindParams) + _, fullBindParams := params["full"] + formattedBindVars = sqltypes.FormatBindVariables( + stats.BindVariables, + fullBindParams, + *streamlog.QueryLogFormat == streamlog.QueryLogFormatJSON, + ) + } // TODO: remove username here we fully enforce immediate caller id remoteAddr, username := stats.RemoteAddrUsername() @@ -251,7 +206,8 @@ func (stats *LogStats) Format(params url.Values) string { fmtString = "{\"Method\": %q, \"RemoteAddr\": %q, \"Username\": %q, \"ImmediateCaller\": %q, \"Effective Caller\": %q, \"Start\": \"%v\", \"End\": \"%v\", \"TotalTime\": %.6f, \"PlanType\": %q, \"OriginalSQL\": %q, \"BindVars\": %v, \"Queries\": %v, \"RewrittenSQL\": %q, \"QuerySources\": %q, \"MysqlTime\": %.6f, \"ConnWaitTime\": %.6f, \"RowsAffected\": %v, \"ResponseSize\": %v, \"Error\": %q}\n" } - return fmt.Sprintf( + _, err := fmt.Fprintf( + w, fmtString, stats.Method, remoteAddr, @@ -273,4 +229,5 @@ func (stats *LogStats) Format(params url.Values) string { stats.SizeOfResponse(), stats.ErrorStr(), ) + return err } diff --git a/go/vt/vttablet/tabletserver/tabletenv/logstats_test.go b/go/vt/vttablet/tabletserver/tabletenv/logstats_test.go index fe51d1d2126..4b33f4fe424 100644 --- a/go/vt/vttablet/tabletserver/tabletenv/logstats_test.go +++ b/go/vt/vttablet/tabletserver/tabletenv/logstats_test.go @@ -17,6 +17,7 @@ limitations under the License. package tabletenv import ( + "bytes" "encoding/json" "errors" "net/url" @@ -49,10 +50,12 @@ func TestLogStats(t *testing.T) { if logStats.SizeOfResponse() <= 0 { t.Fatalf("log stats has some rows, should have positive response size") } +} - params := map[string][]string{"full": {}} - - logStats.Format(url.Values(params)) +func testFormat(stats *LogStats, params url.Values) string { + var b bytes.Buffer + stats.Logf(&b, params) + return b.String() } func TestLogStatsFormat(t *testing.T) { @@ -68,7 +71,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = false *streamlog.QueryLogFormat = "text" - got := logStats.Format(url.Values(params)) + got := testFormat(logStats, url.Values(params)) want := "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t\t\"sql\"\tmap[intVal:type:INT64 value:\"1\" ]\t1\t\"sql with pii\"\tmysql\t0.000000\t0.000000\t0\t1\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) @@ -76,7 +79,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = true *streamlog.QueryLogFormat = "text" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t\t\"sql\"\t\"[REDACTED]\"\t1\t\"[REDACTED]\"\tmysql\t0.000000\t0.000000\t0\t1\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) @@ -84,7 +87,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = false *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) var parsed map[string]interface{} err := json.Unmarshal([]byte(got), &parsed) if err != nil { @@ -101,7 +104,7 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.RedactDebugUIQueries = true *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) err = json.Unmarshal([]byte(got), &parsed) if err != nil { t.Errorf("logstats format: error unmarshaling json: %v -- got:\n%v", err, got) @@ -122,14 +125,14 @@ func TestLogStatsFormat(t *testing.T) { logStats.BindVariables = map[string]*querypb.BindVariable{"strVal": sqltypes.StringBindVariable("abc")} *streamlog.QueryLogFormat = "text" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) want = "test\t\t\t''\t''\t2017-01-01 01:02:03.000000\t2017-01-01 01:02:04.000001\t1.000001\t\t\"sql\"\tmap[strVal:type:VARCHAR value:\"abc\" ]\t1\t\"sql with pii\"\tmysql\t0.000000\t0.000000\t0\t1\t\"\"\t\n" if got != want { t.Errorf("logstats format: got:\n%q\nwant:\n%q\n", got, want) } *streamlog.QueryLogFormat = "json" - got = logStats.Format(url.Values(params)) + got = testFormat(logStats, url.Values(params)) err = json.Unmarshal([]byte(got), &parsed) if err != nil { t.Errorf("logstats format: error unmarshaling json: %v -- got:\n%v", err, got) @@ -146,53 +149,6 @@ func TestLogStatsFormat(t *testing.T) { *streamlog.QueryLogFormat = "text" } -func TestLogStatsFormatBindVariables(t *testing.T) { - tupleBindVar, err := sqltypes.BuildBindVariable([]int64{1, 2}) - if err != nil { - t.Fatalf("failed to create a tuple bind var: %v", err) - } - - logStats := NewLogStats(context.Background(), "test") - logStats.BindVariables = map[string]*querypb.BindVariable{ - "key_1": sqltypes.StringBindVariable("val_1"), - "key_2": sqltypes.Int64BindVariable(789), - "key_3": sqltypes.BytesBindVariable([]byte("val_3")), - "key_4": tupleBindVar, - } - - formattedStr := logStats.FmtBindVariables(true) - if !strings.Contains(formattedStr, "key_1") || - !strings.Contains(formattedStr, "val_1") { - t.Fatalf("bind variable 'key_1': 'val_1' is not formatted") - } - if !strings.Contains(formattedStr, "key_2") || - !strings.Contains(formattedStr, "789") { - t.Fatalf("bind variable 'key_2': '789' is not formatted") - } - if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "val_3") { - t.Fatalf("bind variable 'key_3': 'val_3' is not formatted") - } - if !strings.Contains(formattedStr, "key_4") || - !strings.Contains(formattedStr, "values: values:") { - t.Fatalf("bind variable 'key_4': (1, 2) is not formatted") - } - - formattedStr = logStats.FmtBindVariables(false) - if !strings.Contains(formattedStr, "key_1") { - t.Fatalf("bind variable 'key_1' is not formatted") - } - if !strings.Contains(formattedStr, "key_2") || - !strings.Contains(formattedStr, "789") { - t.Fatalf("bind variable 'key_2': '789' is not formatted") - } - if !strings.Contains(formattedStr, "key_3") || !strings.Contains(formattedStr, "5 bytes") { - t.Fatalf("bind variable 'key_3' is not formatted") - } - if !strings.Contains(formattedStr, "key_4") || !strings.Contains(formattedStr, "2 items") { - t.Fatalf("bind variable 'key_4' is not formatted") - } -} - func TestLogStatsFormatQuerySources(t *testing.T) { logStats := NewLogStats(context.Background(), "test") if logStats.FmtQuerySources() != "none" { diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index 1441cb0f981..2ae3ca6ac82 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -21,9 +21,12 @@ import ( "fmt" "io" "net/http" + "os" + "os/signal" "sort" "strings" "sync" + "syscall" "time" "golang.org/x/net/context" @@ -43,6 +46,7 @@ import ( "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/tableacl" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/heartbeat" @@ -326,7 +330,7 @@ func (tsv *TabletServer) IsServing() bool { return tsv.GetState() == "SERVING" } -// InitDBConfig inititalizes the db config variables for TabletServer. You must call this function before +// InitDBConfig initializes the db config variables for TabletServer. You must call this function before // calling SetServingType. func (tsv *TabletServer) InitDBConfig(target querypb.Target, dbcfgs *dbconfigs.DBConfigs) error { tsv.mu.Lock() @@ -347,6 +351,36 @@ func (tsv *TabletServer) InitDBConfig(target querypb.Target, dbcfgs *dbconfigs.D return nil } +func (tsv *TabletServer) initACL(tableACLConfigFile string, enforceTableACLConfig bool) { + // tabletacl.Init loads ACL from file if *tableACLConfig is not empty + err := tableacl.Init( + tableACLConfigFile, + func() { + tsv.ClearQueryPlanCache() + }, + ) + if err != nil { + log.Errorf("Fail to initialize Table ACL: %v", err) + if enforceTableACLConfig { + log.Exit("Need a valid initial Table ACL when enforce-tableacl-config is set, exiting.") + } + } +} + +// InitACL loads the table ACL and sets up a SIGHUP handler for reloading it. +func (tsv *TabletServer) InitACL(tableACLConfigFile string, enforceTableACLConfig bool) { + tsv.initACL(tableACLConfigFile, enforceTableACLConfig) + + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGHUP) + go func() { + for { + <-sigChan + tsv.initACL(tableACLConfigFile, enforceTableACLConfig) + } + }() +} + // StartService is a convenience function for InitDBConfig->SetServingType // with serving=true. func (tsv *TabletServer) StartService(target querypb.Target, dbcfgs *dbconfigs.DBConfigs) (err error) { diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index 4e8085482ef..fa89040de35 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -20,11 +20,14 @@ import ( "expvar" "fmt" "io" + "io/ioutil" "math/rand" + "os" "reflect" "strconv" "strings" "sync" + "syscall" "testing" "time" @@ -36,6 +39,8 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/tableacl" + "vitess.io/vitess/go/vt/tableacl/simpleacl" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -2719,6 +2724,79 @@ func TestTerseErrorsIgnoreFailoverInProgress(t *testing.T) { } } +var aclJSON1 = `{ + "table_groups": [ + { + "name": "group01", + "table_names_or_prefixes": ["test_table1"], + "readers": ["vt1"], + "writers": ["vt1"] + } + ] +}` +var aclJSON2 = `{ + "table_groups": [ + { + "name": "group02", + "table_names_or_prefixes": ["test_table2"], + "readers": ["vt2"], + "admins": ["vt2"] + } + ] +}` + +func TestACLHUP(t *testing.T) { + tableacl.Register("simpleacl", &simpleacl.Factory{}) + testUtils := newTestUtils() + config := testUtils.newQueryServiceConfig() + tsv := NewTabletServerWithNilTopoServer(config) + + f, err := ioutil.TempFile("", "tableacl") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + + if _, err := io.WriteString(f, aclJSON1); err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Fatal(err) + } + + tsv.InitACL(f.Name(), true) + + groups1 := tableacl.GetCurrentConfig().TableGroups + if name1 := groups1[0].GetName(); name1 != "group01" { + t.Fatalf("Expected name 'group01', got '%s'", name1) + } + + if f, err = os.Create(f.Name()); err != nil { + t.Fatal(err) + } + if _, err = io.WriteString(f, aclJSON2); err != nil { + t.Fatal(err) + } + + syscall.Kill(syscall.Getpid(), syscall.SIGHUP) + time.Sleep(25 * time.Millisecond) // wait for signal handler + + groups2 := tableacl.GetCurrentConfig().TableGroups + if len(groups2) != 1 { + t.Fatalf("Expected only one table group") + } + group2 := groups2[0] + if name2 := group2.GetName(); name2 != "group02" { + t.Fatalf("Expected name 'group02', got '%s'", name2) + } + if group2.GetAdmins() == nil { + t.Fatalf("Expected 'admins' to exist, but it didn't") + } + if group2.GetWriters() != nil { + t.Fatalf("Expected 'writers' to not exist, got '%s'", group2.GetWriters()) + } +} + func TestConfigChanges(t *testing.T) { db := setUpTabletServerTest(t) defer db.Close() diff --git a/go/vt/vttablet/tmclient/rpc_client_api.go b/go/vt/vttablet/tmclient/rpc_client_api.go index 628d3e0987d..d02115afb40 100644 --- a/go/vt/vttablet/tmclient/rpc_client_api.go +++ b/go/vt/vttablet/tmclient/rpc_client_api.go @@ -21,6 +21,7 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -132,20 +133,9 @@ type TabletManagerClient interface { // GetSlaves returns the addresses of the slaves GetSlaves(ctx context.Context, tablet *topodatapb.Tablet) ([]string, error) - // WaitBlpPosition asks the tablet to wait until it reaches that - // position in replication - WaitBlpPosition(ctx context.Context, tablet *topodatapb.Tablet, blpPosition *tabletmanagerdatapb.BlpPosition, waitTime time.Duration) error - - // StopBlp asks the tablet to stop all its binlog players, - // and returns the current position for all of them - StopBlp(ctx context.Context, tablet *topodatapb.Tablet) ([]*tabletmanagerdatapb.BlpPosition, error) - - // StartBlp asks the tablet to restart its binlog players - StartBlp(ctx context.Context, tablet *topodatapb.Tablet) error - - // RunBlpUntil asks the tablet to restart its binlog players until - // it reaches the given positions, if not there yet. - RunBlpUntil(ctx context.Context, tablet *topodatapb.Tablet, positions []*tabletmanagerdatapb.BlpPosition, waitTime time.Duration) (string, error) + // VReplicationExec executes a VReplication command + VReplicationExec(ctx context.Context, tablet *topodatapb.Tablet, query string) (*querypb.QueryResult, error) + VReplicationWaitForPos(ctx context.Context, tablet *topodatapb.Tablet, id int, pos string) error // // Reparenting related functions diff --git a/go/vt/worker/clone_utils.go b/go/vt/worker/clone_utils.go index e5c9d5c0766..1107116222c 100644 --- a/go/vt/worker/clone_utils.go +++ b/go/vt/worker/clone_utils.go @@ -18,79 +18,20 @@ package worker import ( "bytes" - "fmt" "regexp" - "text/template" - "time" - - "golang.org/x/net/context" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/vt/discovery" - "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/wrangler" querypb "vitess.io/vitess/go/vt/proto/query" - topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) // // This file contains utility functions for clone workers. // -// Does a topo lookup for a single shard, and returns: -// 1. Slice of all tablet aliases for the shard. -// 2. Map of tablet alias : tablet record for all tablets. -func resolveRefreshTabletsForShard(ctx context.Context, keyspace, shard string, wr *wrangler.Wrangler) (refreshAliases []*topodatapb.TabletAlias, refreshTablets map[string]*topo.TabletInfo, err error) { - // Keep a long timeout, because we really don't want the copying to succeed, and then the worker to fail at the end. - shortCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) - refreshAliases, err = wr.TopoServer().FindAllTabletAliasesInShard(shortCtx, keyspace, shard) - cancel() - if err != nil { - return nil, nil, fmt.Errorf("cannot find all refresh target tablets in %v/%v: %v", keyspace, shard, err) - } - wr.Logger().Infof("Found %v refresh target aliases in shard %v/%v", len(refreshAliases), keyspace, shard) - - shortCtx, cancel = context.WithTimeout(ctx, 5*time.Minute) - refreshTablets, err = wr.TopoServer().GetTabletMap(shortCtx, refreshAliases) - cancel() - if err != nil { - return nil, nil, fmt.Errorf("cannot read all refresh target tablets in %v/%v: %v", - keyspace, shard, err) - } - return refreshAliases, refreshTablets, nil -} - var errExtract = regexp.MustCompile(`\(errno (\d+)\)`) -// fillStringTemplate returns the string template filled -func fillStringTemplate(tmpl string, vars interface{}) (string, error) { - myTemplate := template.Must(template.New("").Parse(tmpl)) - data := new(bytes.Buffer) - if err := myTemplate.Execute(data, vars); err != nil { - return "", err - } - return data.String(), nil -} - -// runSQLCommands will send the sql commands to the remote tablet. -func runSQLCommands(ctx context.Context, wr *wrangler.Wrangler, tsc *discovery.TabletStatsCache, keyspace, shard, dbName string, commands []string) error { - for _, command := range commands { - command, err := fillStringTemplate(command, map[string]string{"DatabaseName": dbName}) - if err != nil { - return fmt.Errorf("fillStringTemplate failed: %v", err) - } - - executor := newExecutor(wr, tsc, nil /* throttler */, keyspace, shard, 0 /* threadID */) - if err := executor.fetchWithRetries(ctx, command); err != nil { - return err - } - } - - return nil -} - // makeValueString returns a string that contains all the passed-in rows // as an insert SQL command's parameters. func makeValueString(fields []*querypb.Field, rows [][]sqltypes.Value) string { diff --git a/go/vt/worker/events/split.go b/go/vt/worker/events/split.go index 8c93fe4c85a..2f8d8d66feb 100644 --- a/go/vt/worker/events/split.go +++ b/go/vt/worker/events/split.go @@ -25,7 +25,6 @@ type SplitClone struct { Keyspace, Shard, Cell string ExcludeTables []string - Strategy string } // VerticalSplitClone is an event that describes a single step in a vertical @@ -35,5 +34,4 @@ type VerticalSplitClone struct { Keyspace, Shard, Cell string Tables []string - Strategy string } diff --git a/go/vt/worker/executor.go b/go/vt/worker/executor.go index 305a7133759..2018cccef79 100644 --- a/go/vt/worker/executor.go +++ b/go/vt/worker/executor.go @@ -21,11 +21,13 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/throttler" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/wrangler" + querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -34,6 +36,7 @@ import ( // To-be-written data will be passed in through a channel. // The main purpose of this struct is to aggregate the objects which won't // change during the execution and remove them from method signatures. +// executor is also used for executing vreplication and RefreshState commands. type executor struct { wr *wrangler.Wrangler tsc *discovery.TabletStatsCache @@ -68,7 +71,10 @@ func (e *executor) fetchLoop(ctx context.Context, insertChannel chan string) err // no more to read, we're done return nil } - if err := e.fetchWithRetries(ctx, cmd); err != nil { + if err := e.fetchWithRetries(ctx, func(ctx context.Context, tablet *topodatapb.Tablet) error { + _, err := e.wr.TabletManagerClient().ExecuteFetchAsApp(ctx, tablet, true, []byte(cmd), 0) + return err + }); err != nil { return fmt.Errorf("ExecuteFetch failed: %v", err) } case <-ctx.Done(): @@ -80,6 +86,25 @@ func (e *executor) fetchLoop(ctx context.Context, insertChannel chan string) err } } +func (e *executor) vreplicationExec(ctx context.Context, cmd string) (qr *sqltypes.Result, err error) { + var result *querypb.QueryResult + err = e.fetchWithRetries(ctx, func(ctx context.Context, tablet *topodatapb.Tablet) error { + var err error + result, err = e.wr.TabletManagerClient().VReplicationExec(ctx, tablet, cmd) + return err + }) + if err != nil { + return nil, err + } + return sqltypes.Proto3ToResult(result), err +} + +func (e *executor) refreshState(ctx context.Context) error { + return e.fetchWithRetries(ctx, func(ctx context.Context, tablet *topodatapb.Tablet) error { + return e.wr.TabletManagerClient().RefreshState(ctx, tablet) + }) +} + // fetchWithRetries will attempt to run ExecuteFetch for a single command, with // a reasonably small timeout. // If will keep retrying the ExecuteFetch (for a finite but longer duration) if @@ -87,7 +112,7 @@ func (e *executor) fetchLoop(ctx context.Context, insertChannel chan string) err // // executeFetchWithRetries will always get the current MASTER tablet from the // TabletStatsCache instance. If no MASTER is available, it will keep retrying. -func (e *executor) fetchWithRetries(ctx context.Context, command string) error { +func (e *executor) fetchWithRetries(ctx context.Context, action func(ctx context.Context, tablet *topodatapb.Tablet) error) error { retryDuration := *retryDuration // We should keep retrying up until the retryCtx runs out. retryCtx, retryCancel := context.WithTimeout(ctx, retryDuration) @@ -124,7 +149,7 @@ func (e *executor) fetchWithRetries(ctx context.Context, command string) error { // new variables until the label is reached.) { tryCtx, cancel := context.WithTimeout(retryCtx, 2*time.Minute) - _, err = e.wr.TabletManagerClient().ExecuteFetchAsApp(tryCtx, master.Tablet, true, []byte(command), 0) + err = action(tryCtx, master.Tablet) cancel() if err == nil { @@ -155,7 +180,7 @@ func (e *executor) fetchWithRetries(ctx context.Context, command string) error { if retryCtx.Err() == context.DeadlineExceeded { return fmt.Errorf("failed to connect to destination tablet %v after retrying for %v", tabletString, retryDuration) } - return fmt.Errorf("interrupted (context error: %v) while trying to run %v on tablet %v", retryCtx.Err(), command, tabletString) + return fmt.Errorf("interrupted (context error: %v) while trying to run a command on tablet %v", retryCtx.Err(), tabletString) case <-time.After(*executeFetchRetryTime): // Retry 30s after the failure using the current master seen by the HealthCheck. } diff --git a/go/vt/worker/legacy_split_clone.go b/go/vt/worker/legacy_split_clone.go index 326cb42a9a2..df6c0dbc2f2 100644 --- a/go/vt/worker/legacy_split_clone.go +++ b/go/vt/worker/legacy_split_clone.go @@ -42,6 +42,7 @@ import ( "vitess.io/vitess/go/vt/worker/events" "vitess.io/vitess/go/vt/wrangler" + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -56,7 +57,6 @@ type LegacySplitCloneWorker struct { keyspace string shard string excludeTables []string - strategy *splitStrategy sourceReaderCount int destinationPackCount int destinationWriterCount int @@ -92,20 +92,12 @@ type LegacySplitCloneWorker struct { // populated during WorkerStateCopy // tableStatusList holds the status for each table. tableStatusList tableStatusList - // aliases of tablets that need to have their state refreshed. - // Only populated once, read-only after that. - refreshAliases [][]*topodatapb.TabletAlias - refreshTablets []map[string]*topo.TabletInfo ev *events.SplitClone } // NewLegacySplitCloneWorker returns a new LegacySplitCloneWorker object. -func NewLegacySplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, excludeTables []string, strategyStr string, sourceReaderCount, destinationPackCount, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS int64) (Worker, error) { - strategy, err := newSplitStrategy(wr.Logger(), strategyStr) - if err != nil { - return nil, err - } +func NewLegacySplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, excludeTables []string, sourceReaderCount, destinationPackCount, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS int64) (Worker, error) { if maxTPS != throttler.MaxRateModuleDisabled { wr.Logger().Infof("throttling enabled and set to a max of %v transactions/second", maxTPS) } @@ -119,7 +111,6 @@ func NewLegacySplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard stri keyspace: keyspace, shard: shard, excludeTables: excludeTables, - strategy: strategy, sourceReaderCount: sourceReaderCount, destinationPackCount: destinationPackCount, destinationWriterCount: destinationWriterCount, @@ -135,7 +126,6 @@ func NewLegacySplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard stri Keyspace: keyspace, Shard: shard, ExcludeTables: excludeTables, - Strategy: strategy.String(), }, }, nil } @@ -406,9 +396,6 @@ func (scw *LegacySplitCloneWorker) findTargets(ctx context.Context) error { keyspaceAndShard := topoproto.KeyspaceShardString(si.Keyspace(), si.ShardName()) scw.destinationDbNames[keyspaceAndShard] = ti.DbName() - // TODO(mberlin): Verify on the destination master that the - // _vt.blp_checkpoint table has the latest schema. - scw.wr.Logger().Infof("Using tablet %v as destination master for %v/%v", topoproto.TabletAliasString(master.Tablet.Alias), si.Keyspace(), si.ShardName()) } scw.wr.Logger().Infof("NOTE: The used master of a destination shard might change over the course of the copy e.g. due to a reparent. The HealthCheck module will track and log master changes and any error message will always refer the actually used master address.") @@ -427,23 +414,6 @@ func (scw *LegacySplitCloneWorker) findTargets(ctx context.Context) error { return nil } -// Find all tablets on all destination shards. This should be done immediately before refreshing -// state on these tablets, to minimize the chances of the topo changing in between. -func (scw *LegacySplitCloneWorker) findRefreshTargets(ctx context.Context) error { - scw.refreshAliases = make([][]*topodatapb.TabletAlias, len(scw.destinationShards)) - scw.refreshTablets = make([]map[string]*topo.TabletInfo, len(scw.destinationShards)) - - for shardIndex, si := range scw.destinationShards { - refreshAliases, refreshTablets, err := resolveRefreshTabletsForShard(ctx, si.Keyspace(), si.ShardName(), scw.wr) - if err != nil { - return err - } - scw.refreshAliases[shardIndex], scw.refreshTablets[shardIndex] = refreshAliases, refreshTablets - } - - return nil -} - // copy phase: // - copy the data from source tablets to destination masters (with replication on) // Assumes that the schema has already been created on each destination tablet @@ -609,85 +579,47 @@ func (scw *LegacySplitCloneWorker) copy(ctx context.Context) error { return firstError } - // then create and populate the blp_checkpoint table - if scw.strategy.skipPopulateBlpCheckpoint { - scw.wr.Logger().Infof("Skipping populating the blp_checkpoint table") - } else { - queries := make([]string, 0, 4) - queries = append(queries, binlogplayer.CreateBlpCheckpoint()...) - flags := "" - if scw.strategy.dontStartBinlogPlayer { - flags = binlogplayer.BlpFlagDontStart - } - - // get the current position from the sources - for shardIndex := range scw.sourceShards { - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - status, err := scw.wr.TabletManagerClient().SlaveStatus(shortCtx, scw.sourceTablets[shardIndex]) - cancel() - if err != nil { - return err - } - - queries = append(queries, binlogplayer.PopulateBlpCheckpoint(uint32(shardIndex), status.Position, scw.maxTPS, throttler.ReplicationLagModuleDisabled, time.Now().Unix(), flags)) - } - - for _, si := range scw.destinationShards { - destinationWaitGroup.Add(1) - go func(keyspace, shard string) { - defer destinationWaitGroup.Done() - scw.wr.Logger().Infof("Making and populating blp_checkpoint table") - keyspaceAndShard := topoproto.KeyspaceShardString(keyspace, shard) - if err := runSQLCommands(ctx, scw.wr, scw.tsc, keyspace, shard, scw.destinationDbNames[keyspaceAndShard], queries); err != nil { - processError("blp_checkpoint queries failed: %v", err) - } - }(si.Keyspace(), si.ShardName()) - } - destinationWaitGroup.Wait() - if firstError != nil { - return firstError - } - } - - // Now we're done with data copy, update the shard's source info. - // TODO(alainjobart) this is a superset, some shards may not - // overlap, have to deal with this better (for N -> M splits - // where both N>1 and M>1) - if scw.strategy.skipSetSourceShards { - scw.wr.Logger().Infof("Skipping setting SourceShard on destination shards.") - } else { - for _, si := range scw.destinationShards { - scw.wr.Logger().Infof("Setting SourceShard on shard %v/%v", si.Keyspace(), si.ShardName()) - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - err := scw.wr.SetSourceShards(shortCtx, si.Keyspace(), si.ShardName(), scw.sourceAliases, nil) - cancel() - if err != nil { - return fmt.Errorf("failed to set source shards: %v", err) - } + sourcePositions := make([]string, len(scw.sourceShards)) + // get the current position from the sources + for shardIndex := range scw.sourceShards { + shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + status, err := scw.wr.TabletManagerClient().SlaveStatus(shortCtx, scw.sourceTablets[shardIndex]) + cancel() + if err != nil { + return err } + sourcePositions[shardIndex] = status.Position } - err = scw.findRefreshTargets(ctx) - if err != nil { - return fmt.Errorf("failed before refreshing state on destination tablets: %v", err) - } - // And force a state refresh (re-read topo) on all destination tablets. - // The master tablet will end up starting filtered replication - // at this point. - for shardIndex := range scw.destinationShards { - for _, tabletAlias := range scw.refreshAliases[shardIndex] { - destinationWaitGroup.Add(1) - go func(ti *topo.TabletInfo) { - defer destinationWaitGroup.Done() - scw.wr.Logger().Infof("Refreshing state on tablet %v", ti.AliasString()) - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - err := scw.wr.TabletManagerClient().RefreshState(shortCtx, ti.Tablet) - cancel() + for _, si := range scw.destinationShards { + destinationWaitGroup.Add(1) + go func(keyspace, shard string, kr *topodatapb.KeyRange) { + defer destinationWaitGroup.Done() + scw.wr.Logger().Infof("Making and populating vreplication table") + + exc := newExecutor(scw.wr, scw.tsc, nil, keyspace, shard, 0) + for shardIndex, src := range scw.sourceShards { + bls := &binlogdatapb.BinlogSource{ + Keyspace: src.Keyspace(), + Shard: src.ShardName(), + KeyRange: kr, + } + qr, err := exc.vreplicationExec(ctx, binlogplayer.CreateVReplication("LegacySplitClone", bls, sourcePositions[shardIndex], scw.maxTPS, throttler.ReplicationLagModuleDisabled, time.Now().Unix())) if err != nil { - processError("RefreshState failed on tablet %v: %v", ti.AliasString(), err) + processError("vreplication queries failed: %v", err) + break } - }(scw.refreshTablets[shardIndex][topoproto.TabletAliasString(tabletAlias)]) - } + if err := scw.wr.SourceShardAdd(ctx, keyspace, shard, uint32(qr.InsertID), src.Keyspace(), src.ShardName(), src.Shard.KeyRange, nil); err != nil { + processError("could not add source shard: %v", err) + break + } + } + // refreshState will cause the destination to become non-serving because + // it's now participating in the resharding workflow. + if err := exc.refreshState(ctx); err != nil { + processError("RefreshState failed on tablet %v/%v: %v", keyspace, shard, err) + } + }(si.Keyspace(), si.ShardName(), si.KeyRange) } destinationWaitGroup.Wait() return firstError diff --git a/go/vt/worker/legacy_split_clone_cmd.go b/go/vt/worker/legacy_split_clone_cmd.go index dfae46f17da..8abfcd630b2 100644 --- a/go/vt/worker/legacy_split_clone_cmd.go +++ b/go/vt/worker/legacy_split_clone_cmd.go @@ -65,8 +65,6 @@ const legacySplitCloneHTML2 = `

- -

@@ -81,14 +79,6 @@ const legacySplitCloneHTML2 = `
- -

Help

-

Strategy can have the following values, comma separated:

-
    -
  • skipPopulateBlpCheckpoint: skips creating (if necessary) and populating the blp_checkpoint table in the destination. Not skipped by default because it's required for filtered replication to start.
  • -
  • dontStartBinlogPlayer: (requires skipPopulateBlpCheckpoint to be false) will setup, but not start binlog replication on the destination. The flag has to be manually cleared from the _vt.blp_checkpoint table.
  • -
  • skipSetSourceShards: we won't set SourceShards on the destination shards, disabling filtered replication. Useful for worker tests.
  • -
` @@ -97,7 +87,6 @@ var legacySplitCloneTemplate2 = mustParseTemplate("splitClone2", legacySplitClon func commandLegacySplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) (Worker, error) { excludeTables := subFlags.String("exclude_tables", "", "comma separated list of tables to exclude. Each is either an exact match, or a regular expression of the form /regexp/") - strategy := subFlags.String("strategy", "", "which strategy to use for restore, use 'vtworker LegacySplitClone --strategy=-help k/s' for more info") sourceReaderCount := subFlags.Int("source_reader_count", defaultSourceReaderCount, "number of concurrent streaming queries to use on the source") destinationPackCount := subFlags.Int("destination_pack_count", defaultDestinationPackCount, "number of packets to pack in one destination insert") destinationWriterCount := subFlags.Int("destination_writer_count", defaultDestinationWriterCount, "number of concurrent RPCs to execute on the destination") @@ -119,7 +108,7 @@ func commandLegacySplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *flag if *excludeTables != "" { excludeTableArray = strings.Split(*excludeTables, ",") } - worker, err := NewLegacySplitCloneWorker(wr, wi.cell, keyspace, shard, excludeTableArray, *strategy, *sourceReaderCount, *destinationPackCount, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS) + worker, err := NewLegacySplitCloneWorker(wr, wi.cell, keyspace, shard, excludeTableArray, *sourceReaderCount, *destinationPackCount, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS) if err != nil { return nil, fmt.Errorf("cannot create split clone worker: %v", err) } @@ -167,7 +156,6 @@ func interactiveLegacySplitClone(ctx context.Context, wi *Instance, wr *wrangler if excludeTables != "" { excludeTableArray = strings.Split(excludeTables, ",") } - strategy := r.FormValue("strategy") sourceReaderCount, err := strconv.ParseInt(sourceReaderCountStr, 0, 64) if err != nil { return nil, nil, nil, fmt.Errorf("cannot parse sourceReaderCount: %s", err) @@ -193,7 +181,7 @@ func interactiveLegacySplitClone(ctx context.Context, wi *Instance, wr *wrangler } // start the clone job - wrk, err := NewLegacySplitCloneWorker(wr, wi.cell, keyspace, shard, excludeTableArray, strategy, int(sourceReaderCount), int(destinationPackCount), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS) + wrk, err := NewLegacySplitCloneWorker(wr, wi.cell, keyspace, shard, excludeTableArray, int(sourceReaderCount), int(destinationPackCount), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS) if err != nil { return nil, nil, nil, fmt.Errorf("cannot create worker: %v", err) } @@ -203,6 +191,6 @@ func interactiveLegacySplitClone(ctx context.Context, wi *Instance, wr *wrangler func init() { AddCommand("Clones", Command{"LegacySplitClone", commandLegacySplitClone, interactiveLegacySplitClone, - "[--exclude_tables=''] [--strategy=''] ", + "[--exclude_tables=''] ", "Old SplitClone code which supports VARCHAR primary key columns. Use this ONLY if SplitClone failed for you."}) } diff --git a/go/vt/worker/legacy_split_clone_test.go b/go/vt/worker/legacy_split_clone_test.go index 06f9c9f4e58..09bd1329c4a 100644 --- a/go/vt/worker/legacy_split_clone_test.go +++ b/go/vt/worker/legacy_split_clone_test.go @@ -197,8 +197,6 @@ func (tc *legacySplitCloneTestCase) setUp(v3 bool) { // leftReplica is unused by default. tc.rightMasterFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) } - expectBlpCheckpointCreationQueries(tc.leftMasterFakeDb) - expectBlpCheckpointCreationQueries(tc.rightMasterFakeDb) // Fake stream health reponses because vtworker needs them to find the master. tc.leftMasterQs = fakes.NewStreamHealthQueryService(leftMaster.Target()) @@ -382,9 +380,8 @@ func TestLegacySplitCloneV2_RetryDueToReparent(t *testing.T) { defer tc.tearDown() // Provoke a reparent just before the copy finishes. - // leftReplica will take over for the last, 30th, insert and the BLP checkpoint. + // leftReplica will take over for the last, 30th, insert and the vreplication checkpoint. tc.leftReplicaFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) - expectBlpCheckpointCreationQueries(tc.leftReplicaFakeDb) // Do not let leftMaster succeed the 30th write. tc.leftMasterFakeDb.DeleteAllEntriesAfterIndex(28) @@ -442,9 +439,8 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { tc.setUp(false /* v3 */) defer tc.tearDown() - // leftReplica will take over for the last, 30th, insert and the BLP checkpoint. + // leftReplica will take over for the last, 30th, insert and the vreplication checkpoint. tc.leftReplicaFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) - expectBlpCheckpointCreationQueries(tc.leftReplicaFakeDb) // During the 29th write, let the MASTER disappear. tc.leftMasterFakeDb.GetEntry(28).AfterFunc = func() { @@ -488,6 +484,7 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { } // Make leftReplica the new MASTER. + tc.leftReplica.Agent.TabletExternallyReparented(ctx, "1") tc.leftReplicaQs.UpdateType(topodatapb.TabletType_MASTER) tc.leftReplicaQs.AddDefaultHealthResponse() }() diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index 3dcefc5bb03..191676d1857 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -40,6 +40,7 @@ import ( "vitess.io/vitess/go/vt/worker/events" "vitess.io/vitess/go/vt/wrangler" + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -72,7 +73,6 @@ type SplitCloneWorker struct { tables []string // horizontalResharding only: List of tables which will be skipped. excludeTables []string - strategy *splitStrategy chunkCount int minRowsPerChunk int sourceReaderCount int @@ -138,20 +138,20 @@ type SplitCloneWorker struct { } // newSplitCloneWorker returns a new worker object for the SplitClone command. -func newSplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, online, offline bool, excludeTables []string, strategyStr string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { - return newCloneWorker(wr, horizontalResharding, cell, keyspace, shard, online, offline, nil /* tables */, excludeTables, strategyStr, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets, maxTPS, maxReplicationLag) +func newSplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, online, offline bool, excludeTables []string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { + return newCloneWorker(wr, horizontalResharding, cell, keyspace, shard, online, offline, nil /* tables */, excludeTables, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets, maxTPS, maxReplicationLag) } // newVerticalSplitCloneWorker returns a new worker object for the // VerticalSplitClone command. -func newVerticalSplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, online, offline bool, tables []string, strategyStr string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { - return newCloneWorker(wr, verticalSplit, cell, keyspace, shard, online, offline, tables, nil /* excludeTables */, strategyStr, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets, maxTPS, maxReplicationLag) +func newVerticalSplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard string, online, offline bool, tables []string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { + return newCloneWorker(wr, verticalSplit, cell, keyspace, shard, online, offline, tables, nil /* excludeTables */, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets, maxTPS, maxReplicationLag) } // newCloneWorker returns a new SplitCloneWorker object which is used both by // the SplitClone and VerticalSplitClone command. // TODO(mberlin): Rename SplitCloneWorker to cloneWorker. -func newCloneWorker(wr *wrangler.Wrangler, cloneType cloneType, cell, keyspace, shard string, online, offline bool, tables, excludeTables []string, strategyStr string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { +func newCloneWorker(wr *wrangler.Wrangler, cloneType cloneType, cell, keyspace, shard string, online, offline bool, tables, excludeTables []string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyRdonlyTablets int, maxTPS, maxReplicationLag int64) (Worker, error) { if cloneType != horizontalResharding && cloneType != verticalSplit { return nil, fmt.Errorf("unknown cloneType: %v This is a bug. Please report", cloneType) } @@ -163,10 +163,6 @@ func newCloneWorker(wr *wrangler.Wrangler, cloneType cloneType, cell, keyspace, if tables != nil && len(tables) == 0 { return nil, errors.New("list of tablets to be split out must not be empty") } - strategy, err := newSplitStrategy(wr.Logger(), strategyStr) - if err != nil { - return nil, err - } if chunkCount <= 0 { return nil, fmt.Errorf("chunk_count must be > 0: %v", chunkCount) } @@ -209,7 +205,6 @@ func newCloneWorker(wr *wrangler.Wrangler, cloneType cloneType, cell, keyspace, offline: offline, tables: tables, excludeTables: excludeTables, - strategy: strategy, chunkCount: chunkCount, minRowsPerChunk: minRowsPerChunk, sourceReaderCount: sourceReaderCount, @@ -240,7 +235,6 @@ func (scw *SplitCloneWorker) initializeEventDescriptor() { Keyspace: scw.destinationKeyspace, Shard: scw.shard, ExcludeTables: scw.excludeTables, - Strategy: scw.strategy.String(), } case verticalSplit: scw.ev = &events.VerticalSplitClone{ @@ -248,7 +242,6 @@ func (scw *SplitCloneWorker) initializeEventDescriptor() { Keyspace: scw.destinationKeyspace, Shard: scw.shard, Tables: scw.tables, - Strategy: scw.strategy.String(), } } } @@ -776,9 +769,6 @@ func (scw *SplitCloneWorker) findDestinationMasters(ctx context.Context) error { keyspaceAndShard := topoproto.KeyspaceShardString(si.Keyspace(), si.ShardName()) scw.destinationDbNames[keyspaceAndShard] = topoproto.TabletDbName(master.Tablet) - // TODO(mberlin): Verify on the destination master that the - // _vt.blp_checkpoint table has the latest schema. - scw.wr.Logger().Infof("Using tablet %v as destination master for %v/%v", topoproto.TabletAliasString(master.Tablet.Alias), si.Keyspace(), si.ShardName()) } scw.wr.Logger().Infof("NOTE: The used master of a destination shard might change over the course of the copy e.g. due to a reparent. The HealthCheck module will track and log master changes and any error message will always refer the actually used master address.") @@ -1068,99 +1058,61 @@ func (scw *SplitCloneWorker) clone(ctx context.Context, state StatusWorkerState) } if state == WorkerStateCloneOffline { - // Create and populate the blp_checkpoint table to give filtered replication + // Create and populate the vreplication table to give filtered replication // a starting point. - if scw.strategy.skipPopulateBlpCheckpoint { - scw.wr.Logger().Infof("Skipping populating the blp_checkpoint table") - } else { - queries := make([]string, 0, 4) - queries = append(queries, binlogplayer.CreateBlpCheckpoint()...) - flags := "" - if scw.strategy.dontStartBinlogPlayer { - flags = binlogplayer.BlpFlagDontStart - } - - // get the current position from the sources - for shardIndex := range scw.sourceShards { - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - status, err := scw.wr.TabletManagerClient().SlaveStatus(shortCtx, scw.sourceTablets[shardIndex]) - cancel() - if err != nil { - return err - } - - // TODO(mberlin): Fill in scw.maxReplicationLag once the adapative - // throttler is enabled by default. - queries = append(queries, binlogplayer.PopulateBlpCheckpoint(uint32(shardIndex), status.Position, scw.maxTPS, throttler.ReplicationLagModuleDisabled, time.Now().Unix(), flags)) - } - - for _, si := range scw.destinationShards { - destinationWaitGroup.Add(1) - go func(keyspace, shard string) { - defer destinationWaitGroup.Done() - scw.wr.Logger().Infof("Making and populating blp_checkpoint table") - keyspaceAndShard := topoproto.KeyspaceShardString(keyspace, shard) - if err := runSQLCommands(ctx, scw.wr, scw.tsc, keyspace, shard, scw.destinationDbNames[keyspaceAndShard], queries); err != nil { - processError("blp_checkpoint queries failed: %v", err) - } - }(si.Keyspace(), si.ShardName()) - } - destinationWaitGroup.Wait() - if firstError != nil { - return firstError - } - } - - // Configure filtered replication by setting the SourceShard info. - // The master tablets won't enable filtered replication (the binlog player) - // until they re-read the topology due to a restart or a reload. - // TODO(alainjobart) this is a superset, some shards may not - // overlap, have to deal with this better (for N -> M splits - // where both N>1 and M>1) - if scw.strategy.skipSetSourceShards { - scw.wr.Logger().Infof("Skipping setting SourceShard on destination shards.") - } else { - for _, si := range scw.destinationShards { - scw.wr.Logger().Infof("Setting SourceShard on shard %v/%v (tables: %v)", si.Keyspace(), si.ShardName(), scw.tables) - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - err := scw.wr.SetSourceShards(shortCtx, si.Keyspace(), si.ShardName(), scw.offlineSourceAliases, scw.tables) - cancel() - if err != nil { - return fmt.Errorf("failed to set source shards: %v", err) - } + queries := make([]string, 0, 4) + queries = append(queries, binlogplayer.CreateVReplicationTable()...) + + // get the current position from the sources + sourcePositions := make([]string, len(scw.sourceShards)) + for shardIndex := range scw.sourceShards { + shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + status, err := scw.wr.TabletManagerClient().SlaveStatus(shortCtx, scw.sourceTablets[shardIndex]) + cancel() + if err != nil { + return err } + sourcePositions[shardIndex] = status.Position } - // Force a state refresh (re-read of the "Shard" object from the topology) - // on all destination masters to start filtered replication. - rec := concurrency.AllErrorRecorder{} for _, si := range scw.destinationShards { destinationWaitGroup.Add(1) - go func(keyspace, shard string) { + go func(keyspace, shard string, kr *topodatapb.KeyRange) { defer destinationWaitGroup.Done() + scw.wr.Logger().Infof("Making and populating vreplication table") - masters := scw.tsc.GetHealthyTabletStats(keyspace, shard, topodatapb.TabletType_MASTER) - if len(masters) == 0 { - rec.RecordError(fmt.Errorf("cannot find MASTER tablet for destination shard for %v/%v (in cell: %v) in HealthCheck: empty TabletStats list", keyspace, shard, scw.cell)) + exc := newExecutor(scw.wr, scw.tsc, nil, keyspace, shard, 0) + for shardIndex, src := range scw.sourceShards { + bls := &binlogdatapb.BinlogSource{ + Keyspace: src.Keyspace(), + Shard: src.ShardName(), + } + if scw.tables == nil { + bls.KeyRange = kr + } else { + bls.Tables = scw.tables + } + // TODO(mberlin): Fill in scw.maxReplicationLag once the adapative + // throttler is enabled by default. + qr, err := exc.vreplicationExec(ctx, binlogplayer.CreateVReplication("SplitClone", bls, sourcePositions[shardIndex], scw.maxTPS, throttler.ReplicationLagModuleDisabled, time.Now().Unix())) + if err != nil { + processError("vreplication queries failed: %v", err) + break + } + if err := scw.wr.SourceShardAdd(ctx, keyspace, shard, uint32(qr.InsertID), src.Keyspace(), src.ShardName(), src.Shard.KeyRange, scw.tables); err != nil { + processError("could not add source shard: %v", err) + break + } } - master := masters[0] - alias := topoproto.TabletAliasString(master.Tablet.Alias) - - scw.wr.Logger().Infof("Refreshing state on tablet %v", alias) - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - defer cancel() - if err := scw.wr.TabletManagerClient().RefreshState(shortCtx, master.Tablet); err != nil { - rec.RecordError(fmt.Errorf("RefreshState failed on tablet %v: %v", alias, err)) + // refreshState will cause the destination to become non-serving because + // it's now participating in the resharding workflow. + if err := exc.refreshState(ctx); err != nil { + processError("RefreshState failed on tablet %v/%v: %v", keyspace, shard, err) } - }(si.Keyspace(), si.ShardName()) + }(si.Keyspace(), si.ShardName(), si.KeyRange) } destinationWaitGroup.Wait() - if err := rec.Error(); err != nil { - processError("Triggering the start of filtered replication failed for some destination masters. Please run 'vtctl RefreshState' manually on the failed ones. Errors: %v", err) - } } // clonePhase == offline - - destinationWaitGroup.Wait() return firstError } diff --git a/go/vt/worker/split_clone_cmd.go b/go/vt/worker/split_clone_cmd.go index 473efad65b2..281ad912dc6 100644 --- a/go/vt/worker/split_clone_cmd.go +++ b/go/vt/worker/split_clone_cmd.go @@ -68,8 +68,6 @@ const splitCloneHTML2 = `

- -

@@ -92,14 +90,6 @@ const splitCloneHTML2 = ` - -

Help

-

Strategy can have the following values, comma separated:

-
    -
  • skipPopulateBlpCheckpoint: skips creating (if necessary) and populating the blp_checkpoint table in the destination. Not skipped by default because it's required for filtered replication to start.
  • -
  • dontStartBinlogPlayer: (requires skipPopulateBlpCheckpoint to be false) will setup, but not start binlog replication on the destination. The flag has to be manually cleared from the _vt.blp_checkpoint table.
  • -
  • skipSetSourceShards: we won't set SourceShards on the destination shards, disabling filtered replication. Useful for worker tests.
  • -
` @@ -110,7 +100,6 @@ func commandSplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagS online := subFlags.Bool("online", defaultOnline, "do online copy (optional approximate copy, source and destination tablets will not be put out of serving, minimizes downtime during offline copy)") offline := subFlags.Bool("offline", defaultOffline, "do offline copy (exact copy at a specific GTID, required before shard migration, source and destination tablets will be put out of serving during copy)") excludeTables := subFlags.String("exclude_tables", "", "comma separated list of tables to exclude. Each is either an exact match, or a regular expression of the form /regexp/") - strategy := subFlags.String("strategy", "", "which strategy to use for restore, use 'vtworker SplitClone --strategy=-help k/s' for more info") chunkCount := subFlags.Int("chunk_count", defaultChunkCount, "number of chunks per table") minRowsPerChunk := subFlags.Int("min_rows_per_chunk", defaultMinRowsPerChunk, "minimum number of rows per chunk (may reduce --chunk_count)") sourceReaderCount := subFlags.Int("source_reader_count", defaultSourceReaderCount, "number of concurrent streaming queries to use on the source") @@ -136,7 +125,7 @@ func commandSplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagS if *excludeTables != "" { excludeTableArray = strings.Split(*excludeTables, ",") } - worker, err := newSplitCloneWorker(wr, wi.cell, keyspace, shard, *online, *offline, excludeTableArray, *strategy, *chunkCount, *minRowsPerChunk, *sourceReaderCount, *writeQueryMaxRows, *writeQueryMaxSize, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS, *maxReplicationLag) + worker, err := newSplitCloneWorker(wr, wi.cell, keyspace, shard, *online, *offline, excludeTableArray, *chunkCount, *minRowsPerChunk, *sourceReaderCount, *writeQueryMaxRows, *writeQueryMaxSize, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS, *maxReplicationLag) if err != nil { return nil, fmt.Errorf("cannot create split clone worker: %v", err) } @@ -237,7 +226,6 @@ func interactiveSplitClone(ctx context.Context, wi *Instance, wr *wrangler.Wrang if excludeTables != "" { excludeTableArray = strings.Split(excludeTables, ",") } - strategy := r.FormValue("strategy") chunkCountStr := r.FormValue("chunkCount") chunkCount, err := strconv.ParseInt(chunkCountStr, 0, 64) if err != nil { @@ -284,7 +272,7 @@ func interactiveSplitClone(ctx context.Context, wi *Instance, wr *wrangler.Wrang } // start the clone job - wrk, err := newSplitCloneWorker(wr, wi.cell, keyspace, shard, online, offline, excludeTableArray, strategy, int(chunkCount), int(minRowsPerChunk), int(sourceReaderCount), int(writeQueryMaxRows), int(writeQueryMaxSize), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS, maxReplicationLag) + wrk, err := newSplitCloneWorker(wr, wi.cell, keyspace, shard, online, offline, excludeTableArray, int(chunkCount), int(minRowsPerChunk), int(sourceReaderCount), int(writeQueryMaxRows), int(writeQueryMaxSize), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS, maxReplicationLag) if err != nil { return nil, nil, nil, fmt.Errorf("cannot create worker: %v", err) } @@ -294,6 +282,6 @@ func interactiveSplitClone(ctx context.Context, wi *Instance, wr *wrangler.Wrang func init() { AddCommand("Clones", Command{"SplitClone", commandSplitClone, interactiveSplitClone, - "[--online=false] [--offline=false] [--exclude_tables=''] [--strategy=''] ", + "[--online=false] [--offline=false] [--exclude_tables=''] ", "Replicates the data and creates configuration for a horizontal split."}) } diff --git a/go/vt/worker/split_clone_test.go b/go/vt/worker/split_clone_test.go index 7eeba186e65..184e87d1dc1 100644 --- a/go/vt/worker/split_clone_test.go +++ b/go/vt/worker/split_clone_test.go @@ -243,8 +243,6 @@ func (tc *splitCloneTestCase) setUpWithConcurreny(v3 bool, concurrency, writeQue // leftReplica is unused by default. tc.rightMasterFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) } - expectBlpCheckpointCreationQueries(tc.leftMasterFakeDb) - expectBlpCheckpointCreationQueries(tc.rightMasterFakeDb) // Fake stream health reponses because vtworker needs them to find the master. tc.leftMasterQs = fakes.NewStreamHealthQueryService(leftMaster.Target()) @@ -835,8 +833,6 @@ func TestSplitCloneV2_Offline_Reconciliation(t *testing.T) { // Delete statements. (All are combined in one.) tc.leftMasterFakeDb.AddExpectedQuery("DELETE FROM `vt_ks`.`table1` WHERE (`id`=190) OR (`id`=192) OR (`id`=194) OR (`id`=196) OR (`id`=198)", nil) tc.rightMasterFakeDb.AddExpectedQuery("DELETE FROM `vt_ks`.`table1` WHERE (`id`=191) OR (`id`=193) OR (`id`=195) OR (`id`=197) OR (`id`=199)", nil) - expectBlpCheckpointCreationQueries(tc.leftMasterFakeDb) - expectBlpCheckpointCreationQueries(tc.rightMasterFakeDb) // Run the vtworker command. if err := runCommand(t, tc.wi, tc.wi.wr, tc.defaultWorkerArgs); err != nil { @@ -927,9 +923,8 @@ func TestSplitCloneV2_RetryDueToReparent(t *testing.T) { defer tc.tearDown() // Provoke a reparent just before the copy finishes. - // leftReplica will take over for the last, 30th, insert and the BLP checkpoint. + // leftReplica will take over for the last, 30th, insert and the vreplication checkpoint. tc.leftReplicaFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) - expectBlpCheckpointCreationQueries(tc.leftReplicaFakeDb) // Do not let leftMaster succeed the 30th write. tc.leftMasterFakeDb.DeleteAllEntriesAfterIndex(28) @@ -987,9 +982,8 @@ func TestSplitCloneV2_NoMasterAvailable(t *testing.T) { tc.setUp(false /* v3 */) defer tc.tearDown() - // leftReplica will take over for the last, 30th, insert and the BLP checkpoint. + // leftReplica will take over for the last, 30th, insert and the vreplication checkpoint. tc.leftReplicaFakeDb.AddExpectedQuery("INSERT INTO `vt_ks`.`table1` (`id`, `msg`, `keyspace_id`) VALUES (*", nil) - expectBlpCheckpointCreationQueries(tc.leftReplicaFakeDb) // During the 29th write, let the MASTER disappear. tc.leftMasterFakeDb.GetEntry(28).AfterFunc = func() { @@ -1032,6 +1026,7 @@ func TestSplitCloneV2_NoMasterAvailable(t *testing.T) { } // Make leftReplica the new MASTER. + tc.leftReplica.Agent.TabletExternallyReparented(ctx, "1") tc.leftReplicaQs.UpdateType(topodatapb.TabletType_MASTER) tc.leftReplicaQs.AddDefaultHealthResponse() }() diff --git a/go/vt/worker/split_diff.go b/go/vt/worker/split_diff.go index 0729718226f..08eafafbbfd 100644 --- a/go/vt/worker/split_diff.go +++ b/go/vt/worker/split_diff.go @@ -24,12 +24,13 @@ import ( "golang.org/x/net/context" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/sync2" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/mysqlctl/tmutils" "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vtgate/vindexes" "vitess.io/vitess/go/vt/wrangler" @@ -47,6 +48,7 @@ type SplitDiffWorker struct { keyspace string shard string sourceUID uint32 + sourceShard *topodatapb.Shard_SourceShard excludeTables []string minHealthyRdonlyTablets int destinationTabletType topodatapb.TabletType @@ -195,13 +197,21 @@ func (sdw *SplitDiffWorker) init(ctx context.Context) error { if len(sdw.shardInfo.SourceShards) == 0 { return fmt.Errorf("shard %v/%v has no source shard", sdw.keyspace, sdw.shard) } - foundSourceShard := false - for _, ss := range sdw.shardInfo.SourceShards { - if ss.Uid == sdw.sourceUID { - foundSourceShard = true + if sdw.sourceUID == 0 { + if len(sdw.shardInfo.SourceShards) == 1 { + sdw.sourceShard = sdw.shardInfo.SourceShards[0] + } else { + return fmt.Errorf("shard %v/%v has more than one source, please specify a source UID", sdw.keyspace, sdw.shard) + } + } else { + for _, ss := range sdw.shardInfo.SourceShards { + if ss.Uid == sdw.sourceUID { + sdw.sourceShard = ss + break + } } } - if !foundSourceShard { + if sdw.sourceShard == nil { return fmt.Errorf("shard %v/%v has no source shard with UID %v", sdw.keyspace, sdw.shard, sdw.sourceUID) } @@ -237,16 +247,26 @@ func (sdw *SplitDiffWorker) findTargets(ctx context.Context) error { } // find an appropriate tablet in the source shard - for _, ss := range sdw.shardInfo.SourceShards { - if ss.Uid == sdw.sourceUID { - sdw.sourceAlias, err = FindWorkerTablet(ctx, sdw.wr, sdw.cleaner, nil /* tsc */, sdw.cell, sdw.keyspace, ss.Shard, sdw.minHealthyRdonlyTablets, topodatapb.TabletType_RDONLY) + // During an horizontal shard split, multiple workers will race to get + // a RDONLY tablet in the source shard. When this happen, concurrent calls + // to FindWorkerTablet could attempt to set to DRAIN state the same tablet. Only + // one of these calls to FindWorkerTablet will succeed and the rest will fail. + // The following, makes sures we keep trying to find a worker tablet when this error occur. + shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + for { + select { + case <-shortCtx.Done(): + return fmt.Errorf("Could not find healthy table for %v/%v%v: after: %v, aborting", sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, *remoteActionsTimeout) + default: + sdw.sourceAlias, err = FindWorkerTablet(ctx, sdw.wr, sdw.cleaner, nil /* tsc */, sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, sdw.minHealthyRdonlyTablets, topodatapb.TabletType_RDONLY) if err != nil { - return fmt.Errorf("FindWorkerTablet() failed for %v/%v/%v: %v", sdw.cell, sdw.keyspace, ss.Shard, err) + sdw.wr.Logger().Infof("FindWorkerTablet() failed for %v/%v/%v: %v retrying...", sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, err) + continue } + cancel() + return nil } } - - return nil } // synchronizeReplication phase: @@ -272,8 +292,8 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { sdw.SetState(WorkerStateSyncReplication) shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() masterInfo, err := sdw.wr.TopoServer().GetTablet(shortCtx, sdw.shardInfo.MasterAlias) - cancel() if err != nil { return fmt.Errorf("synchronizeReplication: cannot get Tablet record for master %v: %v", sdw.shardInfo.MasterAlias, err) } @@ -281,43 +301,35 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { // 1 - stop the master binlog replication, get its current position sdw.wr.Logger().Infof("Stopping master binlog replication on %v", sdw.shardInfo.MasterAlias) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - blpPositionList, err := sdw.wr.TabletManagerClient().StopBlp(shortCtx, masterInfo.Tablet) - cancel() + defer cancel() + _, err = sdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StopVReplication(sdw.sourceShard.Uid, "for split diff")) if err != nil { - return fmt.Errorf("StopBlp for %v failed: %v", sdw.shardInfo.MasterAlias, err) + return fmt.Errorf("VReplicationExec(stop) for %v failed: %v", sdw.shardInfo.MasterAlias, err) } - wrangler.RecordStartBlpAction(sdw.cleaner, masterInfo.Tablet) - - // 2 - stop the source tablet at a binlog position - // higher than the destination master - - // find where we should be stopping - blpPos := tmutils.FindBlpPositionByID(blpPositionList, sdw.sourceUID) - if blpPos == nil { - return fmt.Errorf("no binlog position on the master for Uid %v", sdw.sourceUID) + wrangler.RecordVReplicationAction(sdw.cleaner, masterInfo.Tablet, binlogplayer.StartVReplication(sdw.sourceShard.Uid)) + p3qr, err := sdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.ReadVReplicationPos(sdw.sourceShard.Uid)) + if err != nil { + return fmt.Errorf("VReplicationExec(stop) for %v failed: %v", sdw.shardInfo.MasterAlias, err) + } + qr := sqltypes.Proto3ToResult(p3qr) + if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { + return fmt.Errorf("Unexpected result while reading position: %v", qr) } + vreplicationPos := qr.Rows[0][0].ToString() + // 2 - stop replication + sdw.wr.Logger().Infof("Stopping slave %v at a minimum of %v", sdw.sourceAlias, vreplicationPos) // read the tablet - shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) sourceTablet, err := sdw.wr.TopoServer().GetTablet(shortCtx, sdw.sourceAlias) - cancel() if err != nil { return err } - // stop replication - sdw.wr.Logger().Infof("Stopping slave %v at a minimum of %v", sdw.sourceAlias, blpPos.Position) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - stoppedAt, err := sdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, sourceTablet.Tablet, blpPos.Position, *remoteActionsTimeout) - cancel() + defer cancel() + mysqlPos, err := sdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, sourceTablet.Tablet, vreplicationPos, *remoteActionsTimeout) if err != nil { - return fmt.Errorf("cannot stop slave %v at right binlog position %v: %v", sdw.sourceAlias, blpPos.Position, err) - } - stopPositionList := []*tabletmanagerdatapb.BlpPosition{ - { - Uid: sdw.sourceUID, - Position: stoppedAt, - }, + return fmt.Errorf("cannot stop slave %v at right binlog position %v: %v", sdw.sourceAlias, vreplicationPos, err) } // change the cleaner actions from ChangeSlaveType(rdonly) @@ -326,27 +338,33 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { // 3 - ask the master of the destination shard to resume filtered // replication up to the new list of positions - sdw.wr.Logger().Infof("Restarting master %v until it catches up to %v", sdw.shardInfo.MasterAlias, stopPositionList) + sdw.wr.Logger().Infof("Restarting master %v until it catches up to %v", sdw.shardInfo.MasterAlias, mysqlPos) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - masterPos, err := sdw.wr.TabletManagerClient().RunBlpUntil(shortCtx, masterInfo.Tablet, stopPositionList, *remoteActionsTimeout) - cancel() + defer cancel() + _, err = sdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StartVReplicationUntil(sdw.sourceShard.Uid, mysqlPos)) + if err != nil { + return fmt.Errorf("VReplication(start until) for %v until %v failed: %v", sdw.shardInfo.MasterAlias, mysqlPos, err) + } + if err := sdw.wr.TabletManagerClient().VReplicationWaitForPos(shortCtx, masterInfo.Tablet, int(sdw.sourceShard.Uid), mysqlPos); err != nil { + return fmt.Errorf("VReplicationWaitForPos for %v until %v failed: %v", sdw.shardInfo.MasterAlias, mysqlPos, err) + } + masterPos, err := sdw.wr.TabletManagerClient().MasterPosition(shortCtx, masterInfo.Tablet) if err != nil { - return fmt.Errorf("RunBlpUntil for %v until %v failed: %v", sdw.shardInfo.MasterAlias, stopPositionList, err) + return fmt.Errorf("MasterPosition for %v failed: %v", sdw.shardInfo.MasterAlias, err) } // 4 - wait until the destination tablet is equal or passed // that master binlog position, and stop its replication. sdw.wr.Logger().Infof("Waiting for destination tablet %v to catch up to %v", sdw.destinationAlias, masterPos) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() destinationTablet, err := sdw.wr.TopoServer().GetTablet(shortCtx, sdw.destinationAlias) - cancel() if err != nil { return err } shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - _, err = sdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, destinationTablet.Tablet, masterPos, *remoteActionsTimeout) - cancel() - if err != nil { + defer cancel() + if _, err = sdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, destinationTablet.Tablet, masterPos, *remoteActionsTimeout); err != nil { return fmt.Errorf("StopSlaveMinimum for %v at %v failed: %v", sdw.destinationAlias, masterPos, err) } wrangler.RecordStartSlaveAction(sdw.cleaner, destinationTablet.Tablet) @@ -354,13 +372,9 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { // 5 - restart filtered replication on destination master sdw.wr.Logger().Infof("Restarting filtered replication on master %v", sdw.shardInfo.MasterAlias) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - err = sdw.wr.TabletManagerClient().StartBlp(shortCtx, masterInfo.Tablet) - if err := sdw.cleaner.RemoveActionByName(wrangler.StartBlpActionName, topoproto.TabletAliasString(sdw.shardInfo.MasterAlias)); err != nil { - sdw.wr.Logger().Warningf("Cannot find cleaning action %v/%v: %v", wrangler.StartBlpActionName, topoproto.TabletAliasString(sdw.shardInfo.MasterAlias), err) - } - cancel() - if err != nil { - return fmt.Errorf("StartBlp failed for %v: %v", sdw.shardInfo.MasterAlias, err) + defer cancel() + if _, err = sdw.wr.TabletManagerClient().VReplicationExec(ctx, masterInfo.Tablet, binlogplayer.StartVReplication(sdw.sourceShard.Uid)); err != nil { + return fmt.Errorf("VReplicationExec(start) failed for %v: %v", sdw.shardInfo.MasterAlias, err) } return nil @@ -435,7 +449,7 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error { // source or destination keyrange. If it matches either, // we'll just ask for all the data. If the overlap is a subset, // we'll filter. - overlap, err := key.KeyRangesOverlap(sdw.shardInfo.KeyRange, sdw.shardInfo.SourceShards[sdw.sourceUID].KeyRange) + overlap, err := key.KeyRangesOverlap(sdw.shardInfo.KeyRange, sdw.sourceShard.KeyRange) if err != nil { return fmt.Errorf("Source shard doesn't overlap with destination: %v", err) } @@ -472,7 +486,7 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error { // On the source, see if we need a full scan // or a filtered scan. var sourceQueryResultReader *QueryResultReader - if key.KeyRangeEqual(overlap, sdw.shardInfo.SourceShards[sdw.sourceUID].KeyRange) { + if key.KeyRangeEqual(overlap, sdw.sourceShard.KeyRange) { sourceQueryResultReader, err = TableScan(ctx, sdw.wr.Logger(), sdw.wr.TopoServer(), sdw.sourceAlias, tableDefinition) } else { sourceQueryResultReader, err = TableScanByKeyRange(ctx, sdw.wr.Logger(), sdw.wr.TopoServer(), sdw.sourceAlias, tableDefinition, overlap, keyspaceSchema, sdw.keyspaceInfo.ShardingColumnName, sdw.keyspaceInfo.ShardingColumnType) diff --git a/go/vt/worker/split_strategy.go b/go/vt/worker/split_strategy.go deleted file mode 100644 index 513735a9802..00000000000 --- a/go/vt/worker/split_strategy.go +++ /dev/null @@ -1,79 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 worker - -import ( - "flag" - "fmt" - "strings" - - "vitess.io/vitess/go/vt/logutil" -) - -// splitStrategy is the configuration for a split clone. -type splitStrategy struct { - // skipPopulateBlpCheckpoint will skip the population of the blp_checkpoint table - skipPopulateBlpCheckpoint bool - - // dontStartBinlogPlayer will delay starting the binlog replication - dontStartBinlogPlayer bool - - // skipSetSourceShards will not set the source shards at the end of restore - skipSetSourceShards bool -} - -func newSplitStrategy(logger logutil.Logger, argsStr string) (*splitStrategy, error) { - var args []string - if argsStr != "" { - args = strings.Split(argsStr, " ") - } - flagSet := flag.NewFlagSet("strategy", flag.ContinueOnError) - flagSet.SetOutput(logutil.NewLoggerWriter(logger)) - flagSet.Usage = func() { - logger.Printf("Strategy flag has the following options:\n") - flagSet.PrintDefaults() - } - skipPopulateBlpCheckpoint := flagSet.Bool("skip_populate_blp_checkpoint", false, "do not populate the blp checkpoint table") - dontStartBinlogPlayer := flagSet.Bool("dont_start_binlog_player", false, "do not start the binlog player after restore is complete") - skipSetSourceShards := flagSet.Bool("skip_set_source_shards", false, "do not set the SourceShar field on destination shards") - if err := flagSet.Parse(args); err != nil { - return nil, fmt.Errorf("cannot parse strategy: %v", err) - } - if flagSet.NArg() > 0 { - return nil, fmt.Errorf("strategy doesn't have positional arguments") - } - - return &splitStrategy{ - skipPopulateBlpCheckpoint: *skipPopulateBlpCheckpoint, - dontStartBinlogPlayer: *dontStartBinlogPlayer, - skipSetSourceShards: *skipSetSourceShards, - }, nil -} - -func (strategy *splitStrategy) String() string { - var result []string - if strategy.skipPopulateBlpCheckpoint { - result = append(result, "-skip_populate_blp_checkpoint") - } - if strategy.dontStartBinlogPlayer { - result = append(result, "-dont_start_binlog_player") - } - if strategy.skipSetSourceShards { - result = append(result, "-skip_set_source_shards") - } - return strings.Join(result, " ") -} diff --git a/go/vt/worker/topo_utils.go b/go/vt/worker/topo_utils.go index 7e0140e791b..6c078352b88 100644 --- a/go/vt/worker/topo_utils.go +++ b/go/vt/worker/topo_utils.go @@ -119,11 +119,17 @@ func FindWorkerTablet(ctx context.Context, wr *wrangler.Wrangler, cleaner *wrang return nil, err } - // We add the tag before calling ChangeSlaveType, so the destination - // vttablet reloads the worker URL when it reloads the tablet. + wr.Logger().Infof("Changing tablet %v to '%v'", topoproto.TabletAliasString(tabletAlias), topodatapb.TabletType_DRAINED) + shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + err = wr.ChangeSlaveType(shortCtx, tabletAlias, topodatapb.TabletType_DRAINED) + cancel() + if err != nil { + return nil, err + } + ourURL := servenv.ListeningURL.String() wr.Logger().Infof("Adding tag[worker]=%v to tablet %v", ourURL, topoproto.TabletAliasString(tabletAlias)) - shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) _, err = wr.TopoServer().UpdateTabletFields(shortCtx, tabletAlias, func(tablet *topodatapb.Tablet) error { if tablet.Tags == nil { tablet.Tags = make(map[string]string) @@ -142,16 +148,17 @@ func FindWorkerTablet(ctx context.Context, wr *wrangler.Wrangler, cleaner *wrang defer wrangler.RecordTabletTagAction(cleaner, tabletAlias, "worker", "") defer wrangler.RecordTabletTagAction(cleaner, tabletAlias, "drain_reason", "") - wr.Logger().Infof("Changing tablet %v to '%v'", topoproto.TabletAliasString(tabletAlias), topodatapb.TabletType_DRAINED) + // Record a clean-up action to take the tablet back to tabletAlias. + wrangler.RecordChangeSlaveTypeAction(cleaner, tabletAlias, topodatapb.TabletType_DRAINED, tabletType) + + // We refresh the destination vttablet reloads the worker URL when it reloads the tablet. shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - err = wr.ChangeSlaveType(shortCtx, tabletAlias, topodatapb.TabletType_DRAINED) - cancel() + wr.RefreshTabletState(shortCtx, tabletAlias) if err != nil { return nil, err } + cancel() - // Record a clean-up action to take the tablet back to rdonly. - wrangler.RecordChangeSlaveTypeAction(cleaner, tabletAlias, topodatapb.TabletType_DRAINED, topodatapb.TabletType_RDONLY) return tabletAlias, nil } diff --git a/go/vt/worker/utils_test.go b/go/vt/worker/utils_test.go index ae327b569fe..ad9dc1c44e8 100644 --- a/go/vt/worker/utils_test.go +++ b/go/vt/worker/utils_test.go @@ -56,22 +56,6 @@ func runCommand(t *testing.T, wi *Instance, wr *wrangler.Wrangler, args []string return nil } -// expectBlpCheckpointCreationQueries fakes out the queries which vtworker -// sends out to create the Binlog Player (BLP) checkpoint. -func expectBlpCheckpointCreationQueries(f *fakesqldb.DB) { - f.AddExpectedQuery("CREATE DATABASE IF NOT EXISTS _vt", nil) - f.AddExpectedQuery("CREATE TABLE IF NOT EXISTS _vt.blp_checkpoint (\n"+ - " source_shard_uid INT(10) UNSIGNED NOT NULL,\n"+ - " pos VARBINARY(64000) DEFAULT NULL,\n"+ - " max_tps BIGINT(20) NOT NULL,\n"+ - " max_replication_lag BIGINT(20) NOT NULL,\n"+ - " time_updated BIGINT(20) UNSIGNED NOT NULL,\n"+ - " transaction_timestamp BIGINT(20) UNSIGNED NOT NULL,\n"+ - " flags VARBINARY(250) DEFAULT NULL,\n"+ - " PRIMARY KEY (source_shard_uid)\n) ENGINE=InnoDB", nil) - f.AddExpectedQuery("INSERT INTO _vt.blp_checkpoint (source_shard_uid, pos, max_tps, max_replication_lag, time_updated, transaction_timestamp, flags) VALUES (0, 'MariaDB/12-34-5678', *", nil) -} - // sourceRdonlyFakeDB fakes out the MIN, MAX query on the primary key. // (This query is used to calculate the split points for reading a table // using multiple threads.) diff --git a/go/vt/worker/vertical_split_clone_cmd.go b/go/vt/worker/vertical_split_clone_cmd.go index f9bb1fab257..ba04fec7d9f 100644 --- a/go/vt/worker/vertical_split_clone_cmd.go +++ b/go/vt/worker/vertical_split_clone_cmd.go @@ -67,8 +67,6 @@ const verticalSplitCloneHTML2 = `

- -

@@ -90,14 +88,6 @@ const verticalSplitCloneHTML2 = ` - -

Help

-

Strategy can have the following values, comma separated:

-
    -
  • skipPopulateBlpCheckpoint: skips creating (if necessary) and populating the blp_checkpoint table in the destination. Not skipped by default because it's required for filtered replication to start.
  • -
  • dontStartBinlogPlayer: (requires skipPopulateBlpCheckpoint to be false) will setup, but not start binlog replication on the destination. The flag has to be manually cleared from the _vt.blp_checkpoint table.
  • -
  • skipSetSourceShards: we won't set SourceShards on the destination shards, disabling filtered replication. Useful for worker tests.
  • -
` @@ -108,7 +98,6 @@ func commandVerticalSplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *fl online := subFlags.Bool("online", defaultOnline, "do online copy (optional approximate copy, source and destination tablets will not be put out of serving, minimizes downtime during offline copy)") offline := subFlags.Bool("offline", defaultOffline, "do offline copy (exact copy at a specific GTID, required before shard migration, source and destination tablets will be put out of serving during copy)") tables := subFlags.String("tables", "", "comma separated list of tables to replicate (used for vertical split). Each is either an exact match, or a regular expression of the form /regexp/") - strategy := subFlags.String("strategy", "", "which strategy to use for restore, use 'vtworker VerticalSplitClone --strategy=-help k/s' for more info") chunkCount := subFlags.Int("chunk_count", defaultChunkCount, "number of chunks per table") minRowsPerChunk := subFlags.Int("min_rows_per_chunk", defaultMinRowsPerChunk, "minimum number of rows per chunk (may reduce --chunk_count)") sourceReaderCount := subFlags.Int("source_reader_count", defaultSourceReaderCount, "number of concurrent streaming queries to use on the source") @@ -136,7 +125,7 @@ func commandVerticalSplitClone(wi *Instance, wr *wrangler.Wrangler, subFlags *fl if *tables != "" { tableArray = strings.Split(*tables, ",") } - worker, err := newVerticalSplitCloneWorker(wr, wi.cell, keyspace, shard, *online, *offline, tableArray, *strategy, *chunkCount, *minRowsPerChunk, *sourceReaderCount, *writeQueryMaxRows, *writeQueryMaxSize, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS, *maxReplicationLag) + worker, err := newVerticalSplitCloneWorker(wr, wi.cell, keyspace, shard, *online, *offline, tableArray, *chunkCount, *minRowsPerChunk, *sourceReaderCount, *writeQueryMaxRows, *writeQueryMaxSize, *destinationWriterCount, *minHealthyRdonlyTablets, *maxTPS, *maxReplicationLag) if err != nil { return nil, fmt.Errorf("cannot create worker: %v", err) } @@ -229,7 +218,6 @@ func interactiveVerticalSplitClone(ctx context.Context, wi *Instance, wr *wrangl online := onlineStr == "true" offlineStr := r.FormValue("offline") offline := offlineStr == "true" - strategy := r.FormValue("strategy") chunkCountStr := r.FormValue("chunkCount") chunkCount, err := strconv.ParseInt(chunkCountStr, 0, 64) if err != nil { @@ -292,7 +280,7 @@ func interactiveVerticalSplitClone(ctx context.Context, wi *Instance, wr *wrangl } // start the clone job - wrk, err := newVerticalSplitCloneWorker(wr, wi.cell, keyspace, shard, online, offline, tableArray, strategy, int(chunkCount), int(minRowsPerChunk), int(sourceReaderCount), int(writeQueryMaxRows), int(writeQueryMaxSize), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS, maxReplicationLag) + wrk, err := newVerticalSplitCloneWorker(wr, wi.cell, keyspace, shard, online, offline, tableArray, int(chunkCount), int(minRowsPerChunk), int(sourceReaderCount), int(writeQueryMaxRows), int(writeQueryMaxSize), int(destinationWriterCount), int(minHealthyRdonlyTablets), maxTPS, maxReplicationLag) if err != nil { return nil, nil, nil, fmt.Errorf("cannot create worker: %v", err) } @@ -302,6 +290,6 @@ func interactiveVerticalSplitClone(ctx context.Context, wi *Instance, wr *wrangl func init() { AddCommand("Clones", Command{"VerticalSplitClone", commandVerticalSplitClone, interactiveVerticalSplitClone, - "[--tables=''] [--strategy=''] ", + "[--tables=''] ", "Replicates the data and creates configuration for a vertical split."}) } diff --git a/go/vt/worker/vertical_split_clone_test.go b/go/vt/worker/vertical_split_clone_test.go index 20017eb9d85..9f31da571da 100644 --- a/go/vt/worker/vertical_split_clone_test.go +++ b/go/vt/worker/vertical_split_clone_test.go @@ -52,8 +52,6 @@ func createVerticalSplitCloneDestinationFakeDb(t *testing.T, name string, insert f.AddExpectedQuery("INSERT INTO `vt_destination_ks`.`moving1` (`id`, `msg`) VALUES (*", nil) } - expectBlpCheckpointCreationQueries(f) - return f } diff --git a/go/vt/worker/vertical_split_diff.go b/go/vt/worker/vertical_split_diff.go index 361733a48e1..f6766e17b90 100644 --- a/go/vt/worker/vertical_split_diff.go +++ b/go/vt/worker/vertical_split_diff.go @@ -23,7 +23,9 @@ import ( "golang.org/x/net/context" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/sync2" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/mysqlctl/tmutils" "vitess.io/vitess/go/vt/topo" @@ -254,49 +256,44 @@ func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) vsdw.SetState(WorkerStateSyncReplication) shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() masterInfo, err := vsdw.wr.TopoServer().GetTablet(shortCtx, vsdw.shardInfo.MasterAlias) - cancel() if err != nil { return fmt.Errorf("synchronizeReplication: cannot get Tablet record for master %v: %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), err) } + ss := vsdw.shardInfo.SourceShards[0] + // 1 - stop the master binlog replication, get its current position vsdw.wr.Logger().Infof("Stopping master binlog replication on %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias)) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - blpPositionList, err := vsdw.wr.TabletManagerClient().StopBlp(shortCtx, masterInfo.Tablet) - cancel() + defer cancel() + _, err = vsdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StopVReplication(ss.Uid, "for split diff")) if err != nil { - return fmt.Errorf("StopBlp on master %v failed: %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), err) + return fmt.Errorf("Stop VReplication on master %v failed: %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), err) } - wrangler.RecordStartBlpAction(vsdw.cleaner, masterInfo.Tablet) - - // 2 - stop the source tablet at a binlog position - // higher than the destination master - stopPositionList := make([]*tabletmanagerdatapb.BlpPosition, 1) - ss := vsdw.shardInfo.SourceShards[0] - // find where we should be stopping - blpPos := tmutils.FindBlpPositionByID(blpPositionList, ss.Uid) - if blpPos == nil { - return fmt.Errorf("no binlog position on the master for Uid %v", ss.Uid) + wrangler.RecordVReplicationAction(vsdw.cleaner, masterInfo.Tablet, binlogplayer.StartVReplication(ss.Uid)) + p3qr, err := vsdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.ReadVReplicationPos(ss.Uid)) + if err != nil { + return fmt.Errorf("VReplicationExec(stop) for %v failed: %v", vsdw.shardInfo.MasterAlias, err) + } + qr := sqltypes.Proto3ToResult(p3qr) + if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { + return fmt.Errorf("Unexpected result while reading position: %v", qr) } + vreplicationPos := qr.Rows[0][0].ToString() // stop replication - vsdw.wr.Logger().Infof("Stopping slave %v at a minimum of %v", topoproto.TabletAliasString(vsdw.sourceAlias), blpPos.Position) + vsdw.wr.Logger().Infof("Stopping slave %v at a minimum of %v", topoproto.TabletAliasString(vsdw.sourceAlias), vreplicationPos) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() sourceTablet, err := vsdw.wr.TopoServer().GetTablet(shortCtx, vsdw.sourceAlias) - cancel() if err != nil { return err } - shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - stoppedAt, err := vsdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, sourceTablet.Tablet, blpPos.Position, *remoteActionsTimeout) - cancel() + mysqlPos, err := vsdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, sourceTablet.Tablet, vreplicationPos, *remoteActionsTimeout) if err != nil { - return fmt.Errorf("cannot stop slave %v at right binlog position %v: %v", topoproto.TabletAliasString(vsdw.sourceAlias), blpPos.Position, err) - } - stopPositionList[0] = &tabletmanagerdatapb.BlpPosition{ - Uid: ss.Uid, - Position: stoppedAt, + return fmt.Errorf("cannot stop slave %v at right binlog position %v: %v", topoproto.TabletAliasString(vsdw.sourceAlias), vreplicationPos, err) } // change the cleaner actions from ChangeSlaveType(rdonly) @@ -305,26 +302,33 @@ func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) // 3 - ask the master of the destination shard to resume filtered // replication up to the new list of positions - vsdw.wr.Logger().Infof("Restarting master %v until it catches up to %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), stopPositionList) + vsdw.wr.Logger().Infof("Restarting master %v until it catches up to %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), mysqlPos) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - masterPos, err := vsdw.wr.TabletManagerClient().RunBlpUntil(shortCtx, masterInfo.Tablet, stopPositionList, *remoteActionsTimeout) - cancel() + defer cancel() + _, err = vsdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StartVReplicationUntil(ss.Uid, mysqlPos)) + if err != nil { + return fmt.Errorf("VReplication(start until) for %v until %v failed: %v", vsdw.shardInfo.MasterAlias, mysqlPos, err) + } + if err := vsdw.wr.TabletManagerClient().VReplicationWaitForPos(shortCtx, masterInfo.Tablet, int(ss.Uid), mysqlPos); err != nil { + return fmt.Errorf("VReplicationWaitForPos for %v until %v failed: %v", vsdw.shardInfo.MasterAlias, mysqlPos, err) + } + masterPos, err := vsdw.wr.TabletManagerClient().MasterPosition(shortCtx, masterInfo.Tablet) if err != nil { - return fmt.Errorf("RunBlpUntil on %v until %v failed: %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), stopPositionList, err) + return fmt.Errorf("MasterPosition for %v failed: %v", vsdw.shardInfo.MasterAlias, err) } // 4 - wait until the destination tablet is equal or passed // that master binlog position, and stop its replication. vsdw.wr.Logger().Infof("Waiting for destination tablet %v to catch up to %v", topoproto.TabletAliasString(vsdw.destinationAlias), masterPos) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() destinationTablet, err := vsdw.wr.TopoServer().GetTablet(shortCtx, vsdw.destinationAlias) - cancel() if err != nil { return err } shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) + defer cancel() _, err = vsdw.wr.TabletManagerClient().StopSlaveMinimum(shortCtx, destinationTablet.Tablet, masterPos, *remoteActionsTimeout) - cancel() if err != nil { return fmt.Errorf("StopSlaveMinimum on %v at %v failed: %v", topoproto.TabletAliasString(vsdw.destinationAlias), masterPos, err) } @@ -333,13 +337,9 @@ func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) // 5 - restart filtered replication on destination master vsdw.wr.Logger().Infof("Restarting filtered replication on master %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias)) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) - err = vsdw.wr.TabletManagerClient().StartBlp(shortCtx, masterInfo.Tablet) - if err := vsdw.cleaner.RemoveActionByName(wrangler.StartBlpActionName, topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias)); err != nil { - vsdw.wr.Logger().Warningf("Cannot find cleaning action %v/%v: %v", wrangler.StartBlpActionName, topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), err) - } - cancel() - if err != nil { - return fmt.Errorf("StartBlp on %v failed: %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias), err) + defer cancel() + if _, err = vsdw.wr.TabletManagerClient().VReplicationExec(ctx, masterInfo.Tablet, binlogplayer.StartVReplication(ss.Uid)); err != nil { + return fmt.Errorf("VReplicationExec(start) failed for %v: %v", vsdw.shardInfo.MasterAlias, err) } return nil diff --git a/go/vt/workflow/resharding/checkpoint.go b/go/vt/workflow/checkpoint.go similarity index 99% rename from go/vt/workflow/resharding/checkpoint.go rename to go/vt/workflow/checkpoint.go index f98921099c4..ee888579f5a 100644 --- a/go/vt/workflow/resharding/checkpoint.go +++ b/go/vt/workflow/checkpoint.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resharding +package workflow import ( "sync" diff --git a/go/vt/workflow/long_polling_test.go b/go/vt/workflow/long_polling_test.go index 383dfdbac8a..eeeb6c3a388 100644 --- a/go/vt/workflow/long_polling_test.go +++ b/go/vt/workflow/long_polling_test.go @@ -42,7 +42,7 @@ func TestLongPolling(t *testing.T) { go http.Serve(listener, nil) // Run the manager in the background. - wg, cancel := startManager(t, m) + wg, _, cancel := StartManager(m) // Get the original tree with a 'create'. u := url.URL{Scheme: "http", Host: listener.Addr().String(), Path: "/workflow/create"} diff --git a/go/vt/workflow/manager.go b/go/vt/workflow/manager.go index 366de4cd3b9..ea93a79207d 100644 --- a/go/vt/workflow/manager.go +++ b/go/vt/workflow/manager.go @@ -244,7 +244,7 @@ func (m *Manager) loadAndStartJobsLocked() { } // Create creates a workflow from the given factory name with the -// provided args. Returns the unique UUID of the workflow. The +// provided args. Returns the unique UUID of the workflow. The // workflowpb.Workflow object is saved in the topo server after // creation. func (m *Manager) Create(ctx context.Context, factoryName string, args []string) (string, error) { @@ -260,6 +260,7 @@ func (m *Manager) Create(ctx context.Context, factoryName string, args []string) // Create the initial workflowpb.Workflow object. w := &workflowpb.Workflow{ Uuid: gouuid.NewUUID().String(), + CreateTime: time.Now().UnixNano(), FactoryName: factoryName, State: workflowpb.WorkflowState_NotStarted, } @@ -295,6 +296,7 @@ func (m *Manager) instantiateWorkflow(w *workflowpb.Workflow) (*runningWorkflow, } rw.rootNode.Name = w.Name rw.rootNode.PathName = w.Uuid + rw.rootNode.CreateTime = w.CreateTime rw.rootNode.Path = "/" + rw.rootNode.PathName rw.rootNode.State = w.State @@ -588,3 +590,18 @@ func AvailableFactories() map[string]bool { } return result } + +// StartManager starts a manager. This function should only be used for tests purposes. +func StartManager(m *Manager) (*sync.WaitGroup, context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + wg := &sync.WaitGroup{} + wg.Add(1) + go func() { + m.Run(ctx) + wg.Done() + }() + + m.WaitUntilRunning() + + return wg, ctx, cancel +} diff --git a/go/vt/workflow/manager_test.go b/go/vt/workflow/manager_test.go index 473d17a532d..03192f45b7f 100644 --- a/go/vt/workflow/manager_test.go +++ b/go/vt/workflow/manager_test.go @@ -18,7 +18,6 @@ package workflow import ( "strings" - "sync" "testing" "time" @@ -29,20 +28,6 @@ import ( workflowpb "vitess.io/vitess/go/vt/proto/workflow" ) -func startManager(t *testing.T, m *Manager) (*sync.WaitGroup, context.CancelFunc) { - ctx, cancel := context.WithCancel(context.Background()) - wg := &sync.WaitGroup{} - wg.Add(1) - go func() { - m.Run(ctx) - wg.Done() - }() - - m.WaitUntilRunning() - - return wg, cancel -} - // TestWaitUntilRunning verifies that WaitUntilRunning() works as expected // (blocking until Run() has advanced far enough), even across multiple Manager // starts and stops. @@ -53,7 +38,7 @@ func TestWaitUntilRunning(t *testing.T) { // Start it 3 times i.e. restart it 2 times. for i := 1; i <= 3; i++ { // Run the manager in the background. - wg, cancel := startManager(t, m) + wg, _, cancel := StartManager(m) // Shut it down and wait for the shutdown to complete. cancel() @@ -67,7 +52,7 @@ func TestManagerSimpleRun(t *testing.T) { m := NewManager(ts) // Run the manager in the background. - wg, cancel := startManager(t, m) + wg, _, cancel := StartManager(m) // Create a Sleep job. uuid, err := m.Create(context.Background(), sleepFactoryName, []string{"-duration", "60"}) @@ -96,7 +81,7 @@ func TestManagerRestart(t *testing.T) { m := NewManager(ts) // Run the manager in the background. - wg, cancel := startManager(t, m) + wg, _, cancel := StartManager(m) // Create a Sleep job. uuid, err := m.Create(context.Background(), sleepFactoryName, []string{"-duration", "60"}) @@ -127,7 +112,7 @@ func TestManagerRestart(t *testing.T) { } // Restart the manager. - wg, cancel = startManager(t, m) + wg, _, cancel = StartManager(m) // Make sure the job is in there shortly. timeout := 0 diff --git a/go/vt/workflow/node.go b/go/vt/workflow/node.go index 26519ff733b..b1087bc3993 100644 --- a/go/vt/workflow/node.go +++ b/go/vt/workflow/node.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "path" + "sort" "strings" "sync" "time" @@ -139,6 +140,7 @@ type Node struct { Path string `json:"path"` Children []*Node `json:"children,omitempty"` LastChanged int64 `json:"lastChanged"` + CreateTime int64 `json:"createTime"` Progress int `json:"progress"` ProgressMessage string `json:"progressMsg"` State workflowpb.WorkflowState `json:"state"` @@ -333,6 +335,9 @@ func (m *NodeManager) toJSON(index int) ([]byte, error) { for _, n := range m.roots { u.Nodes = append(u.Nodes, n) } + sort.Slice(u.Nodes, func(i, j int) bool { + return u.Nodes[i].CreateTime < u.Nodes[j].CreateTime + }) return json.Marshal(u) } diff --git a/go/vt/workflow/resharding/parallel_runner.go b/go/vt/workflow/parallel_runner.go similarity index 79% rename from go/vt/workflow/resharding/parallel_runner.go rename to go/vt/workflow/parallel_runner.go index f9d56c2438a..847bfb8b868 100644 --- a/go/vt/workflow/resharding/parallel_runner.go +++ b/go/vt/workflow/parallel_runner.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resharding +package workflow import ( "fmt" @@ -24,9 +24,11 @@ import ( "golang.org/x/net/context" + "github.com/golang/protobuf/proto" + "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" - "vitess.io/vitess/go/vt/workflow" + "vitess.io/vitess/go/vt/topo" workflowpb "vitess.io/vitess/go/vt/proto/workflow" ) @@ -50,13 +52,16 @@ const ( const taskFinishedMessage = "task finished" +// PhaseType is used to store the phase name in a workflow. +type PhaseType string + // ParallelRunner is used to control executing tasks concurrently. // Each phase has its own ParallelRunner object. type ParallelRunner struct { ctx context.Context uiLogger *logutil.MemoryLogger - rootUINode *workflow.Node - phaseUINode *workflow.Node + rootUINode *Node + phaseUINode *Node checkpointWriter *CheckpointWriter // tasks stores selected tasks for the phase with expected execution order. tasks []*workflowpb.Task @@ -76,7 +81,7 @@ type ParallelRunner struct { } // NewParallelRunner returns a new ParallelRunner. -func NewParallelRunner(ctx context.Context, rootUINode *workflow.Node, cp *CheckpointWriter, tasks []*workflowpb.Task, executeFunc func(context.Context, *workflowpb.Task) error, concurrencyLevel level, enableApprovals bool) *ParallelRunner { +func NewParallelRunner(ctx context.Context, rootUINode *Node, cp *CheckpointWriter, tasks []*workflowpb.Task, executeFunc func(context.Context, *workflowpb.Task) error, concurrencyLevel level, enableApprovals bool) *ParallelRunner { if len(tasks) < 1 { log.Fatal("BUG: No tasks passed into ParallelRunner") } @@ -251,7 +256,7 @@ func (p *ParallelRunner) triggerRetry(taskID string) error { if len(node.Actions) == 0 { log.Fatal("BUG: node actions should not be empty") } - node.Actions = []*workflow.Action{} + node.Actions = []*Action{} node.BroadcastChanges(false /* updateChildren */) close(retryChannel) return nil @@ -274,12 +279,12 @@ func (p *ParallelRunner) addRetryAction(taskID string) chan struct{} { p.retryActionRegistry[taskID] = retryChannel // Enable retry action on the node. - retryAction := &workflow.Action{ + retryAction := &Action{ Name: actionNameRetry, - State: workflow.ActionStateEnabled, - Style: workflow.ActionStyleWaiting, + State: ActionStateEnabled, + Style: ActionStyleWaiting, } - node.Actions = []*workflow.Action{retryAction} + node.Actions = []*Action{retryAction} node.Listener = p node.BroadcastChanges(false /* updateChildren */) return retryChannel @@ -298,10 +303,10 @@ func (p *ParallelRunner) initApprovalActions() { return } - actionFirstApproval := &workflow.Action{ + actionFirstApproval := &Action{ Name: actionNameApproveFirstTask, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, } if isTaskSucceeded(p.tasks[0]) || isTaskRunning(p.tasks[0]) { // Reset the action name if the first task is running or has succeeded. @@ -311,14 +316,14 @@ func (p *ParallelRunner) initApprovalActions() { p.mu.Lock() defer p.mu.Unlock() - p.phaseUINode.Actions = []*workflow.Action{actionFirstApproval} + p.phaseUINode.Actions = []*Action{actionFirstApproval} // Add the approval action for the remaining tasks, // if there are more than one tasks. if len(p.tasks) > 1 { - actionRemainingTasksApproval := &workflow.Action{ + actionRemainingTasksApproval := &Action{ Name: actionNameApproveRemainingTasks, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, } if isTaskSucceeded(p.tasks[1]) || isTaskRunning(p.tasks[1]) { // Reset the action name if the second task is running or has succeeded. @@ -349,7 +354,7 @@ func (p *ParallelRunner) waitForApproval(taskIndex int) { p.mu.Lock() p.firstTaskApproved = make(chan struct{}) firstTaskApproved := p.firstTaskApproved - p.updateApprovalActionLocked(0, actionNameApproveFirstTask, workflow.ActionStateEnabled, workflow.ActionStyleWaiting) + p.updateApprovalActionLocked(0, actionNameApproveFirstTask, ActionStateEnabled, ActionStyleWaiting) p.mu.Unlock() p.setUIMessage(fmt.Sprintf("approve first task enabled: %v", taskIndex)) @@ -358,7 +363,7 @@ func (p *ParallelRunner) waitForApproval(taskIndex int) { case <-firstTaskApproved: p.mu.Lock() defer p.mu.Unlock() - p.updateApprovalActionLocked(0, actionNameApproveFirstTaskDone, workflow.ActionStateDisabled, workflow.ActionStyleTriggered) + p.updateApprovalActionLocked(0, actionNameApproveFirstTaskDone, ActionStateDisabled, ActionStyleTriggered) case <-p.ctx.Done(): return } @@ -367,7 +372,7 @@ func (p *ParallelRunner) waitForApproval(taskIndex int) { p.remainingTasksApproved = make(chan struct{}) remainingTasksApproved := p.remainingTasksApproved - p.updateApprovalActionLocked(1, actionNameApproveRemainingTasks, workflow.ActionStateEnabled, workflow.ActionStyleWaiting) + p.updateApprovalActionLocked(1, actionNameApproveRemainingTasks, ActionStateEnabled, ActionStyleWaiting) p.mu.Unlock() p.setUIMessage(fmt.Sprintf("approve remaining task enabled: %v", taskIndex)) @@ -376,14 +381,14 @@ func (p *ParallelRunner) waitForApproval(taskIndex int) { case <-remainingTasksApproved: p.mu.Lock() defer p.mu.Unlock() - p.updateApprovalActionLocked(1, actionNameApproveRemainingTasksDone, workflow.ActionStateDisabled, workflow.ActionStyleTriggered) + p.updateApprovalActionLocked(1, actionNameApproveRemainingTasksDone, ActionStateDisabled, ActionStyleTriggered) case <-p.ctx.Done(): return } } } -func (p *ParallelRunner) updateApprovalActionLocked(index int, name string, state workflow.ActionState, style workflow.ActionStyle) { +func (p *ParallelRunner) updateApprovalActionLocked(index int, name string, state ActionState, style ActionStyle) { action := p.phaseUINode.Actions[index] action.Name = name action.State = state @@ -396,7 +401,7 @@ func (p *ParallelRunner) clearPhaseActions() { defer p.mu.Unlock() if len(p.phaseUINode.Actions) != 0 { - p.phaseUINode.Actions = []*workflow.Action{} + p.phaseUINode.Actions = []*Action{} p.phaseUINode.BroadcastChanges(false /* updateChildren */) } } @@ -422,3 +427,50 @@ func (p *ParallelRunner) setUIMessage(message string) { p.phaseUINode.Message = message p.phaseUINode.BroadcastChanges(false /* updateChildren */) } + +// VerifyAllTasksDone checks that all tasks are done in a workflow. This should only be used for test purposes. +func VerifyAllTasksDone(ctx context.Context, ts *topo.Server, uuid string) error { + return verifyAllTasksState(ctx, ts, uuid, workflowpb.TaskState_TaskDone) +} + +//verifyAllTasksState verifies that all tasks are in taskState. Only for tests purposes. +func verifyAllTasksState(ctx context.Context, ts *topo.Server, uuid string, taskState workflowpb.TaskState) error { + checkpoint, err := checkpoint(ctx, ts, uuid) + if err != nil { + return err + } + + for _, task := range checkpoint.Tasks { + if task.State != taskState || task.Error != "" { + return fmt.Errorf("task: %v should succeed: task status: %v, %v", task.Id, task.State, task.Attributes) + } + } + return nil +} + +// verifyTask verifies that a task is in taskState. Only for test purposes. +func verifyTask(ctx context.Context, ts *topo.Server, uuid, taskID string, taskState workflowpb.TaskState, taskError string) error { + checkpoint, err := checkpoint(ctx, ts, uuid) + if err != nil { + return err + } + task := checkpoint.Tasks[taskID] + + if task.State != taskState || task.Error != taskError { + return fmt.Errorf("task status: %v, %v fails to match expected status: %v, %v", task.State, task.Error, taskState, taskError) + } + return nil +} + +// checkpoint gets Worfklow from topo server. Only for test purposes. +func checkpoint(ctx context.Context, ts *topo.Server, uuid string) (*workflowpb.WorkflowCheckpoint, error) { + wi, err := ts.GetWorkflow(ctx, uuid) + if err != nil { + return nil, fmt.Errorf("fail to get workflow for: %v", uuid) + } + checkpoint := &workflowpb.WorkflowCheckpoint{} + if err := proto.Unmarshal(wi.Data, checkpoint); err != nil { + return nil, fmt.Errorf("fails to get checkpoint for the workflow: %v", err) + } + return checkpoint, nil +} diff --git a/go/vt/workflow/resharding/parallel_runner_test.go b/go/vt/workflow/parallel_runner_test.go similarity index 81% rename from go/vt/workflow/resharding/parallel_runner_test.go rename to go/vt/workflow/parallel_runner_test.go index 0e7adc2824f..e796f0c3b08 100644 --- a/go/vt/workflow/resharding/parallel_runner_test.go +++ b/go/vt/workflow/parallel_runner_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resharding +package workflow import ( "encoding/json" @@ -26,10 +26,8 @@ import ( "golang.org/x/net/context" - "github.com/golang/protobuf/proto" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" - "vitess.io/vitess/go/vt/workflow" workflowpb "vitess.io/vitess/go/vt/proto/workflow" ) @@ -51,7 +49,7 @@ func TestParallelRunner(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -90,7 +88,7 @@ func TestParallelRunnerApproval(t *testing.T) { // Wait for the workflow to end. m.Wait(context.Background(), uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -192,7 +190,7 @@ func TestParallelRunnerApprovalFromFirstDone(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -244,7 +242,7 @@ func TestParallelRunnerApprovalFromFirstRunning(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -298,7 +296,7 @@ func TestParallelRunnerApprovalFromFirstDoneSecondRunning(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -352,7 +350,7 @@ func TestParallelRunnerApprovalFirstRunningSecondRunning(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } @@ -388,7 +386,7 @@ func TestParallelRunnerApprovalFromAllDone(t *testing.T) { task2ID := createTestTaskID(phaseSimple, 1) checkpointWriter.UpdateTask(task2ID, workflowpb.TaskState_TaskDone, nil) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } @@ -412,7 +410,7 @@ func TestParallelRunnerApprovalFromAllDone(t *testing.T) { t.Fatalf("there should be no actions for node %v: %v, %v", phaseSimple, message, err) } - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -447,23 +445,23 @@ func TestParallelRunnerRetry(t *testing.T) { task1ID := createTestTaskID(phaseSimple, 0) task2ID := createTestTaskID(phaseSimple, 1) - task1Node := &workflow.Node{ + task1Node := &Node{ PathName: "0", - Actions: []*workflow.Action{ + Actions: []*Action{ { Name: actionNameRetry, - State: workflow.ActionStateEnabled, - Style: workflow.ActionStyleWaiting, + State: ActionStateEnabled, + Style: ActionStyleWaiting, }, }, } - task2Node := &workflow.Node{ + task2Node := &Node{ PathName: "1", - Actions: []*workflow.Action{ + Actions: []*Action{ { Name: actionNameRetry, - State: workflow.ActionStateEnabled, - Style: workflow.ActionStyleWaiting, + State: ActionStateEnabled, + Style: ActionStyleWaiting, }, }, } @@ -484,7 +482,7 @@ func TestParallelRunnerRetry(t *testing.T) { t.Fatal(err) } // Check the retry action is removed. - task1Node.Actions = []*workflow.Action{} + task1Node.Actions = []*Action{} if err := consumeNotificationsUntil(notifications, task1Node); err != nil { t.Fatalf("Should get expected update of nodes: %v", task1Node) } @@ -501,7 +499,7 @@ func TestParallelRunnerRetry(t *testing.T) { t.Fatal(err) } // Check the retry action is removed. Task2 is launched after removing actions. - task2Node.Actions = []*workflow.Action{} + task2Node.Actions = []*Action{} if err := consumeNotificationsUntil(notifications, task2Node); err != nil { t.Fatalf("Should get expected update of nodes: %v", task2Node) } @@ -516,7 +514,7 @@ func TestParallelRunnerRetry(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } // Stop the manager. @@ -527,10 +525,10 @@ func TestParallelRunnerRetry(t *testing.T) { wg.Wait() } -func setupTestWorkflow(ctx context.Context, ts *topo.Server, enableApprovals, retry, sequential bool) (*workflow.Manager, string, *sync.WaitGroup, context.CancelFunc, error) { - m := workflow.NewManager(ts) +func setupTestWorkflow(ctx context.Context, ts *topo.Server, enableApprovals, retry, sequential bool) (*Manager, string, *sync.WaitGroup, context.CancelFunc, error) { + m := NewManager(ts) // Run the manager in the background. - wg, _, cancel := startManager(m) + wg, _, cancel := StartManager(m) // Create a testworkflow. enableApprovalsFlag := fmt.Sprintf("-enable_approvals=%v", enableApprovals) @@ -544,7 +542,7 @@ func setupTestWorkflow(ctx context.Context, ts *topo.Server, enableApprovals, re return m, uuid, wg, cancel, nil } -func testworkflow(m *workflow.Manager, uuid string) (*TestWorkflow, error) { +func testworkflow(m *Manager, uuid string) (*TestWorkflow, error) { w, err := m.WorkflowForTesting(uuid) if err != nil { return nil, fmt.Errorf("fail to get workflow from manager: %v", err) @@ -553,28 +551,14 @@ func testworkflow(m *workflow.Manager, uuid string) (*TestWorkflow, error) { return tw, nil } -func startManager(m *workflow.Manager) (*sync.WaitGroup, context.Context, context.CancelFunc) { - // Run the manager in the background. - ctx, cancel := context.WithCancel(context.Background()) - wg := &sync.WaitGroup{} - wg.Add(1) - go func() { - defer wg.Done() - m.Run(ctx) - }() - - m.WaitUntilRunning() - return wg, ctx, cancel -} - -func triggerAction(ctx context.Context, m *workflow.Manager, nodePath, actionName string) error { - return m.NodeManager().Action(ctx, &workflow.ActionParameters{ +func triggerAction(ctx context.Context, m *Manager, nodePath, actionName string) error { + return m.NodeManager().Action(ctx, &ActionParameters{ Path: nodePath, Name: actionName, }) } -func setupNotifications(m *workflow.Manager) (chan []byte, int, error) { +func setupNotifications(m *Manager) (chan []byte, int, error) { // Set up notifications channel to monitor UI updates. notifications := make(chan []byte, 10) _, index, err := m.NodeManager().GetAndWatchFullTree(notifications) @@ -584,19 +568,19 @@ func setupNotifications(m *workflow.Manager) (chan []byte, int, error) { return notifications, index, nil } -func checkUIChangeFromNoneStarted(m *workflow.Manager, uuid string, notifications chan []byte) error { - wantNode := &workflow.Node{ +func checkUIChangeFromNoneStarted(m *Manager, uuid string, notifications chan []byte) error { + wantNode := &Node{ PathName: string(phaseSimple), - Actions: []*workflow.Action{ + Actions: []*Action{ { Name: actionNameApproveFirstTask, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, { Name: actionNameApproveRemainingTasks, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, }, } @@ -607,8 +591,8 @@ func checkUIChangeFromNoneStarted(m *workflow.Manager, uuid string, notification } // First task is ready and approval button is enabled. - wantNode.Actions[0].State = workflow.ActionStateEnabled - wantNode.Actions[0].Style = workflow.ActionStyleWaiting + wantNode.Actions[0].State = ActionStateEnabled + wantNode.Actions[0].Style = ActionStyleWaiting if err := consumeNotificationsUntil(notifications, wantNode); err != nil { return fmt.Errorf("should get expected update of node: %v", wantNode) } @@ -630,18 +614,18 @@ func checkUIChangeFromNoneStarted(m *workflow.Manager, uuid string, notification // 2. the first and second tasks have succeeded, but remaining tasks haven't // succeeded yet. func checkUIChangeAllApproved(notifications chan []byte) error { - wantNode := &workflow.Node{ + wantNode := &Node{ PathName: string(phaseSimple), - Actions: []*workflow.Action{ + Actions: []*Action{ { Name: actionNameApproveFirstTaskDone, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, { Name: actionNameApproveRemainingTasksDone, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, }, } @@ -652,7 +636,7 @@ func checkUIChangeAllApproved(notifications chan []byte) error { } // Approval buttons are cleared after the phase is finished. - wantNode.Actions = []*workflow.Action{} + wantNode.Actions = []*Action{} if err := consumeNotificationsUntil(notifications, wantNode); err != nil { return fmt.Errorf("should get expected update of node: %v", wantNode) } @@ -662,19 +646,19 @@ func checkUIChangeAllApproved(notifications chan []byte) error { // checkUIChangeFirstApproved observes the UI change for 2 scenarios: // 1. the first task is running and the second hasn't started. // 2. the first task is done and the second hasn't started. -func checkUIChangeFirstApproved(m *workflow.Manager, uuid string, notifications chan []byte) error { - wantNode := &workflow.Node{ +func checkUIChangeFirstApproved(m *Manager, uuid string, notifications chan []byte) error { + wantNode := &Node{ PathName: string(phaseSimple), - Actions: []*workflow.Action{ + Actions: []*Action{ { Name: actionNameApproveFirstTaskDone, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, { Name: actionNameApproveRemainingTasks, - State: workflow.ActionStateDisabled, - Style: workflow.ActionStyleTriggered, + State: ActionStateDisabled, + Style: ActionStyleTriggered, }, }, } @@ -687,8 +671,8 @@ func checkUIChangeFirstApproved(m *workflow.Manager, uuid string, notifications // The second task is ready and approval button for remaining tasks is // enabled. - wantNode.Actions[1].State = workflow.ActionStateEnabled - wantNode.Actions[1].Style = workflow.ActionStyleWaiting + wantNode.Actions[1].State = ActionStateEnabled + wantNode.Actions[1].Style = ActionStyleWaiting if err := consumeNotificationsUntil(notifications, wantNode); err != nil { return fmt.Errorf("should get expected update of node: %v", wantNode) } @@ -702,14 +686,14 @@ func checkUIChangeFirstApproved(m *workflow.Manager, uuid string, notifications // consumeNotificationsUntil waits for all wantNodes to be seen from the // notifications of UI change. -func consumeNotificationsUntil(notifications chan []byte, wantNodes ...*workflow.Node) error { - wantSet := make(map[*workflow.Node]bool) +func consumeNotificationsUntil(notifications chan []byte, wantNodes ...*Node) error { + wantSet := make(map[*Node]bool) for _, n := range wantNodes { wantSet[n] = true } for monitor := range notifications { - update := &workflow.Update{} + update := &Update{} if err := json.Unmarshal(monitor, update); err != nil { return err } @@ -733,7 +717,7 @@ func consumeNotificationsUntil(notifications chan []byte, wantNodes ...*workflow return fmt.Errorf("notifications channel is closed unexpectedly when waiting for expected nodes") } -func checkNode(gotNode *workflow.Node, wantNode *workflow.Node) bool { +func checkNode(gotNode *Node, wantNode *Node) bool { if gotNode.PathName != wantNode.PathName || len(gotNode.Actions) != len(wantNode.Actions) { return false } @@ -748,7 +732,7 @@ func checkNode(gotNode *workflow.Node, wantNode *workflow.Node) bool { func checkNoActions(notifications chan []byte, nodePath string) (string, error) { for monitor := range notifications { - update := &workflow.Update{} + update := &Update{} if err := json.Unmarshal(monitor, update); err != nil { return "", err } @@ -768,7 +752,7 @@ func checkNoActions(notifications chan []byte, nodePath string) (string, error) func waitForFinished(notifications chan []byte, path, message string) error { for monitor := range notifications { - update := &workflow.Update{} + update := &Update{} if err := json.Unmarshal(monitor, update); err != nil { return err } @@ -785,46 +769,3 @@ func waitForFinished(notifications chan []byte, path, message string) error { } return fmt.Errorf("notifications channel is closed unexpectedly when waiting for expected nodes") } - -func verifyAllTasksState(ctx context.Context, ts *topo.Server, uuid string, taskState workflowpb.TaskState) error { - checkpoint, err := checkpoint(ctx, ts, uuid) - if err != nil { - return err - } - - for _, task := range checkpoint.Tasks { - if task.State != taskState || task.Error != "" { - return fmt.Errorf("task: %v should succeed: task status: %v, %v", task.Id, task.State, task.Attributes) - } - } - return nil -} - -func verifyAllTasksDone(ctx context.Context, ts *topo.Server, uuid string) error { - return verifyAllTasksState(ctx, ts, uuid, workflowpb.TaskState_TaskDone) -} - -func verifyTask(ctx context.Context, ts *topo.Server, uuid, taskID string, taskState workflowpb.TaskState, taskError string) error { - checkpoint, err := checkpoint(ctx, ts, uuid) - if err != nil { - return err - } - task := checkpoint.Tasks[taskID] - - if task.State != taskState || task.Error != taskError { - return fmt.Errorf("task status: %v, %v fails to match expected status: %v, %v", task.State, task.Error, taskState, taskError) - } - return nil -} - -func checkpoint(ctx context.Context, ts *topo.Server, uuid string) (*workflowpb.WorkflowCheckpoint, error) { - wi, err := ts.GetWorkflow(ctx, uuid) - if err != nil { - return nil, fmt.Errorf("fail to get workflow for: %v", uuid) - } - checkpoint := &workflowpb.WorkflowCheckpoint{} - if err := proto.Unmarshal(wi.Workflow.Data, checkpoint); err != nil { - return nil, fmt.Errorf("fails to get checkpoint for the workflow: %v", err) - } - return checkpoint, nil -} diff --git a/go/vt/workflow/resharding/tasks.go b/go/vt/workflow/resharding/tasks.go index cb283fcb0b6..61ae80e5b97 100644 --- a/go/vt/workflow/resharding/tasks.go +++ b/go/vt/workflow/resharding/tasks.go @@ -25,19 +25,20 @@ import ( "vitess.io/vitess/go/vt/automation" "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/workflow" "vitess.io/vitess/go/vt/wrangler" topodatapb "vitess.io/vitess/go/vt/proto/topodata" workflowpb "vitess.io/vitess/go/vt/proto/workflow" ) -func createTaskID(phase PhaseType, shardName string) string { +func createTaskID(phase workflow.PhaseType, shardName string) string { return fmt.Sprintf("%s/%s", phase, shardName) } // GetTasks returns selected tasks for a phase from the checkpoint // with expected execution order. -func (hw *HorizontalReshardingWorkflow) GetTasks(phase PhaseType) []*workflowpb.Task { +func (hw *horizontalReshardingWorkflow) GetTasks(phase workflow.PhaseType) []*workflowpb.Task { var shards []string switch phase { case phaseCopySchema, phaseWaitForFilteredReplication, phaseDiff: @@ -56,7 +57,7 @@ func (hw *HorizontalReshardingWorkflow) GetTasks(phase PhaseType) []*workflowpb. return tasks } -func (hw *HorizontalReshardingWorkflow) runCopySchema(ctx context.Context, t *workflowpb.Task) error { +func (hw *horizontalReshardingWorkflow) runCopySchema(ctx context.Context, t *workflowpb.Task) error { keyspace := t.Attributes["keyspace"] sourceShard := t.Attributes["source_shard"] destShard := t.Attributes["destination_shard"] @@ -64,7 +65,7 @@ func (hw *HorizontalReshardingWorkflow) runCopySchema(ctx context.Context, t *wo keyspace, sourceShard, keyspace, destShard, wrangler.DefaultWaitSlaveTimeout) } -func (hw *HorizontalReshardingWorkflow) runSplitClone(ctx context.Context, t *workflowpb.Task) error { +func (hw *horizontalReshardingWorkflow) runSplitClone(ctx context.Context, t *workflowpb.Task) error { keyspace := t.Attributes["keyspace"] sourceShard := t.Attributes["source_shard"] worker := t.Attributes["vtworker"] @@ -83,13 +84,13 @@ func (hw *HorizontalReshardingWorkflow) runSplitClone(ctx context.Context, t *wo return err } -func (hw *HorizontalReshardingWorkflow) runWaitForFilteredReplication(ctx context.Context, t *workflowpb.Task) error { +func (hw *horizontalReshardingWorkflow) runWaitForFilteredReplication(ctx context.Context, t *workflowpb.Task) error { keyspace := t.Attributes["keyspace"] destShard := t.Attributes["destination_shard"] return hw.wr.WaitForFilteredReplication(ctx, keyspace, destShard, wrangler.DefaultWaitForFilteredReplicationMaxDelay) } -func (hw *HorizontalReshardingWorkflow) runSplitDiff(ctx context.Context, t *workflowpb.Task) error { +func (hw *horizontalReshardingWorkflow) runSplitDiff(ctx context.Context, t *workflowpb.Task) error { keyspace := t.Attributes["keyspace"] destShard := t.Attributes["destination_shard"] destinationTabletType := t.Attributes["dest_tablet_type"] @@ -103,7 +104,7 @@ func (hw *HorizontalReshardingWorkflow) runSplitDiff(ctx context.Context, t *wor return err } -func (hw *HorizontalReshardingWorkflow) runMigrate(ctx context.Context, t *workflowpb.Task) error { +func (hw *horizontalReshardingWorkflow) runMigrate(ctx context.Context, t *workflowpb.Task) error { keyspace := t.Attributes["keyspace"] sourceShard := t.Attributes["source_shard"] servedTypeStr := t.Attributes["served_type"] diff --git a/go/vt/workflow/resharding/horizontal_resharding_workflow.go b/go/vt/workflow/resharding/workflow.go similarity index 54% rename from go/vt/workflow/resharding/horizontal_resharding_workflow.go rename to go/vt/workflow/resharding/workflow.go index 5152da21bfa..c0fe36df72b 100644 --- a/go/vt/workflow/resharding/horizontal_resharding_workflow.go +++ b/go/vt/workflow/resharding/workflow.go @@ -32,9 +32,8 @@ import ( "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/vttablet/tmclient" - "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/workflow" "vitess.io/vitess/go/vt/wrangler" @@ -43,43 +42,43 @@ import ( ) const ( - codeVersion = 1 + codeVersion = 2 horizontalReshardingFactoryName = "horizontal_resharding" ) -// PhaseType is used to store the phase name in a workflow. -type PhaseType string - const ( - phaseCopySchema PhaseType = "copy_schema" - phaseClone PhaseType = "clone" - phaseWaitForFilteredReplication PhaseType = "wait_for_filtered_replication" - phaseDiff PhaseType = "diff" - phaseMigrateRdonly PhaseType = "migrate_rdonly" - phaseMigrateReplica PhaseType = "migrate_replica" - phaseMigrateMaster PhaseType = "migrate_master" + phaseCopySchema workflow.PhaseType = "copy_schema" + phaseClone workflow.PhaseType = "clone" + phaseWaitForFilteredReplication workflow.PhaseType = "wait_for_filtered_replication" + phaseDiff workflow.PhaseType = "diff" + phaseMigrateRdonly workflow.PhaseType = "migrate_rdonly" + phaseMigrateReplica workflow.PhaseType = "migrate_replica" + phaseMigrateMaster workflow.PhaseType = "migrate_master" ) // Register registers the HorizontalReshardingWorkflowFactory as a factory // in the workflow framework. func Register() { - workflow.Register(horizontalReshardingFactoryName, &HorizontalReshardingWorkflowFactory{}) + workflow.Register(horizontalReshardingFactoryName, &Factory{}) } -// HorizontalReshardingWorkflowFactory is the factory to create +// Factory is the factory to create // a horizontal resharding workflow. -type HorizontalReshardingWorkflowFactory struct{} +type Factory struct{} // Init is part of the workflow.Factory interface. -func (*HorizontalReshardingWorkflowFactory) Init(m *workflow.Manager, w *workflowpb.Workflow, args []string) error { +func (*Factory) Init(m *workflow.Manager, w *workflowpb.Workflow, args []string) error { subFlags := flag.NewFlagSet(horizontalReshardingFactoryName, flag.ContinueOnError) keyspace := subFlags.String("keyspace", "", "Name of keyspace to perform horizontal resharding") vtworkersStr := subFlags.String("vtworkers", "", "A comma-separated list of vtworker addresses") + sourceShardsStr := subFlags.String("source_shards", "", "A comma-separated list of source shards") + destinationShardsStr := subFlags.String("destination_shards", "", "A comma-separated list of destination shards") minHealthyRdonlyTablets := subFlags.String("min_healthy_rdonly_tablets", "1", "Minimum number of healthy RDONLY tablets required in source shards") splitCmd := subFlags.String("split_cmd", "SplitClone", "Split command to use to perform horizontal resharding (either SplitClone or LegacySplitClone)") splitDiffDestTabletType := subFlags.String("split_diff_dest_tablet_type", "RDONLY", "Specifies tablet type to use in destination shards while performing SplitDiff operation") - enableApprovals := subFlags.Bool("enable_approvals", true, "If true, executions of tasks require user's approvals on the UI.") + phaseEnaableApprovalsDesc := fmt.Sprintf("Comma separated phases that require explicit approval in the UI to execute. Phase names are: %v", strings.Join(WorkflowPhases(), ",")) + phaseEnableApprovalsStr := subFlags.String("phase_enable_approvals", strings.Join(WorkflowPhases(), ","), phaseEnaableApprovalsDesc) if err := subFlags.Parse(args); err != nil { return err @@ -89,14 +88,33 @@ func (*HorizontalReshardingWorkflowFactory) Init(m *workflow.Manager, w *workflo } vtworkers := strings.Split(*vtworkersStr, ",") - w.Name = fmt.Sprintf("Horizontal resharding on keyspace %s", *keyspace) + sourceShards := strings.Split(*sourceShardsStr, ",") + destinationShards := strings.Split(*destinationShardsStr, ",") + phaseEnableApprovals := parsePhaseEnableApprovals(*phaseEnableApprovalsStr) + for _, phase := range phaseEnableApprovals { + validPhase := false + for _, registeredPhase := range WorkflowPhases() { + if phase == registeredPhase { + validPhase = true + } + } + if !validPhase { + return fmt.Errorf("Invalid phase in phase_enable_approvals: %v", phase) + } + } + + err := validateWorkflow(m, *keyspace, vtworkers, sourceShards, destinationShards, *minHealthyRdonlyTablets) + if err != nil { + return err + } - checkpoint, err := initCheckpoint(m.TopoServer(), *keyspace, vtworkers, *minHealthyRdonlyTablets, *splitCmd, *splitDiffDestTabletType) + w.Name = fmt.Sprintf("Reshard shards %v into shards %v of keyspace %v.", *keyspace, *sourceShardsStr, *destinationShardsStr) + checkpoint, err := initCheckpoint(*keyspace, vtworkers, sourceShards, destinationShards, *minHealthyRdonlyTablets, *splitCmd, *splitDiffDestTabletType) if err != nil { return err } - checkpoint.Settings["enable_approvals"] = fmt.Sprintf("%v", *enableApprovals) + checkpoint.Settings["phase_enable_approvals"] = *phaseEnableApprovalsStr w.Data, err = proto.Marshal(checkpoint) if err != nil { @@ -106,7 +124,7 @@ func (*HorizontalReshardingWorkflowFactory) Init(m *workflow.Manager, w *workflo } // Instantiate is part the workflow.Factory interface. -func (*HorizontalReshardingWorkflowFactory) Instantiate(m *workflow.Manager, w *workflowpb.Workflow, rootNode *workflow.Node) (workflow.Workflow, error) { +func (*Factory) Instantiate(m *workflow.Manager, w *workflowpb.Workflow, rootNode *workflow.Node) (workflow.Workflow, error) { rootNode.Message = "This is a workflow to execute horizontal resharding automatically." checkpoint := &workflowpb.WorkflowCheckpoint{} @@ -114,19 +132,19 @@ func (*HorizontalReshardingWorkflowFactory) Instantiate(m *workflow.Manager, w * return nil, err } - enableApprovals, err := strconv.ParseBool(checkpoint.Settings["enable_approvals"]) - if err != nil { - return nil, err + phaseEnableApprovals := make(map[string]bool) + for _, phase := range parsePhaseEnableApprovals(checkpoint.Settings["phase_enable_approvals"]) { + phaseEnableApprovals[phase] = true } - hw := &HorizontalReshardingWorkflow{ - checkpoint: checkpoint, - rootUINode: rootNode, - logger: logutil.NewMemoryLogger(), - wr: wrangler.New(logutil.NewConsoleLogger(), m.TopoServer(), tmclient.NewTabletManagerClient()), - topoServer: m.TopoServer(), - manager: m, - enableApprovals: enableApprovals, + hw := &horizontalReshardingWorkflow{ + checkpoint: checkpoint, + rootUINode: rootNode, + logger: logutil.NewMemoryLogger(), + wr: wrangler.New(logutil.NewConsoleLogger(), m.TopoServer(), tmclient.NewTabletManagerClient()), + topoServer: m.TopoServer(), + manager: m, + phaseEnableApprovals: phaseEnableApprovals, } copySchemaUINode := &workflow.Node{ Name: "CopySchemaShard", @@ -195,7 +213,7 @@ func (*HorizontalReshardingWorkflowFactory) Instantiate(m *workflow.Manager, w * return hw, nil } -func createUINodes(rootNode *workflow.Node, phaseName PhaseType, shards []string) error { +func createUINodes(rootNode *workflow.Node, phaseName workflow.PhaseType, shards []string) error { phaseNode, err := rootNode.GetChildByPath(string(phaseName)) if err != nil { return fmt.Errorf("fails to find phase node for: %v", phaseName) @@ -211,47 +229,46 @@ func createUINodes(rootNode *workflow.Node, phaseName PhaseType, shards []string return nil } -// initCheckpoint initialize the checkpoint for the horizontal workflow. -func initCheckpoint(ts *topo.Server, keyspace string, vtworkers []string, minHealthyRdonlyTablets, splitCmd, splitDiffDestTabletType string) (*workflowpb.WorkflowCheckpoint, error) { - sourceShards, destinationShards, err := findSourceAndDestinationShards(ts, keyspace) - if err != nil { - return nil, err +// validateWorkflow validates that workflow has valid input parameters. +func validateWorkflow(m *workflow.Manager, keyspace string, vtworkers, sourceShards, destinationShards []string, minHealthyRdonlyTablets string) error { + if len(sourceShards) == 0 || len(destinationShards) == 0 { + return fmt.Errorf("invalid source or destination shards") + } + if len(vtworkers) != len(destinationShards) { + return fmt.Errorf("there are %v vtworkers, %v destination shards: the number should be same", len(vtworkers), len(destinationShards)) } - return initCheckpointFromShards(keyspace, vtworkers, sourceShards, destinationShards, minHealthyRdonlyTablets, splitCmd, splitDiffDestTabletType) -} -func findSourceAndDestinationShards(ts *topo.Server, keyspace string) ([]string, []string, error) { - overlappingShards, err := topotools.FindOverlappingShards(context.Background(), ts, keyspace) - if err != nil { - return nil, nil, err + splitRatio := len(destinationShards) / len(sourceShards) + if minHealthyRdonlyTabletsVal, err := strconv.Atoi(minHealthyRdonlyTablets); err != nil || minHealthyRdonlyTabletsVal < splitRatio { + return fmt.Errorf("there are not enough rdonly tablets in source shards. You need at least %v, it got: %v", splitRatio, minHealthyRdonlyTablets) } - var sourceShards, destinationShards []string + // find the OverlappingShards in the keyspace + osList, err := topotools.FindOverlappingShards(context.Background(), m.TopoServer(), keyspace) + if err != nil { + return fmt.Errorf("cannot FindOverlappingShards in %v: %v", keyspace, err) + } - for _, os := range overlappingShards { - var sourceShardInfo *topo.ShardInfo - var destinationShardInfos []*topo.ShardInfo - // Judge which side is source shard by checking the number of servedTypes. - if len(os.Left[0].ServedTypes) > 0 { - sourceShardInfo = os.Left[0] - destinationShardInfos = os.Right - } else { - sourceShardInfo = os.Right[0] - destinationShardInfos = os.Left + // find the shard we mentioned in there, if any + os := topotools.OverlappingShardsForShard(osList, sourceShards[0]) + if os == nil { + return fmt.Errorf("the specified source shard %v/%v is not in any overlapping shard", keyspace, sourceShards[0]) + } + for _, sourceShard := range sourceShards { + if !os.ContainsShard(sourceShard) { + return fmt.Errorf("the specified source shard %v/%v is not in any overlapping shard", keyspace, sourceShard) } - sourceShards = append(sourceShards, sourceShardInfo.ShardName()) - for _, d := range destinationShardInfos { - destinationShards = append(destinationShards, d.ShardName()) + } + for _, destinationShard := range destinationShards { + if !os.ContainsShard(destinationShard) { + return fmt.Errorf("the specified destination shard %v/%v is not in any overlapping shard", keyspace, destinationShard) } } - return sourceShards, destinationShards, nil + return nil } -func initCheckpointFromShards(keyspace string, vtworkers, sourceShards, destinationShards []string, minHealthyRdonlyTablets, splitCmd, splitDiffDestTabletType string) (*workflowpb.WorkflowCheckpoint, error) { - if len(vtworkers) != len(sourceShards) { - return nil, fmt.Errorf("there are %v vtworkers, %v source shards: the number should be same", len(vtworkers), len(sourceShards)) - } - +// initCheckpoint initialize the checkpoint for the horizontal workflow. +func initCheckpoint(keyspace string, vtworkers, sourceShards, destinationShards []string, minHealthyRdonlyTablets, splitCmd, splitDiffDestTabletType string) (*workflowpb.WorkflowCheckpoint, error) { tasks := make(map[string]*workflowpb.Task) initTasks(tasks, phaseCopySchema, destinationShards, func(i int, shard string) map[string]string { return map[string]string{ @@ -280,7 +297,7 @@ func initCheckpointFromShards(keyspace string, vtworkers, sourceShards, destinat "keyspace": keyspace, "destination_shard": shard, "dest_tablet_type": splitDiffDestTabletType, - "vtworker": vtworkers[0], + "vtworker": vtworkers[i], } }) initTasks(tasks, phaseMigrateRdonly, sourceShards, func(i int, shard string) map[string]string { @@ -315,7 +332,7 @@ func initCheckpointFromShards(keyspace string, vtworkers, sourceShards, destinat }, nil } -func initTasks(tasks map[string]*workflowpb.Task, phase PhaseType, shards []string, getAttributes func(int, string) map[string]string) { +func initTasks(tasks map[string]*workflowpb.Task, phase workflow.PhaseType, shards []string, getAttributes func(int, string) map[string]string) { for i, shard := range shards { taskID := createTaskID(phase, shard) tasks[taskID] = &workflowpb.Task{ @@ -326,9 +343,9 @@ func initTasks(tasks map[string]*workflowpb.Task, phase PhaseType, shards []stri } } -// HorizontalReshardingWorkflow contains meta-information and methods to +// horizontalReshardingWorkflow contains meta-information and methods to // control the horizontal resharding workflow. -type HorizontalReshardingWorkflow struct { +type horizontalReshardingWorkflow struct { ctx context.Context wr ReshardingWrangler manager *workflow.Manager @@ -341,17 +358,17 @@ type HorizontalReshardingWorkflow struct { rootUINode *workflow.Node checkpoint *workflowpb.WorkflowCheckpoint - checkpointWriter *CheckpointWriter + checkpointWriter *workflow.CheckpointWriter - enableApprovals bool + phaseEnableApprovals map[string]bool } // Run executes the horizontal resharding process. // It implements the workflow.Workflow interface. -func (hw *HorizontalReshardingWorkflow) Run(ctx context.Context, manager *workflow.Manager, wi *topo.WorkflowInfo) error { +func (hw *horizontalReshardingWorkflow) Run(ctx context.Context, manager *workflow.Manager, wi *topo.WorkflowInfo) error { hw.ctx = ctx hw.wi = wi - hw.checkpointWriter = NewCheckpointWriter(hw.topoServer, hw.checkpoint, hw.wi) + hw.checkpointWriter = workflow.NewCheckpointWriter(hw.topoServer, hw.checkpoint, hw.wi) hw.rootUINode.Display = workflow.NodeDisplayDeterminate hw.rootUINode.BroadcastChanges(true /* updateChildren */) @@ -362,55 +379,89 @@ func (hw *HorizontalReshardingWorkflow) Run(ctx context.Context, manager *workfl return nil } -func (hw *HorizontalReshardingWorkflow) runWorkflow() error { +func (hw *horizontalReshardingWorkflow) runWorkflow() error { copySchemaTasks := hw.GetTasks(phaseCopySchema) - copySchemaRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, copySchemaTasks, hw.runCopySchema, Parallel, hw.enableApprovals) + copySchemaRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, copySchemaTasks, hw.runCopySchema, workflow.Parallel, hw.phaseEnableApprovals[string(phaseCopySchema)]) if err := copySchemaRunner.Run(); err != nil { return err } cloneTasks := hw.GetTasks(phaseClone) - cloneRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, cloneTasks, hw.runSplitClone, Parallel, hw.enableApprovals) + cloneRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, cloneTasks, hw.runSplitClone, workflow.Parallel, hw.phaseEnableApprovals[string(phaseClone)]) if err := cloneRunner.Run(); err != nil { return err } waitForFilteredReplicationTasks := hw.GetTasks(phaseWaitForFilteredReplication) - waitForFilteredReplicationRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, waitForFilteredReplicationTasks, hw.runWaitForFilteredReplication, Parallel, hw.enableApprovals) + waitForFilteredReplicationRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, waitForFilteredReplicationTasks, hw.runWaitForFilteredReplication, workflow.Parallel, hw.phaseEnableApprovals[string(phaseWaitForFilteredReplication)]) if err := waitForFilteredReplicationRunner.Run(); err != nil { return err } diffTasks := hw.GetTasks(phaseDiff) - diffRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, diffTasks, hw.runSplitDiff, Sequential, hw.enableApprovals) + diffRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, diffTasks, hw.runSplitDiff, workflow.Parallel, hw.phaseEnableApprovals[string(phaseWaitForFilteredReplication)]) if err := diffRunner.Run(); err != nil { return err } migrateRdonlyTasks := hw.GetTasks(phaseMigrateRdonly) - migrateRdonlyRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateRdonlyTasks, hw.runMigrate, Sequential, hw.enableApprovals) + migrateRdonlyRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateRdonlyTasks, hw.runMigrate, workflow.Sequential, hw.phaseEnableApprovals[string(phaseMigrateRdonly)]) if err := migrateRdonlyRunner.Run(); err != nil { return err } migrateReplicaTasks := hw.GetTasks(phaseMigrateReplica) - migrateReplicaRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateReplicaTasks, hw.runMigrate, Sequential, hw.enableApprovals) + migrateReplicaRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateReplicaTasks, hw.runMigrate, workflow.Sequential, hw.phaseEnableApprovals[string(phaseMigrateReplica)]) if err := migrateReplicaRunner.Run(); err != nil { return err } migrateMasterTasks := hw.GetTasks(phaseMigrateMaster) - migrateMasterRunner := NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateMasterTasks, hw.runMigrate, Sequential, hw.enableApprovals) - if err := migrateMasterRunner.Run(); err != nil { - return err - } - - return nil + migrateMasterRunner := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, migrateMasterTasks, hw.runMigrate, workflow.Sequential, hw.phaseEnableApprovals[string(phaseMigrateReplica)]) + return migrateMasterRunner.Run() } -func (hw *HorizontalReshardingWorkflow) setUIMessage(message string) { +func (hw *horizontalReshardingWorkflow) setUIMessage(message string) { log.Infof("Horizontal resharding : %v.", message) + hw.logger.Infof(message) hw.rootUINode.Log = hw.logger.String() hw.rootUINode.Message = message hw.rootUINode.BroadcastChanges(false /* updateChildren */) } + +func defaultPhaseDisableApprovals() map[workflow.PhaseType]bool { + return map[workflow.PhaseType]bool{ + phaseCopySchema: false, + phaseClone: false, + phaseWaitForFilteredReplication: false, + phaseDiff: false, + phaseMigrateRdonly: false, + phaseMigrateReplica: false, + phaseMigrateMaster: false, + } +} + +// WorkflowPhases returns phases for resharding workflow +func WorkflowPhases() []string { + return []string{ + string(phaseCopySchema), + string(phaseClone), + string(phaseWaitForFilteredReplication), + string(phaseDiff), + string(phaseMigrateReplica), + string(phaseMigrateRdonly), + string(phaseMigrateMaster), + } +} + +func parsePhaseEnableApprovals(phaseEnableApprovalsStr string) []string { + var phaseEnableApprovals []string + if phaseEnableApprovalsStr == "" { + return phaseEnableApprovals + } + phaseEnableApprovals = strings.Split(phaseEnableApprovalsStr, ",") + for i, phase := range phaseEnableApprovals { + phaseEnableApprovals[i] = strings.Trim(phase, " ") + } + return phaseEnableApprovals +} diff --git a/go/vt/workflow/resharding/horizontal_resharding_workflow_test.go b/go/vt/workflow/resharding/workflow_test.go similarity index 66% rename from go/vt/workflow/resharding/horizontal_resharding_workflow_test.go rename to go/vt/workflow/resharding/workflow_test.go index 56170203801..b5c384a85f1 100644 --- a/go/vt/workflow/resharding/horizontal_resharding_workflow_test.go +++ b/go/vt/workflow/resharding/workflow_test.go @@ -45,6 +45,49 @@ func init() { Register() } +// TestSourceDestShards tests that provided source/dest shards are valid +func TestSourceDestShards(t *testing.T) { + ctx := context.Background() + + // Set up the mock wrangler. It is used for the CopySchema, + // WaitforFilteredReplication and Migrate phase. + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // Set up the fakeworkerclient. It is used at SplitClone and SplitDiff phase. + fakeVtworkerClient := setupFakeVtworker(testKeyspace, testVtworkers) + vtworkerclient.RegisterFactory("fake", fakeVtworkerClient.FakeVtworkerClientFactory) + defer vtworkerclient.UnregisterFactoryForTest("fake") + + // Initialize the topology. + ts := setupTopology(ctx, t, testKeyspace) + m := workflow.NewManager(ts) + // Run the manager in the background. + _, _, cancel := workflow.StartManager(m) + // Create the workflow. + vtworkersParameter := testVtworkers + "," + testVtworkers + _, err := m.Create(ctx, horizontalReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + vtworkersParameter, "-phase_enable_approvals=", "-min_healthy_rdonly_tablets=2", "-source_shards=0", "-destination_shards=-40,40-"}) + want := "the specified destination shard test_keyspace/-40 is not in any overlapping shard" + if err == nil || err.Error() != want { + t.Errorf("workflow error: %v, want %s", err, want) + } + + _, err = m.Create(ctx, horizontalReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + vtworkersParameter, "-phase_enable_approvals=", "-min_healthy_rdonly_tablets=2", "-source_shards=0", "-destination_shards=-80,40-"}) + + want = "the specified destination shard test_keyspace/40- is not in any overlapping shard" + if err == nil || err.Error() != want { + t.Errorf("workflow error: %v, want %s", err, want) + } + + _, err = m.Create(ctx, horizontalReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + vtworkersParameter, "-phase_enable_approvals=", "-min_healthy_rdonly_tablets=2", "-source_shards=-20", "-destination_shards=-80,80-"}) + + want = "the specified source shard test_keyspace/-20 is not in any overlapping shard" + if err == nil || err.Error() != want { + t.Errorf("workflow error: %v, want %s", err, want) + } + cancel() +} + // TestHorizontalResharding runs the happy path of HorizontalReshardingWorkflow. func TestHorizontalResharding(t *testing.T) { ctx := context.Background() @@ -64,9 +107,10 @@ func TestHorizontalResharding(t *testing.T) { ts := setupTopology(ctx, t, testKeyspace) m := workflow.NewManager(ts) // Run the manager in the background. - wg, _, cancel := startManager(m) + wg, _, cancel := workflow.StartManager(m) // Create the workflow. - uuid, err := m.Create(ctx, horizontalReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + testVtworkers, "-enable_approvals=false"}) + vtworkersParameter := testVtworkers + "," + testVtworkers + uuid, err := m.Create(ctx, horizontalReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + vtworkersParameter, "-phase_enable_approvals=", "-min_healthy_rdonly_tablets=2", "-source_shards=0", "-destination_shards=-80,80-"}) if err != nil { t.Fatalf("cannot create resharding workflow: %v", err) } @@ -75,7 +119,7 @@ func TestHorizontalResharding(t *testing.T) { if err != nil { t.Fatalf("fail to get workflow from manager: %v", err) } - hw := w.(*HorizontalReshardingWorkflow) + hw := w.(*horizontalReshardingWorkflow) hw.wr = mockWranglerInterface // Start the job. @@ -85,7 +129,7 @@ func TestHorizontalResharding(t *testing.T) { // Wait for the workflow to end. m.Wait(ctx, uuid) - if err := verifyAllTasksDone(ctx, ts, uuid); err != nil { + if err := workflow.VerifyAllTasksDone(ctx, ts, uuid); err != nil { t.Fatal(err) } @@ -101,7 +145,7 @@ func setupFakeVtworker(keyspace, vtworkers string) *fakevtworkerclient.FakeVtwor flag.Set("vtworker_client_protocol", "fake") fakeVtworkerClient := fakevtworkerclient.NewFakeVtworkerClient() fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"Reset"}, "", nil) - fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"SplitClone", "--min_healthy_rdonly_tablets=1", keyspace + "/0"}, "", nil) + fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"SplitClone", "--min_healthy_rdonly_tablets=2", keyspace + "/0"}, "", nil) fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"Reset"}, "", nil) fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"SplitDiff", "--min_healthy_rdonly_tablets=1", "--dest_tablet_type=RDONLY", keyspace + "/-80"}, "", nil) fakeVtworkerClient.RegisterResultForAddr(vtworkers, []string{"Reset"}, "", nil) diff --git a/go/vt/workflow/reshardingworkflowgen/workflow.go b/go/vt/workflow/reshardingworkflowgen/workflow.go new file mode 100644 index 00000000000..d3d655bf98d --- /dev/null +++ b/go/vt/workflow/reshardingworkflowgen/workflow.go @@ -0,0 +1,338 @@ +/* +Copyright 2018 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 agreedto 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 reshardingworkflowgen + +// This package contains a workflow to generate horizontal resharding workflows +// that automatically discovers available overlapping shards to split/merge. + +import ( + "flag" + "fmt" + "path" + "strconv" + "strings" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + + "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/workflow" + "vitess.io/vitess/go/vt/workflow/resharding" + + workflowpb "vitess.io/vitess/go/vt/proto/workflow" +) + +const ( + codeVersion = 1 + + keyspaceReshardingFactoryName = "hr_workflow_gen" + phaseName = "create_workflows" +) + +// Register registers the KeyspaceResharding as a factory +// in the workflow framework. +func Register() { + workflow.Register(keyspaceReshardingFactoryName, &Factory{}) +} + +// Factory is the factory to create +// a horizontal resharding workflow. +type Factory struct{} + +// Init is part of the workflow.Factory interface. +func (*Factory) Init(m *workflow.Manager, w *workflowpb.Workflow, args []string) error { + subFlags := flag.NewFlagSet(keyspaceReshardingFactoryName, flag.ContinueOnError) + keyspace := subFlags.String("keyspace", "", "Name of keyspace to perform horizontal resharding") + vtworkersStr := subFlags.String("vtworkers", "", "A comma-separated list of vtworker addresses") + minHealthyRdonlyTablets := subFlags.String("min_healthy_rdonly_tablets", "1", "Minimum number of healthy RDONLY tablets required in source shards") + splitCmd := subFlags.String("split_cmd", "SplitClone", "Split command to use to perform horizontal resharding (either SplitClone or LegacySplitClone)") + splitDiffDestTabletType := subFlags.String("split_diff_dest_tablet_type", "RDONLY", "Specifies tablet type to use in destination shards while performing SplitDiff operation") + skipStartWorkflows := subFlags.Bool("skip_start_workflows", true, "If true, newly created workflows will have skip_start set") + phaseEnableApprovalsDesc := fmt.Sprintf("Comma separated phases that require explicit approval in the UI to execute. Phase names are: %v", strings.Join(resharding.WorkflowPhases(), ",")) + phaseEnableApprovalsStr := subFlags.String("phase_enable_approvals", strings.Join(resharding.WorkflowPhases(), ","), phaseEnableApprovalsDesc) + + if err := subFlags.Parse(args); err != nil { + return err + } + if *keyspace == "" || *vtworkersStr == "" || *minHealthyRdonlyTablets == "" || *splitCmd == "" { + return fmt.Errorf("Keyspace name, min healthy rdonly tablets, split command, and vtworkers information must be provided for horizontal resharding") + } + + vtworkers := strings.Split(*vtworkersStr, ",") + + w.Name = fmt.Sprintf("Keyspace reshard on %s", *keyspace) + shardsToSplit, err := findSourceAndDestinationShards(m.TopoServer(), *keyspace) + if err != nil { + return err + } + + checkpoint, err := initCheckpoint( + *keyspace, + vtworkers, + shardsToSplit, + *minHealthyRdonlyTablets, + *splitCmd, + *splitDiffDestTabletType, + *phaseEnableApprovalsStr, + *skipStartWorkflows, + ) + if err != nil { + return err + } + + w.Data, err = proto.Marshal(checkpoint) + if err != nil { + return err + } + return nil +} + +// Instantiate is part the workflow.Factory interface. +func (*Factory) Instantiate(m *workflow.Manager, w *workflowpb.Workflow, rootNode *workflow.Node) (workflow.Workflow, error) { + rootNode.Message = "This is a workflow to execute a keyspace resharding automatically." + + checkpoint := &workflowpb.WorkflowCheckpoint{} + if err := proto.Unmarshal(w.Data, checkpoint); err != nil { + return nil, err + } + + workflowsCount, err := strconv.Atoi(checkpoint.Settings["workflows_count"]) + if err != nil { + return nil, err + } + + hw := &reshardingWorkflowGen{ + checkpoint: checkpoint, + rootUINode: rootNode, + logger: logutil.NewMemoryLogger(), + topoServer: m.TopoServer(), + manager: m, + phaseEnableApprovalsParam: checkpoint.Settings["phase_enable_approvals"], + skipStartWorkflowParam: checkpoint.Settings["skip_start_workflows"], + minHealthyRdonlyTabletsParam: checkpoint.Settings["min_healthy_rdonly_tablets"], + keyspaceParam: checkpoint.Settings["keyspace"], + splitDiffDestTabletTypeParam: checkpoint.Settings["split_diff_dest_tablet_type"], + splitCmdParam: checkpoint.Settings["split_cmd"], + workflowsCount: workflowsCount, + } + createWorkflowsUINode := &workflow.Node{ + Name: "CreateWorkflows", + PathName: phaseName, + } + hw.rootUINode.Children = []*workflow.Node{ + createWorkflowsUINode, + } + + phaseNode, err := rootNode.GetChildByPath(phaseName) + if err != nil { + return nil, fmt.Errorf("fails to find phase node for: %v", phaseName) + } + + for i := 0; i < workflowsCount; i++ { + taskID := fmt.Sprintf("%s/%v", phaseName, i) + task := hw.checkpoint.Tasks[taskID] + taskUINode := &workflow.Node{ + Name: fmt.Sprintf("Split shards %v to %v workflow creation", task.Attributes["source_shards"], task.Attributes["destination_shards"]), + PathName: fmt.Sprintf("%v", i), + } + phaseNode.Children = append(phaseNode.Children, taskUINode) + } + return hw, nil +} + +func findSourceAndDestinationShards(ts *topo.Server, keyspace string) ([][][]string, error) { + overlappingShards, err := topotools.FindOverlappingShards(context.Background(), ts, keyspace) + if err != nil { + return nil, err + } + + var shardsToSplit [][][]string + + for _, os := range overlappingShards { + var sourceShards, destinationShards []string + var sourceShardInfo *topo.ShardInfo + var destinationShardInfos []*topo.ShardInfo + // Judge which side is source shard by checking the number of servedTypes. + if len(os.Left[0].ServedTypes) > 0 { + sourceShardInfo = os.Left[0] + destinationShardInfos = os.Right + } else { + sourceShardInfo = os.Right[0] + destinationShardInfos = os.Left + } + sourceShards = append(sourceShards, sourceShardInfo.ShardName()) + for _, d := range destinationShardInfos { + destinationShards = append(destinationShards, d.ShardName()) + } + shardsToSplit = append(shardsToSplit, [][]string{sourceShards, destinationShards}) + } + return shardsToSplit, nil +} + +// initCheckpoint initialize the checkpoint for keyspace reshard +func initCheckpoint(keyspace string, vtworkers []string, shardsToSplit [][][]string, minHealthyRdonlyTablets, splitCmd, splitDiffDestTabletType, phaseEnableApprovals string, skipStartWorkflows bool) (*workflowpb.WorkflowCheckpoint, error) { + sourceShards := 0 + destShards := 0 + for _, shardToSplit := range shardsToSplit { + sourceShards = sourceShards + len(shardToSplit[0]) + destShards = destShards + len(shardToSplit[1]) + } + if sourceShards == 0 || destShards == 0 { + return nil, fmt.Errorf("invalid source or destination shards") + } + if len(vtworkers) != destShards { + return nil, fmt.Errorf("there are %v vtworkers, %v destination shards: the number should be same", len(vtworkers), destShards) + } + + splitRatio := destShards / sourceShards + if minHealthyRdonlyTabletsVal, err := strconv.Atoi(minHealthyRdonlyTablets); err != nil || minHealthyRdonlyTabletsVal < splitRatio { + return nil, fmt.Errorf("there are not enough rdonly tablets in source shards. You need at least %v, it got: %v", splitRatio, minHealthyRdonlyTablets) + } + + tasks := make(map[string]*workflowpb.Task) + usedVtworkersIdx := 0 + for i, shardToSplit := range shardsToSplit { + taskID := fmt.Sprintf("%s/%v", phaseName, i) + tasks[taskID] = &workflowpb.Task{ + Id: taskID, + State: workflowpb.TaskState_TaskNotStarted, + Attributes: map[string]string{ + "source_shards": strings.Join(shardToSplit[0], ","), + "destination_shards": strings.Join(shardToSplit[1], ","), + "vtworkers": strings.Join(vtworkers[usedVtworkersIdx:usedVtworkersIdx+len(shardToSplit[1])], ","), + }, + } + usedVtworkersIdx = usedVtworkersIdx + len(shardToSplit[1]) + } + return &workflowpb.WorkflowCheckpoint{ + CodeVersion: codeVersion, + Tasks: tasks, + Settings: map[string]string{ + "vtworkers": strings.Join(vtworkers, ","), + "min_healthy_rdonly_tablets": minHealthyRdonlyTablets, + "split_cmd": splitCmd, + "split_diff_dest_tablet_type": splitDiffDestTabletType, + "phase_enable_approvals": phaseEnableApprovals, + "skip_start_workflows": fmt.Sprintf("%v", skipStartWorkflows), + "workflows_count": fmt.Sprintf("%v", len(shardsToSplit)), + "keyspace": keyspace, + }, + }, nil +} + +// reshardingWorkflowGen contains meta-information and methods to +// control workflow. +type reshardingWorkflowGen struct { + ctx context.Context + manager *workflow.Manager + topoServer *topo.Server + wi *topo.WorkflowInfo + // logger is the logger we export UI logs from. + logger *logutil.MemoryLogger + + // rootUINode is the root node representing the workflow in the UI. + rootUINode *workflow.Node + + checkpoint *workflowpb.WorkflowCheckpoint + checkpointWriter *workflow.CheckpointWriter + + workflowsCount int + + // params to horizontal reshard workflow + phaseEnableApprovalsParam string + minHealthyRdonlyTabletsParam string + keyspaceParam string + splitDiffDestTabletTypeParam string + splitCmdParam string + skipStartWorkflowParam string +} + +// Run implements workflow.Workflow interface. It creates one horizontal resharding workflow per shard to split +func (hw *reshardingWorkflowGen) Run(ctx context.Context, manager *workflow.Manager, wi *topo.WorkflowInfo) error { + hw.ctx = ctx + hw.wi = wi + hw.checkpointWriter = workflow.NewCheckpointWriter(hw.topoServer, hw.checkpoint, hw.wi) + hw.rootUINode.Display = workflow.NodeDisplayDeterminate + hw.rootUINode.BroadcastChanges(true /* updateChildren */) + + if err := hw.runWorkflow(); err != nil { + hw.setUIMessage(hw.rootUINode, fmt.Sprintf("Keyspace resharding failed to create workflows")) + return err + } + hw.setUIMessage(hw.rootUINode, fmt.Sprintf("Keyspace resharding is finished successfully.")) + return nil +} + +func (hw *reshardingWorkflowGen) runWorkflow() error { + var tasks []*workflowpb.Task + for i := 0; i < hw.workflowsCount; i++ { + taskID := fmt.Sprintf("%s/%v", phaseName, i) + tasks = append(tasks, hw.checkpoint.Tasks[taskID]) + } + + workflowsCreator := workflow.NewParallelRunner(hw.ctx, hw.rootUINode, hw.checkpointWriter, tasks, hw.workflowCreator, workflow.Sequential, false /*phaseEnableApprovals we don't require enable approvals in this workflow*/) + return workflowsCreator.Run() +} + +func (hw *reshardingWorkflowGen) workflowCreator(ctx context.Context, task *workflowpb.Task) error { + horizontalReshardingParams := []string{ + "-keyspace=" + hw.keyspaceParam, + "-vtworkers=" + task.Attributes["vtworkers"], + "-split_cmd=" + hw.splitCmdParam, + "-split_diff_dest_tablet_type=" + hw.splitDiffDestTabletTypeParam, + "-min_healthy_rdonly_tablets=" + hw.minHealthyRdonlyTabletsParam, + "-source_shards=" + task.Attributes["source_shards"], + "-destination_shards=" + task.Attributes["destination_shards"], + "-phase_enable_approvals=" + hw.phaseEnableApprovalsParam, + } + + skipStart, err := strconv.ParseBool(hw.skipStartWorkflowParam) + if err != nil { + return err + + } + phaseID := path.Dir(task.Id) + phaseUINode, err := hw.rootUINode.GetChildByPath(phaseID) + if err != nil { + return err + } + + uuid, err := hw.manager.Create(ctx, "horizontal_resharding", horizontalReshardingParams) + if err != nil { + hw.setUIMessage(phaseUINode, fmt.Sprintf("Couldn't create shard split workflow for source shards: %v. Got error: %v", task.Attributes["source_shards"], err)) + return err + } + hw.setUIMessage(phaseUINode, fmt.Sprintf("Created shard split workflow: %v for source shards: %v.", uuid, task.Attributes["source_shards"])) + workflowCmd := "WorkflowCreate horizontal_resharding" + strings.Join(horizontalReshardingParams, " ") + hw.setUIMessage(phaseUINode, fmt.Sprintf("Created workflow with the following params: %v", workflowCmd)) + if !skipStart { + err = hw.manager.Start(ctx, uuid) + if err != nil { + hw.setUIMessage(phaseUINode, fmt.Sprintf("Couldn't start shard split workflow: %v for source shards: %v. Got error: %v", uuid, task.Attributes["source_shards"], err)) + return err + } + } + return nil +} + +func (hw *reshardingWorkflowGen) setUIMessage(node *workflow.Node, message string) { + log.Infof("Keyspace resharding : %v.", message) + hw.logger.Infof(message) + node.Log = hw.logger.String() + node.Message = message + node.BroadcastChanges(false /* updateChildren */) +} diff --git a/go/vt/workflow/reshardingworkflowgen/workflow_test.go b/go/vt/workflow/reshardingworkflowgen/workflow_test.go new file mode 100644 index 00000000000..2291d28afb5 --- /dev/null +++ b/go/vt/workflow/reshardingworkflowgen/workflow_test.go @@ -0,0 +1,86 @@ +/* +Copyright 2017 Google Inc. + +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 agreedto 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 reshardingworkflowgen + +import ( + "testing" + + "golang.org/x/net/context" + + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/workflow" + "vitess.io/vitess/go/vt/workflow/resharding" + + // import the gRPC client implementation for tablet manager + _ "vitess.io/vitess/go/vt/vttablet/grpctmclient" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) + +var ( + testKeyspace = "test_keyspace" + testVtworkers = "localhost:15032" +) + +func init() { + Register() + resharding.Register() +} + +// TestWorkflowGenerator runs the happy path of HorizontalReshardingWorkflow. +func TestWorfklowGenerator(t *testing.T) { + ctx := context.Background() + + // Initialize the topology. + ts := setupTopology(ctx, t, testKeyspace) + m := workflow.NewManager(ts) + // Run the manager in the background. + workflow.StartManager(m) + // Create the workflow. + vtworkersParameter := testVtworkers + "," + testVtworkers + uuid, err := m.Create(ctx, keyspaceReshardingFactoryName, []string{"-keyspace=" + testKeyspace, "-vtworkers=" + vtworkersParameter, "-min_healthy_rdonly_tablets=2"}) + if err != nil { + t.Fatalf("cannot create resharding workflow: %v", err) + } + + // Start the job. + if err := m.Start(ctx, uuid); err != nil { + t.Fatalf("cannot start resharding workflow: %v", err) + } + + // Wait for the workflow to end. + m.Wait(ctx, uuid) + if err := workflow.VerifyAllTasksDone(ctx, ts, uuid); err != nil { + t.Fatal(err) + } + // Stop the manager. + if err := m.Stop(ctx, uuid); err != nil { + t.Fatalf("cannot stop resharding workflow: %v", err) + } +} + +func setupTopology(ctx context.Context, t *testing.T, keyspace string) *topo.Server { + ts := memorytopo.NewServer("cell") + if err := ts.CreateKeyspace(ctx, keyspace, &topodatapb.Keyspace{}); err != nil { + t.Fatalf("CreateKeyspace: %v", err) + } + ts.CreateShard(ctx, keyspace, "0") + ts.CreateShard(ctx, keyspace, "-80") + ts.CreateShard(ctx, keyspace, "80-") + return ts +} diff --git a/go/vt/workflow/websocket_test.go b/go/vt/workflow/websocket_test.go index c4b911bbc2a..ca13e5cfd27 100644 --- a/go/vt/workflow/websocket_test.go +++ b/go/vt/workflow/websocket_test.go @@ -41,7 +41,7 @@ func TestWebSocket(t *testing.T) { go http.Serve(listener, nil) // Run the manager in the background. - wg, cancel := startManager(t, m) + wg, _, cancel := StartManager(m) // Start a client websocket. u := url.URL{Scheme: "ws", Host: listener.Addr().String(), Path: "/workflow"} diff --git a/go/vt/workflow/resharding/test_workflow_test.go b/go/vt/workflow/workflow_test.go similarity index 89% rename from go/vt/workflow/resharding/test_workflow_test.go rename to go/vt/workflow/workflow_test.go index 7cf0c12ce53..9b3e3c2b8c2 100644 --- a/go/vt/workflow/resharding/test_workflow_test.go +++ b/go/vt/workflow/workflow_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resharding +package workflow import ( "errors" @@ -29,7 +29,6 @@ import ( "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/workflow" workflowpb "vitess.io/vitess/go/vt/proto/workflow" ) @@ -47,14 +46,14 @@ func createTestTaskID(phase PhaseType, count int) string { } func init() { - workflow.Register(testWorkflowFactoryName, &TestWorkflowFactory{}) + Register(testWorkflowFactoryName, &TestWorkflowFactory{}) } // TestWorkflowFactory is the factory to create a test workflow. type TestWorkflowFactory struct{} // Init is part of the workflow.Factory interface. -func (*TestWorkflowFactory) Init(_ *workflow.Manager, w *workflowpb.Workflow, args []string) error { +func (*TestWorkflowFactory) Init(_ *Manager, w *workflowpb.Workflow, args []string) error { subFlags := flag.NewFlagSet(testWorkflowFactoryName, flag.ContinueOnError) retryFlag := subFlags.Bool("retry", false, "The retry flag should be true if the retry action should be tested") count := subFlags.Int("count", 0, "The number of simple tasks") @@ -88,7 +87,7 @@ func (*TestWorkflowFactory) Init(_ *workflow.Manager, w *workflowpb.Workflow, ar } // Instantiate is part the workflow.Factory interface. -func (*TestWorkflowFactory) Instantiate(m *workflow.Manager, w *workflowpb.Workflow, rootNode *workflow.Node) (workflow.Workflow, error) { +func (*TestWorkflowFactory) Instantiate(m *Manager, w *workflowpb.Workflow, rootNode *Node) (Workflow, error) { checkpoint := &workflowpb.WorkflowCheckpoint{} if err := proto.Unmarshal(w.Data, checkpoint); err != nil { return nil, err @@ -134,7 +133,7 @@ func (*TestWorkflowFactory) Instantiate(m *workflow.Manager, w *workflowpb.Workf return nil, err } - phaseNode := &workflow.Node{ + phaseNode := &Node{ Name: string(phaseSimple), PathName: string(phaseSimple), } @@ -142,7 +141,7 @@ func (*TestWorkflowFactory) Instantiate(m *workflow.Manager, w *workflowpb.Workf for i := 0; i < count; i++ { taskName := fmt.Sprintf("%v", i) - taskUINode := &workflow.Node{ + taskUINode := &Node{ Name: taskName, PathName: taskName, } @@ -157,7 +156,7 @@ func (*TestWorkflowFactory) Instantiate(m *workflow.Manager, w *workflowpb.Workf // after a retry. type TestWorkflow struct { ctx context.Context - manager *workflow.Manager + manager *Manager topoServer *topo.Server wi *topo.WorkflowInfo logger *logutil.MemoryLogger @@ -166,7 +165,7 @@ type TestWorkflow struct { // retryFlags stores the retry flag for all tasks. retryFlags map[string]bool - rootUINode *workflow.Node + rootUINode *Node checkpoint *workflowpb.WorkflowCheckpoint checkpointWriter *CheckpointWriter @@ -176,12 +175,12 @@ type TestWorkflow struct { } // Run implements the workflow.Workflow interface. -func (tw *TestWorkflow) Run(ctx context.Context, manager *workflow.Manager, wi *topo.WorkflowInfo) error { +func (tw *TestWorkflow) Run(ctx context.Context, manager *Manager, wi *topo.WorkflowInfo) error { tw.ctx = ctx tw.wi = wi tw.checkpointWriter = NewCheckpointWriter(tw.topoServer, tw.checkpoint, tw.wi) - tw.rootUINode.Display = workflow.NodeDisplayDeterminate + tw.rootUINode.Display = NodeDisplayDeterminate tw.rootUINode.BroadcastChanges(true /* updateChildren */) simpleTasks := tw.getTasks(phaseSimple) @@ -190,10 +189,7 @@ func (tw *TestWorkflow) Run(ctx context.Context, manager *workflow.Manager, wi * concurrencyLevel = Sequential } simpleRunner := NewParallelRunner(tw.ctx, tw.rootUINode, tw.checkpointWriter, simpleTasks, tw.runSimple, concurrencyLevel, tw.enableApprovals) - if err := simpleRunner.Run(); err != nil { - return err - } - return nil + return simpleRunner.Run() } func (tw *TestWorkflow) getTasks(phaseName PhaseType) []*workflowpb.Task { diff --git a/go/vt/wrangler/cleaner.go b/go/vt/wrangler/cleaner.go index b373cde1417..d65d7b6eed0 100644 --- a/go/vt/wrangler/cleaner.go +++ b/go/vt/wrangler/cleaner.go @@ -103,26 +103,6 @@ func (cleaner *Cleaner) CleanUp(wr *Wrangler) error { return rec.Error() } -// RemoveActionByName removes an action from the cleaner list -func (cleaner *Cleaner) RemoveActionByName(name, target string) error { - cleaner.mu.Lock() - defer cleaner.mu.Unlock() - for i, action := range cleaner.actions { - if action.name == name && action.target == target { - newActions := make([]cleanerActionReference, 0, len(cleaner.actions)-1) - if i > 0 { - newActions = append(newActions, cleaner.actions[0:i]...) - } - if i < len(cleaner.actions)-1 { - newActions = append(newActions, cleaner.actions[i+1:len(cleaner.actions)]...) - } - cleaner.actions = newActions - return nil - } - } - return topo.NewError(topo.NoNode, name+":"+target) -} - // // ChangeSlaveTypeAction CleanerFunction // @@ -193,16 +173,17 @@ func RecordStartSlaveAction(cleaner *Cleaner, tablet *topodatapb.Tablet) { } // -// StartBlpAction CleanerAction +// VReplication CleanerAction // -// StartBlpActionName is the name of the action to start binlog player -const StartBlpActionName = "StartBlpAction" +// VReplicationActionName is the name of the action to execute VReplication commands +const VReplicationActionName = "VReplicationAction" -// RecordStartBlpAction records an action to restart binlog replication on a server +// RecordVReplicationAction records an action to restart binlog replication on a server // into the specified Cleaner -func RecordStartBlpAction(cleaner *Cleaner, tablet *topodatapb.Tablet) { - cleaner.Record(StartBlpActionName, topoproto.TabletAliasString(tablet.Alias), func(ctx context.Context, wr *Wrangler) error { - return wr.TabletManagerClient().StartBlp(ctx, tablet) +func RecordVReplicationAction(cleaner *Cleaner, tablet *topodatapb.Tablet, query string) { + cleaner.Record(VReplicationActionName, topoproto.TabletAliasString(tablet.Alias), func(ctx context.Context, wr *Wrangler) error { + _, err := wr.TabletManagerClient().VReplicationExec(ctx, tablet, query) + return err }) } diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 5dbc52852eb..f8bec63978a 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -25,6 +25,7 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/event" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/topo" @@ -32,7 +33,6 @@ import ( "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/topotools/events" - tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" vschemapb "vitess.io/vitess/go/vt/proto/vschema" ) @@ -101,6 +101,9 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri if skipReFreshState { return fmt.Errorf("Cannot skip refresh state for master migration on %v/%v", keyspace, shard) } + if cells != nil { + return fmt.Errorf("Cannot specify cells for master migration on %v/%v", keyspace, shard) + } } // lock the keyspace @@ -155,9 +158,28 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri } } + // re-read all the shards so we are up to date + wr.Logger().Infof("Re-reading all shards") + for i, si := range sourceShards { + if sourceShards[i], err = wr.ts.GetShard(ctx, si.Keyspace(), si.ShardName()); err != nil { + return err + } + } + for i, si := range destinationShards { + if destinationShards[i], err = wr.ts.GetShard(ctx, si.Keyspace(), si.ShardName()); err != nil { + return err + } + } + // execute the migration - if err = wr.migrateServedTypesLocked(ctx, keyspace, sourceShards, destinationShards, cells, servedType, reverse, filteredReplicationWaitTime); err != nil { - return err + if servedType == topodatapb.TabletType_MASTER { + if err = wr.masterMigrateServedType(ctx, keyspace, sourceShards, destinationShards, filteredReplicationWaitTime); err != nil { + return err + } + } else { + if err = wr.replicaMigrateServedType(ctx, keyspace, sourceShards, destinationShards, cells, servedType, reverse); err != nil { + return err + } } // rebuild the keyspace serving graph now that there is no error @@ -244,16 +266,16 @@ func (wr *Wrangler) waitForFilteredReplication(ctx context.Context, sourcePositi wg.Add(1) go func(si *topo.ShardInfo) { defer wg.Done() - for _, sourceShard := range si.SourceShards { - // we're waiting on this guy - blpPosition := &tabletmanagerdatapb.BlpPosition{ - Uid: sourceShard.Uid, - } + ctx, cancel := context.WithTimeout(ctx, waitTime) + defer cancel() + var pos string + for _, sourceShard := range si.SourceShards { // find the position it should be at - for s, pos := range sourcePositions { + for s, sp := range sourcePositions { if s.Keyspace() == sourceShard.Keyspace && s.ShardName() == sourceShard.Shard { - blpPosition.Position = pos + pos = sp + break } } @@ -265,7 +287,7 @@ func (wr *Wrangler) waitForFilteredReplication(ctx context.Context, sourcePositi return } - if err := wr.tmc.WaitBlpPosition(ctx, ti.Tablet, blpPosition, waitTime); err != nil { + if err := wr.tmc.VReplicationWaitForPos(ctx, ti.Tablet, int(sourceShard.Uid), pos); err != nil { rec.RecordError(err) } else { wr.Logger().Infof("%v caught up", topoproto.TabletAliasString(si.MasterAlias)) @@ -303,28 +325,52 @@ func (wr *Wrangler) refreshMasters(ctx context.Context, shards []*topo.ShardInfo return rec.Error() } -// migrateServedTypesLocked operates with the keyspace locked -func (wr *Wrangler) migrateServedTypesLocked(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, reverse bool, filteredReplicationWaitTime time.Duration) (err error) { - - // re-read all the shards so we are up to date - wr.Logger().Infof("Re-reading all shards") - for i, si := range sourceShards { - if sourceShards[i], err = wr.ts.GetShard(ctx, si.Keyspace(), si.ShardName()); err != nil { - return err - } +// replicaMigrateServedType operates with the keyspace locked +func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, reverse bool) (err error) { + ev := &events.MigrateServedTypes{ + KeyspaceName: keyspace, + SourceShards: sourceShards, + DestinationShards: destinationShards, + ServedType: servedType, + Reverse: reverse, } - for i, si := range destinationShards { - if destinationShards[i], err = wr.ts.GetShard(ctx, si.Keyspace(), si.ShardName()); err != nil { - return err + event.DispatchUpdate(ev, "start") + defer func() { + if err != nil { + event.DispatchUpdate(ev, "failed: "+err.Error()) } + }() + + fromShards, toShards := sourceShards, destinationShards + if reverse { + fromShards, toShards = toShards, fromShards + } + + // Check and update all source shard records. + // Enable query service if needed + event.DispatchUpdate(ev, "updating shards to migrate from") + if err = wr.updateShardRecords(ctx, fromShards, cells, servedType, true); err != nil { + return err + } + + // Do the same for destination shards + event.DispatchUpdate(ev, "updating shards to migrate to") + if err = wr.updateShardRecords(ctx, toShards, cells, servedType, false); err != nil { + return err } + event.DispatchUpdate(ev, "finished") + return nil +} + +// masterMigrateServedType operates with the keyspace locked +func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, filteredReplicationWaitTime time.Duration) (err error) { + ev := &events.MigrateServedTypes{ KeyspaceName: keyspace, SourceShards: sourceShards, DestinationShards: destinationShards, - ServedType: servedType, - Reverse: reverse, + ServedType: topodatapb.TabletType_MASTER, } event.DispatchUpdate(ev, "start") defer func() { @@ -337,138 +383,88 @@ func (wr *Wrangler) migrateServedTypesLocked(ctx context.Context, keyspace strin // - switch the source shards to read-only by disabling query service // - gather all replication points // - wait for filtered replication to catch up before we continue - // - we will disable filtered replication after the fact in the - // next phases - if servedType == topodatapb.TabletType_MASTER { - event.DispatchUpdate(ev, "disabling query service on all source masters") - for i, si := range sourceShards { - // update our internal record too - if sourceShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { - return si.UpdateDisableQueryService(ctx, topodatapb.TabletType_MASTER, nil, true) - }); err != nil { - return err - } - } - if err := wr.refreshMasters(ctx, sourceShards); err != nil { - return err - } + event.DispatchUpdate(ev, "disabling query service on all source masters") + if err = wr.updateShardRecords(ctx, sourceShards, nil, topodatapb.TabletType_MASTER, true); err != nil { + return err + } + if err := wr.refreshMasters(ctx, sourceShards); err != nil { + return err + } - event.DispatchUpdate(ev, "getting positions of source masters") - masterPositions, err := wr.getMastersPosition(ctx, sourceShards) - if err != nil { - return err - } + event.DispatchUpdate(ev, "getting positions of source masters") + masterPositions, err := wr.getMastersPosition(ctx, sourceShards) + if err != nil { + return err + } - event.DispatchUpdate(ev, "waiting for destination masters to catch up") - if err := wr.waitForFilteredReplication(ctx, masterPositions, destinationShards, filteredReplicationWaitTime); err != nil { - return err - } + event.DispatchUpdate(ev, "waiting for destination masters to catch up") + if err := wr.waitForFilteredReplication(ctx, masterPositions, destinationShards, filteredReplicationWaitTime); err != nil { + return err } - // Check and update all source shard records. - // We remember if we need to refresh the state of the source tablets - // so their query service is enabled again, for reverse migration. - event.DispatchUpdate(ev, "updating source shards") - needToRefreshSourceTablets := false - for i, si := range sourceShards { - sourceShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { - if err := si.UpdateServedTypesMap(servedType, cells, !reverse); err != nil { - return err - } - if tc := si.GetTabletControl(servedType); reverse && tc != nil && tc.DisableQueryService { - // this is a backward migration, where the - // source tablets were disabled previously, so - // we need to refresh them - if err := si.UpdateDisableQueryService(ctx, servedType, cells, false); err != nil { - return err - } - needToRefreshSourceTablets = true - } - if !reverse && servedType != topodatapb.TabletType_MASTER { - // this is a forward migration, we need to - // disable query service on the source shards. - // (this was already done for masters earlier) - if err := si.UpdateDisableQueryService(ctx, servedType, cells, true); err != nil { - return err - } - } - return nil - }) + // Destination shards need different handling than what updateShardRecords does. + event.DispatchUpdate(ev, "updating destination shards") + for i, si := range destinationShards { + // Stop VReplication streams if we're migrating master (forward only). + ti, err := wr.ts.GetTablet(ctx, si.MasterAlias) if err != nil { return err } - } - if needToRefreshSourceTablets { - event.DispatchUpdate(ev, "refreshing source shard tablets so they restart their query service") - for _, si := range sourceShards { - wr.RefreshTabletsByShard(ctx, si, []topodatapb.TabletType{servedType}, cells) + for _, sourceShard := range si.SourceShards { + if _, err := wr.tmc.VReplicationExec(ctx, ti.Tablet, binlogplayer.DeleteVReplication(sourceShard.Uid)); err != nil { + return err + } } - } - - // We remember if we need to refresh the state of the - // destination tablets so their query service will be enabled. - event.DispatchUpdate(ev, "updating destination shards") - needToRefreshDestinationTablets := false - for i, si := range destinationShards { destinationShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { - if err := si.UpdateServedTypesMap(servedType, cells, reverse); err != nil { + if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, false); err != nil { return err } - if tc := si.GetTabletControl(servedType); !reverse && tc != nil && tc.DisableQueryService { - // This is a forwards migration, and the - // destination query service was already in a - // disabled state. We need to enable and force - // a refresh, otherwise it's possible that both - // the source and destination will have query - // service disabled at the same time, and - // queries would have nowhere to go. - if err := si.UpdateDisableQueryService(ctx, servedType, cells, false); err != nil { - return err - } - needToRefreshDestinationTablets = true - } - if reverse && servedType != topodatapb.TabletType_MASTER { - // this is a backwards migration, we need to - // disable query service on the destination - // shards. (we're not allowed to reverse a - // master migration). - if err := si.UpdateDisableQueryService(ctx, servedType, cells, true); err != nil { - return err - } + if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_MASTER, nil, false); err != nil { + return err } - // for master migration, also disable filtered - // replication - if servedType == topodatapb.TabletType_MASTER { - si.SourceShards = nil - } + // Final migration. Remove source shards. + si.SourceShards = nil return nil }) if err != nil { return err } } - if needToRefreshDestinationTablets { - event.DispatchUpdate(ev, "refreshing destination shard tablets so they restart their query service") - for _, si := range destinationShards { - wr.RefreshTabletsByShard(ctx, si, []topodatapb.TabletType{servedType}, cells) - } - } // And tell the new shards masters they can now be read-write. // Invoking a remote action will also make the tablet stop filtered // replication. - if servedType == topodatapb.TabletType_MASTER { - event.DispatchUpdate(ev, "setting destination masters read-write") - if err := wr.refreshMasters(ctx, destinationShards); err != nil { - return err - } + event.DispatchUpdate(ev, "setting destination masters read-write") + if err := wr.refreshMasters(ctx, destinationShards); err != nil { + return err } event.DispatchUpdate(ev, "finished") return nil } +// updateShardRecords updates the shard records based on 'from' or 'to' direction. +func (wr *Wrangler) updateShardRecords(ctx context.Context, shards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, isFrom bool) (err error) { + for i, si := range shards { + shards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { + if err := si.UpdateServedTypesMap(servedType, cells, isFrom /* remove */); err != nil { + return err + } + return si.UpdateDisableQueryService(ctx, servedType, cells, isFrom /* disable */) + }) + if err != nil { + return err + } + // For 'to' shards, refresh to make them serve. + // The 'from' shards will be refreshed after traffic has migrated. + if !isFrom { + wr.RefreshTabletsByShard(ctx, si, []topodatapb.TabletType{servedType}, cells) + } + } + return nil +} + // WaitForDrain blocks until the selected tablets (cells/keyspace/shard/tablet_type) // have reported a QPS rate of 0.0. // NOTE: This is just an observation of one point in time and no guarantee that @@ -723,6 +719,8 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp // replication and starts accepting writes func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.KeyspaceInfo, sourceShard *topo.ShardInfo, destinationShard *topo.ShardInfo, tables []string, ev *events.MigrateServedFrom, filteredReplicationWaitTime time.Duration) error { // Read the data we need + ctx, cancel := context.WithTimeout(ctx, filteredReplicationWaitTime) + defer cancel() sourceMasterTabletInfo, err := wr.ts.GetTablet(ctx, sourceShard.MasterAlias) if err != nil { return err @@ -755,10 +753,14 @@ func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.Keyspa // wait for it event.DispatchUpdate(ev, "waiting for destination master to catch up to source master") - if err := wr.tmc.WaitBlpPosition(ctx, destinationMasterTabletInfo.Tablet, &tabletmanagerdatapb.BlpPosition{ - Uid: 0, - Position: masterPosition, - }, filteredReplicationWaitTime); err != nil { + uid := destinationShard.SourceShards[0].Uid + if err := wr.tmc.VReplicationWaitForPos(ctx, destinationMasterTabletInfo.Tablet, int(uid), masterPosition); err != nil { + return err + } + + // Stop the VReplication stream. + event.DispatchUpdate(ev, "stopping vreplication") + if _, err := wr.tmc.VReplicationExec(ctx, destinationMasterTabletInfo.Tablet, binlogplayer.DeleteVReplication(uid)); err != nil { return err } diff --git a/go/vt/wrangler/reparent.go b/go/vt/wrangler/reparent.go index 7fad88e4f5e..ccb56dd388d 100644 --- a/go/vt/wrangler/reparent.go +++ b/go/vt/wrangler/reparent.go @@ -336,6 +336,15 @@ func (wr *Wrangler) PlannedReparentShard(ctx context.Context, keyspace, shard st // Create reusable Reparent event with available info ev := &events.Reparent{} + // Attempt to set avoidMasterAlias if not provided by parameters + if masterElectTabletAlias == nil && avoidMasterAlias == nil { + shardInfo, err := wr.ts.GetShard(ctx, keyspace, shard) + if err != nil { + return err + } + avoidMasterAlias = shardInfo.MasterAlias + } + // do the work err = wr.plannedReparentShardLocked(ctx, ev, keyspace, shard, masterElectTabletAlias, avoidMasterAlias, waitSlaveTimeout) if err != nil { diff --git a/go/vt/wrangler/split.go b/go/vt/wrangler/split.go index 1267c6d8892..e374336ba3a 100644 --- a/go/vt/wrangler/split.go +++ b/go/vt/wrangler/split.go @@ -48,7 +48,7 @@ func (wr *Wrangler) SetSourceShards(ctx context.Context, keyspace, shard string, // Insert their KeyRange in the SourceShards array. // We use a linear 0-based id, that matches what worker/split_clone.go - // inserts into _vt.blp_checkpoint. + // inserts into _vt.vreplication. // We want to guarantee sourceShards[i] is using sources[i], // So iterating over the sourceTablets map would be a bad idea. sourceShards := make([]*topodatapb.Shard_SourceShard, len(sourceTablets)) diff --git a/go/vt/wrangler/tablet.go b/go/vt/wrangler/tablet.go index 7b8b7393f13..956403fea8c 100644 --- a/go/vt/wrangler/tablet.go +++ b/go/vt/wrangler/tablet.go @@ -161,6 +161,18 @@ func (wr *Wrangler) ChangeSlaveType(ctx context.Context, tabletAlias *topodatapb return wr.tmc.ChangeType(ctx, ti.Tablet, tabletType) } +// RefreshTabletState refreshes tablet state +func (wr *Wrangler) RefreshTabletState(ctx context.Context, tabletAlias *topodatapb.TabletAlias) error { + // Load tablet to find endpoint, and keyspace and shard assignment. + ti, err := wr.ts.GetTablet(ctx, tabletAlias) + if err != nil { + return err + } + + // and ask the tablet to refresh itself + return wr.tmc.RefreshState(ctx, ti.Tablet) +} + // ExecuteFetchAsDba executes a query remotely using the DBA pool func (wr *Wrangler) ExecuteFetchAsDba(ctx context.Context, tabletAlias *topodatapb.TabletAlias, query string, maxRows int, disableBinlogs bool, reloadSchema bool) (*querypb.QueryResult, error) { ti, err := wr.ts.GetTablet(ctx, tabletAlias) @@ -169,3 +181,12 @@ func (wr *Wrangler) ExecuteFetchAsDba(ctx context.Context, tabletAlias *topodata } return wr.tmc.ExecuteFetchAsDba(ctx, ti.Tablet, false, []byte(query), maxRows, disableBinlogs, reloadSchema) } + +// VReplicationExec executes a query remotely using the DBA pool +func (wr *Wrangler) VReplicationExec(ctx context.Context, tabletAlias *topodatapb.TabletAlias, query string) (*querypb.QueryResult, error) { + ti, err := wr.ts.GetTablet(ctx, tabletAlias) + if err != nil { + return nil, err + } + return wr.tmc.VReplicationExec(ctx, ti.Tablet, query) +} diff --git a/go/vt/wrangler/testlib/migrate_served_from_test.go b/go/vt/wrangler/testlib/migrate_served_from_test.go index 3c6aa3acada..f4eba888103 100644 --- a/go/vt/wrangler/testlib/migrate_served_from_test.go +++ b/go/vt/wrangler/testlib/migrate_served_from_test.go @@ -24,8 +24,10 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -96,23 +98,25 @@ func TestMigrateServedFrom(t *testing.T) { destReplica.StartActionLoop(t, wr) defer destReplica.StopActionLoop(t) - // destMaster will see the refresh, and has to respond to it. - // It will also need to respond to WaitBlpPosition, saying it's already caught up. - destMaster.FakeMysqlDaemon.FetchSuperQueryMap = map[string]*sqltypes.Result{ - "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=0": { - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary(mysql.EncodePosition(sourceMaster.FakeMysqlDaemon.CurrentMasterPosition)), - sqltypes.NewVarBinary(""), - }, - }, - }, - } destMaster.StartActionLoop(t, wr) defer destMaster.StopActionLoop(t) + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient := binlogplayer.NewMockDBClient(t) + dbClientFactory := func() binlogplayer.DBClient { return dbClient } + destMaster.Agent.VREngine = vreplication.NewEngine(ts, "", destMaster.FakeMysqlDaemon, dbClientFactory) + dbClient.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := destMaster.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + // select pos from _vt.vreplication + dbClient.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + }}}, nil) + dbClient.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + // simulate the clone, by fixing the dest shard record - if err := vp.Run([]string{"SourceShardAdd", "--tables", "gone1,gone2", "dest/0", "0", "source/0"}); err != nil { + if err := vp.Run([]string{"SourceShardAdd", "--tables", "gone1,gone2", "dest/0", "1", "source/0"}); err != nil { t.Fatalf("SourceShardAdd failed: %v", err) } diff --git a/go/vt/wrangler/testlib/migrate_served_types_test.go b/go/vt/wrangler/testlib/migrate_served_types_test.go index 87d9fa9157b..b1778fb3e63 100644 --- a/go/vt/wrangler/testlib/migrate_served_types_test.go +++ b/go/vt/wrangler/testlib/migrate_served_types_test.go @@ -25,9 +25,11 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -131,21 +133,24 @@ func TestMigrateServedTypes(t *testing.T) { dest1Replica.StartActionLoop(t, wr) defer dest1Replica.StopActionLoop(t) - // dest1Master will see the refresh, and has to respond to it. - // It will also need to respond to WaitBlpPosition, saying it's already caught up. - dest1Master.FakeMysqlDaemon.FetchSuperQueryMap = map[string]*sqltypes.Result{ - "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=0": { - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary(mysql.EncodePosition(sourceMaster.FakeMysqlDaemon.CurrentMasterPosition)), - sqltypes.NewVarBinary(""), - }, - }, - }, - } dest1Master.StartActionLoop(t, wr) defer dest1Master.StopActionLoop(t) + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient1 := binlogplayer.NewMockDBClient(t) + dbClientFactory1 := func() binlogplayer.DBClient { return dbClient1 } + dest1Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest1Master.FakeMysqlDaemon, dbClientFactory1) + // select * from _vt.vreplication during Open + dbClient1.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest1Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + // select pos from _vt.vreplication + dbClient1.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + }}}, nil) + dbClient1.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + // dest2Rdonly will see the refresh dest2Rdonly.StartActionLoop(t, wr) defer dest2Rdonly.StopActionLoop(t) @@ -154,21 +159,24 @@ func TestMigrateServedTypes(t *testing.T) { dest2Replica.StartActionLoop(t, wr) defer dest2Replica.StopActionLoop(t) - // dest2Master will see the refresh, and has to respond to it. - // It will also need to respond to WaitBlpPosition, saying it's already caught up. - dest2Master.FakeMysqlDaemon.FetchSuperQueryMap = map[string]*sqltypes.Result{ - "SELECT pos, flags FROM _vt.blp_checkpoint WHERE source_shard_uid=0": { - Rows: [][]sqltypes.Value{ - { - sqltypes.NewVarBinary(mysql.EncodePosition(sourceMaster.FakeMysqlDaemon.CurrentMasterPosition)), - sqltypes.NewVarBinary(""), - }, - }, - }, - } dest2Master.StartActionLoop(t, wr) defer dest2Master.StopActionLoop(t) + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient2 := binlogplayer.NewMockDBClient(t) + dbClientFactory2 := func() binlogplayer.DBClient { return dbClient2 } + dest2Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest2Master.FakeMysqlDaemon, dbClientFactory2) + // select * from _vt.vreplication during Open + dbClient2.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest2Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + // select pos from _vt.vreplication + dbClient2.ExpectRequest("select pos from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + }}}, nil) + dbClient2.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + // migrate will error if the overlapping shards have no "SourceShard" entry // and we cannot decide which shard is the source or the destination. if err := vp.Run([]string{"MigrateServedTypes", "ks/0", "rdonly"}); err == nil || !strings.Contains(err.Error(), "' have a 'SourceShards' entry. Did you successfully run vtworker SplitClone before? Or did you already migrate the MASTER type?") { @@ -178,10 +186,10 @@ func TestMigrateServedTypes(t *testing.T) { // simulate the clone, by fixing the dest shard record checkShardSourceShards(t, ts, "-80", 0) checkShardSourceShards(t, ts, "80-", 0) - if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/-80", "0", "ks/0"}); err != nil { + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/-80", "1", "ks/0"}); err != nil { t.Fatalf("SourceShardAdd failed: %v", err) } - if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/80-", "0", "ks/0"}); err != nil { + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/80-", "1", "ks/0"}); err != nil { t.Fatalf("SourceShardAdd failed: %v", err) } checkShardSourceShards(t, ts, "-80", 1) diff --git a/go/vt/wrangler/testlib/planned_reparent_shard_test.go b/go/vt/wrangler/testlib/planned_reparent_shard_test.go index fef98a15d7f..3bf5a31cc03 100644 --- a/go/vt/wrangler/testlib/planned_reparent_shard_test.go +++ b/go/vt/wrangler/testlib/planned_reparent_shard_test.go @@ -31,6 +31,107 @@ import ( topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) +func TestPlannedReparentShardNoMasterProvided(t *testing.T) { + ts := memorytopo.NewServer("cell1", "cell2") + wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) + vp := NewVtctlPipe(t, ts) + defer vp.Close() + + // Create a master, a couple good slaves + oldMaster := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_MASTER, nil) + newMaster := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil) + goodSlave1 := NewFakeTablet(t, wr, "cell2", 2, topodatapb.TabletType_REPLICA, nil) + + // new master + newMaster.FakeMysqlDaemon.ReadOnly = true + newMaster.FakeMysqlDaemon.Replicating = true + newMaster.FakeMysqlDaemon.WaitMasterPosition = mysql.Position{ + GTIDSet: mysql.MariadbGTID{ + Domain: 7, + Server: 123, + Sequence: 990, + }, + } + newMaster.FakeMysqlDaemon.PromoteSlaveResult = mysql.Position{ + GTIDSet: mysql.MariadbGTID{ + Domain: 7, + Server: 456, + Sequence: 991, + }, + } + newMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "CREATE DATABASE IF NOT EXISTS _vt", + "SUBCREATE TABLE IF NOT EXISTS _vt.reparent_journal", + "SUBINSERT INTO _vt.reparent_journal (time_created_ns, action_name, master_alias, replication_position) VALUES", + } + newMaster.StartActionLoop(t, wr) + defer newMaster.StopActionLoop(t) + + // old master + oldMaster.FakeMysqlDaemon.ReadOnly = false + oldMaster.FakeMysqlDaemon.Replicating = false + oldMaster.FakeMysqlDaemon.DemoteMasterPosition = newMaster.FakeMysqlDaemon.WaitMasterPosition + oldMaster.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + oldMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "FAKE SET MASTER", + "START SLAVE", + } + oldMaster.StartActionLoop(t, wr) + defer oldMaster.StopActionLoop(t) + oldMaster.Agent.QueryServiceControl.(*tabletservermock.Controller).SetQueryServiceEnabledForTests(true) + + // good slave 1 is replicating + goodSlave1.FakeMysqlDaemon.ReadOnly = true + goodSlave1.FakeMysqlDaemon.Replicating = true + goodSlave1.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + goodSlave1.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "STOP SLAVE", + "FAKE SET MASTER", + "START SLAVE", + } + goodSlave1.StartActionLoop(t, wr) + defer goodSlave1.StopActionLoop(t) + + // run PlannedReparentShard + if err := vp.Run([]string{"PlannedReparentShard", "-wait_slave_timeout", "10s", "-keyspace_shard", newMaster.Tablet.Keyspace + "/" + newMaster.Tablet.Shard}); err != nil { + t.Fatalf("PlannedReparentShard failed: %v", err) + } + + // // check what was run + if err := newMaster.FakeMysqlDaemon.CheckSuperQueryList(); err != nil { + t.Errorf("newMaster.FakeMysqlDaemon.CheckSuperQueryList failed: %v", err) + } + if err := oldMaster.FakeMysqlDaemon.CheckSuperQueryList(); err != nil { + t.Errorf("oldMaster.FakeMysqlDaemon.CheckSuperQueryList failed: %v", err) + } + if err := goodSlave1.FakeMysqlDaemon.CheckSuperQueryList(); err != nil { + t.Errorf("goodSlave1.FakeMysqlDaemon.CheckSuperQueryList failed: %v", err) + } + if newMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("newMaster.FakeMysqlDaemon.ReadOnly set") + } + if !oldMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("oldMaster.FakeMysqlDaemon.ReadOnly not set") + } + if !goodSlave1.FakeMysqlDaemon.ReadOnly { + t.Errorf("goodSlave1.FakeMysqlDaemon.ReadOnly not set") + } + if !oldMaster.Agent.QueryServiceControl.IsServing() { + t.Errorf("oldMaster...QueryServiceControl not serving") + } + + // // verify the old master was told to start replicating (and not + // // the slave that wasn't replicating in the first place) + if !oldMaster.FakeMysqlDaemon.Replicating { + t.Errorf("oldMaster.FakeMysqlDaemon.Replicating not set") + } + if !goodSlave1.FakeMysqlDaemon.Replicating { + t.Errorf("goodSlave1.FakeMysqlDaemon.Replicating not set") + } + checkSemiSyncEnabled(t, true, true, newMaster) + checkSemiSyncEnabled(t, false, true, goodSlave1, oldMaster) +} + func TestPlannedReparentShard(t *testing.T) { ts := memorytopo.NewServer("cell1", "cell2") wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) diff --git a/go/vt/wrangler/testlib/wait_for_filtered_replication_test.go b/go/vt/wrangler/testlib/wait_for_filtered_replication_test.go deleted file mode 100644 index 81a7932b0b8..00000000000 --- a/go/vt/wrangler/testlib/wait_for_filtered_replication_test.go +++ /dev/null @@ -1,170 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 testlib - -import ( - "strings" - "testing" - "time" - - "golang.org/x/net/context" - - "vitess.io/vitess/go/vt/logutil" - "vitess.io/vitess/go/vt/topo/memorytopo" - "vitess.io/vitess/go/vt/vttablet/grpcqueryservice" - "vitess.io/vitess/go/vt/vttablet/tabletmanager" - "vitess.io/vitess/go/vt/vttablet/tabletserver" - "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" - "vitess.io/vitess/go/vt/vttablet/tmclient" - "vitess.io/vitess/go/vt/wrangler" - - querypb "vitess.io/vitess/go/vt/proto/query" - topodatapb "vitess.io/vitess/go/vt/proto/topodata" -) - -const keyspace = "ks" -const destShard = "-80" - -// TestWaitForFilteredReplication tests the vtctl command "WaitForFilteredReplication". -// WaitForFilteredReplication ensures that the dest shard has caught up -// with the source shard up to a maximum replication delay (in seconds). -func TestWaitForFilteredReplication(t *testing.T) { - // Replication is lagging behind. - oneHourDelay := &querypb.RealtimeStats{ - BinlogPlayersCount: 1, - SecondsBehindMasterFilteredReplication: 3600, - } - - // Replication caught up. - oneSecondDelayFunc := func() *querypb.RealtimeStats { - return &querypb.RealtimeStats{ - BinlogPlayersCount: 1, - SecondsBehindMasterFilteredReplication: 1, - } - } - - waitForFilteredReplication(t, "" /* expectedErr */, oneHourDelay, oneSecondDelayFunc) -} - -// TestWaitForFilteredReplication_noFilteredReplication checks that -// vtctl WaitForFilteredReplication fails when no filtered replication is -// running (judging by the tablet's returned stream health record). -func TestWaitForFilteredReplication_noFilteredReplication(t *testing.T) { - noFilteredReplication := &querypb.RealtimeStats{ - BinlogPlayersCount: 0, - } - noFilteredReplicationFunc := func() *querypb.RealtimeStats { - return noFilteredReplication - } - - waitForFilteredReplication(t, "no filtered replication running", noFilteredReplication, noFilteredReplicationFunc) -} - -// TestWaitForFilteredReplication_unhealthy checks that -// vtctl WaitForFilteredReplication fails when a tablet is not healthy. -func TestWaitForFilteredReplication_unhealthy(t *testing.T) { - unhealthy := &querypb.RealtimeStats{ - HealthError: "WaitForFilteredReplication: unhealthy test", - } - unhealthyFunc := func() *querypb.RealtimeStats { - return unhealthy - } - - waitForFilteredReplication(t, "tablet is not healthy", unhealthy, unhealthyFunc) -} - -func waitForFilteredReplication(t *testing.T, expectedErr string, initialStats *querypb.RealtimeStats, broadcastStatsFunc func() *querypb.RealtimeStats) { - ts := memorytopo.NewServer("cell1", "cell2") - wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) - vp := NewVtctlPipe(t, ts) - defer vp.Close() - - // create keyspace - if err := ts.CreateKeyspace(context.Background(), keyspace, &topodatapb.Keyspace{ - ShardingColumnName: "keyspace_id", - ShardingColumnType: topodatapb.KeyspaceIdType_UINT64, - }); err != nil { - t.Fatalf("CreateKeyspace failed: %v", err) - } - - // source of the filtered replication. We don't start its loop because we don't connect to it. - source := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_MASTER, nil, - TabletKeyspaceShard(t, keyspace, "0")) - // dest is the master of the dest shard which receives filtered replication events. - dest := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_MASTER, nil, - TabletKeyspaceShard(t, keyspace, destShard)) - - // Use real, but trimmed down QueryService. - qs := tabletserver.NewTabletServerWithNilTopoServer(tabletenv.DefaultQsConfig) - grpcqueryservice.Register(dest.RPCServer, qs) - - // And start the action loop, after having registered the extra service. - dest.StartActionLoop(t, wr) - defer dest.StopActionLoop(t) - - // Build topology state as we would expect it when filtered replication is enabled. - ctx := context.Background() - wr.SetSourceShards(ctx, keyspace, destShard, []*topodatapb.TabletAlias{source.Tablet.GetAlias()}, nil) - - // Set a BinlogPlayerMap to avoid a nil panic when the explicit RunHealthCheck - // is called by WaitForFilteredReplication. - // Note that for this test we don't mock the BinlogPlayerMap i.e. although - // its state says no filtered replication is running, the code under test will - // observe otherwise because we call TabletServer.BroadcastHealth() directly and - // skip going through the tabletmanager's agent. - dest.Agent.BinlogPlayerMap = tabletmanager.NewBinlogPlayerMap(ts, nil, nil) - - qs.BroadcastHealth(42, initialStats) - - // run vtctl WaitForFilteredReplication - stopBroadcasting := make(chan struct{}) - go func() { - defer close(stopBroadcasting) - err := vp.Run([]string{"WaitForFilteredReplication", "-max_delay", "10s", dest.Tablet.Keyspace + "/" + dest.Tablet.Shard}) - if expectedErr == "" { - if err != nil { - t.Fatalf("WaitForFilteredReplication must not fail: %v", err) - } - } else { - if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Fatalf("WaitForFilteredReplication wrong error. got: %v want substring: %v", err, expectedErr) - } - } - }() - - // Broadcast health record as long as vtctl is running. - for { - // Give vtctl a head start to consume the initial stats. - // (We do this because there's unfortunately no way to explicitly - // synchronize with the point where conn.StreamHealth() has started.) - // (Tests won't break if vtctl misses the initial stats. Only coverage - // will be impacted.) - timer := time.NewTimer(1 * time.Millisecond) - - select { - case <-stopBroadcasting: - timer.Stop() - return - case <-timer.C: - qs.BroadcastHealth(42, broadcastStatsFunc()) - // Pace the flooding broadcasting to waste less CPU. - timer.Reset(1 * time.Millisecond) - } - } - - // vtctl WaitForFilteredReplication returned. -} diff --git a/java/client/src/main/java/io/vitess/client/VTGateConnection.java b/java/client/src/main/java/io/vitess/client/VTGateConnection.java index fe1a9d0dcf1..485897f0da5 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateConnection.java +++ b/java/client/src/main/java/io/vitess/client/VTGateConnection.java @@ -252,4 +252,11 @@ public void close() throws IOException { client.close(); } + @Override + public String toString() { + return String.format("[VTGateConnection-%s client=%s]", + Integer.toHexString(this.hashCode()), + client.toString() + ); + } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index d35b751c3e6..5ad84c572c8 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; +import io.grpc.internal.WithLogId; import io.vitess.client.Context; import io.vitess.client.Proto; import io.vitess.client.RpcClient; @@ -79,11 +80,17 @@ */ public class GrpcClient implements RpcClient { private final ManagedChannel channel; + private final String channelId; private final VitessStub asyncStub; private final VitessFutureStub futureStub; public GrpcClient(ManagedChannel channel) { this.channel = channel; + if (channel instanceof WithLogId) { + channelId = ((WithLogId) channel).getLogId().toString(); + } else { + channelId = channel.toString(); + } asyncStub = VitessGrpc.newStub(channel); futureStub = VitessGrpc.newFutureStub(channel); } @@ -296,4 +303,12 @@ private VitessFutureStub getFutureStub(Context ctx) { } return futureStub.withDeadlineAfter(timeout.getMillis(), TimeUnit.MILLISECONDS); } + + @Override + public String toString() { + return String.format("[GrpcClient-%s channel=%s]", + Integer.toHexString(this.hashCode()), + channelId + ); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java index 27dd9839aed..72850bb666a 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java @@ -31,7 +31,6 @@ import io.vitess.proto.Topodata; import io.vitess.util.Constants; import io.vitess.util.StringUtils; -import java.util.function.Function; public class ConnectionProperties { @@ -194,6 +193,14 @@ public class ConnectionProperties { "refreshSeconds", "How often in seconds the driver will monitor for changes to the keystore and truststore files, when refreshConnection is enabled.", 60); + private BooleanConnectionProperty refreshClosureDelayed = new BooleanConnectionProperty( + "refreshClosureDelayed", + "When enabled, the closing of the old connections will be delayed instead of happening instantly.", + false); + private LongConnectionProperty refreshClosureDelaySeconds = new LongConnectionProperty( + "refreshClosureDelaySeconds", + "How often in seconds the grace period before closing the old connections that had been recreated.", + 300); private StringConnectionProperty keyStore = new StringConnectionProperty( Constants.Property.KEYSTORE, "The Java .JKS keystore file to use when TLS is enabled", @@ -517,6 +524,22 @@ public void setRefreshSeconds(long refreshSeconds) { this.refreshSeconds.setValue(refreshSeconds); } + public boolean getRefreshClosureDelayed() { + return refreshClosureDelayed.getValueAsBoolean(); + } + + public void setRefreshClosureDelayed(boolean refreshClosureDelayed) { + this.refreshClosureDelayed.setValue(refreshClosureDelayed); + } + + public long getRefreshClosureDelaySeconds() { + return refreshClosureDelaySeconds.getValueAsLong(); + } + + public void setRefreshClosureDelaySeconds(long refreshClosureDelaySeconds) { + this.refreshClosureDelaySeconds.setValue(refreshClosureDelaySeconds); + } + public String getKeyStore() { return keyStore.getValueAsString(); } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java index 278bea6d809..f4a0904824f 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java @@ -591,7 +591,7 @@ protected void checkSQLNullOrEmpty(String sql) throws SQLException { protected int[] generateBatchUpdateResult(List cursorWithErrorList, List batchedArgs) throws BatchUpdateException { int[] updateCounts = new int[cursorWithErrorList.size()]; - long[][] generatedKeys = new long[cursorWithErrorList.size()][2]; + ArrayList generatedKeys = new ArrayList(); Vtrpc.RPCError rpcError = null; String batchCommand = null; @@ -603,6 +603,7 @@ protected int[] generateBatchUpdateResult(List cursorWithErrorL try { long rowsAffected = cursorWithError.getCursor().getRowsAffected(); int truncatedUpdateCount; + boolean queryBatchUpsert = false; if (rowsAffected > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; } else { @@ -610,13 +611,15 @@ protected int[] generateBatchUpdateResult(List cursorWithErrorL // mimicking mysql-connector-j here. // but it would fail for: insert into t1 values ('a'), ('b') on duplicate key update ts = now(); truncatedUpdateCount = 1; + queryBatchUpsert = true; } else { truncatedUpdateCount = (int) rowsAffected; } } updateCounts[i] = truncatedUpdateCount; - if (this.retrieveGeneratedKeys) { - generatedKeys[i] = new long[]{cursorWithError.getCursor().getInsertId(), truncatedUpdateCount}; + long insertId = cursorWithError.getCursor().getInsertId(); + if (this.retrieveGeneratedKeys && (!queryBatchUpsert || insertId > 0)) { + generatedKeys.add(new long[]{insertId, truncatedUpdateCount}); } } catch (SQLException ex) { /* This case should not happen as API has returned cursor and not error. @@ -624,14 +627,14 @@ protected int[] generateBatchUpdateResult(List cursorWithErrorL */ updateCounts[i] = Statement.SUCCESS_NO_INFO; if (this.retrieveGeneratedKeys) { - generatedKeys[i] = new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}; + generatedKeys.add(new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}); } } } else { rpcError = cursorWithError.getError(); updateCounts[i] = Statement.EXECUTE_FAILED; if (this.retrieveGeneratedKeys) { - generatedKeys[i] = new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}; + generatedKeys.add(new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}); } } } @@ -642,7 +645,7 @@ protected int[] generateBatchUpdateResult(List cursorWithErrorL throw new BatchUpdateException(rpcError.toString(), sqlState, errno, updateCounts); } if (this.retrieveGeneratedKeys) { - this.batchGeneratedKeys = generatedKeys; + this.batchGeneratedKeys = generatedKeys.toArray(new long[generatedKeys.size()][2]); } return updateCounts; } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java index c5fe83679e2..895f8ef3f70 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java @@ -16,7 +16,6 @@ package io.vitess.jdbc; -import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; @@ -30,10 +29,7 @@ import java.util.logging.Logger; import java.util.logging.Level; -import com.google.common.io.Closeables; - import io.vitess.client.Context; -import io.vitess.client.RpcClient; import io.vitess.client.VTGateConnection; import io.vitess.client.RefreshableVTGateConnection; import io.vitess.client.grpc.GrpcClientFactory; @@ -52,6 +48,8 @@ public class VitessVTGateManager { private static ConcurrentHashMap vtGateConnHashMap = new ConcurrentHashMap<>(); private static Timer vtgateConnRefreshTimer = null; + private static Timer vtgateClosureTimer = null; + private static long vtgateClosureDelaySeconds = 0L; /** * VTGateConnections object consist of vtGateIdentifire list and return vtGate object in round robin. @@ -66,6 +64,7 @@ public static class VTGateConnections { * @param connection */ public VTGateConnections(final VitessConnection connection) { + maybeStartClosureTimer(connection); for (final VitessJDBCUrl.HostInfo hostInfo : connection.getUrl().getHostInfos()) { String identifier = getIdentifer(hostInfo.getHostname(), hostInfo.getPort(), connection.getUsername(), connection.getTarget()); synchronized (VitessVTGateManager.class) { @@ -105,6 +104,17 @@ public VTGateConnection getVtGateConnInstance() { } + private static void maybeStartClosureTimer(VitessConnection connection) { + if (connection.getRefreshClosureDelayed() && vtgateClosureTimer == null) { + synchronized (VitessVTGateManager.class) { + if (vtgateClosureTimer == null) { + vtgateClosureTimer = new Timer("vtgate-conn-closure", true); + vtgateClosureDelaySeconds = connection.getRefreshClosureDelaySeconds(); + } + } + } + } + private static String getIdentifer(String hostname, int port, String userIdentifer, String keyspace) { return (hostname + port + userIdentifer + keyspace); } @@ -130,11 +140,7 @@ private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo if (existing.checkKeystoreUpdates()) { updatedCount++; VTGateConnection old = vtGateConnHashMap.replace(entry.getKey(), getVtGateConn(hostInfo, connection)); - try { - old.close(); - } catch (IOException ioe) { - logger.log(Level.WARNING, "Error closing VTGateConnection", ioe); - } + closeRefreshedConnection(old); } } } @@ -144,6 +150,30 @@ private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo } } + private static void closeRefreshedConnection(final VTGateConnection old) { + if (vtgateClosureTimer != null) { + logger.info(String.format("%s Closing connection with a %s second delay", old, vtgateClosureDelaySeconds)); + vtgateClosureTimer.schedule(new TimerTask() { + @Override + public void run() { + actuallyCloseRefreshedConnection(old); + } + }, + TimeUnit.SECONDS.toMillis(vtgateClosureDelaySeconds)); + } else { + actuallyCloseRefreshedConnection(old); + } + } + + private static void actuallyCloseRefreshedConnection(final VTGateConnection old) { + try { + logger.info(old + " Closing connection because it had been refreshed"); + old.close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, String.format("Error closing VTGateConnection %s", old), ioe); + } + } + /** * Create vtGateConn object with given identifier. * diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java index 6d8ef013f52..6d1e8cc5c4b 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java @@ -31,7 +31,7 @@ public class ConnectionPropertiesTest { - private static final int NUM_PROPS = 37; + private static final int NUM_PROPS = 39; @Test public void testReflection() throws Exception { @@ -154,8 +154,8 @@ public void testDriverPropertiesOutput() throws SQLException { Assert.assertEquals("grpcRetriesInitialBackoffMillis", infos[7].name); Assert.assertEquals("grpcRetriesMaxBackoffMillis", infos[8].name); Assert.assertEquals(Constants.Property.INCLUDED_FIELDS, infos[9].name); - Assert.assertEquals(Constants.Property.TABLET_TYPE, infos[19].name); - Assert.assertEquals(Constants.Property.TWOPC_ENABLED, infos[27].name); + Assert.assertEquals(Constants.Property.TABLET_TYPE, infos[21].name); + Assert.assertEquals(Constants.Property.TWOPC_ENABLED, infos[29].name); } @Test diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java index 6e0e4a77799..39482e9f14c 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java @@ -742,5 +742,15 @@ private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRun Assert.assertEquals(i, 0); // we should only have one i++; } + + VitessStatement noUpdate = new VitessStatement(mockConn); + PowerMockito.when(mockCursor.getInsertId()).thenReturn(0L); + PowerMockito.when(mockCursor.getRowsAffected()).thenReturn(1L); + + noUpdate.addBatch(sqlUpsert); + noUpdate.executeBatch(); + + ResultSet empty = noUpdate.getGeneratedKeys(); + Assert.assertFalse(empty.next()); } } diff --git a/proto/binlogdata.proto b/proto/binlogdata.proto index 4fb7cf56987..252cdb05abc 100644 --- a/proto/binlogdata.proto +++ b/proto/binlogdata.proto @@ -113,3 +113,23 @@ message StreamTablesRequest { message StreamTablesResponse { BinlogTransaction binlog_transaction = 1; } + +// BinlogSource specifies the source and filter parameters for +// Filtered Replication. It currently supports a keyrange +// or a list of tables. +message BinlogSource { + // the source keyspace + string keyspace = 1; + + // the source shard + string shard = 2; + + // the source tablet type + topodata.TabletType tablet_type = 3; + + // key_range is set if the request is for a keyrange + topodata.KeyRange key_range = 4; + + // tables is set if the request is for a list of tables + repeated string tables = 5; +} diff --git a/proto/tabletmanagerdata.proto b/proto/tabletmanagerdata.proto index 2ea3555ae84..0898209b5a6 100644 --- a/proto/tabletmanagerdata.proto +++ b/proto/tabletmanagerdata.proto @@ -93,12 +93,6 @@ message Permissions { repeated DbPermission db_permissions = 2; } -// BlpPosition is a replication position for a given binlog player -message BlpPosition { - uint32 uid = 1; - string position = 2; -} - // // RPC payloads // @@ -309,40 +303,26 @@ message GetSlavesResponse { repeated string addrs = 1; } -message WaitBlpPositionRequest { - BlpPosition blp_position = 1; - int64 wait_timeout = 2; -} - -message WaitBlpPositionResponse { -} - -message StopBlpRequest { -} - -message StopBlpResponse { - repeated BlpPosition blp_positions = 1; -} - -message StartBlpRequest { +message ResetReplicationRequest { } -message StartBlpResponse { +message ResetReplicationResponse { } -message RunBlpUntilRequest { - repeated BlpPosition blp_positions = 1; - int64 wait_timeout = 2; +message VReplicationExecRequest { + string query = 1; } -message RunBlpUntilResponse { - string position = 1; +message VReplicationExecResponse { + query.QueryResult result = 1; } -message ResetReplicationRequest { +message VReplicationWaitForPosRequest { + int64 id = 1; + string position = 2; } -message ResetReplicationResponse { +message VReplicationWaitForPosResponse { } message InitMasterRequest { diff --git a/proto/tabletmanagerservice.proto b/proto/tabletmanagerservice.proto index 99d08fc0fe5..e43de2938e1 100644 --- a/proto/tabletmanagerservice.proto +++ b/proto/tabletmanagerservice.proto @@ -125,19 +125,9 @@ service TabletManager { // GetSlaves asks for the list of mysql slaves rpc GetSlaves(tabletmanagerdata.GetSlavesRequest) returns (tabletmanagerdata.GetSlavesResponse) {}; - // WaitBlpPosition tells the remote tablet to wait until it reaches - // the specified binolg player position - rpc WaitBlpPosition(tabletmanagerdata.WaitBlpPositionRequest) returns (tabletmanagerdata.WaitBlpPositionResponse) {}; - - // StopBlp asks the tablet to stop all its binlog players, - // and returns the current position for all of them - rpc StopBlp(tabletmanagerdata.StopBlpRequest) returns (tabletmanagerdata.StopBlpResponse) {}; - - // StartBlp asks the tablet to restart its binlog players - rpc StartBlp(tabletmanagerdata.StartBlpRequest) returns (tabletmanagerdata.StartBlpResponse) {}; - - // RunBlpUntil asks the tablet to restart its binlog players - rpc RunBlpUntil(tabletmanagerdata.RunBlpUntilRequest) returns (tabletmanagerdata.RunBlpUntilResponse) {}; + // VReplication API + rpc VReplicationExec(tabletmanagerdata.VReplicationExecRequest) returns(tabletmanagerdata.VReplicationExecResponse) {}; + rpc VReplicationWaitForPos(tabletmanagerdata.VReplicationWaitForPosRequest) returns(tabletmanagerdata.VReplicationWaitForPosResponse) {}; // // Reparenting related functions diff --git a/proto/vschema.proto b/proto/vschema.proto index 7dc8d3fb6db..81276a767b5 100644 --- a/proto/vschema.proto +++ b/proto/vschema.proto @@ -60,6 +60,11 @@ message Table { AutoIncrement auto_increment = 3; // columns lists the columns for the table. repeated Column columns = 4; + // pinned pins an unsharded table to a specific + // shard, as dictated by the keyspace id. + // The keyspace id is represened in hex form + // like in keyranges. + string pinned =5; } // ColumnVindex is used to associate a column to a vindex. diff --git a/proto/workflow.proto b/proto/workflow.proto index e943e662f26..df3cecfbf80 100644 --- a/proto/workflow.proto +++ b/proto/workflow.proto @@ -74,6 +74,9 @@ message Workflow { // end_time is set when the workflow is finished. // This field only makes sense if 'state' is Done. int64 end_time = 8; + + // create_time is set when the workflow is created. + int64 create_time = 9; } message WorkflowCheckpoint { diff --git a/py/vtproto/binlogdata_pb2.py b/py/vtproto/binlogdata_pb2.py index e22a3468718..97cae7e7c3f 100644 --- a/py/vtproto/binlogdata_pb2.py +++ b/py/vtproto/binlogdata_pb2.py @@ -21,7 +21,7 @@ name='binlogdata.proto', package='binlogdata', syntax='proto3', - serialized_pb=_b('\n\x10\x62inlogdata.proto\x12\nbinlogdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\"7\n\x07\x43harset\x12\x0e\n\x06\x63lient\x18\x01 \x01(\x05\x12\x0c\n\x04\x63onn\x18\x02 \x01(\x05\x12\x0e\n\x06server\x18\x03 \x01(\x05\"\xb5\x03\n\x11\x42inlogTransaction\x12;\n\nstatements\x18\x01 \x03(\x0b\x32\'.binlogdata.BinlogTransaction.Statement\x12&\n\x0b\x65vent_token\x18\x04 \x01(\x0b\x32\x11.query.EventToken\x1a\xae\x02\n\tStatement\x12\x42\n\x08\x63\x61tegory\x18\x01 \x01(\x0e\x32\x30.binlogdata.BinlogTransaction.Statement.Category\x12$\n\x07\x63harset\x18\x02 \x01(\x0b\x32\x13.binlogdata.Charset\x12\x0b\n\x03sql\x18\x03 \x01(\x0c\"\xa9\x01\n\x08\x43\x61tegory\x12\x13\n\x0f\x42L_UNRECOGNIZED\x10\x00\x12\x0c\n\x08\x42L_BEGIN\x10\x01\x12\r\n\tBL_COMMIT\x10\x02\x12\x0f\n\x0b\x42L_ROLLBACK\x10\x03\x12\x15\n\x11\x42L_DML_DEPRECATED\x10\x04\x12\n\n\x06\x42L_DDL\x10\x05\x12\n\n\x06\x42L_SET\x10\x06\x12\r\n\tBL_INSERT\x10\x07\x12\r\n\tBL_UPDATE\x10\x08\x12\r\n\tBL_DELETE\x10\tJ\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\"v\n\x15StreamKeyRangeRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"S\n\x16StreamKeyRangeResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"]\n\x13StreamTablesRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x0e\n\x06tables\x18\x02 \x03(\t\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"Q\n\x14StreamTablesResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransactionB)Z\'vitess.io/vitess/go/vt/proto/binlogdatab\x06proto3') + serialized_pb=_b('\n\x10\x62inlogdata.proto\x12\nbinlogdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\"7\n\x07\x43harset\x12\x0e\n\x06\x63lient\x18\x01 \x01(\x05\x12\x0c\n\x04\x63onn\x18\x02 \x01(\x05\x12\x0e\n\x06server\x18\x03 \x01(\x05\"\xb5\x03\n\x11\x42inlogTransaction\x12;\n\nstatements\x18\x01 \x03(\x0b\x32\'.binlogdata.BinlogTransaction.Statement\x12&\n\x0b\x65vent_token\x18\x04 \x01(\x0b\x32\x11.query.EventToken\x1a\xae\x02\n\tStatement\x12\x42\n\x08\x63\x61tegory\x18\x01 \x01(\x0e\x32\x30.binlogdata.BinlogTransaction.Statement.Category\x12$\n\x07\x63harset\x18\x02 \x01(\x0b\x32\x13.binlogdata.Charset\x12\x0b\n\x03sql\x18\x03 \x01(\x0c\"\xa9\x01\n\x08\x43\x61tegory\x12\x13\n\x0f\x42L_UNRECOGNIZED\x10\x00\x12\x0c\n\x08\x42L_BEGIN\x10\x01\x12\r\n\tBL_COMMIT\x10\x02\x12\x0f\n\x0b\x42L_ROLLBACK\x10\x03\x12\x15\n\x11\x42L_DML_DEPRECATED\x10\x04\x12\n\n\x06\x42L_DDL\x10\x05\x12\n\n\x06\x42L_SET\x10\x06\x12\r\n\tBL_INSERT\x10\x07\x12\r\n\tBL_UPDATE\x10\x08\x12\r\n\tBL_DELETE\x10\tJ\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\"v\n\x15StreamKeyRangeRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"S\n\x16StreamKeyRangeResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"]\n\x13StreamTablesRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x0e\n\x06tables\x18\x02 \x03(\t\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"Q\n\x14StreamTablesResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"\x91\x01\n\x0c\x42inlogSource\x12\x10\n\x08keyspace\x18\x01 \x01(\t\x12\r\n\x05shard\x18\x02 \x01(\t\x12)\n\x0btablet_type\x18\x03 \x01(\x0e\x32\x14.topodata.TabletType\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\tB)Z\'vitess.io/vitess/go/vt/proto/binlogdatab\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,]) @@ -361,6 +361,65 @@ serialized_end=939, ) + +_BINLOGSOURCE = _descriptor.Descriptor( + name='BinlogSource', + full_name='binlogdata.BinlogSource', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='keyspace', full_name='binlogdata.BinlogSource.keyspace', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='shard', full_name='binlogdata.BinlogSource.shard', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='tablet_type', full_name='binlogdata.BinlogSource.tablet_type', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='key_range', full_name='binlogdata.BinlogSource.key_range', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='tables', full_name='binlogdata.BinlogSource.tables', index=4, + number=5, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=942, + serialized_end=1087, +) + _BINLOGTRANSACTION_STATEMENT.fields_by_name['category'].enum_type = _BINLOGTRANSACTION_STATEMENT_CATEGORY _BINLOGTRANSACTION_STATEMENT.fields_by_name['charset'].message_type = _CHARSET _BINLOGTRANSACTION_STATEMENT.containing_type = _BINLOGTRANSACTION @@ -372,12 +431,15 @@ _STREAMKEYRANGERESPONSE.fields_by_name['binlog_transaction'].message_type = _BINLOGTRANSACTION _STREAMTABLESREQUEST.fields_by_name['charset'].message_type = _CHARSET _STREAMTABLESRESPONSE.fields_by_name['binlog_transaction'].message_type = _BINLOGTRANSACTION +_BINLOGSOURCE.fields_by_name['tablet_type'].enum_type = topodata__pb2._TABLETTYPE +_BINLOGSOURCE.fields_by_name['key_range'].message_type = topodata__pb2._KEYRANGE DESCRIPTOR.message_types_by_name['Charset'] = _CHARSET DESCRIPTOR.message_types_by_name['BinlogTransaction'] = _BINLOGTRANSACTION DESCRIPTOR.message_types_by_name['StreamKeyRangeRequest'] = _STREAMKEYRANGEREQUEST DESCRIPTOR.message_types_by_name['StreamKeyRangeResponse'] = _STREAMKEYRANGERESPONSE DESCRIPTOR.message_types_by_name['StreamTablesRequest'] = _STREAMTABLESREQUEST DESCRIPTOR.message_types_by_name['StreamTablesResponse'] = _STREAMTABLESRESPONSE +DESCRIPTOR.message_types_by_name['BinlogSource'] = _BINLOGSOURCE _sym_db.RegisterFileDescriptor(DESCRIPTOR) Charset = _reflection.GeneratedProtocolMessageType('Charset', (_message.Message,), dict( @@ -430,6 +492,13 @@ )) _sym_db.RegisterMessage(StreamTablesResponse) +BinlogSource = _reflection.GeneratedProtocolMessageType('BinlogSource', (_message.Message,), dict( + DESCRIPTOR = _BINLOGSOURCE, + __module__ = 'binlogdata_pb2' + # @@protoc_insertion_point(class_scope:binlogdata.BinlogSource) + )) +_sym_db.RegisterMessage(BinlogSource) + DESCRIPTOR.has_options = True DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('Z\'vitess.io/vitess/go/vt/proto/binlogdata')) diff --git a/py/vtproto/tabletmanagerdata_pb2.py b/py/vtproto/tabletmanagerdata_pb2.py index fbde157f234..a728e5b07fb 100644 --- a/py/vtproto/tabletmanagerdata_pb2.py +++ b/py/vtproto/tabletmanagerdata_pb2.py @@ -23,7 +23,7 @@ name='tabletmanagerdata.proto', package='tabletmanagerdata', syntax='proto3', - serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\",\n\x0b\x42lpPosition\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08position\x18\x02 \x01(\t\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"d\n\x16WaitBlpPositionRequest\x12\x34\n\x0c\x62lp_position\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.BlpPosition\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\x19\n\x17WaitBlpPositionResponse\"\x10\n\x0eStopBlpRequest\"H\n\x0fStopBlpResponse\x12\x35\n\rblp_positions\x18\x01 \x03(\x0b\x32\x1e.tabletmanagerdata.BlpPosition\"\x11\n\x0fStartBlpRequest\"\x12\n\x10StartBlpResponse\"a\n\x12RunBlpUntilRequest\x12\x35\n\rblp_positions\x18\x01 \x03(\x0b\x32\x1e.tabletmanagerdata.BlpPosition\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\'\n\x13RunBlpUntilResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"$\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') + serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"(\n\x17VReplicationExecRequest\x12\r\n\x05query\x18\x01 \x01(\t\">\n\x18VReplicationExecResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"=\n\x1dVReplicationWaitForPosRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08position\x18\x02 \x01(\t\" \n\x1eVReplicationWaitForPosResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"$\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,replicationdata__pb2.DESCRIPTOR,logutil__pb2.DESCRIPTOR,]) @@ -402,44 +402,6 @@ ) -_BLPPOSITION = _descriptor.Descriptor( - name='BlpPosition', - full_name='tabletmanagerdata.BlpPosition', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='uid', full_name='tabletmanagerdata.BlpPosition.uid', index=0, - number=1, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='position', full_name='tabletmanagerdata.BlpPosition.position', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1037, - serialized_end=1081, -) - - _PINGREQUEST = _descriptor.Descriptor( name='PingRequest', full_name='tabletmanagerdata.PingRequest', @@ -466,8 +428,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1083, - serialized_end=1113, + serialized_start=1037, + serialized_end=1067, ) @@ -497,8 +459,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1115, - serialized_end=1146, + serialized_start=1069, + serialized_end=1100, ) @@ -528,8 +490,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1148, - serialized_end=1180, + serialized_start=1102, + serialized_end=1134, ) @@ -552,8 +514,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1182, - serialized_end=1197, + serialized_start=1136, + serialized_end=1151, ) @@ -590,8 +552,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1328, - serialized_end=1375, + serialized_start=1282, + serialized_end=1329, ) _EXECUTEHOOKREQUEST = _descriptor.Descriptor( @@ -634,8 +596,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1200, - serialized_end=1375, + serialized_start=1154, + serialized_end=1329, ) @@ -679,8 +641,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1377, - serialized_end=1451, + serialized_start=1331, + serialized_end=1405, ) @@ -724,8 +686,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1453, - serialized_end=1534, + serialized_start=1407, + serialized_end=1488, ) @@ -755,8 +717,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1536, - serialized_end=1619, + serialized_start=1490, + serialized_end=1573, ) @@ -779,8 +741,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1621, - serialized_end=1644, + serialized_start=1575, + serialized_end=1598, ) @@ -810,8 +772,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1646, - serialized_end=1723, + serialized_start=1600, + serialized_end=1677, ) @@ -834,8 +796,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1725, - serialized_end=1745, + serialized_start=1679, + serialized_end=1699, ) @@ -858,8 +820,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1747, - serialized_end=1768, + serialized_start=1701, + serialized_end=1722, ) @@ -882,8 +844,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1770, - serialized_end=1791, + serialized_start=1724, + serialized_end=1745, ) @@ -906,8 +868,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1793, - serialized_end=1815, + serialized_start=1747, + serialized_end=1769, ) @@ -937,8 +899,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1817, - serialized_end=1879, + serialized_start=1771, + serialized_end=1833, ) @@ -961,8 +923,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1881, - serialized_end=1901, + serialized_start=1835, + serialized_end=1855, ) @@ -985,8 +947,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1903, - serialized_end=1924, + serialized_start=1857, + serialized_end=1878, ) @@ -1009,8 +971,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1926, - serialized_end=1948, + serialized_start=1880, + serialized_end=1902, ) @@ -1033,8 +995,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1950, - serialized_end=1973, + serialized_start=1904, + serialized_end=1927, ) @@ -1057,8 +1019,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1975, - serialized_end=1999, + serialized_start=1929, + serialized_end=1953, ) @@ -1088,8 +1050,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2001, - serialized_end=2044, + serialized_start=1955, + serialized_end=1998, ) @@ -1112,8 +1074,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2046, - serialized_end=2073, + serialized_start=2000, + serialized_end=2027, ) @@ -1143,8 +1105,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2075, - serialized_end=2119, + serialized_start=2029, + serialized_end=2073, ) @@ -1167,8 +1129,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2121, - serialized_end=2143, + serialized_start=2075, + serialized_end=2097, ) @@ -1198,8 +1160,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2145, - serialized_end=2186, + serialized_start=2099, + serialized_end=2140, ) @@ -1229,8 +1191,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2188, - serialized_end=2276, + serialized_start=2142, + serialized_end=2230, ) @@ -1288,8 +1250,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2279, - serialized_end=2473, + serialized_start=2233, + serialized_end=2427, ) @@ -1326,8 +1288,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2476, - serialized_end=2616, + serialized_start=2430, + serialized_end=2570, ) @@ -1385,8 +1347,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2618, - serialized_end=2742, + serialized_start=2572, + serialized_end=2696, ) @@ -1416,8 +1378,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2744, - serialized_end=2807, + serialized_start=2698, + serialized_end=2761, ) @@ -1468,8 +1430,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2809, - serialized_end=2913, + serialized_start=2763, + serialized_end=2867, ) @@ -1499,8 +1461,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2915, - serialized_end=2983, + serialized_start=2869, + serialized_end=2937, ) @@ -1537,8 +1499,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2985, - serialized_end=3044, + serialized_start=2939, + serialized_end=2998, ) @@ -1568,8 +1530,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3046, - serialized_end=3109, + serialized_start=3000, + serialized_end=3063, ) @@ -1592,8 +1554,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3111, - serialized_end=3131, + serialized_start=3065, + serialized_end=3085, ) @@ -1623,8 +1585,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3133, - serialized_end=3195, + serialized_start=3087, + serialized_end=3149, ) @@ -1647,8 +1609,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3197, - serialized_end=3220, + serialized_start=3151, + serialized_end=3174, ) @@ -1678,8 +1640,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3222, - serialized_end=3264, + serialized_start=3176, + serialized_end=3218, ) @@ -1702,8 +1664,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3266, - serialized_end=3284, + serialized_start=3220, + serialized_end=3238, ) @@ -1726,8 +1688,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3286, - serialized_end=3305, + serialized_start=3240, + serialized_end=3259, ) @@ -1764,8 +1726,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3307, - serialized_end=3372, + serialized_start=3261, + serialized_end=3326, ) @@ -1795,8 +1757,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3374, - serialized_end=3418, + serialized_start=3328, + serialized_end=3372, ) @@ -1819,8 +1781,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3420, - serialized_end=3439, + serialized_start=3374, + serialized_end=3393, ) @@ -1843,8 +1805,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3441, - serialized_end=3461, + serialized_start=3395, + serialized_end=3415, ) @@ -1874,8 +1836,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3463, - serialized_end=3519, + serialized_start=3417, + serialized_end=3473, ) @@ -1898,8 +1860,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3521, - serialized_end=3557, + serialized_start=3475, + serialized_end=3511, ) @@ -1922,8 +1884,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3559, - serialized_end=3591, + serialized_start=3513, + serialized_end=3545, ) @@ -1946,8 +1908,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3593, - serialized_end=3626, + serialized_start=3547, + serialized_end=3580, ) @@ -1970,8 +1932,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3628, - serialized_end=3646, + serialized_start=3582, + serialized_end=3600, ) @@ -2001,52 +1963,14 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3648, - serialized_end=3682, -) - - -_WAITBLPPOSITIONREQUEST = _descriptor.Descriptor( - name='WaitBlpPositionRequest', - full_name='tabletmanagerdata.WaitBlpPositionRequest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='blp_position', full_name='tabletmanagerdata.WaitBlpPositionRequest.blp_position', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='wait_timeout', full_name='tabletmanagerdata.WaitBlpPositionRequest.wait_timeout', index=1, - number=2, type=3, cpp_type=2, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3684, - serialized_end=3784, + serialized_start=3602, + serialized_end=3636, ) -_WAITBLPPOSITIONRESPONSE = _descriptor.Descriptor( - name='WaitBlpPositionResponse', - full_name='tabletmanagerdata.WaitBlpPositionResponse', +_RESETREPLICATIONREQUEST = _descriptor.Descriptor( + name='ResetReplicationRequest', + full_name='tabletmanagerdata.ResetReplicationRequest', filename=None, file=DESCRIPTOR, containing_type=None, @@ -2063,14 +1987,14 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3786, - serialized_end=3811, + serialized_start=3638, + serialized_end=3663, ) -_STOPBLPREQUEST = _descriptor.Descriptor( - name='StopBlpRequest', - full_name='tabletmanagerdata.StopBlpRequest', +_RESETREPLICATIONRESPONSE = _descriptor.Descriptor( + name='ResetReplicationResponse', + full_name='tabletmanagerdata.ResetReplicationResponse', filename=None, file=DESCRIPTOR, containing_type=None, @@ -2087,22 +2011,22 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3813, - serialized_end=3829, + serialized_start=3665, + serialized_end=3691, ) -_STOPBLPRESPONSE = _descriptor.Descriptor( - name='StopBlpResponse', - full_name='tabletmanagerdata.StopBlpResponse', +_VREPLICATIONEXECREQUEST = _descriptor.Descriptor( + name='VReplicationExecRequest', + full_name='tabletmanagerdata.VReplicationExecRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='blp_positions', full_name='tabletmanagerdata.StopBlpResponse.blp_positions', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], + name='query', full_name='tabletmanagerdata.VReplicationExecRequest.query', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), @@ -2118,42 +2042,25 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3831, - serialized_end=3903, + serialized_start=3693, + serialized_end=3733, ) -_STARTBLPREQUEST = _descriptor.Descriptor( - name='StartBlpRequest', - full_name='tabletmanagerdata.StartBlpRequest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3905, - serialized_end=3922, -) - - -_STARTBLPRESPONSE = _descriptor.Descriptor( - name='StartBlpResponse', - full_name='tabletmanagerdata.StartBlpResponse', +_VREPLICATIONEXECRESPONSE = _descriptor.Descriptor( + name='VReplicationExecResponse', + full_name='tabletmanagerdata.VReplicationExecResponse', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ + _descriptor.FieldDescriptor( + name='result', full_name='tabletmanagerdata.VReplicationExecResponse.result', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -2166,59 +2073,28 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3924, - serialized_end=3942, + serialized_start=3735, + serialized_end=3797, ) -_RUNBLPUNTILREQUEST = _descriptor.Descriptor( - name='RunBlpUntilRequest', - full_name='tabletmanagerdata.RunBlpUntilRequest', +_VREPLICATIONWAITFORPOSREQUEST = _descriptor.Descriptor( + name='VReplicationWaitForPosRequest', + full_name='tabletmanagerdata.VReplicationWaitForPosRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='blp_positions', full_name='tabletmanagerdata.RunBlpUntilRequest.blp_positions', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='wait_timeout', full_name='tabletmanagerdata.RunBlpUntilRequest.wait_timeout', index=1, - number=2, type=3, cpp_type=2, label=1, + name='id', full_name='tabletmanagerdata.VReplicationWaitForPosRequest.id', index=0, + number=1, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3944, - serialized_end=4041, -) - - -_RUNBLPUNTILRESPONSE = _descriptor.Descriptor( - name='RunBlpUntilResponse', - full_name='tabletmanagerdata.RunBlpUntilResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ _descriptor.FieldDescriptor( - name='position', full_name='tabletmanagerdata.RunBlpUntilResponse.position', index=0, - number=1, type=9, cpp_type=9, label=1, + name='position', full_name='tabletmanagerdata.VReplicationWaitForPosRequest.position', index=1, + number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, @@ -2235,14 +2111,14 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4043, - serialized_end=4082, + serialized_start=3799, + serialized_end=3860, ) -_RESETREPLICATIONREQUEST = _descriptor.Descriptor( - name='ResetReplicationRequest', - full_name='tabletmanagerdata.ResetReplicationRequest', +_VREPLICATIONWAITFORPOSRESPONSE = _descriptor.Descriptor( + name='VReplicationWaitForPosResponse', + full_name='tabletmanagerdata.VReplicationWaitForPosResponse', filename=None, file=DESCRIPTOR, containing_type=None, @@ -2259,32 +2135,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4084, - serialized_end=4109, -) - - -_RESETREPLICATIONRESPONSE = _descriptor.Descriptor( - name='ResetReplicationResponse', - full_name='tabletmanagerdata.ResetReplicationResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=4111, - serialized_end=4137, + serialized_start=3862, + serialized_end=3894, ) @@ -2307,8 +2159,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4139, - serialized_end=4158, + serialized_start=3896, + serialized_end=3915, ) @@ -2338,8 +2190,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4160, - serialized_end=4198, + serialized_start=3917, + serialized_end=3955, ) @@ -2390,8 +2242,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4201, - serialized_end=4354, + serialized_start=3958, + serialized_end=4111, ) @@ -2414,8 +2266,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4356, - serialized_end=4389, + serialized_start=4113, + serialized_end=4146, ) @@ -2459,8 +2311,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4391, - serialized_end=4503, + serialized_start=4148, + serialized_end=4260, ) @@ -2483,8 +2335,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4505, - serialized_end=4524, + serialized_start=4262, + serialized_end=4281, ) @@ -2507,8 +2359,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4526, - serialized_end=4547, + serialized_start=4283, + serialized_end=4304, ) @@ -2538,8 +2390,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4549, - serialized_end=4589, + serialized_start=4306, + serialized_end=4346, ) @@ -2569,8 +2421,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4591, - serialized_end=4642, + serialized_start=4348, + serialized_end=4399, ) @@ -2600,8 +2452,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4644, - serialized_end=4696, + serialized_start=4401, + serialized_end=4453, ) @@ -2624,8 +2476,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4698, - serialized_end=4723, + serialized_start=4455, + serialized_end=4480, ) @@ -2648,8 +2500,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4725, - serialized_end=4751, + serialized_start=4482, + serialized_end=4508, ) @@ -2693,8 +2545,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4753, - serialized_end=4862, + serialized_start=4510, + serialized_end=4619, ) @@ -2717,8 +2569,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4864, - serialized_end=4883, + serialized_start=4621, + serialized_end=4640, ) @@ -2748,8 +2600,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4885, - serialized_end=4950, + serialized_start=4642, + serialized_end=4707, ) @@ -2772,8 +2624,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4952, - serialized_end=4979, + serialized_start=4709, + serialized_end=4736, ) @@ -2796,8 +2648,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4981, - serialized_end=5017, + serialized_start=4738, + serialized_end=4774, ) @@ -2827,8 +2679,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5019, - serialized_end=5097, + serialized_start=4776, + serialized_end=4854, ) @@ -2851,8 +2703,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5099, - serialized_end=5120, + serialized_start=4856, + serialized_end=4877, ) @@ -2882,8 +2734,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5122, - serialized_end=5162, + serialized_start=4879, + serialized_end=4919, ) @@ -2913,8 +2765,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5164, - serialized_end=5200, + serialized_start=4921, + serialized_end=4957, ) @@ -2944,8 +2796,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5202, - serialized_end=5249, + serialized_start=4959, + serialized_end=5006, ) @@ -2968,8 +2820,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5251, - serialized_end=5277, + serialized_start=5008, + serialized_end=5034, ) @@ -2999,8 +2851,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5279, - serialized_end=5337, + serialized_start=5036, + serialized_end=5094, ) _SCHEMADEFINITION.fields_by_name['table_definitions'].message_type = _TABLEDEFINITION @@ -3026,9 +2878,7 @@ _EXECUTEFETCHASALLPRIVSRESPONSE.fields_by_name['result'].message_type = query__pb2._QUERYRESULT _EXECUTEFETCHASAPPRESPONSE.fields_by_name['result'].message_type = query__pb2._QUERYRESULT _SLAVESTATUSRESPONSE.fields_by_name['status'].message_type = replicationdata__pb2._STATUS -_WAITBLPPOSITIONREQUEST.fields_by_name['blp_position'].message_type = _BLPPOSITION -_STOPBLPRESPONSE.fields_by_name['blp_positions'].message_type = _BLPPOSITION -_RUNBLPUNTILREQUEST.fields_by_name['blp_positions'].message_type = _BLPPOSITION +_VREPLICATIONEXECRESPONSE.fields_by_name['result'].message_type = query__pb2._QUERYRESULT _POPULATEREPARENTJOURNALREQUEST.fields_by_name['master_alias'].message_type = topodata__pb2._TABLETALIAS _INITSLAVEREQUEST.fields_by_name['parent'].message_type = topodata__pb2._TABLETALIAS _SETMASTERREQUEST.fields_by_name['parent'].message_type = topodata__pb2._TABLETALIAS @@ -3042,7 +2892,6 @@ DESCRIPTOR.message_types_by_name['UserPermission'] = _USERPERMISSION DESCRIPTOR.message_types_by_name['DbPermission'] = _DBPERMISSION DESCRIPTOR.message_types_by_name['Permissions'] = _PERMISSIONS -DESCRIPTOR.message_types_by_name['BlpPosition'] = _BLPPOSITION DESCRIPTOR.message_types_by_name['PingRequest'] = _PINGREQUEST DESCRIPTOR.message_types_by_name['PingResponse'] = _PINGRESPONSE DESCRIPTOR.message_types_by_name['SleepRequest'] = _SLEEPREQUEST @@ -3093,16 +2942,12 @@ DESCRIPTOR.message_types_by_name['TabletExternallyElectedResponse'] = _TABLETEXTERNALLYELECTEDRESPONSE DESCRIPTOR.message_types_by_name['GetSlavesRequest'] = _GETSLAVESREQUEST DESCRIPTOR.message_types_by_name['GetSlavesResponse'] = _GETSLAVESRESPONSE -DESCRIPTOR.message_types_by_name['WaitBlpPositionRequest'] = _WAITBLPPOSITIONREQUEST -DESCRIPTOR.message_types_by_name['WaitBlpPositionResponse'] = _WAITBLPPOSITIONRESPONSE -DESCRIPTOR.message_types_by_name['StopBlpRequest'] = _STOPBLPREQUEST -DESCRIPTOR.message_types_by_name['StopBlpResponse'] = _STOPBLPRESPONSE -DESCRIPTOR.message_types_by_name['StartBlpRequest'] = _STARTBLPREQUEST -DESCRIPTOR.message_types_by_name['StartBlpResponse'] = _STARTBLPRESPONSE -DESCRIPTOR.message_types_by_name['RunBlpUntilRequest'] = _RUNBLPUNTILREQUEST -DESCRIPTOR.message_types_by_name['RunBlpUntilResponse'] = _RUNBLPUNTILRESPONSE DESCRIPTOR.message_types_by_name['ResetReplicationRequest'] = _RESETREPLICATIONREQUEST DESCRIPTOR.message_types_by_name['ResetReplicationResponse'] = _RESETREPLICATIONRESPONSE +DESCRIPTOR.message_types_by_name['VReplicationExecRequest'] = _VREPLICATIONEXECREQUEST +DESCRIPTOR.message_types_by_name['VReplicationExecResponse'] = _VREPLICATIONEXECRESPONSE +DESCRIPTOR.message_types_by_name['VReplicationWaitForPosRequest'] = _VREPLICATIONWAITFORPOSREQUEST +DESCRIPTOR.message_types_by_name['VReplicationWaitForPosResponse'] = _VREPLICATIONWAITFORPOSRESPONSE DESCRIPTOR.message_types_by_name['InitMasterRequest'] = _INITMASTERREQUEST DESCRIPTOR.message_types_by_name['InitMasterResponse'] = _INITMASTERRESPONSE DESCRIPTOR.message_types_by_name['PopulateReparentJournalRequest'] = _POPULATEREPARENTJOURNALREQUEST @@ -3187,13 +3032,6 @@ )) _sym_db.RegisterMessage(Permissions) -BlpPosition = _reflection.GeneratedProtocolMessageType('BlpPosition', (_message.Message,), dict( - DESCRIPTOR = _BLPPOSITION, - __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.BlpPosition) - )) -_sym_db.RegisterMessage(BlpPosition) - PingRequest = _reflection.GeneratedProtocolMessageType('PingRequest', (_message.Message,), dict( DESCRIPTOR = _PINGREQUEST, __module__ = 'tabletmanagerdata_pb2' @@ -3552,75 +3390,47 @@ )) _sym_db.RegisterMessage(GetSlavesResponse) -WaitBlpPositionRequest = _reflection.GeneratedProtocolMessageType('WaitBlpPositionRequest', (_message.Message,), dict( - DESCRIPTOR = _WAITBLPPOSITIONREQUEST, - __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.WaitBlpPositionRequest) - )) -_sym_db.RegisterMessage(WaitBlpPositionRequest) - -WaitBlpPositionResponse = _reflection.GeneratedProtocolMessageType('WaitBlpPositionResponse', (_message.Message,), dict( - DESCRIPTOR = _WAITBLPPOSITIONRESPONSE, - __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.WaitBlpPositionResponse) - )) -_sym_db.RegisterMessage(WaitBlpPositionResponse) - -StopBlpRequest = _reflection.GeneratedProtocolMessageType('StopBlpRequest', (_message.Message,), dict( - DESCRIPTOR = _STOPBLPREQUEST, - __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.StopBlpRequest) - )) -_sym_db.RegisterMessage(StopBlpRequest) - -StopBlpResponse = _reflection.GeneratedProtocolMessageType('StopBlpResponse', (_message.Message,), dict( - DESCRIPTOR = _STOPBLPRESPONSE, - __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.StopBlpResponse) - )) -_sym_db.RegisterMessage(StopBlpResponse) - -StartBlpRequest = _reflection.GeneratedProtocolMessageType('StartBlpRequest', (_message.Message,), dict( - DESCRIPTOR = _STARTBLPREQUEST, +ResetReplicationRequest = _reflection.GeneratedProtocolMessageType('ResetReplicationRequest', (_message.Message,), dict( + DESCRIPTOR = _RESETREPLICATIONREQUEST, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.StartBlpRequest) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.ResetReplicationRequest) )) -_sym_db.RegisterMessage(StartBlpRequest) +_sym_db.RegisterMessage(ResetReplicationRequest) -StartBlpResponse = _reflection.GeneratedProtocolMessageType('StartBlpResponse', (_message.Message,), dict( - DESCRIPTOR = _STARTBLPRESPONSE, +ResetReplicationResponse = _reflection.GeneratedProtocolMessageType('ResetReplicationResponse', (_message.Message,), dict( + DESCRIPTOR = _RESETREPLICATIONRESPONSE, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.StartBlpResponse) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.ResetReplicationResponse) )) -_sym_db.RegisterMessage(StartBlpResponse) +_sym_db.RegisterMessage(ResetReplicationResponse) -RunBlpUntilRequest = _reflection.GeneratedProtocolMessageType('RunBlpUntilRequest', (_message.Message,), dict( - DESCRIPTOR = _RUNBLPUNTILREQUEST, +VReplicationExecRequest = _reflection.GeneratedProtocolMessageType('VReplicationExecRequest', (_message.Message,), dict( + DESCRIPTOR = _VREPLICATIONEXECREQUEST, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.RunBlpUntilRequest) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.VReplicationExecRequest) )) -_sym_db.RegisterMessage(RunBlpUntilRequest) +_sym_db.RegisterMessage(VReplicationExecRequest) -RunBlpUntilResponse = _reflection.GeneratedProtocolMessageType('RunBlpUntilResponse', (_message.Message,), dict( - DESCRIPTOR = _RUNBLPUNTILRESPONSE, +VReplicationExecResponse = _reflection.GeneratedProtocolMessageType('VReplicationExecResponse', (_message.Message,), dict( + DESCRIPTOR = _VREPLICATIONEXECRESPONSE, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.RunBlpUntilResponse) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.VReplicationExecResponse) )) -_sym_db.RegisterMessage(RunBlpUntilResponse) +_sym_db.RegisterMessage(VReplicationExecResponse) -ResetReplicationRequest = _reflection.GeneratedProtocolMessageType('ResetReplicationRequest', (_message.Message,), dict( - DESCRIPTOR = _RESETREPLICATIONREQUEST, +VReplicationWaitForPosRequest = _reflection.GeneratedProtocolMessageType('VReplicationWaitForPosRequest', (_message.Message,), dict( + DESCRIPTOR = _VREPLICATIONWAITFORPOSREQUEST, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.ResetReplicationRequest) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.VReplicationWaitForPosRequest) )) -_sym_db.RegisterMessage(ResetReplicationRequest) +_sym_db.RegisterMessage(VReplicationWaitForPosRequest) -ResetReplicationResponse = _reflection.GeneratedProtocolMessageType('ResetReplicationResponse', (_message.Message,), dict( - DESCRIPTOR = _RESETREPLICATIONRESPONSE, +VReplicationWaitForPosResponse = _reflection.GeneratedProtocolMessageType('VReplicationWaitForPosResponse', (_message.Message,), dict( + DESCRIPTOR = _VREPLICATIONWAITFORPOSRESPONSE, __module__ = 'tabletmanagerdata_pb2' - # @@protoc_insertion_point(class_scope:tabletmanagerdata.ResetReplicationResponse) + # @@protoc_insertion_point(class_scope:tabletmanagerdata.VReplicationWaitForPosResponse) )) -_sym_db.RegisterMessage(ResetReplicationResponse) +_sym_db.RegisterMessage(VReplicationWaitForPosResponse) InitMasterRequest = _reflection.GeneratedProtocolMessageType('InitMasterRequest', (_message.Message,), dict( DESCRIPTOR = _INITMASTERREQUEST, diff --git a/py/vtproto/tabletmanagerservice_pb2.py b/py/vtproto/tabletmanagerservice_pb2.py index 6040152a98e..515efe78587 100644 --- a/py/vtproto/tabletmanagerservice_pb2.py +++ b/py/vtproto/tabletmanagerservice_pb2.py @@ -20,7 +20,7 @@ name='tabletmanagerservice.proto', package='tabletmanagerservice', syntax='proto3', - serialized_pb=_b('\n\x1atabletmanagerservice.proto\x12\x14tabletmanagerservice\x1a\x17tabletmanagerdata.proto2\x9c\"\n\rTabletManager\x12I\n\x04Ping\x12\x1e.tabletmanagerdata.PingRequest\x1a\x1f.tabletmanagerdata.PingResponse\"\x00\x12L\n\x05Sleep\x12\x1f.tabletmanagerdata.SleepRequest\x1a .tabletmanagerdata.SleepResponse\"\x00\x12^\n\x0b\x45xecuteHook\x12%.tabletmanagerdata.ExecuteHookRequest\x1a&.tabletmanagerdata.ExecuteHookResponse\"\x00\x12X\n\tGetSchema\x12#.tabletmanagerdata.GetSchemaRequest\x1a$.tabletmanagerdata.GetSchemaResponse\"\x00\x12g\n\x0eGetPermissions\x12(.tabletmanagerdata.GetPermissionsRequest\x1a).tabletmanagerdata.GetPermissionsResponse\"\x00\x12^\n\x0bSetReadOnly\x12%.tabletmanagerdata.SetReadOnlyRequest\x1a&.tabletmanagerdata.SetReadOnlyResponse\"\x00\x12\x61\n\x0cSetReadWrite\x12&.tabletmanagerdata.SetReadWriteRequest\x1a\'.tabletmanagerdata.SetReadWriteResponse\"\x00\x12[\n\nChangeType\x12$.tabletmanagerdata.ChangeTypeRequest\x1a%.tabletmanagerdata.ChangeTypeResponse\"\x00\x12\x61\n\x0cRefreshState\x12&.tabletmanagerdata.RefreshStateRequest\x1a\'.tabletmanagerdata.RefreshStateResponse\"\x00\x12g\n\x0eRunHealthCheck\x12(.tabletmanagerdata.RunHealthCheckRequest\x1a).tabletmanagerdata.RunHealthCheckResponse\"\x00\x12p\n\x11IgnoreHealthError\x12+.tabletmanagerdata.IgnoreHealthErrorRequest\x1a,.tabletmanagerdata.IgnoreHealthErrorResponse\"\x00\x12\x61\n\x0cReloadSchema\x12&.tabletmanagerdata.ReloadSchemaRequest\x1a\'.tabletmanagerdata.ReloadSchemaResponse\"\x00\x12j\n\x0fPreflightSchema\x12).tabletmanagerdata.PreflightSchemaRequest\x1a*.tabletmanagerdata.PreflightSchemaResponse\"\x00\x12^\n\x0b\x41pplySchema\x12%.tabletmanagerdata.ApplySchemaRequest\x1a&.tabletmanagerdata.ApplySchemaResponse\"\x00\x12p\n\x11\x45xecuteFetchAsDba\x12+.tabletmanagerdata.ExecuteFetchAsDbaRequest\x1a,.tabletmanagerdata.ExecuteFetchAsDbaResponse\"\x00\x12\x7f\n\x16\x45xecuteFetchAsAllPrivs\x12\x30.tabletmanagerdata.ExecuteFetchAsAllPrivsRequest\x1a\x31.tabletmanagerdata.ExecuteFetchAsAllPrivsResponse\"\x00\x12p\n\x11\x45xecuteFetchAsApp\x12+.tabletmanagerdata.ExecuteFetchAsAppRequest\x1a,.tabletmanagerdata.ExecuteFetchAsAppResponse\"\x00\x12^\n\x0bSlaveStatus\x12%.tabletmanagerdata.SlaveStatusRequest\x1a&.tabletmanagerdata.SlaveStatusResponse\"\x00\x12g\n\x0eMasterPosition\x12(.tabletmanagerdata.MasterPositionRequest\x1a).tabletmanagerdata.MasterPositionResponse\"\x00\x12X\n\tStopSlave\x12#.tabletmanagerdata.StopSlaveRequest\x1a$.tabletmanagerdata.StopSlaveResponse\"\x00\x12m\n\x10StopSlaveMinimum\x12*.tabletmanagerdata.StopSlaveMinimumRequest\x1a+.tabletmanagerdata.StopSlaveMinimumResponse\"\x00\x12[\n\nStartSlave\x12$.tabletmanagerdata.StartSlaveRequest\x1a%.tabletmanagerdata.StartSlaveResponse\"\x00\x12\x8b\x01\n\x1aTabletExternallyReparented\x12\x34.tabletmanagerdata.TabletExternallyReparentedRequest\x1a\x35.tabletmanagerdata.TabletExternallyReparentedResponse\"\x00\x12\x82\x01\n\x17TabletExternallyElected\x12\x31.tabletmanagerdata.TabletExternallyElectedRequest\x1a\x32.tabletmanagerdata.TabletExternallyElectedResponse\"\x00\x12X\n\tGetSlaves\x12#.tabletmanagerdata.GetSlavesRequest\x1a$.tabletmanagerdata.GetSlavesResponse\"\x00\x12j\n\x0fWaitBlpPosition\x12).tabletmanagerdata.WaitBlpPositionRequest\x1a*.tabletmanagerdata.WaitBlpPositionResponse\"\x00\x12R\n\x07StopBlp\x12!.tabletmanagerdata.StopBlpRequest\x1a\".tabletmanagerdata.StopBlpResponse\"\x00\x12U\n\x08StartBlp\x12\".tabletmanagerdata.StartBlpRequest\x1a#.tabletmanagerdata.StartBlpResponse\"\x00\x12^\n\x0bRunBlpUntil\x12%.tabletmanagerdata.RunBlpUntilRequest\x1a&.tabletmanagerdata.RunBlpUntilResponse\"\x00\x12m\n\x10ResetReplication\x12*.tabletmanagerdata.ResetReplicationRequest\x1a+.tabletmanagerdata.ResetReplicationResponse\"\x00\x12[\n\nInitMaster\x12$.tabletmanagerdata.InitMasterRequest\x1a%.tabletmanagerdata.InitMasterResponse\"\x00\x12\x82\x01\n\x17PopulateReparentJournal\x12\x31.tabletmanagerdata.PopulateReparentJournalRequest\x1a\x32.tabletmanagerdata.PopulateReparentJournalResponse\"\x00\x12X\n\tInitSlave\x12#.tabletmanagerdata.InitSlaveRequest\x1a$.tabletmanagerdata.InitSlaveResponse\"\x00\x12\x61\n\x0c\x44\x65moteMaster\x12&.tabletmanagerdata.DemoteMasterRequest\x1a\'.tabletmanagerdata.DemoteMasterResponse\"\x00\x12\x85\x01\n\x18PromoteSlaveWhenCaughtUp\x12\x32.tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest\x1a\x33.tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse\"\x00\x12m\n\x10SlaveWasPromoted\x12*.tabletmanagerdata.SlaveWasPromotedRequest\x1a+.tabletmanagerdata.SlaveWasPromotedResponse\"\x00\x12X\n\tSetMaster\x12#.tabletmanagerdata.SetMasterRequest\x1a$.tabletmanagerdata.SetMasterResponse\"\x00\x12p\n\x11SlaveWasRestarted\x12+.tabletmanagerdata.SlaveWasRestartedRequest\x1a,.tabletmanagerdata.SlaveWasRestartedResponse\"\x00\x12\x8e\x01\n\x1bStopReplicationAndGetStatus\x12\x35.tabletmanagerdata.StopReplicationAndGetStatusRequest\x1a\x36.tabletmanagerdata.StopReplicationAndGetStatusResponse\"\x00\x12\x61\n\x0cPromoteSlave\x12&.tabletmanagerdata.PromoteSlaveRequest\x1a\'.tabletmanagerdata.PromoteSlaveResponse\"\x00\x12Q\n\x06\x42\x61\x63kup\x12 .tabletmanagerdata.BackupRequest\x1a!.tabletmanagerdata.BackupResponse\"\x00\x30\x01\x12r\n\x11RestoreFromBackup\x12+.tabletmanagerdata.RestoreFromBackupRequest\x1a,.tabletmanagerdata.RestoreFromBackupResponse\"\x00\x30\x01\x42\x33Z1vitess.io/vitess/go/vt/proto/tabletmanagerserviceb\x06proto3') + serialized_pb=_b('\n\x1atabletmanagerservice.proto\x12\x14tabletmanagerservice\x1a\x17tabletmanagerdata.proto2\x95!\n\rTabletManager\x12I\n\x04Ping\x12\x1e.tabletmanagerdata.PingRequest\x1a\x1f.tabletmanagerdata.PingResponse\"\x00\x12L\n\x05Sleep\x12\x1f.tabletmanagerdata.SleepRequest\x1a .tabletmanagerdata.SleepResponse\"\x00\x12^\n\x0b\x45xecuteHook\x12%.tabletmanagerdata.ExecuteHookRequest\x1a&.tabletmanagerdata.ExecuteHookResponse\"\x00\x12X\n\tGetSchema\x12#.tabletmanagerdata.GetSchemaRequest\x1a$.tabletmanagerdata.GetSchemaResponse\"\x00\x12g\n\x0eGetPermissions\x12(.tabletmanagerdata.GetPermissionsRequest\x1a).tabletmanagerdata.GetPermissionsResponse\"\x00\x12^\n\x0bSetReadOnly\x12%.tabletmanagerdata.SetReadOnlyRequest\x1a&.tabletmanagerdata.SetReadOnlyResponse\"\x00\x12\x61\n\x0cSetReadWrite\x12&.tabletmanagerdata.SetReadWriteRequest\x1a\'.tabletmanagerdata.SetReadWriteResponse\"\x00\x12[\n\nChangeType\x12$.tabletmanagerdata.ChangeTypeRequest\x1a%.tabletmanagerdata.ChangeTypeResponse\"\x00\x12\x61\n\x0cRefreshState\x12&.tabletmanagerdata.RefreshStateRequest\x1a\'.tabletmanagerdata.RefreshStateResponse\"\x00\x12g\n\x0eRunHealthCheck\x12(.tabletmanagerdata.RunHealthCheckRequest\x1a).tabletmanagerdata.RunHealthCheckResponse\"\x00\x12p\n\x11IgnoreHealthError\x12+.tabletmanagerdata.IgnoreHealthErrorRequest\x1a,.tabletmanagerdata.IgnoreHealthErrorResponse\"\x00\x12\x61\n\x0cReloadSchema\x12&.tabletmanagerdata.ReloadSchemaRequest\x1a\'.tabletmanagerdata.ReloadSchemaResponse\"\x00\x12j\n\x0fPreflightSchema\x12).tabletmanagerdata.PreflightSchemaRequest\x1a*.tabletmanagerdata.PreflightSchemaResponse\"\x00\x12^\n\x0b\x41pplySchema\x12%.tabletmanagerdata.ApplySchemaRequest\x1a&.tabletmanagerdata.ApplySchemaResponse\"\x00\x12p\n\x11\x45xecuteFetchAsDba\x12+.tabletmanagerdata.ExecuteFetchAsDbaRequest\x1a,.tabletmanagerdata.ExecuteFetchAsDbaResponse\"\x00\x12\x7f\n\x16\x45xecuteFetchAsAllPrivs\x12\x30.tabletmanagerdata.ExecuteFetchAsAllPrivsRequest\x1a\x31.tabletmanagerdata.ExecuteFetchAsAllPrivsResponse\"\x00\x12p\n\x11\x45xecuteFetchAsApp\x12+.tabletmanagerdata.ExecuteFetchAsAppRequest\x1a,.tabletmanagerdata.ExecuteFetchAsAppResponse\"\x00\x12^\n\x0bSlaveStatus\x12%.tabletmanagerdata.SlaveStatusRequest\x1a&.tabletmanagerdata.SlaveStatusResponse\"\x00\x12g\n\x0eMasterPosition\x12(.tabletmanagerdata.MasterPositionRequest\x1a).tabletmanagerdata.MasterPositionResponse\"\x00\x12X\n\tStopSlave\x12#.tabletmanagerdata.StopSlaveRequest\x1a$.tabletmanagerdata.StopSlaveResponse\"\x00\x12m\n\x10StopSlaveMinimum\x12*.tabletmanagerdata.StopSlaveMinimumRequest\x1a+.tabletmanagerdata.StopSlaveMinimumResponse\"\x00\x12[\n\nStartSlave\x12$.tabletmanagerdata.StartSlaveRequest\x1a%.tabletmanagerdata.StartSlaveResponse\"\x00\x12\x8b\x01\n\x1aTabletExternallyReparented\x12\x34.tabletmanagerdata.TabletExternallyReparentedRequest\x1a\x35.tabletmanagerdata.TabletExternallyReparentedResponse\"\x00\x12\x82\x01\n\x17TabletExternallyElected\x12\x31.tabletmanagerdata.TabletExternallyElectedRequest\x1a\x32.tabletmanagerdata.TabletExternallyElectedResponse\"\x00\x12X\n\tGetSlaves\x12#.tabletmanagerdata.GetSlavesRequest\x1a$.tabletmanagerdata.GetSlavesResponse\"\x00\x12m\n\x10VReplicationExec\x12*.tabletmanagerdata.VReplicationExecRequest\x1a+.tabletmanagerdata.VReplicationExecResponse\"\x00\x12\x7f\n\x16VReplicationWaitForPos\x12\x30.tabletmanagerdata.VReplicationWaitForPosRequest\x1a\x31.tabletmanagerdata.VReplicationWaitForPosResponse\"\x00\x12m\n\x10ResetReplication\x12*.tabletmanagerdata.ResetReplicationRequest\x1a+.tabletmanagerdata.ResetReplicationResponse\"\x00\x12[\n\nInitMaster\x12$.tabletmanagerdata.InitMasterRequest\x1a%.tabletmanagerdata.InitMasterResponse\"\x00\x12\x82\x01\n\x17PopulateReparentJournal\x12\x31.tabletmanagerdata.PopulateReparentJournalRequest\x1a\x32.tabletmanagerdata.PopulateReparentJournalResponse\"\x00\x12X\n\tInitSlave\x12#.tabletmanagerdata.InitSlaveRequest\x1a$.tabletmanagerdata.InitSlaveResponse\"\x00\x12\x61\n\x0c\x44\x65moteMaster\x12&.tabletmanagerdata.DemoteMasterRequest\x1a\'.tabletmanagerdata.DemoteMasterResponse\"\x00\x12\x85\x01\n\x18PromoteSlaveWhenCaughtUp\x12\x32.tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest\x1a\x33.tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse\"\x00\x12m\n\x10SlaveWasPromoted\x12*.tabletmanagerdata.SlaveWasPromotedRequest\x1a+.tabletmanagerdata.SlaveWasPromotedResponse\"\x00\x12X\n\tSetMaster\x12#.tabletmanagerdata.SetMasterRequest\x1a$.tabletmanagerdata.SetMasterResponse\"\x00\x12p\n\x11SlaveWasRestarted\x12+.tabletmanagerdata.SlaveWasRestartedRequest\x1a,.tabletmanagerdata.SlaveWasRestartedResponse\"\x00\x12\x8e\x01\n\x1bStopReplicationAndGetStatus\x12\x35.tabletmanagerdata.StopReplicationAndGetStatusRequest\x1a\x36.tabletmanagerdata.StopReplicationAndGetStatusResponse\"\x00\x12\x61\n\x0cPromoteSlave\x12&.tabletmanagerdata.PromoteSlaveRequest\x1a\'.tabletmanagerdata.PromoteSlaveResponse\"\x00\x12Q\n\x06\x42\x61\x63kup\x12 .tabletmanagerdata.BackupRequest\x1a!.tabletmanagerdata.BackupResponse\"\x00\x30\x01\x12r\n\x11RestoreFromBackup\x12+.tabletmanagerdata.RestoreFromBackupRequest\x1a,.tabletmanagerdata.RestoreFromBackupResponse\"\x00\x30\x01\x42\x33Z1vitess.io/vitess/go/vt/proto/tabletmanagerserviceb\x06proto3') , dependencies=[tabletmanagerdata__pb2.DESCRIPTOR,]) @@ -39,7 +39,7 @@ index=0, options=None, serialized_start=78, - serialized_end=4458, + serialized_end=4323, methods=[ _descriptor.MethodDescriptor( name='Ping', @@ -267,45 +267,27 @@ options=None, ), _descriptor.MethodDescriptor( - name='WaitBlpPosition', - full_name='tabletmanagerservice.TabletManager.WaitBlpPosition', + name='VReplicationExec', + full_name='tabletmanagerservice.TabletManager.VReplicationExec', index=25, containing_service=None, - input_type=tabletmanagerdata__pb2._WAITBLPPOSITIONREQUEST, - output_type=tabletmanagerdata__pb2._WAITBLPPOSITIONRESPONSE, + input_type=tabletmanagerdata__pb2._VREPLICATIONEXECREQUEST, + output_type=tabletmanagerdata__pb2._VREPLICATIONEXECRESPONSE, options=None, ), _descriptor.MethodDescriptor( - name='StopBlp', - full_name='tabletmanagerservice.TabletManager.StopBlp', + name='VReplicationWaitForPos', + full_name='tabletmanagerservice.TabletManager.VReplicationWaitForPos', index=26, containing_service=None, - input_type=tabletmanagerdata__pb2._STOPBLPREQUEST, - output_type=tabletmanagerdata__pb2._STOPBLPRESPONSE, - options=None, - ), - _descriptor.MethodDescriptor( - name='StartBlp', - full_name='tabletmanagerservice.TabletManager.StartBlp', - index=27, - containing_service=None, - input_type=tabletmanagerdata__pb2._STARTBLPREQUEST, - output_type=tabletmanagerdata__pb2._STARTBLPRESPONSE, - options=None, - ), - _descriptor.MethodDescriptor( - name='RunBlpUntil', - full_name='tabletmanagerservice.TabletManager.RunBlpUntil', - index=28, - containing_service=None, - input_type=tabletmanagerdata__pb2._RUNBLPUNTILREQUEST, - output_type=tabletmanagerdata__pb2._RUNBLPUNTILRESPONSE, + input_type=tabletmanagerdata__pb2._VREPLICATIONWAITFORPOSREQUEST, + output_type=tabletmanagerdata__pb2._VREPLICATIONWAITFORPOSRESPONSE, options=None, ), _descriptor.MethodDescriptor( name='ResetReplication', full_name='tabletmanagerservice.TabletManager.ResetReplication', - index=29, + index=27, containing_service=None, input_type=tabletmanagerdata__pb2._RESETREPLICATIONREQUEST, output_type=tabletmanagerdata__pb2._RESETREPLICATIONRESPONSE, @@ -314,7 +296,7 @@ _descriptor.MethodDescriptor( name='InitMaster', full_name='tabletmanagerservice.TabletManager.InitMaster', - index=30, + index=28, containing_service=None, input_type=tabletmanagerdata__pb2._INITMASTERREQUEST, output_type=tabletmanagerdata__pb2._INITMASTERRESPONSE, @@ -323,7 +305,7 @@ _descriptor.MethodDescriptor( name='PopulateReparentJournal', full_name='tabletmanagerservice.TabletManager.PopulateReparentJournal', - index=31, + index=29, containing_service=None, input_type=tabletmanagerdata__pb2._POPULATEREPARENTJOURNALREQUEST, output_type=tabletmanagerdata__pb2._POPULATEREPARENTJOURNALRESPONSE, @@ -332,7 +314,7 @@ _descriptor.MethodDescriptor( name='InitSlave', full_name='tabletmanagerservice.TabletManager.InitSlave', - index=32, + index=30, containing_service=None, input_type=tabletmanagerdata__pb2._INITSLAVEREQUEST, output_type=tabletmanagerdata__pb2._INITSLAVERESPONSE, @@ -341,7 +323,7 @@ _descriptor.MethodDescriptor( name='DemoteMaster', full_name='tabletmanagerservice.TabletManager.DemoteMaster', - index=33, + index=31, containing_service=None, input_type=tabletmanagerdata__pb2._DEMOTEMASTERREQUEST, output_type=tabletmanagerdata__pb2._DEMOTEMASTERRESPONSE, @@ -350,7 +332,7 @@ _descriptor.MethodDescriptor( name='PromoteSlaveWhenCaughtUp', full_name='tabletmanagerservice.TabletManager.PromoteSlaveWhenCaughtUp', - index=34, + index=32, containing_service=None, input_type=tabletmanagerdata__pb2._PROMOTESLAVEWHENCAUGHTUPREQUEST, output_type=tabletmanagerdata__pb2._PROMOTESLAVEWHENCAUGHTUPRESPONSE, @@ -359,7 +341,7 @@ _descriptor.MethodDescriptor( name='SlaveWasPromoted', full_name='tabletmanagerservice.TabletManager.SlaveWasPromoted', - index=35, + index=33, containing_service=None, input_type=tabletmanagerdata__pb2._SLAVEWASPROMOTEDREQUEST, output_type=tabletmanagerdata__pb2._SLAVEWASPROMOTEDRESPONSE, @@ -368,7 +350,7 @@ _descriptor.MethodDescriptor( name='SetMaster', full_name='tabletmanagerservice.TabletManager.SetMaster', - index=36, + index=34, containing_service=None, input_type=tabletmanagerdata__pb2._SETMASTERREQUEST, output_type=tabletmanagerdata__pb2._SETMASTERRESPONSE, @@ -377,7 +359,7 @@ _descriptor.MethodDescriptor( name='SlaveWasRestarted', full_name='tabletmanagerservice.TabletManager.SlaveWasRestarted', - index=37, + index=35, containing_service=None, input_type=tabletmanagerdata__pb2._SLAVEWASRESTARTEDREQUEST, output_type=tabletmanagerdata__pb2._SLAVEWASRESTARTEDRESPONSE, @@ -386,7 +368,7 @@ _descriptor.MethodDescriptor( name='StopReplicationAndGetStatus', full_name='tabletmanagerservice.TabletManager.StopReplicationAndGetStatus', - index=38, + index=36, containing_service=None, input_type=tabletmanagerdata__pb2._STOPREPLICATIONANDGETSTATUSREQUEST, output_type=tabletmanagerdata__pb2._STOPREPLICATIONANDGETSTATUSRESPONSE, @@ -395,7 +377,7 @@ _descriptor.MethodDescriptor( name='PromoteSlave', full_name='tabletmanagerservice.TabletManager.PromoteSlave', - index=39, + index=37, containing_service=None, input_type=tabletmanagerdata__pb2._PROMOTESLAVEREQUEST, output_type=tabletmanagerdata__pb2._PROMOTESLAVERESPONSE, @@ -404,7 +386,7 @@ _descriptor.MethodDescriptor( name='Backup', full_name='tabletmanagerservice.TabletManager.Backup', - index=40, + index=38, containing_service=None, input_type=tabletmanagerdata__pb2._BACKUPREQUEST, output_type=tabletmanagerdata__pb2._BACKUPRESPONSE, @@ -413,7 +395,7 @@ _descriptor.MethodDescriptor( name='RestoreFromBackup', full_name='tabletmanagerservice.TabletManager.RestoreFromBackup', - index=41, + index=39, containing_service=None, input_type=tabletmanagerdata__pb2._RESTOREFROMBACKUPREQUEST, output_type=tabletmanagerdata__pb2._RESTOREFROMBACKUPRESPONSE, diff --git a/py/vtproto/tabletmanagerservice_pb2_grpc.py b/py/vtproto/tabletmanagerservice_pb2_grpc.py index 34661100362..f21854be9f0 100644 --- a/py/vtproto/tabletmanagerservice_pb2_grpc.py +++ b/py/vtproto/tabletmanagerservice_pb2_grpc.py @@ -142,25 +142,15 @@ def __init__(self, channel): request_serializer=tabletmanagerdata__pb2.GetSlavesRequest.SerializeToString, response_deserializer=tabletmanagerdata__pb2.GetSlavesResponse.FromString, ) - self.WaitBlpPosition = channel.unary_unary( - '/tabletmanagerservice.TabletManager/WaitBlpPosition', - request_serializer=tabletmanagerdata__pb2.WaitBlpPositionRequest.SerializeToString, - response_deserializer=tabletmanagerdata__pb2.WaitBlpPositionResponse.FromString, - ) - self.StopBlp = channel.unary_unary( - '/tabletmanagerservice.TabletManager/StopBlp', - request_serializer=tabletmanagerdata__pb2.StopBlpRequest.SerializeToString, - response_deserializer=tabletmanagerdata__pb2.StopBlpResponse.FromString, - ) - self.StartBlp = channel.unary_unary( - '/tabletmanagerservice.TabletManager/StartBlp', - request_serializer=tabletmanagerdata__pb2.StartBlpRequest.SerializeToString, - response_deserializer=tabletmanagerdata__pb2.StartBlpResponse.FromString, - ) - self.RunBlpUntil = channel.unary_unary( - '/tabletmanagerservice.TabletManager/RunBlpUntil', - request_serializer=tabletmanagerdata__pb2.RunBlpUntilRequest.SerializeToString, - response_deserializer=tabletmanagerdata__pb2.RunBlpUntilResponse.FromString, + self.VReplicationExec = channel.unary_unary( + '/tabletmanagerservice.TabletManager/VReplicationExec', + request_serializer=tabletmanagerdata__pb2.VReplicationExecRequest.SerializeToString, + response_deserializer=tabletmanagerdata__pb2.VReplicationExecResponse.FromString, + ) + self.VReplicationWaitForPos = channel.unary_unary( + '/tabletmanagerservice.TabletManager/VReplicationWaitForPos', + request_serializer=tabletmanagerdata__pb2.VReplicationWaitForPosRequest.SerializeToString, + response_deserializer=tabletmanagerdata__pb2.VReplicationWaitForPosResponse.FromString, ) self.ResetReplication = channel.unary_unary( '/tabletmanagerservice.TabletManager/ResetReplication', @@ -441,32 +431,16 @@ def GetSlaves(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') - def WaitBlpPosition(self, request, context): - """WaitBlpPosition tells the remote tablet to wait until it reaches - the specified binolg player position - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def StopBlp(self, request, context): - """StopBlp asks the tablet to stop all its binlog players, - and returns the current position for all of them + def VReplicationExec(self, request, context): + """VReplication API """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') - def StartBlp(self, request, context): - """StartBlp asks the tablet to restart its binlog players - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def RunBlpUntil(self, request, context): - """RunBlpUntil asks the tablet to restart its binlog players - """ + def VReplicationWaitForPos(self, request, context): + # missing associated documentation comment in .proto file + pass context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') @@ -700,25 +674,15 @@ def add_TabletManagerServicer_to_server(servicer, server): request_deserializer=tabletmanagerdata__pb2.GetSlavesRequest.FromString, response_serializer=tabletmanagerdata__pb2.GetSlavesResponse.SerializeToString, ), - 'WaitBlpPosition': grpc.unary_unary_rpc_method_handler( - servicer.WaitBlpPosition, - request_deserializer=tabletmanagerdata__pb2.WaitBlpPositionRequest.FromString, - response_serializer=tabletmanagerdata__pb2.WaitBlpPositionResponse.SerializeToString, - ), - 'StopBlp': grpc.unary_unary_rpc_method_handler( - servicer.StopBlp, - request_deserializer=tabletmanagerdata__pb2.StopBlpRequest.FromString, - response_serializer=tabletmanagerdata__pb2.StopBlpResponse.SerializeToString, - ), - 'StartBlp': grpc.unary_unary_rpc_method_handler( - servicer.StartBlp, - request_deserializer=tabletmanagerdata__pb2.StartBlpRequest.FromString, - response_serializer=tabletmanagerdata__pb2.StartBlpResponse.SerializeToString, - ), - 'RunBlpUntil': grpc.unary_unary_rpc_method_handler( - servicer.RunBlpUntil, - request_deserializer=tabletmanagerdata__pb2.RunBlpUntilRequest.FromString, - response_serializer=tabletmanagerdata__pb2.RunBlpUntilResponse.SerializeToString, + 'VReplicationExec': grpc.unary_unary_rpc_method_handler( + servicer.VReplicationExec, + request_deserializer=tabletmanagerdata__pb2.VReplicationExecRequest.FromString, + response_serializer=tabletmanagerdata__pb2.VReplicationExecResponse.SerializeToString, + ), + 'VReplicationWaitForPos': grpc.unary_unary_rpc_method_handler( + servicer.VReplicationWaitForPos, + request_deserializer=tabletmanagerdata__pb2.VReplicationWaitForPosRequest.FromString, + response_serializer=tabletmanagerdata__pb2.VReplicationWaitForPosResponse.SerializeToString, ), 'ResetReplication': grpc.unary_unary_rpc_method_handler( servicer.ResetReplication, diff --git a/py/vtproto/vschema_pb2.py b/py/vtproto/vschema_pb2.py index f516b73a840..81c5b4064e8 100644 --- a/py/vtproto/vschema_pb2.py +++ b/py/vtproto/vschema_pb2.py @@ -20,7 +20,7 @@ name='vschema.proto', package='vschema', syntax='proto3', - serialized_pb=_b('\n\rvschema.proto\x12\x07vschema\x1a\x0bquery.proto\"\xfe\x01\n\x08Keyspace\x12\x0f\n\x07sharded\x18\x01 \x01(\x08\x12\x31\n\x08vindexes\x18\x02 \x03(\x0b\x32\x1f.vschema.Keyspace.VindexesEntry\x12-\n\x06tables\x18\x03 \x03(\x0b\x32\x1d.vschema.Keyspace.TablesEntry\x1a@\n\rVindexesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.vschema.Vindex:\x02\x38\x01\x1a=\n\x0bTablesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.vschema.Table:\x02\x38\x01\"\x81\x01\n\x06Vindex\x12\x0c\n\x04type\x18\x01 \x01(\t\x12+\n\x06params\x18\x02 \x03(\x0b\x32\x1b.vschema.Vindex.ParamsEntry\x12\r\n\x05owner\x18\x03 \x01(\t\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x97\x01\n\x05Table\x12\x0c\n\x04type\x18\x01 \x01(\t\x12.\n\x0f\x63olumn_vindexes\x18\x02 \x03(\x0b\x32\x15.vschema.ColumnVindex\x12.\n\x0e\x61uto_increment\x18\x03 \x01(\x0b\x32\x16.vschema.AutoIncrement\x12 \n\x07\x63olumns\x18\x04 \x03(\x0b\x32\x0f.vschema.Column\"=\n\x0c\x43olumnVindex\x12\x0e\n\x06\x63olumn\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\"1\n\rAutoIncrement\x12\x0e\n\x06\x63olumn\x18\x01 \x01(\t\x12\x10\n\x08sequence\x18\x02 \x01(\t\"1\n\x06\x43olumn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x19\n\x04type\x18\x02 \x01(\x0e\x32\x0b.query.Type\"\x88\x01\n\nSrvVSchema\x12\x35\n\tkeyspaces\x18\x01 \x03(\x0b\x32\".vschema.SrvVSchema.KeyspacesEntry\x1a\x43\n\x0eKeyspacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.vschema.Keyspace:\x02\x38\x01\x42&Z$vitess.io/vitess/go/vt/proto/vschemab\x06proto3') + serialized_pb=_b('\n\rvschema.proto\x12\x07vschema\x1a\x0bquery.proto\"\xfe\x01\n\x08Keyspace\x12\x0f\n\x07sharded\x18\x01 \x01(\x08\x12\x31\n\x08vindexes\x18\x02 \x03(\x0b\x32\x1f.vschema.Keyspace.VindexesEntry\x12-\n\x06tables\x18\x03 \x03(\x0b\x32\x1d.vschema.Keyspace.TablesEntry\x1a@\n\rVindexesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1e\n\x05value\x18\x02 \x01(\x0b\x32\x0f.vschema.Vindex:\x02\x38\x01\x1a=\n\x0bTablesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.vschema.Table:\x02\x38\x01\"\x81\x01\n\x06Vindex\x12\x0c\n\x04type\x18\x01 \x01(\t\x12+\n\x06params\x18\x02 \x03(\x0b\x32\x1b.vschema.Vindex.ParamsEntry\x12\r\n\x05owner\x18\x03 \x01(\t\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa7\x01\n\x05Table\x12\x0c\n\x04type\x18\x01 \x01(\t\x12.\n\x0f\x63olumn_vindexes\x18\x02 \x03(\x0b\x32\x15.vschema.ColumnVindex\x12.\n\x0e\x61uto_increment\x18\x03 \x01(\x0b\x32\x16.vschema.AutoIncrement\x12 \n\x07\x63olumns\x18\x04 \x03(\x0b\x32\x0f.vschema.Column\x12\x0e\n\x06pinned\x18\x05 \x01(\t\"=\n\x0c\x43olumnVindex\x12\x0e\n\x06\x63olumn\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\"1\n\rAutoIncrement\x12\x0e\n\x06\x63olumn\x18\x01 \x01(\t\x12\x10\n\x08sequence\x18\x02 \x01(\t\"1\n\x06\x43olumn\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x19\n\x04type\x18\x02 \x01(\x0e\x32\x0b.query.Type\"\x88\x01\n\nSrvVSchema\x12\x35\n\tkeyspaces\x18\x01 \x03(\x0b\x32\".vschema.SrvVSchema.KeyspacesEntry\x1a\x43\n\x0eKeyspacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12 \n\x05value\x18\x02 \x01(\x0b\x32\x11.vschema.Keyspace:\x02\x38\x01\x42&Z$vitess.io/vitess/go/vt/proto/vschemab\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,]) @@ -263,6 +263,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='pinned', full_name='vschema.Table.pinned', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -276,7 +283,7 @@ oneofs=[ ], serialized_start=429, - serialized_end=580, + serialized_end=596, ) @@ -320,8 +327,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=582, - serialized_end=643, + serialized_start=598, + serialized_end=659, ) @@ -358,8 +365,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=645, - serialized_end=694, + serialized_start=661, + serialized_end=710, ) @@ -396,8 +403,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=696, - serialized_end=745, + serialized_start=712, + serialized_end=761, ) @@ -434,8 +441,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=817, - serialized_end=884, + serialized_start=833, + serialized_end=900, ) _SRVVSCHEMA = _descriptor.Descriptor( @@ -464,8 +471,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=748, - serialized_end=884, + serialized_start=764, + serialized_end=900, ) _KEYSPACE_VINDEXESENTRY.fields_by_name['value'].message_type = _VINDEX diff --git a/py/vtproto/workflow_pb2.py b/py/vtproto/workflow_pb2.py index 37f6cb38928..5d856a412f0 100644 --- a/py/vtproto/workflow_pb2.py +++ b/py/vtproto/workflow_pb2.py @@ -20,7 +20,7 @@ name='workflow.proto', package='workflow', syntax='proto3', - serialized_pb=_b('\n\x0eworkflow.proto\x12\x08workflow\"\xa7\x01\n\x08Workflow\x12\x0c\n\x04uuid\x18\x01 \x01(\t\x12\x14\n\x0c\x66\x61\x63tory_name\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12&\n\x05state\x18\x04 \x01(\x0e\x32\x17.workflow.WorkflowState\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x12\x12\n\nstart_time\x18\x07 \x01(\x03\x12\x10\n\x08\x65nd_time\x18\x08 \x01(\x03\"\x8f\x02\n\x12WorkflowCheckpoint\x12\x14\n\x0c\x63ode_version\x18\x01 \x01(\x05\x12\x36\n\x05tasks\x18\x02 \x03(\x0b\x32\'.workflow.WorkflowCheckpoint.TasksEntry\x12<\n\x08settings\x18\x03 \x03(\x0b\x32*.workflow.WorkflowCheckpoint.SettingsEntry\x1a<\n\nTasksEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.workflow.Task:\x02\x38\x01\x1a/\n\rSettingsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xac\x01\n\x04Task\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x05state\x18\x02 \x01(\x0e\x32\x13.workflow.TaskState\x12\x32\n\nattributes\x18\x03 \x03(\x0b\x32\x1e.workflow.Task.AttributesEntry\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*6\n\rWorkflowState\x12\x0e\n\nNotStarted\x10\x00\x12\x0b\n\x07Running\x10\x01\x12\x08\n\x04\x44one\x10\x02*>\n\tTaskState\x12\x12\n\x0eTaskNotStarted\x10\x00\x12\x0f\n\x0bTaskRunning\x10\x01\x12\x0c\n\x08TaskDone\x10\x02\x42\'Z%vitess.io/vitess/go/vt/proto/workflowb\x06proto3') + serialized_pb=_b('\n\x0eworkflow.proto\x12\x08workflow\"\xbc\x01\n\x08Workflow\x12\x0c\n\x04uuid\x18\x01 \x01(\t\x12\x14\n\x0c\x66\x61\x63tory_name\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12&\n\x05state\x18\x04 \x01(\x0e\x32\x17.workflow.WorkflowState\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x12\x12\n\nstart_time\x18\x07 \x01(\x03\x12\x10\n\x08\x65nd_time\x18\x08 \x01(\x03\x12\x13\n\x0b\x63reate_time\x18\t \x01(\x03\"\x8f\x02\n\x12WorkflowCheckpoint\x12\x14\n\x0c\x63ode_version\x18\x01 \x01(\x05\x12\x36\n\x05tasks\x18\x02 \x03(\x0b\x32\'.workflow.WorkflowCheckpoint.TasksEntry\x12<\n\x08settings\x18\x03 \x03(\x0b\x32*.workflow.WorkflowCheckpoint.SettingsEntry\x1a<\n\nTasksEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.workflow.Task:\x02\x38\x01\x1a/\n\rSettingsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xac\x01\n\x04Task\x12\n\n\x02id\x18\x01 \x01(\t\x12\"\n\x05state\x18\x02 \x01(\x0e\x32\x13.workflow.TaskState\x12\x32\n\nattributes\x18\x03 \x03(\x0b\x32\x1e.workflow.Task.AttributesEntry\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x1a\x31\n\x0f\x41ttributesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*6\n\rWorkflowState\x12\x0e\n\nNotStarted\x10\x00\x12\x0b\n\x07Running\x10\x01\x12\x08\n\x04\x44one\x10\x02*>\n\tTaskState\x12\x12\n\x0eTaskNotStarted\x10\x00\x12\x0f\n\x0bTaskRunning\x10\x01\x12\x0c\n\x08TaskDone\x10\x02\x42\'Z%vitess.io/vitess/go/vt/proto/workflowb\x06proto3') ) _WORKFLOWSTATE = _descriptor.EnumDescriptor( @@ -44,8 +44,8 @@ ], containing_type=None, options=None, - serialized_start=647, - serialized_end=701, + serialized_start=668, + serialized_end=722, ) _sym_db.RegisterEnumDescriptor(_WORKFLOWSTATE) @@ -71,8 +71,8 @@ ], containing_type=None, options=None, - serialized_start=703, - serialized_end=765, + serialized_start=724, + serialized_end=786, ) _sym_db.RegisterEnumDescriptor(_TASKSTATE) @@ -149,6 +149,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='create_time', full_name='workflow.Workflow.create_time', index=8, + number=9, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -162,7 +169,7 @@ oneofs=[ ], serialized_start=29, - serialized_end=196, + serialized_end=217, ) @@ -199,8 +206,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=361, - serialized_end=421, + serialized_start=382, + serialized_end=442, ) _WORKFLOWCHECKPOINT_SETTINGSENTRY = _descriptor.Descriptor( @@ -236,8 +243,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=423, - serialized_end=470, + serialized_start=444, + serialized_end=491, ) _WORKFLOWCHECKPOINT = _descriptor.Descriptor( @@ -280,8 +287,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=199, - serialized_end=470, + serialized_start=220, + serialized_end=491, ) @@ -318,8 +325,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=596, - serialized_end=645, + serialized_start=617, + serialized_end=666, ) _TASK = _descriptor.Descriptor( @@ -369,8 +376,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=473, - serialized_end=645, + serialized_start=494, + serialized_end=666, ) _WORKFLOW.fields_by_name['state'].enum_type = _WORKFLOWSTATE diff --git a/test/base_sharding.py b/test/base_sharding.py index b485747a999..89b1490804f 100644 --- a/test/base_sharding.py +++ b/test/base_sharding.py @@ -183,29 +183,29 @@ def check_binlog_player_vars(self, tablet_obj, source_shards, this value. """ v = utils.get_vars(tablet_obj.port) - self.assertIn('BinlogPlayerMapSize', v) - self.assertEquals(v['BinlogPlayerMapSize'], len(source_shards)) - self.assertIn('BinlogPlayerSecondsBehindMaster', v) - self.assertIn('BinlogPlayerSecondsBehindMasterMap', v) - self.assertIn('BinlogPlayerSourceShardNameMap', v) - shards = v['BinlogPlayerSourceShardNameMap'].values() + self.assertIn('VReplicationStreamCount', v) + self.assertEquals(v['VReplicationStreamCount'], len(source_shards)) + self.assertIn('VReplicationSecondsBehindMasterMax', v) + self.assertIn('VReplicationSecondsBehindMaster', v) + self.assertIn('VReplicationSource', v) + shards = v['VReplicationSource'].values() self.assertEquals(sorted(shards), sorted(source_shards)) - self.assertIn('BinlogPlayerSourceTabletAliasMap', v) - for i in xrange(len(source_shards)): - self.assertIn('%d' % i, v['BinlogPlayerSourceTabletAliasMap']) + self.assertIn('VReplicationSourceTablet', v) + for uid in v['VReplicationSource']: + self.assertIn(uid, v['VReplicationSourceTablet']) if seconds_behind_master_max != 0: self.assertTrue( - v['BinlogPlayerSecondsBehindMaster'] < + v['VReplicationSecondsBehindMasterMax'] < seconds_behind_master_max, - 'BinlogPlayerSecondsBehindMaster is too high: %d > %d' % ( - v['BinlogPlayerSecondsBehindMaster'], + 'VReplicationSecondsBehindMasterMax is too high: %d > %d' % ( + v['VReplicationSecondsBehindMasterMax'], seconds_behind_master_max)) - for i in xrange(len(source_shards)): + for uid in v['VReplicationSource']: self.assertTrue( - v['BinlogPlayerSecondsBehindMasterMap']['%d' % i] < + v['VReplicationSecondsBehindMaster'][uid] < seconds_behind_master_max, - 'BinlogPlayerSecondsBehindMasterMap is too high: %d > %d' % ( - v['BinlogPlayerSecondsBehindMasterMap']['%d' % i], + 'VReplicationSecondsBehindMaster is too high: %d > %d' % ( + v['VReplicationSecondsBehindMaster'][uid], seconds_behind_master_max)) def check_binlog_server_vars(self, tablet_obj, horizontal=True, @@ -245,7 +245,7 @@ def check_stream_health_equals_binlog_player_vars(self, tablet_obj, count): """ blp_stats = utils.get_vars(tablet_obj.port) - self.assertEqual(blp_stats['BinlogPlayerMapSize'], count) + self.assertEqual(blp_stats['VReplicationStreamCount'], count) # Enforce health check because it's not running by default as # tablets may not be started with it, or may not run it in time. @@ -258,9 +258,9 @@ def check_stream_health_equals_binlog_player_vars(self, tablet_obj, count): self.assertIn('realtime_stats', stream_health) self.assertNotIn('health_error', stream_health['realtime_stats']) self.assertIn('binlog_players_count', stream_health['realtime_stats']) - self.assertEqual(blp_stats['BinlogPlayerMapSize'], + self.assertEqual(blp_stats['VReplicationStreamCount'], stream_health['realtime_stats']['binlog_players_count']) - self.assertEqual(blp_stats['BinlogPlayerSecondsBehindMaster'], + self.assertEqual(blp_stats['VReplicationSecondsBehindMasterMax'], stream_health['realtime_stats'].get( 'seconds_behind_master_filtered_replication', 0)) @@ -292,7 +292,7 @@ def check_running_binlog_player(self, tablet_obj, query, transaction, extra_text: if present, look for it in status too. """ status = tablet_obj.get_status() - self.assertIn('Binlog player state: Running', status) + self.assertIn('VReplication state: Open', status) self.assertIn( 'All: %d
Query: %d
' 'Transaction: %d
' % (query+transaction, query, @@ -311,10 +311,6 @@ def check_no_binlog_player(self, tablet_obj): """ tablet_obj.wait_for_binlog_player_count(0) - status = tablet_obj.get_status() - self.assertIn('No binlog player is running', status) - self.assertIn('', status) - def check_throttler_service(self, throttler_server, names, rate): """Checks that the throttler responds to RPC requests. diff --git a/test/binlog.py b/test/binlog.py index bf0c25d2852..cb677f051ab 100755 --- a/test/binlog.py +++ b/test/binlog.py @@ -172,19 +172,13 @@ def test_charset(self): # Vitess tablets default to using utf8, so we insert something crazy and # pretend it's latin1. If the binlog player doesn't also pretend it's # latin1, it will be inserted as utf8, which will change its value. + sql = ("INSERT INTO test_table (id, keyspace_id, msg) " + "VALUES (41523, 1, 'Šṛ́rỏé') /* vtgate:: keyspace_id:00000001 */") src_master.mquery( 'vt_test_keyspace', - "INSERT INTO test_table (id, keyspace_id, msg) " - "VALUES (41523, 1, 'Šṛ́rỏé') /* vtgate:: keyspace_id:00000001 */", + sql, conn_params={'charset': 'latin1'}, write=True) - - # Wait for it to replicate. - event = utils.run_vtctl_json(['VtTabletUpdateStream', - '-position', start_position, - '-count', '1', - dst_replica.tablet_alias]) - self.assertIn('event_token', event) - self.assertIn('timestamp', event['event_token']) + self._wait_for_replica_event(start_position, sql) # Check the value. data = dst_master.mquery( diff --git a/test/legacy_resharding.py b/test/legacy_resharding.py index 5640c6043ba..4f0ecd41998 100755 --- a/test/legacy_resharding.py +++ b/test/legacy_resharding.py @@ -386,8 +386,6 @@ def test_resharding(self): utils.run_vtctl(['ChangeSlaveType', shard_1_rdonly1.tablet_alias, 'rdonly'], auto_log=True) - # TODO(alainjobart): experiment with the dontStartBinlogPlayer option - # check the startup values are in the right place self._check_startup_values() @@ -403,10 +401,12 @@ def test_resharding(self): self.check_binlog_server_vars(shard_1_slave1, horizontal=True) # Check that the throttler was enabled. + # The stream id is hard-coded as 1, which is the first id generated + # through auto-inc. self.check_throttler_service(shard_2_master.rpc_endpoint(), - ['BinlogPlayer/0'], 9999) + ['BinlogPlayer/1'], 9999) self.check_throttler_service(shard_3_master.rpc_endpoint(), - ['BinlogPlayer/0'], 9999) + ['BinlogPlayer/1'], 9999) # testing filtered replication: insert a bunch of data on shard 1, # check we get most of it after a few seconds, wait for binlog server @@ -591,10 +591,10 @@ def test_resharding(self): # mock with the SourceShard records to test 'vtctl SourceShardDelete' # and 'vtctl SourceShardAdd' - utils.run_vtctl(['SourceShardDelete', 'test_keyspace/c0-', '0'], + utils.run_vtctl(['SourceShardDelete', 'test_keyspace/c0-', '1'], auto_log=True) utils.run_vtctl(['SourceShardAdd', '--key_range=80-', - 'test_keyspace/c0-', '0', 'test_keyspace/80-'], + 'test_keyspace/c0-', '1', 'test_keyspace/80-'], auto_log=True) # then serve master from the split shards, make sure the source master's diff --git a/test/merge_sharding.py b/test/merge_sharding.py index f9ee14f4049..72e71e4dbfd 100755 --- a/test/merge_sharding.py +++ b/test/merge_sharding.py @@ -366,7 +366,7 @@ def test_merge_sharding(self): 'SplitDiff', '--exclude_tables', 'unrelated', '--min_healthy_rdonly_tablets', '1', - '--source_uid', '0', + '--source_uid', '1', 'test_keyspace/-80'], auto_log=True) utils.run_vtctl(['ChangeSlaveType', shard_0_rdonly.tablet_alias, 'rdonly'], @@ -379,7 +379,7 @@ def test_merge_sharding(self): 'SplitDiff', '--exclude_tables', 'unrelated', '--min_healthy_rdonly_tablets', '1', - '--source_uid', '1', + '--source_uid', '2', 'test_keyspace/-80'], auto_log=True) utils.run_vtctl(['ChangeSlaveType', shard_1_rdonly.tablet_alias, 'rdonly'], diff --git a/test/resharding.py b/test/resharding.py index f5a74d45c72..8d1379855f0 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -179,7 +179,7 @@ def run(self): self.lag_sum_ms += lag_ms if lag_ms > self.max_lag_ms: self.max_lag_ms = lag_ms - time.sleep(1.0) + time.sleep(5.0) except Exception: # pylint: disable=broad-except logging.exception('MonitorLagThread got exception.') @@ -202,6 +202,14 @@ def _create_schema(self): parent_id bigint not null, primary key (parent_id, id), index by_msg (msg) +) Engine=InnoDB''' + create_table_bindata_template = '''create table %s( +custom_ksid_col ''' + t + ''' not null, +id bigint not null, +parent_id bigint not null, +msg bit(8), +primary key (parent_id, id), +index by_msg (msg) ) Engine=InnoDB''' create_view_template = ( 'create view %s' @@ -236,6 +244,10 @@ def _create_schema(self): '-sql=' + create_table_template % ('resharding2'), 'test_keyspace'], auto_log=True) + utils.run_vtctl(['ApplySchema', + '-sql=' + create_table_bindata_template % ('resharding3'), + 'test_keyspace'], + auto_log=True) utils.run_vtctl(['ApplySchema', '-sql=' + create_view_template % ('view1', 'resharding1'), 'test_keyspace'], @@ -259,6 +271,12 @@ def _insert_startup_values(self): 0x9000000000000000) self._insert_value(shard_1_master, 'resharding1', 3, 'msg3', 0xD000000000000000) + self._insert_value(shard_0_master, 'resharding3', 1, 'a', + 0x1000000000000000) + self._insert_value(shard_1_master, 'resharding3', 2, 'b', + 0x9000000000000000) + self._insert_value(shard_1_master, 'resharding3', 3, 'c', + 0xD000000000000000) if base_sharding.use_rbr: self._insert_value(shard_1_master, 'no_pk', 1, 'msg1', 0xA000000000000000) @@ -270,16 +288,22 @@ def _check_startup_values(self): # check first value is in the right shard for t in shard_2_tablets: self._check_value(t, 'resharding1', 2, 'msg2', 0x9000000000000000) + self._check_value(t, 'resharding3', 2, 'b', 0x9000000000000000) for t in shard_3_tablets: self._check_value(t, 'resharding1', 2, 'msg2', 0x9000000000000000, should_be_here=False) + self._check_value(t, 'resharding3', 2, 'b', 0x9000000000000000, + should_be_here=False) # check second value is in the right shard too for t in shard_2_tablets: self._check_value(t, 'resharding1', 3, 'msg3', 0xD000000000000000, should_be_here=False) + self._check_value(t, 'resharding3', 3, 'c', 0xD000000000000000, + should_be_here=False) for t in shard_3_tablets: self._check_value(t, 'resharding1', 3, 'msg3', 0xD000000000000000) + self._check_value(t, 'resharding3', 3, 'c', 0xD000000000000000) if base_sharding.use_rbr: for t in shard_2_tablets: @@ -314,6 +338,7 @@ def _exec_multi_shard_dmls(self): keyspace_ids = [0x9000000000000000, 0xD000000000000000, 0xE000000000000000] self._insert_multi_value(shard_1_master, 'resharding1', mids, msg_ids, keyspace_ids) + # This update targets two shards. self._exec_non_annotated_update(shard_1_master, 'resharding1', [10000011, 10000012], 'update1') @@ -326,12 +351,51 @@ def _exec_multi_shard_dmls(self): keyspace_ids = [0x9000000000000000, 0xD000000000000000, 0xE000000000000000] self._insert_multi_value(shard_1_master, 'resharding1', mids, msg_ids, keyspace_ids) + # This delete targets two shards. self._exec_non_annotated_delete(shard_1_master, 'resharding1', [10000014, 10000015]) + # This delete targets one shard. self._exec_non_annotated_delete(shard_1_master, 'resharding1', [10000016]) + # repeat DMLs for table with msg as bit(8) + mids = [10000001, 10000002, 10000003] + keyspace_ids = [0x9000000000000000, 0xD000000000000000, + 0xE000000000000000] + self._insert_multi_value(shard_1_master, 'resharding3', mids, + ['a','b','c'], keyspace_ids) + + mids = [10000004, 10000005] + keyspace_ids = [0xD000000000000000, 0xE000000000000000] + self._insert_multi_value(shard_1_master, 'resharding3', mids, + ['d', 'e'], keyspace_ids) + mids = [10000011, 10000012, 10000013] + keyspace_ids = [0x9000000000000000, 0xD000000000000000, 0xE000000000000000] + + self._insert_multi_value(shard_1_master, 'resharding3', mids, + ['k', 'l', 'm'], keyspace_ids) + + # This update targets two shards. + self._exec_non_annotated_update(shard_1_master, 'resharding3', + [10000011, 10000012], 'g') + + # This update targets one shard. + self._exec_non_annotated_update(shard_1_master, 'resharding3', + [10000013], 'h') + + mids = [10000014, 10000015, 10000016] + keyspace_ids = [0x9000000000000000, 0xD000000000000000, 0xE000000000000000] + self._insert_multi_value(shard_1_master, 'resharding3', mids, + ['n', 'o', 'p'], keyspace_ids) + + # This delete targets two shards. + self._exec_non_annotated_delete(shard_1_master, 'resharding3', + [10000014, 10000015]) + + # This delete targets one shard. + self._exec_non_annotated_delete(shard_1_master, 'resharding3', [10000016]) + def _check_multi_shard_values(self): self._check_multi_dbs( [shard_2_master, shard_2_replica1, shard_2_replica2], @@ -396,6 +460,70 @@ def _check_multi_shard_values(self): 'resharding1', 10000016, 'msg-id10000016', 0xF000000000000000, should_be_here=False) + # checks for bit(8) table + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000001, 'a', 0x9000000000000000) + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000002, 'b', 0xD000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000003, 'c', 0xE000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000001, 'a', 0x9000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000002, 'b', 0xD000000000000000) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000003, 'c', 0xE000000000000000) + + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000004, 'd', 0xD000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000005, 'e', 0xE000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000004, 'd', 0xD000000000000000) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000005, 'e', 0xE000000000000000) + + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2], + 'resharding3', 10000011, 'g', 0x9000000000000000) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000012, 'g', 0xD000000000000000) + self._check_multi_dbs( + [shard_3_master, shard_3_replica], + 'resharding3', 10000013, 'h', 0xE000000000000000) + + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2, + shard_3_master, shard_3_replica], + 'resharding3', 10000014, 'n', 0x9000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2, + shard_3_master, shard_3_replica], + 'resharding3', 10000015, 'o', 0xD000000000000000, + should_be_here=False) + self._check_multi_dbs( + [shard_2_master, shard_2_replica1, shard_2_replica2, + shard_3_master, shard_3_replica], + 'resharding3', 10000016, 'p', 0xF000000000000000, + should_be_here=False) + # _check_multi_dbs checks the row in multiple dbs. def _check_multi_dbs(self, dblist, table, mid, msg, keyspace_id, should_be_here=True): @@ -680,8 +808,6 @@ def test_resharding(self): # Terminate worker daemon because it is no longer needed. utils.kill_sub_process(worker_proc, soft=True) - # TODO(alainjobart): experiment with the dontStartBinlogPlayer option - # check the startup values are in the right place self._check_startup_values() @@ -689,6 +815,20 @@ def test_resharding(self): utils.run_vtctl(['ValidateSchemaKeyspace', '--exclude_tables=unrelated', 'test_keyspace'], auto_log=True) + # Verify vreplication table entries + result = shard_2_master.mquery('_vt', 'select * from vreplication') + self.assertEqual(len(result), 1) + self.assertEqual(result[0][1], 'SplitClone') + self.assertEqual(result[0][2], + 'keyspace:"test_keyspace" shard:"80-" ' + 'key_range: ') + + result = shard_3_master.mquery('_vt', 'select * from vreplication') + self.assertEqual(len(result), 1) + self.assertEqual(result[0][1], 'SplitClone') + self.assertEqual(result[0][2], + 'keyspace:"test_keyspace" shard:"80-" key_range: ') + # check the binlog players are running and exporting vars self.check_destination_master(shard_2_master, ['test_keyspace/80-']) self.check_destination_master(shard_3_master, ['test_keyspace/80-']) @@ -704,10 +844,12 @@ def test_resharding(self): self.check_binlog_server_vars(shard_1_slave1, horizontal=True) # Check that the throttler was enabled. + # The stream id is hard-coded as 1, which is the first id generated + # through auto-inc. self.check_throttler_service(shard_2_master.rpc_endpoint(), - ['BinlogPlayer/0'], 9999) + ['BinlogPlayer/1'], 9999) self.check_throttler_service(shard_3_master.rpc_endpoint(), - ['BinlogPlayer/0'], 9999) + ['BinlogPlayer/1'], 9999) # testing filtered replication: insert a bunch of data on shard 1, # check we get most of it after a few seconds, wait for binlog server @@ -760,11 +902,11 @@ def test_resharding(self): # are smaller. In the second shard, we submitted statements # that affect more than one keyspace id. These will result # in two queries with RBR. So the count there is higher. - self.check_running_binlog_player(shard_2_master, 4018, 2008) - self.check_running_binlog_player(shard_3_master, 4028, 2008) + self.check_running_binlog_player(shard_2_master, 4036, 2016) + self.check_running_binlog_player(shard_3_master, 4056, 2016) else: - self.check_running_binlog_player(shard_2_master, 4022, 2008) - self.check_running_binlog_player(shard_3_master, 4024, 2008) + self.check_running_binlog_player(shard_2_master, 4044, 2016) + self.check_running_binlog_player(shard_3_master, 4048, 2016) # start a thread to insert data into shard_1 in the background # with current time, and monitor the delay @@ -943,10 +1085,10 @@ def test_resharding(self): # mock with the SourceShard records to test 'vtctl SourceShardDelete' # and 'vtctl SourceShardAdd' - utils.run_vtctl(['SourceShardDelete', 'test_keyspace/c0-', '0'], + utils.run_vtctl(['SourceShardDelete', 'test_keyspace/c0-', '1'], auto_log=True) utils.run_vtctl(['SourceShardAdd', '--key_range=80-', - 'test_keyspace/c0-', '0', 'test_keyspace/80-'], + 'test_keyspace/c0-', '1', 'test_keyspace/80-'], auto_log=True) # then serve master from the split shards, make sure the source master's diff --git a/test/schema_swap_test.py b/test/schema_swap_test.py index 556d005f405..c94b81a2c97 100755 --- a/test/schema_swap_test.py +++ b/test/schema_swap_test.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # Copyright 2017 Google Inc. -# +# # 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. @@ -32,12 +32,12 @@ shard_0_master = tablet.Tablet(use_mysqlctld=True) shard_0_replica = tablet.Tablet(use_mysqlctld=True) shard_0_rdonly = tablet.Tablet(use_mysqlctld=True) -all_shard_0_tablets = [shard_0_master, shard_0_replica, shard_0_rdonly] +all_shard_0_tablets = (shard_0_master, shard_0_replica, shard_0_rdonly) # range 80 - '' shard_1_master = tablet.Tablet(use_mysqlctld=True) shard_1_replica = tablet.Tablet(use_mysqlctld=True) shard_1_rdonly = tablet.Tablet(use_mysqlctld=True) -all_shard_1_tablets = [shard_1_master, shard_1_replica, shard_1_rdonly] +all_shard_1_tablets = (shard_1_master, shard_1_replica, shard_1_rdonly) # all tablets all_tablets = all_shard_0_tablets + all_shard_1_tablets @@ -120,27 +120,45 @@ def _start_tablets(cls, shard_name, replica_tablets, rdonly_tablets): init_shard=shard_name, extra_args=utils.vtctld.process_args()) + keyspace = 'vt_test_keyspace' create_table_sql = ('DROP TABLE IF EXISTS test; ' 'CREATE TABLE test (id int, PRIMARY KEY(id)) ' 'Engine=InnoDB') schema_swap_sql = 'ALTER TABLE test ADD COLUMN (t TEXT)' show_schema_sql = 'SHOW CREATE TABLE test' - schema_check_string = '`t` text,' - - def _check_final_schema(self): - """Check that schema of test table is correct after a successful swap.""" - schema_0 = shard_0_master.mquery('vt_test_keyspace', - self.show_schema_sql)[0][1] - schema_1 = shard_1_master.mquery('vt_test_keyspace', - self.show_schema_sql)[0][1] + final_schema_check_string = '`t` text,' + initial_schema_check_string = 'CREATE TABLE `test`' + + def _get_schema(self, source=shard_0_master): + return source.mquery(self.keyspace, self.show_schema_sql)[0][1] + + def _check_schema(self, contents): + """Check that schema of test table matches the given string.""" + schema_0 = self._get_schema(shard_0_master) + schema_1 = self._get_schema(shard_1_master) + logging.debug('shard 0 schema: %s', schema_0) + logging.debug('shard 1 schema: %s', schema_0) self.assertEqual(schema_0, schema_1) - self.assertIn(self.schema_check_string, schema_0) + self.assertIn(contents, schema_0) + + def _wait_for_schema_propagation(self, + source=shard_0_master, + targets=all_tablets): + """Wait until the current schema has propagated to all tablets.""" + schema = self._get_schema(source) + timeout = 60 # seconds + condition_msg = 'propagation of schema: %s' % schema + for target in targets: + while schema != self._get_schema(target): + timeout = utils.wait_step(condition_msg, timeout) def setUp(self): utils.run_vtctl(['ApplySchema', '-sql=%s' % self.create_table_sql, 'test_keyspace'], auto_log=True) + self._check_schema(self.initial_schema_check_string) + self._wait_for_schema_propagation() for t in [shard_0_master, shard_1_master]: tablet_info = utils.run_vtctl_json(['GetTablet', t.tablet_alias]) @@ -344,7 +362,7 @@ def test_successful_swap(self): swap_uuid = self._start_swap(self.schema_swap_sql) err = self._wait_for_success_or_error(swap_uuid) self.assertEqual(err, 'Schema swap is finished') - self._check_final_schema() + self._check_schema(self.final_schema_check_string) self._delete_swap(swap_uuid) def test_restarted_swap(self): @@ -370,7 +388,7 @@ def test_restarted_swap(self): swap_uuid = self._start_swap(self.schema_swap_sql) err = self._wait_for_success_or_error(swap_uuid) self.assertEqual(err, 'Schema swap is finished') - self._check_final_schema() + self._check_schema(self.final_schema_check_string) self._delete_swap(swap_uuid) def _retry_or_restart_swap(self, swap_uuid, use_retry): @@ -405,7 +423,7 @@ def _test_init_error(self, use_retry): swap_uuid = self._retry_or_restart_swap(swap_uuid, use_retry=use_retry) err = self._wait_for_success_or_error(swap_uuid, reset_error=True) self.assertEqual(err, 'Schema swap is finished') - self._check_final_schema() + self._check_schema(self.final_schema_check_string) self._delete_swap(swap_uuid) def test_init_error_with_retry(self): @@ -418,16 +436,20 @@ def _test_apply_error(self, use_retry): """Schema swap interrupted while applying seed schema change.""" # Renaming the test table to cause ALTER TABLE executed during schema swap # to fail. - shard_1_master.mquery('vt_test_keyspace', 'RENAME TABLE test TO test2') + logging.debug('running in shard 1: "RENAME TABLE test TO test2"') + shard_1_master.mquery(self.keyspace, 'RENAME TABLE test TO test2') + # self._wait_for_schema_propagation(shard_1_master, all_shard_1_tablets) swap_uuid = self._start_swap(self.schema_swap_sql) err = self._wait_for_success_or_error(swap_uuid) - self.assertIn("Table 'vt_test_keyspace.test' doesn't exist", err) + self.assertIn("Table '"+self.keyspace+".test' doesn't exist", err) - shard_1_master.mquery('vt_test_keyspace', 'RENAME TABLE test2 TO test') + logging.debug('running in shard 1: "RENAME TABLE test2 TO test"') + shard_1_master.mquery(self.keyspace, 'RENAME TABLE test2 TO test') + # self._wait_for_schema_propagation(shard_1_master, all_shard_1_tablets) swap_uuid = self._retry_or_restart_swap(swap_uuid, use_retry=use_retry) err = self._wait_for_success_or_error(swap_uuid, reset_error=True) self.assertEqual(err, 'Schema swap is finished') - self._check_final_schema() + self._check_schema(self.final_schema_check_string) self._delete_swap(swap_uuid) def test_apply_error_with_retry(self): @@ -469,7 +491,7 @@ def test_reparent_error(self): # restarted by vtctld when it's started. err = self._wait_for_success_or_error(swap_uuid, reset_error=True) self.assertEqual(err, 'Schema swap is finished') - self._check_final_schema() + self._check_schema(self.final_schema_check_string) self._delete_swap(swap_uuid) diff --git a/test/tablet.py b/test/tablet.py index 8c08738dfc7..930f5941295 100644 --- a/test/tablet.py +++ b/test/tablet.py @@ -465,9 +465,9 @@ def start_vttablet( args.extend(['-tablet_manager_protocol', protocols_flavor().tablet_manager_protocol()]) args.extend(['-tablet_protocol', protocols_flavor().tabletconn_protocol()]) - args.extend(['-binlog_player_healthcheck_topology_refresh', '1s']) - args.extend(['-binlog_player_healthcheck_retry_delay', '1s']) - args.extend(['-binlog_player_retry_delay', '1s']) + args.extend(['-vreplication_healthcheck_topology_refresh', '1s']) + args.extend(['-vreplication_healthcheck_retry_delay', '1s']) + args.extend(['-vreplication_retry_delay', '1s']) args.extend(['-pid_file', os.path.join(self.tablet_dir, 'vttablet.pid')]) # always enable_replication_reporter with somewhat short values for tests args.extend(['-health_check_interval', '2s']) @@ -739,11 +739,11 @@ def wait_for_binlog_player_count(self, expected, timeout=30.0): expected) logging.debug(' vttablet not answering at /debug/vars, waiting...') else: - if 'BinlogPlayerMapSize' not in v: + if 'VReplicationStreamCount' not in v: logging.debug( - ' vttablet not exporting BinlogPlayerMapSize, waiting...') + ' vttablet not exporting VReplicationStreamCount, waiting...') else: - s = v['BinlogPlayerMapSize'] + s = v['VReplicationStreamCount'] if s != expected: logging.debug(" vttablet's binlog player map has count %d != %d", s, expected) diff --git a/test/tabletmanager.py b/test/tabletmanager.py index 2cfc236aabc..68a5bf9f645 100755 --- a/test/tabletmanager.py +++ b/test/tabletmanager.py @@ -507,6 +507,12 @@ def test_health_check_drained_state_does_not_shutdown_query_service(self): # implementation.) The tablet will stay healthy, and the # query service is still running. utils.run_vtctl(['ChangeSlaveType', tablet_62044.tablet_alias, 'drained']) + # Trying to drain the same tablet again, should error + try: + utils.run_vtctl(['ChangeSlaveType', tablet_62044.tablet_alias, 'drained']) + except Exception as e: + s = str(e) + self.assertIn("already drained", s) utils.run_vtctl(['StopSlave', tablet_62044.tablet_alias]) # Trigger healthcheck explicitly to avoid waiting for the next interval. utils.run_vtctl(['RunHealthCheck', tablet_62044.tablet_alias]) diff --git a/test/utils.py b/test/utils.py index ff5f6566dba..045bfcf86c3 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1205,7 +1205,7 @@ def start(self, enable_schema_change_dir=False, extra_flags=None): '-enable_queries', '-cell', 'test_nj', '-web_dir', environment.vttop + '/web/vtctld', - '-web_dir2', environment.vttop + '/web/vtctld2/dist', + '-web_dir2', environment.vttop + '/web/vtctld2', '--log_dir', environment.vtlogroot, '--port', str(self.port), '-tablet_manager_protocol', diff --git a/test/vertical_split.py b/test/vertical_split.py index 8a382839095..e895cf22f07 100755 --- a/test/vertical_split.py +++ b/test/vertical_split.py @@ -435,6 +435,13 @@ def test_vertical_split(self): self._check_values(destination_master, 'vt_destination_keyspace', 'moving3_no_pk', self.moving3_no_pk_first, 100) + # Verify vreplication table entries + result = destination_master.mquery('_vt', 'select * from vreplication') + self.assertEqual(len(result), 1) + self.assertEqual(result[0][1], 'SplitClone') + self.assertEqual(result[0][2], + 'keyspace:"source_keyspace" shard:"0" tables:"/moving/" tables:"view1" ') + # check the binlog player is running and exporting vars self.check_destination_master(destination_master, ['source_keyspace/0']) diff --git a/test/worker.py b/test/worker.py index 91de8c58481..d3f373ba6d9 100755 --- a/test/worker.py +++ b/test/worker.py @@ -403,9 +403,9 @@ def tearDown(self): t.reset_replication() t.set_semi_sync_enabled(master=False) t.clean_dbs() - # _vt.blp_checkpoint should be dropped to avoid interference between + # _vt.vreplication should be dropped to avoid interference between # test cases - t.mquery('', 'drop table if exists _vt.blp_checkpoint') + t.mquery('', 'drop table if exists _vt.vreplication') t.kill_vttablet() # we allow failures here as some tablets will be gone sometimes # (the master tablets after an emergency reparent) diff --git a/web/vtctld2/app/index.html b/web/vtctld2/app/index.html index a238afc4783..70ef85f14ed 100644 --- a/web/vtctld2/app/index.html +++ b/web/vtctld2/app/index.html @@ -27,5 +27,5 @@ Loading... - + diff --git a/web/vtctld2/app/inline.js b/web/vtctld2/app/inline.js index be2264c84f3..2ac73298ee9 100644 --- a/web/vtctld2/app/inline.js +++ b/web/vtctld2/app/inline.js @@ -1 +1 @@ -!function(e){function __webpack_require__(r){if(t[r])return t[r].exports;var n=t[r]={i:r,l:!1,exports:{}};return e[r].call(n.exports,n,n.exports,__webpack_require__),n.l=!0,n.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,o,c){for(var _,a,i,u=0,p=[];u1;){var o=r.shift();i=i.hasOwnProperty(o)&&isPresent(i[o])?i[o]:i[o]={}}void 0!==i&&null!==i||(i={}),i[r.shift()]=n}function getSymbolIterator(){if(isBlank(h))if(isPresent(n.Symbol)&&isPresent(Symbol.iterator))h=Symbol.iterator;else for(var e=Object.getOwnPropertyNames(Map.prototype),t=0;t=0&&e[r]==t;r--)n--;e=e.substring(0,n)}return e},StringWrapper.replace=function(e,t,n){return e.replace(t,n)},StringWrapper.replaceAll=function(e,t,n){return e.replace(t,n)},StringWrapper.slice=function(e,t,n){return void 0===t&&(t=0),void 0===n&&(n=null),e.slice(t,null===n?void 0:n)},StringWrapper.replaceAllMapped=function(e,t,n){return e.replace(t,function(){for(var e=[],t=0;tt?1:0},StringWrapper}();t.StringWrapper=s;var a=function(){function StringJoiner(e){void 0===e&&(e=[]),this.parts=e}return StringJoiner.prototype.add=function(e){this.parts.push(e)},StringJoiner.prototype.toString=function(){return this.parts.join("")},StringJoiner}();t.StringJoiner=a;var l=function(e){function NumberParseError(t){e.call(this),this.message=t}return r(NumberParseError,e),NumberParseError.prototype.toString=function(){return this.message},NumberParseError}(Error);t.NumberParseError=l;var c=function(){function NumberWrapper(){}return NumberWrapper.toFixed=function(e,t){return e.toFixed(t)},NumberWrapper.equal=function(e,t){return e===t},NumberWrapper.parseIntAutoRadix=function(e){var t=parseInt(e);if(isNaN(t))throw new l("Invalid integer literal when parsing "+e);return t},NumberWrapper.parseInt=function(e,t){if(10==t){if(/^(\-|\+)?[0-9]+$/.test(e))return parseInt(e,t)}else if(16==t){if(/^(\-|\+)?[0-9ABCDEFabcdef]+$/.test(e))return parseInt(e,t)}else{var n=parseInt(e,t);if(!isNaN(n))return n}throw new l("Invalid integer literal when parsing "+e+" in base "+t)},NumberWrapper.parseFloat=function(e){return parseFloat(e)},Object.defineProperty(NumberWrapper,"NaN",{get:function(){return NaN},enumerable:!0,configurable:!0}),NumberWrapper.isNumeric=function(e){return!isNaN(e-parseFloat(e))},NumberWrapper.isNaN=function(e){return isNaN(e)},NumberWrapper.isInteger=function(e){return Number.isInteger(e)},NumberWrapper}();t.NumberWrapper=c,t.RegExp=i.RegExp;var u=function(){function FunctionWrapper(){}return FunctionWrapper.apply=function(e,t){return e.apply(null,t)},FunctionWrapper.bind=function(e,t){return e.bind(t)},FunctionWrapper}();t.FunctionWrapper=u,t.looseIdentical=looseIdentical,t.getMapKey=getMapKey,t.normalizeBlank=normalizeBlank,t.normalizeBool=normalizeBool,t.isJsObject=isJsObject,t.print=print,t.warn=warn;var p=function(){function Json(){}return Json.parse=function(e){return i.JSON.parse(e)},Json.stringify=function(e){return i.JSON.stringify(e,null,2)},Json}();t.Json=p;var d=function(){function DateWrapper(){}return DateWrapper.create=function(e,n,r,i,o,s,a){return void 0===n&&(n=1),void 0===r&&(r=1),void 0===i&&(i=0),void 0===o&&(o=0),void 0===s&&(s=0),void 0===a&&(a=0),new t.Date(e,n-1,r,i,o,s,a)},DateWrapper.fromISOString=function(e){return new t.Date(e)},DateWrapper.fromMillis=function(e){return new t.Date(e)},DateWrapper.toMillis=function(e){return e.getTime()},DateWrapper.now=function(){return new t.Date},DateWrapper.toJson=function(e){return e.toJSON()},DateWrapper}();t.DateWrapper=d,t.setValueOnPath=setValueOnPath;var h=null;t.getSymbolIterator=getSymbolIterator,t.evalExpression=evalExpression,t.isPrimitive=isPrimitive,t.hasConstructor=hasConstructor,t.escape=escape,t.escapeRegExp=escapeRegExp}).call(t,n(82))},4,function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(217),o=n(41),s=n(215),a=n(897),l=function(e){function Subscriber(t,n,r){switch(e.call(this),this.syncErrorValue=null,this.syncErrorThrown=!1,this.syncErrorThrowable=!1,this.isStopped=!1,arguments.length){case 0:this.destination=a.empty;break;case 1:if(!t){this.destination=a.empty;break}if("object"==typeof t){t instanceof Subscriber?(this.destination=t,this.destination.add(this)):(this.syncErrorThrowable=!0,this.destination=new c(this,t));break}default:this.syncErrorThrowable=!0,this.destination=new c(this,t,n,r)}}return r(Subscriber,e),Subscriber.create=function(e,t,n){var r=new Subscriber(e,t,n);return r.syncErrorThrowable=!1,r},Subscriber.prototype.next=function(e){this.isStopped||this._next(e)},Subscriber.prototype.error=function(e){this.isStopped||(this.isStopped=!0,this._error(e))},Subscriber.prototype.complete=function(){this.isStopped||(this.isStopped=!0,this._complete())},Subscriber.prototype.unsubscribe=function(){this.isUnsubscribed||(this.isStopped=!0,e.prototype.unsubscribe.call(this))},Subscriber.prototype._next=function(e){this.destination.next(e)},Subscriber.prototype._error=function(e){this.destination.error(e),this.unsubscribe()},Subscriber.prototype._complete=function(){this.destination.complete(),this.unsubscribe()},Subscriber.prototype[s.$$rxSubscriber]=function(){return this},Subscriber}(o.Subscription);t.Subscriber=l;var c=function(e){function SafeSubscriber(t,n,r,o){e.call(this),this._parent=t;var s,a=this;i.isFunction(n)?s=n:n&&(a=n,s=n.next,r=n.error,o=n.complete,i.isFunction(a.unsubscribe)&&this.add(a.unsubscribe.bind(a)),a.unsubscribe=this.unsubscribe.bind(this)),this._context=a,this._next=s,this._error=r,this._complete=o}return r(SafeSubscriber,e),SafeSubscriber.prototype.next=function(e){if(!this.isStopped&&this._next){var t=this._parent;t.syncErrorThrowable?this.__tryOrSetError(t,this._next,e)&&this.unsubscribe():this.__tryOrUnsub(this._next,e)}},SafeSubscriber.prototype.error=function(e){if(!this.isStopped){var t=this._parent;if(this._error)t.syncErrorThrowable?(this.__tryOrSetError(t,this._error,e),this.unsubscribe()):(this.__tryOrUnsub(this._error,e),this.unsubscribe());else{if(!t.syncErrorThrowable)throw this.unsubscribe(),e;t.syncErrorValue=e,t.syncErrorThrown=!0,this.unsubscribe()}}},SafeSubscriber.prototype.complete=function(){if(!this.isStopped){var e=this._parent;this._complete?e.syncErrorThrowable?(this.__tryOrSetError(e,this._complete),this.unsubscribe()):(this.__tryOrUnsub(this._complete),this.unsubscribe()):this.unsubscribe()}},SafeSubscriber.prototype.__tryOrUnsub=function(e,t){try{e.call(this._context,t)}catch(n){throw this.unsubscribe(),n}},SafeSubscriber.prototype.__tryOrSetError=function(e,t,n){try{t.call(this._context,n)}catch(r){return e.syncErrorValue=r,e.syncErrorThrown=!0,!0}return!1},SafeSubscriber.prototype._unsubscribe=function(){var e=this._parent;this._context=null,this._parent=null,e.unsubscribe()},SafeSubscriber}(l)},4,function(e,t,n){var r=n(15);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){"use strict";var r=this&&this.__decorate||function(e,t,n,r){var i,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},o=n(0),s=function(){function DomHandler(){}return DomHandler.prototype.addClass=function(e,t){e.classList?e.classList.add(t):e.className+=" "+t},DomHandler.prototype.addMultipleClasses=function(e,t){if(e.classList)for(var n=t.split(" "),r=0;rwindow.innerHeight?-1*i.height:o,r=a.left+i.width>window.innerWidth?s-i.width:0,e.style.top=n+"px",e.style.left=r+"px"},DomHandler.prototype.absolutePosition=function(e,t){var n,r,i=e.offsetParent?{width:e.offsetWidth,height:e.offsetHeight}:this.getHiddenElementDimensions(e),o=i.height,s=i.width,a=t.offsetHeight,l=t.offsetWidth,c=t.getBoundingClientRect(),u=this.getWindowScrollTop(),p=this.getWindowScrollLeft();n=c.top+a+o>window.innerHeight?c.top+u-o:a+c.top+u,r=c.left+l+s>window.innerWidth?c.left+p+l-s:c.left+p,e.style.top=n+"px",e.style.left=r+"px"},DomHandler.prototype.getHiddenElementOuterHeight=function(e){e.style.visibility="hidden",e.style.display="block";var t=e.offsetHeight;return e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.getHiddenElementOuterWidth=function(e){e.style.visibility="hidden",e.style.display="block";var t=e.offsetWidth;return e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.getHiddenElementDimensions=function(e){var t={};return e.style.visibility="hidden",e.style.display="block",t.width=e.offsetWidth,t.height=e.offsetHeight,e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.scrollInView=function(e,t){var n=getComputedStyle(e).getPropertyValue("borderTopWidth"),r=n?parseFloat(n):0,i=getComputedStyle(e).getPropertyValue("paddingTop"),o=i?parseFloat(i):0,s=e.getBoundingClientRect(),a=t.getBoundingClientRect(),l=a.top+document.body.scrollTop-(s.top+document.body.scrollTop)-r-o,c=e.scrollTop,u=e.clientHeight,p=this.getOuterHeight(t);l<0?e.scrollTop=c+l:l+p>u&&(e.scrollTop=c+l-u+p)},DomHandler.prototype.fadeIn=function(e,t){e.style.opacity=0;var n=+new Date,r=function(){e.style.opacity=+e.style.opacity+((new Date).getTime()-n)/t,n=+new Date,+e.style.opacity<1&&(window.requestAnimationFrame&&requestAnimationFrame(r)||setTimeout(r,16))};r()},DomHandler.prototype.fadeOut=function(e,t){var n=1,r=50,i=t,o=r/i,s=setInterval(function(){n-=o,e.style.opacity=n,n<=0&&clearInterval(s)},r)},DomHandler.prototype.getWindowScrollTop=function(){var e=document.documentElement;return(window.pageYOffset||e.scrollTop)-(e.clientTop||0)},DomHandler.prototype.getWindowScrollLeft=function(){var e=document.documentElement;return(window.pageXOffset||e.scrollLeft)-(e.clientLeft||0)},DomHandler.prototype.matches=function(e,t){var n=Element.prototype,r=n.matches||n.webkitMatchesSelector||n.mozMatchesSelector||n.msMatchesSelector||function(e){return[].indexOf.call(document.querySelectorAll(e),this)!==-1};return r.call(e,t)},DomHandler.prototype.getOuterWidth=function(e,t){var n=e.offsetWidth;if(t){var r=getComputedStyle(e);n+=parseInt(r.paddingLeft)+parseInt(r.paddingRight)}return n},DomHandler.prototype.getHorizontalMargin=function(e){var t=getComputedStyle(e);return parseInt(t.marginLeft)+parseInt(t.marginRight)},DomHandler.prototype.innerWidth=function(e){var t=e.offsetWidth,n=getComputedStyle(e);return t+=parseInt(n.paddingLeft)+parseInt(n.paddingRight)},DomHandler.prototype.width=function(e){var t=e.offsetWidth,n=getComputedStyle(e);return t-=parseInt(n.paddingLeft)+parseInt(n.paddingRight)},DomHandler.prototype.getOuterHeight=function(e,t){var n=e.offsetHeight;if(t){var r=getComputedStyle(e);n+=parseInt(r.marginTop)+parseInt(r.marginBottom)}return n},DomHandler.prototype.getHeight=function(e){var t=e.offsetHeight,n=getComputedStyle(e);return t-=parseInt(n.paddingTop)+parseInt(n.paddingBottom)+parseInt(n.borderTopWidth)+parseInt(n.borderBottomWidth)},DomHandler.prototype.getViewport=function(){var e=window,t=document,n=t.documentElement,r=t.getElementsByTagName("body")[0],i=e.innerWidth||n.clientWidth||r.clientWidth,o=e.innerHeight||n.clientHeight||r.clientHeight;return{width:i,height:o}},DomHandler.prototype.equals=function(e,t){if(null==e||null==t)return!1;if(e==t)return!0;if("object"==typeof e&&"object"==typeof t){for(var n in e){if(e.hasOwnProperty(n)!==t.hasOwnProperty(n))return!1;switch(typeof e[n]){case"object":if(!this.equals(e[n],t[n]))return!1;break;case"function":if("undefined"==typeof t[n]||"compare"!=n&&e[n].toString()!=t[n].toString())return!1;break;default:if(e[n]!=t[n])return!1}}for(var n in t)if("undefined"==typeof e[n])return!1;return!0}return!1},DomHandler.zindex=1e3,DomHandler=r([o.Injectable(),i("design:paramtypes",[])],DomHandler)}();t.DomHandler=s},[1104,5],function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(6),o=function(e){function OuterSubscriber(){e.apply(this,arguments)}return r(OuterSubscriber,e),OuterSubscriber.prototype.notifyNext=function(e,t,n,r,i){this.destination.next(t)},OuterSubscriber.prototype.notifyError=function(e,t){this.destination.error(e)},OuterSubscriber.prototype.notifyComplete=function(e){this.destination.complete()},OuterSubscriber}(i.Subscriber);t.OuterSubscriber=o},function(e,t,n){"use strict";function subscribeToResult(e,t,n,u){var p=new c.InnerSubscriber(e,n,u);if(!p.isUnsubscribed){if(t instanceof s.Observable)return t._isScalar?(p.next(t.value),void p.complete()):t.subscribe(p);if(i.isArray(t)){for(var d=0,h=t.length;d=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},o=n(0),s=n(3),a=n(0),l=function(){function Header(){}return Header=r([a.Component({selector:"header",template:""}),i("design:paramtypes",[])],Header)}();t.Header=l;var c=function(){function Footer(){}return Footer=r([a.Component({selector:"footer",template:""}),i("design:paramtypes",[])],Footer)}();t.Footer=c;var u=function(){function TemplateWrapper(e){this.viewContainer=e}return TemplateWrapper.prototype.ngOnInit=function(){this.viewContainer.createEmbeddedView(this.templateRef,{$implicit:this.item})},r([o.Input(),i("design:type",Object)],TemplateWrapper.prototype,"item",void 0),r([o.Input("pTemplateWrapper"),i("design:type",o.TemplateRef)],TemplateWrapper.prototype,"templateRef",void 0),TemplateWrapper=r([o.Directive({selector:"[pTemplateWrapper]"}),i("design:paramtypes",[o.ViewContainerRef])],TemplateWrapper)}();t.TemplateWrapper=u;var p=function(){function Column(){this.sortFunction=new o.EventEmitter}return r([o.Input(),i("design:type",String)],Column.prototype,"field",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"header",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"footer",void 0),r([o.Input(),i("design:type",Object)],Column.prototype,"sortable",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"editable",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"filter",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"filterMatchMode",void 0),r([o.Input(),i("design:type",Number)],Column.prototype,"rowspan",void 0),r([o.Input(),i("design:type",Number)],Column.prototype,"colspan",void 0),r([o.Input(),i("design:type",Object)],Column.prototype,"style",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"styleClass",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"hidden",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"expander",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"selectionMode",void 0),r([o.Output(),i("design:type",o.EventEmitter)],Column.prototype,"sortFunction",void 0),r([o.ContentChild(o.TemplateRef),i("design:type",o.TemplateRef)],Column.prototype,"template",void 0),Column=r([a.Component({selector:"p-column",template:""}),i("design:paramtypes",[])],Column)}();t.Column=p;var d=function(){function ColumnTemplateLoader(e){this.viewContainer=e}return ColumnTemplateLoader.prototype.ngOnInit=function(){this.viewContainer.createEmbeddedView(this.column.template,{$implicit:this.column,rowData:this.rowData,rowIndex:this.rowIndex})},r([o.Input(),i("design:type",Object)],ColumnTemplateLoader.prototype,"column",void 0),r([o.Input(),i("design:type",Object)],ColumnTemplateLoader.prototype,"rowData",void 0),r([o.Input(),i("design:type",Number)],ColumnTemplateLoader.prototype,"rowIndex",void 0),ColumnTemplateLoader=r([a.Component({selector:"p-columnTemplateLoader",template:""}),i("design:paramtypes",[o.ViewContainerRef])],ColumnTemplateLoader)}();t.ColumnTemplateLoader=d;var h=function(){function SharedModule(){}return SharedModule=r([o.NgModule({imports:[s.CommonModule],exports:[l,c,p,u,d],declarations:[l,c,p,u,d]}),i("design:paramtypes",[])],SharedModule)}();t.SharedModule=h},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(1),o=n(6),s=n(41),a=n(899),l=n(215),c=n(517),u=n(317),p=function(e){function Subject(t,n){e.call(this),this.destination=t,this.source=n,this.observers=[],this.isUnsubscribed=!1,this.isStopped=!1,this.hasErrored=!1,this.dispatching=!1,this.hasCompleted=!1,this.source=n}return r(Subject,e),Subject.prototype.lift=function(e){var t=new Subject(this.destination||this,this);return t.operator=e,t},Subject.prototype.add=function(e){return s.Subscription.prototype.add.call(this,e)},Subject.prototype.remove=function(e){s.Subscription.prototype.remove.call(this,e)},Subject.prototype.unsubscribe=function(){s.Subscription.prototype.unsubscribe.call(this)},Subject.prototype._subscribe=function(e){if(this.source)return this.source.subscribe(e);if(!e.isUnsubscribed){if(this.hasErrored)return e.error(this.errorValue);if(this.hasCompleted)return e.complete();this.throwIfUnsubscribed();var t=new a.SubjectSubscription(this,e);return this.observers.push(e),t}},Subject.prototype._unsubscribe=function(){this.source=null,this.isStopped=!0,this.observers=null,this.destination=null},Subject.prototype.next=function(e){this.throwIfUnsubscribed(),this.isStopped||(this.dispatching=!0,this._next(e),this.dispatching=!1,this.hasErrored?this._error(this.errorValue):this.hasCompleted&&this._complete())},Subject.prototype.error=function(e){this.throwIfUnsubscribed(),this.isStopped||(this.isStopped=!0,this.hasErrored=!0,this.errorValue=e,this.dispatching||this._error(e))},Subject.prototype.complete=function(){this.throwIfUnsubscribed(),this.isStopped||(this.isStopped=!0,this.hasCompleted=!0,this.dispatching||this._complete())},Subject.prototype.asObservable=function(){var e=new d(this);return e},Subject.prototype._next=function(e){this.destination?this.destination.next(e):this._finalNext(e)},Subject.prototype._finalNext=function(e){for(var t=-1,n=this.observers.slice(0),r=n.length;++t"+i+""};e.exports=function(e,t){var n={};n[e]=t(a),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t,n){"use strict";var r=n(81),i=n(514),o=n(217),s=n(42),a=n(38),l=n(513),c=function(){function Subscription(e){this.isUnsubscribed=!1,e&&(this._unsubscribe=e)}return Subscription.prototype.unsubscribe=function(){var e,t=!1;if(!this.isUnsubscribed){this.isUnsubscribed=!0;var n=this,c=n._unsubscribe,u=n._subscriptions;if(this._subscriptions=null,o.isFunction(c)){var p=s.tryCatch(c).call(this);p===a.errorObject&&(t=!0,(e=e||[]).push(a.errorObject.e))}if(r.isArray(u))for(var d=-1,h=u.length;++d0?i(r(e),9007199254740991):0}},function(e,t,n){"use strict";var r=n(1082);t.async=new r.AsyncScheduler},function(e,t,n){"use strict";function __export(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}var r=n(86);t.HostMetadata=r.HostMetadata,t.InjectMetadata=r.InjectMetadata,t.InjectableMetadata=r.InjectableMetadata,t.OptionalMetadata=r.OptionalMetadata,t.SelfMetadata=r.SelfMetadata,t.SkipSelfMetadata=r.SkipSelfMetadata,__export(n(115));var i=n(162);t.forwardRef=i.forwardRef,t.resolveForwardRef=i.resolveForwardRef;var o=n(163);t.Injector=o.Injector;var s=n(571);t.ReflectiveInjector=s.ReflectiveInjector;var a=n(250);t.Binding=a.Binding,t.ProviderBuilder=a.ProviderBuilder,t.bind=a.bind,t.Provider=a.Provider,t.provide=a.provide;var l=n(253);t.ResolvedReflectiveFactory=l.ResolvedReflectiveFactory;var c=n(252);t.ReflectiveKey=c.ReflectiveKey;var u=n(251);t.NoProviderError=u.NoProviderError,t.AbstractProviderError=u.AbstractProviderError,t.CyclicDependencyError=u.CyclicDependencyError,t.InstantiationError=u.InstantiationError,t.InvalidProviderError=u.InvalidProviderError,t.NoAnnotationError=u.NoAnnotationError,t.OutOfBoundsError=u.OutOfBoundsError;var p=n(374);t.OpaqueToken=p.OpaqueToken},[1104,32],function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){"use strict";var r=n(13);e.exports=function(e,t){return!!e&&r(function(){t?e.call(null,function(){},1):e.call(null)})}},function(e,t,n){var r=n(75);e.exports=function(e){return Object(r(e))}},function(e,t,n){"use strict";(function(e,n){var r={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1};t.root=r[typeof self]&&self||r[typeof window]&&window;var i=(r[typeof t]&&t&&!t.nodeType&&t,r[typeof e]&&e&&!e.nodeType&&e,r[typeof n]&&n);!i||i.global!==i&&i.window!==i||(t.root=i)}).call(t,n(1100)(e),n(82))},function(e,t,n){"use strict";var r=n(0);t.NG_VALUE_ACCESSOR=new r.OpaqueToken("NgValueAccessor")},52,function(e,t,n){"use strict";function _convertToPromise(e){return s.isPromise(e)?e:i.toPromise.call(e)}function _executeValidators(e,t){return t.map(function(t){return t(e)})}function _executeAsyncValidators(e,t){return t.map(function(t){return t(e)})}function _mergeErrors(e){var t=e.reduce(function(e,t){return s.isPresent(t)?o.StringMapWrapper.merge(e,t):e},{});return o.StringMapWrapper.isEmpty(t)?null:t}var r=n(0),i=n(313),o=n(47),s=n(32);t.NG_VALIDATORS=new r.OpaqueToken("NgValidators"),t.NG_ASYNC_VALIDATORS=new r.OpaqueToken("NgAsyncValidators");var a=function(){function Validators(){}return Validators.required=function(e){return s.isBlank(e.value)||s.isString(e.value)&&""==e.value?{required:!0}:null},Validators.minLength=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=t.value;return n.lengthe?{maxlength:{requiredLength:e,actualLength:n.length}}:null}},Validators.pattern=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=new RegExp("^"+e+"$"),r=t.value;return n.test(r)?null:{pattern:{requiredPattern:"^"+e+"$",actualValue:r}}}},Validators.nullValidator=function(e){return null},Validators.compose=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){return _mergeErrors(_executeValidators(e,t))}},Validators.composeAsync=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){var n=_executeAsyncValidators(e,t).map(_convertToPromise);return Promise.all(n).then(_mergeErrors)}},Validators}();t.Validators=a},function(e,t,n){"use strict";var r=n(0),i=n(123),o=n(72),s=n(16),a=n(126),l=n(278);t.PRIMITIVE=String;var c=function(){function Serializer(e){this._renderStore=e}return Serializer.prototype.serialize=function(e,n){var i=this;if(!s.isPresent(e))return null;if(s.isArray(e))return e.map(function(e){return i.serialize(e,n)});if(n==t.PRIMITIVE)return e;if(n==u)return this._renderStore.serialize(e);if(n===r.RenderComponentType)return this._serializeRenderComponentType(e);if(n===r.ViewEncapsulation)return s.serializeEnum(e);if(n===l.LocationType)return this._serializeLocation(e);throw new o.BaseException("No serializer for "+n.toString())},Serializer.prototype.deserialize=function(e,n,a){var c=this;if(!s.isPresent(e))return null;if(s.isArray(e)){var p=[];return e.forEach(function(e){return p.push(c.deserialize(e,n,a))}),p}if(n==t.PRIMITIVE)return e;if(n==u)return this._renderStore.deserialize(e);if(n===r.RenderComponentType)return this._deserializeRenderComponentType(e);if(n===r.ViewEncapsulation)return i.VIEW_ENCAPSULATION_VALUES[e];if(n===l.LocationType)return this._deserializeLocation(e);throw new o.BaseException("No deserializer for "+n.toString())},Serializer.prototype._serializeLocation=function(e){return{href:e.href,protocol:e.protocol,host:e.host,hostname:e.hostname,port:e.port,pathname:e.pathname,search:e.search,hash:e.hash,origin:e.origin}},Serializer.prototype._deserializeLocation=function(e){return new l.LocationType(e.href,e.protocol,e.host,e.hostname,e.port,e.pathname,e.search,e.hash,e.origin)},Serializer.prototype._serializeRenderComponentType=function(e){return{id:e.id,templateUrl:e.templateUrl,slotCount:e.slotCount,encapsulation:this.serialize(e.encapsulation,r.ViewEncapsulation),styles:this.serialize(e.styles,t.PRIMITIVE)}},Serializer.prototype._deserializeRenderComponentType=function(e){return new r.RenderComponentType(e.id,e.templateUrl,e.slotCount,this.deserialize(e.encapsulation,r.ViewEncapsulation),this.deserialize(e.styles,t.PRIMITIVE),{})},Serializer.decorators=[{type:r.Injectable}],Serializer.ctorParameters=[{type:a.RenderStore}],Serializer}();t.Serializer=c;var u=function(){function RenderStoreObject(){}return RenderStoreObject}();t.RenderStoreObject=u},function(e,t,n){var r=n(2),i=n(24),o=n(13);e.exports=function(e,t){var n=(i.Object||{})[e]||Object[e],s={};s[e]=t(n),r(r.S+r.F*o(function(){n(1)}),"Object",s)}},function(e,t,n){var r=n(133),i=n(75);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";function _convertToPromise(e){return s.isPromise(e)?e:i.toPromise.call(e)}function _executeValidators(e,t){return t.map(function(t){return t(e)})}function _executeAsyncValidators(e,t){return t.map(function(t){return t(e)})}function _mergeErrors(e){var t=e.reduce(function(e,t){return s.isPresent(t)?o.StringMapWrapper.merge(e,t):e},{});return o.StringMapWrapper.isEmpty(t)?null:t}var r=n(0),i=n(313),o=n(34),s=n(7);t.NG_VALIDATORS=new r.OpaqueToken("NgValidators"),t.NG_ASYNC_VALIDATORS=new r.OpaqueToken("NgAsyncValidators");var a=function(){function Validators(){}return Validators.required=function(e){return s.isBlank(e.value)||s.isString(e.value)&&""==e.value?{required:!0}:null},Validators.minLength=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=t.value;return n.lengthe?{maxlength:{requiredLength:e,actualLength:n.length}}:null}},Validators.pattern=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=new RegExp("^"+e+"$"),r=t.value;return n.test(r)?null:{pattern:{requiredPattern:"^"+e+"$",actualValue:r}}}},Validators.nullValidator=function(e){return null},Validators.compose=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){return _mergeErrors(_executeValidators(e,t))}},Validators.composeAsync=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){var n=_executeAsyncValidators(e,t).map(_convertToPromise);return Promise.all(n).then(_mergeErrors)}},Validators}();t.Validators=a},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(83),o=n(7),s=function(e){function InvalidPipeArgumentException(t,n){e.call(this,"Invalid argument '"+n+"' for pipe '"+o.stringify(t)+"'")}return r(InvalidPipeArgumentException,e),InvalidPipeArgumentException}(i.BaseException);t.InvalidPipeArgumentException=s},function(e,t,n){"use strict";/** +webpackJsonp([0,2],[function(e,t,n){"use strict";function __export(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}__export(n(386)),__export(n(585)),__export(n(46));var r=n(248);t.createPlatform=r.createPlatform,t.assertPlatform=r.assertPlatform,t.disposePlatform=r.disposePlatform,t.getPlatform=r.getPlatform,t.coreBootstrap=r.coreBootstrap,t.coreLoadAndBootstrap=r.coreLoadAndBootstrap,t.PlatformRef=r.PlatformRef,t.ApplicationRef=r.ApplicationRef,t.enableProdMode=r.enableProdMode,t.lockRunMode=r.lockRunMode,t.isDevMode=r.isDevMode,t.createPlatformFactory=r.createPlatformFactory;var i=n(157);t.APP_ID=i.APP_ID,t.PACKAGE_ROOT_URL=i.PACKAGE_ROOT_URL,t.PLATFORM_INITIALIZER=i.PLATFORM_INITIALIZER,t.APP_BOOTSTRAP_LISTENER=i.APP_BOOTSTRAP_LISTENER;var o=n(247);t.APP_INITIALIZER=o.APP_INITIALIZER,t.ApplicationInitStatus=o.ApplicationInitStatus,__export(n(586)),__export(n(584)),__export(n(573));var s=n(373);t.DebugElement=s.DebugElement,t.DebugNode=s.DebugNode,t.asNativeElements=s.asNativeElements,t.getDebugNode=s.getDebugNode,__export(n(261)),__export(n(568)),__export(n(581)),__export(n(580));var a=n(567);t.APPLICATION_COMMON_PROVIDERS=a.APPLICATION_COMMON_PROVIDERS,t.ApplicationModule=a.ApplicationModule;var l=n(167);t.wtfCreateScope=l.wtfCreateScope,t.wtfLeave=l.wtfLeave,t.wtfStartTimeRange=l.wtfStartTimeRange,t.wtfEndTimeRange=l.wtfEndTimeRange;var c=n(4);t.Type=c.Type;var u=n(254);t.EventEmitter=u.EventEmitter;var p=n(14);t.ExceptionHandler=p.ExceptionHandler,t.WrappedException=p.WrappedException,t.BaseException=p.BaseException,__export(n(561)),__export(n(369));var d=n(246);t.AnimationPlayer=d.AnimationPlayer;var h=n(394);t.SanitizationService=h.SanitizationService,t.SecurityContext=h.SecurityContext},function(e,t,n){"use strict";var r=n(51),i=n(214),o=n(1089),s=function(){function Observable(e){this._isScalar=!1,e&&(this._subscribe=e)}return Observable.prototype.lift=function(e){var t=new Observable;return t.source=this,t.operator=e,t},Observable.prototype.subscribe=function(e,t,n){var r=this.operator,i=o.toSubscriber(e,t,n);if(i.add(r?r.call(i,this):this._subscribe(i)),i.syncErrorThrowable&&(i.syncErrorThrowable=!1,i.syncErrorThrown))throw i.syncErrorValue;return i},Observable.prototype.forEach=function(e,t){var n=this;if(t||(r.root.Rx&&r.root.Rx.config&&r.root.Rx.config.Promise?t=r.root.Rx.config.Promise:r.root.Promise&&(t=r.root.Promise)),!t)throw new Error("no Promise impl found");return new t(function(t,r){var i=n.subscribe(function(t){if(i)try{e(t)}catch(n){r(n),i.unsubscribe()}else e(t)},r,t)})},Observable.prototype._subscribe=function(e){return this.source.subscribe(e)},Observable.prototype[i.$$observable]=function(){return this},Observable.create=function(e){return new Observable(e)},Observable}();t.Observable=s},function(e,t,n){var r=n(26),i=n(24),o=n(65),s=n(39),a=n(106),l="prototype",c=function(e,t,n){var u,p,d,h,f=e&c.F,m=e&c.G,y=e&c.S,g=e&c.P,v=e&c.B,b=m?r:y?r[t]||(r[t]={}):(r[t]||{})[l],_=m?i:i[t]||(i[t]={}),w=_[l]||(_[l]={});m&&(n=t);for(u in n)p=!f&&b&&void 0!==b[u],d=(p?b:n)[u],h=v&&p?a(d,r):g&&"function"==typeof d?a(Function.call,d):d,b&&s(b,u,d,e&c.U),_[u]!=d&&o(_,u,h),g&&w[u]!=d&&(w[u]=d)};r.core=i,c.F=1,c.G=2,c.S=4,c.P=8,c.B=16,c.W=32,c.U=64,c.R=128,e.exports=c},function(e,t,n){"use strict";function __export(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}var r=n(0),i=n(321),o=n(334);__export(n(334)),__export(n(322)),__export(n(525)),__export(n(321)),__export(n(527));var s=n(230);t.NgLocalization=s.NgLocalization;var a=function(){function CommonModule(){}return CommonModule.decorators=[{type:r.NgModule,args:[{declarations:[i.COMMON_DIRECTIVES,o.COMMON_PIPES],exports:[i.COMMON_DIRECTIVES,o.COMMON_PIPES]}]}],CommonModule}();t.CommonModule=a},function(e,t,n){"use strict";(function(e){function scheduleMicroTask(e){Zone.current.scheduleMicroTask("scheduleMicrotask",e)}function getTypeNameForDebugging(e){return e.name?e.name:typeof e}function isPresent(e){return void 0!==e&&null!==e}function isBlank(e){return void 0===e||null===e}function isBoolean(e){return"boolean"==typeof e}function isNumber(e){return"number"==typeof e}function isString(e){return"string"==typeof e}function isFunction(e){return"function"==typeof e}function isType(e){return isFunction(e)}function isStringMap(e){return"object"==typeof e&&null!==e}function isStrictStringMap(e){return isStringMap(e)&&Object.getPrototypeOf(e)===o}function isPromise(e){return isPresent(e)&&isFunction(e.then)}function isArray(e){return Array.isArray(e)}function isDate(e){return e instanceof t.Date&&!isNaN(e.valueOf())}function noop(){}function stringify(e){if("string"==typeof e)return e;if(void 0===e||null===e)return""+e;if(e.overriddenName)return e.overriddenName;if(e.name)return e.name;var t=e.toString(),n=t.indexOf("\n");return n===-1?t:t.substring(0,n)}function serializeEnum(e){return e}function deserializeEnum(e,t){return e}function resolveEnumToken(e,t){return e[t]}function looseIdentical(e,t){return e===t||"number"==typeof e&&"number"==typeof t&&isNaN(e)&&isNaN(t)}function getMapKey(e){return e}function normalizeBlank(e){return isBlank(e)?null:e}function normalizeBool(e){return!isBlank(e)&&e}function isJsObject(e){return null!==e&&("function"==typeof e||"object"==typeof e)}function print(e){console.log(e)}function warn(e){console.warn(e)}function setValueOnPath(e,t,n){for(var r=t.split("."),i=e;r.length>1;){var o=r.shift();i=i.hasOwnProperty(o)&&isPresent(i[o])?i[o]:i[o]={}}void 0!==i&&null!==i||(i={}),i[r.shift()]=n}function getSymbolIterator(){if(isBlank(h))if(isPresent(n.Symbol)&&isPresent(Symbol.iterator))h=Symbol.iterator;else for(var e=Object.getOwnPropertyNames(Map.prototype),t=0;t=0&&e[r]==t;r--)n--;e=e.substring(0,n)}return e},StringWrapper.replace=function(e,t,n){return e.replace(t,n)},StringWrapper.replaceAll=function(e,t,n){return e.replace(t,n)},StringWrapper.slice=function(e,t,n){return void 0===t&&(t=0),void 0===n&&(n=null),e.slice(t,null===n?void 0:n)},StringWrapper.replaceAllMapped=function(e,t,n){return e.replace(t,function(){for(var e=[],t=0;tt?1:0},StringWrapper}();t.StringWrapper=s;var a=function(){function StringJoiner(e){void 0===e&&(e=[]),this.parts=e}return StringJoiner.prototype.add=function(e){this.parts.push(e)},StringJoiner.prototype.toString=function(){return this.parts.join("")},StringJoiner}();t.StringJoiner=a;var l=function(e){function NumberParseError(t){e.call(this),this.message=t}return r(NumberParseError,e),NumberParseError.prototype.toString=function(){return this.message},NumberParseError}(Error);t.NumberParseError=l;var c=function(){function NumberWrapper(){}return NumberWrapper.toFixed=function(e,t){return e.toFixed(t)},NumberWrapper.equal=function(e,t){return e===t},NumberWrapper.parseIntAutoRadix=function(e){var t=parseInt(e);if(isNaN(t))throw new l("Invalid integer literal when parsing "+e);return t},NumberWrapper.parseInt=function(e,t){if(10==t){if(/^(\-|\+)?[0-9]+$/.test(e))return parseInt(e,t)}else if(16==t){if(/^(\-|\+)?[0-9ABCDEFabcdef]+$/.test(e))return parseInt(e,t)}else{var n=parseInt(e,t);if(!isNaN(n))return n}throw new l("Invalid integer literal when parsing "+e+" in base "+t)},NumberWrapper.parseFloat=function(e){return parseFloat(e)},Object.defineProperty(NumberWrapper,"NaN",{get:function(){return NaN},enumerable:!0,configurable:!0}),NumberWrapper.isNumeric=function(e){return!isNaN(e-parseFloat(e))},NumberWrapper.isNaN=function(e){return isNaN(e)},NumberWrapper.isInteger=function(e){return Number.isInteger(e)},NumberWrapper}();t.NumberWrapper=c,t.RegExp=i.RegExp;var u=function(){function FunctionWrapper(){}return FunctionWrapper.apply=function(e,t){return e.apply(null,t)},FunctionWrapper.bind=function(e,t){return e.bind(t)},FunctionWrapper}();t.FunctionWrapper=u,t.looseIdentical=looseIdentical,t.getMapKey=getMapKey,t.normalizeBlank=normalizeBlank,t.normalizeBool=normalizeBool,t.isJsObject=isJsObject,t.print=print,t.warn=warn;var p=function(){function Json(){}return Json.parse=function(e){return i.JSON.parse(e)},Json.stringify=function(e){return i.JSON.stringify(e,null,2)},Json}();t.Json=p;var d=function(){function DateWrapper(){}return DateWrapper.create=function(e,n,r,i,o,s,a){return void 0===n&&(n=1),void 0===r&&(r=1),void 0===i&&(i=0),void 0===o&&(o=0),void 0===s&&(s=0),void 0===a&&(a=0),new t.Date(e,n-1,r,i,o,s,a)},DateWrapper.fromISOString=function(e){return new t.Date(e)},DateWrapper.fromMillis=function(e){return new t.Date(e)},DateWrapper.toMillis=function(e){return e.getTime()},DateWrapper.now=function(){return new t.Date},DateWrapper.toJson=function(e){return e.toJSON()},DateWrapper}();t.DateWrapper=d,t.setValueOnPath=setValueOnPath;var h=null;t.getSymbolIterator=getSymbolIterator,t.evalExpression=evalExpression,t.isPrimitive=isPrimitive,t.hasConstructor=hasConstructor,t.escape=escape,t.escapeRegExp=escapeRegExp}).call(t,n(82))},4,function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(217),o=n(41),s=n(215),a=n(897),l=function(e){function Subscriber(t,n,r){switch(e.call(this),this.syncErrorValue=null,this.syncErrorThrown=!1,this.syncErrorThrowable=!1,this.isStopped=!1,arguments.length){case 0:this.destination=a.empty;break;case 1:if(!t){this.destination=a.empty;break}if("object"==typeof t){t instanceof Subscriber?(this.destination=t,this.destination.add(this)):(this.syncErrorThrowable=!0,this.destination=new c(this,t));break}default:this.syncErrorThrowable=!0,this.destination=new c(this,t,n,r)}}return r(Subscriber,e),Subscriber.create=function(e,t,n){var r=new Subscriber(e,t,n);return r.syncErrorThrowable=!1,r},Subscriber.prototype.next=function(e){this.isStopped||this._next(e)},Subscriber.prototype.error=function(e){this.isStopped||(this.isStopped=!0,this._error(e))},Subscriber.prototype.complete=function(){this.isStopped||(this.isStopped=!0,this._complete())},Subscriber.prototype.unsubscribe=function(){this.isUnsubscribed||(this.isStopped=!0,e.prototype.unsubscribe.call(this))},Subscriber.prototype._next=function(e){this.destination.next(e)},Subscriber.prototype._error=function(e){this.destination.error(e),this.unsubscribe()},Subscriber.prototype._complete=function(){this.destination.complete(),this.unsubscribe()},Subscriber.prototype[s.$$rxSubscriber]=function(){return this},Subscriber}(o.Subscription);t.Subscriber=l;var c=function(e){function SafeSubscriber(t,n,r,o){e.call(this),this._parent=t;var s,a=this;i.isFunction(n)?s=n:n&&(a=n,s=n.next,r=n.error,o=n.complete,i.isFunction(a.unsubscribe)&&this.add(a.unsubscribe.bind(a)),a.unsubscribe=this.unsubscribe.bind(this)),this._context=a,this._next=s,this._error=r,this._complete=o}return r(SafeSubscriber,e),SafeSubscriber.prototype.next=function(e){if(!this.isStopped&&this._next){var t=this._parent;t.syncErrorThrowable?this.__tryOrSetError(t,this._next,e)&&this.unsubscribe():this.__tryOrUnsub(this._next,e)}},SafeSubscriber.prototype.error=function(e){if(!this.isStopped){var t=this._parent;if(this._error)t.syncErrorThrowable?(this.__tryOrSetError(t,this._error,e),this.unsubscribe()):(this.__tryOrUnsub(this._error,e),this.unsubscribe());else{if(!t.syncErrorThrowable)throw this.unsubscribe(),e;t.syncErrorValue=e,t.syncErrorThrown=!0,this.unsubscribe()}}},SafeSubscriber.prototype.complete=function(){if(!this.isStopped){var e=this._parent;this._complete?e.syncErrorThrowable?(this.__tryOrSetError(e,this._complete),this.unsubscribe()):(this.__tryOrUnsub(this._complete),this.unsubscribe()):this.unsubscribe()}},SafeSubscriber.prototype.__tryOrUnsub=function(e,t){try{e.call(this._context,t)}catch(n){throw this.unsubscribe(),n}},SafeSubscriber.prototype.__tryOrSetError=function(e,t,n){try{t.call(this._context,n)}catch(r){return e.syncErrorValue=r,e.syncErrorThrown=!0,!0}return!1},SafeSubscriber.prototype._unsubscribe=function(){var e=this._parent;this._context=null,this._parent=null,e.unsubscribe()},SafeSubscriber}(l)},4,function(e,t,n){var r=n(15);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){"use strict";var r=this&&this.__decorate||function(e,t,n,r){var i,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},o=n(0),s=function(){function DomHandler(){}return DomHandler.prototype.addClass=function(e,t){e.classList?e.classList.add(t):e.className+=" "+t},DomHandler.prototype.addMultipleClasses=function(e,t){if(e.classList)for(var n=t.split(" "),r=0;rwindow.innerHeight?-1*i.height:o,r=a.left+i.width>window.innerWidth?s-i.width:0,e.style.top=n+"px",e.style.left=r+"px"},DomHandler.prototype.absolutePosition=function(e,t){var n,r,i=e.offsetParent?{width:e.offsetWidth,height:e.offsetHeight}:this.getHiddenElementDimensions(e),o=i.height,s=i.width,a=t.offsetHeight,l=t.offsetWidth,c=t.getBoundingClientRect(),u=this.getWindowScrollTop(),p=this.getWindowScrollLeft();n=c.top+a+o>window.innerHeight?c.top+u-o:a+c.top+u,r=c.left+l+s>window.innerWidth?c.left+p+l-s:c.left+p,e.style.top=n+"px",e.style.left=r+"px"},DomHandler.prototype.getHiddenElementOuterHeight=function(e){e.style.visibility="hidden",e.style.display="block";var t=e.offsetHeight;return e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.getHiddenElementOuterWidth=function(e){e.style.visibility="hidden",e.style.display="block";var t=e.offsetWidth;return e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.getHiddenElementDimensions=function(e){var t={};return e.style.visibility="hidden",e.style.display="block",t.width=e.offsetWidth,t.height=e.offsetHeight,e.style.display="none",e.style.visibility="visible",t},DomHandler.prototype.scrollInView=function(e,t){var n=getComputedStyle(e).getPropertyValue("borderTopWidth"),r=n?parseFloat(n):0,i=getComputedStyle(e).getPropertyValue("paddingTop"),o=i?parseFloat(i):0,s=e.getBoundingClientRect(),a=t.getBoundingClientRect(),l=a.top+document.body.scrollTop-(s.top+document.body.scrollTop)-r-o,c=e.scrollTop,u=e.clientHeight,p=this.getOuterHeight(t);l<0?e.scrollTop=c+l:l+p>u&&(e.scrollTop=c+l-u+p)},DomHandler.prototype.fadeIn=function(e,t){e.style.opacity=0;var n=+new Date,r=function(){e.style.opacity=+e.style.opacity+((new Date).getTime()-n)/t,n=+new Date,+e.style.opacity<1&&(window.requestAnimationFrame&&requestAnimationFrame(r)||setTimeout(r,16))};r()},DomHandler.prototype.fadeOut=function(e,t){var n=1,r=50,i=t,o=r/i,s=setInterval(function(){n-=o,e.style.opacity=n,n<=0&&clearInterval(s)},r)},DomHandler.prototype.getWindowScrollTop=function(){var e=document.documentElement;return(window.pageYOffset||e.scrollTop)-(e.clientTop||0)},DomHandler.prototype.getWindowScrollLeft=function(){var e=document.documentElement;return(window.pageXOffset||e.scrollLeft)-(e.clientLeft||0)},DomHandler.prototype.matches=function(e,t){var n=Element.prototype,r=n.matches||n.webkitMatchesSelector||n.mozMatchesSelector||n.msMatchesSelector||function(e){return[].indexOf.call(document.querySelectorAll(e),this)!==-1};return r.call(e,t)},DomHandler.prototype.getOuterWidth=function(e,t){var n=e.offsetWidth;if(t){var r=getComputedStyle(e);n+=parseInt(r.paddingLeft)+parseInt(r.paddingRight)}return n},DomHandler.prototype.getHorizontalMargin=function(e){var t=getComputedStyle(e);return parseInt(t.marginLeft)+parseInt(t.marginRight)},DomHandler.prototype.innerWidth=function(e){var t=e.offsetWidth,n=getComputedStyle(e);return t+=parseInt(n.paddingLeft)+parseInt(n.paddingRight)},DomHandler.prototype.width=function(e){var t=e.offsetWidth,n=getComputedStyle(e);return t-=parseInt(n.paddingLeft)+parseInt(n.paddingRight)},DomHandler.prototype.getOuterHeight=function(e,t){var n=e.offsetHeight;if(t){var r=getComputedStyle(e);n+=parseInt(r.marginTop)+parseInt(r.marginBottom)}return n},DomHandler.prototype.getHeight=function(e){var t=e.offsetHeight,n=getComputedStyle(e);return t-=parseInt(n.paddingTop)+parseInt(n.paddingBottom)+parseInt(n.borderTopWidth)+parseInt(n.borderBottomWidth)},DomHandler.prototype.getViewport=function(){var e=window,t=document,n=t.documentElement,r=t.getElementsByTagName("body")[0],i=e.innerWidth||n.clientWidth||r.clientWidth,o=e.innerHeight||n.clientHeight||r.clientHeight;return{width:i,height:o}},DomHandler.prototype.equals=function(e,t){if(null==e||null==t)return!1;if(e==t)return!0;if("object"==typeof e&&"object"==typeof t){for(var n in e){if(e.hasOwnProperty(n)!==t.hasOwnProperty(n))return!1;switch(typeof e[n]){case"object":if(!this.equals(e[n],t[n]))return!1;break;case"function":if("undefined"==typeof t[n]||"compare"!=n&&e[n].toString()!=t[n].toString())return!1;break;default:if(e[n]!=t[n])return!1}}for(var n in t)if("undefined"==typeof e[n])return!1;return!0}return!1},DomHandler.zindex=1e3,DomHandler=r([o.Injectable(),i("design:paramtypes",[])],DomHandler)}();t.DomHandler=s},[1104,5],function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(6),o=function(e){function OuterSubscriber(){e.apply(this,arguments)}return r(OuterSubscriber,e),OuterSubscriber.prototype.notifyNext=function(e,t,n,r,i){this.destination.next(t)},OuterSubscriber.prototype.notifyError=function(e,t){this.destination.error(e)},OuterSubscriber.prototype.notifyComplete=function(e){this.destination.complete()},OuterSubscriber}(i.Subscriber);t.OuterSubscriber=o},function(e,t,n){"use strict";function subscribeToResult(e,t,n,u){var p=new c.InnerSubscriber(e,n,u);if(!p.isUnsubscribed){if(t instanceof s.Observable)return t._isScalar?(p.next(t.value),void p.complete()):t.subscribe(p);if(i.isArray(t)){for(var d=0,h=t.length;d=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},o=n(0),s=n(3),a=n(0),l=function(){function Header(){}return Header=r([a.Component({selector:"header",template:""}),i("design:paramtypes",[])],Header)}();t.Header=l;var c=function(){function Footer(){}return Footer=r([a.Component({selector:"footer",template:""}),i("design:paramtypes",[])],Footer)}();t.Footer=c;var u=function(){function TemplateWrapper(e){this.viewContainer=e}return TemplateWrapper.prototype.ngOnInit=function(){this.viewContainer.createEmbeddedView(this.templateRef,{$implicit:this.item})},r([o.Input(),i("design:type",Object)],TemplateWrapper.prototype,"item",void 0),r([o.Input("pTemplateWrapper"),i("design:type",o.TemplateRef)],TemplateWrapper.prototype,"templateRef",void 0),TemplateWrapper=r([o.Directive({selector:"[pTemplateWrapper]"}),i("design:paramtypes",[o.ViewContainerRef])],TemplateWrapper)}();t.TemplateWrapper=u;var p=function(){function Column(){this.sortFunction=new o.EventEmitter}return r([o.Input(),i("design:type",String)],Column.prototype,"field",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"header",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"footer",void 0),r([o.Input(),i("design:type",Object)],Column.prototype,"sortable",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"editable",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"filter",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"filterMatchMode",void 0),r([o.Input(),i("design:type",Number)],Column.prototype,"rowspan",void 0),r([o.Input(),i("design:type",Number)],Column.prototype,"colspan",void 0),r([o.Input(),i("design:type",Object)],Column.prototype,"style",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"styleClass",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"hidden",void 0),r([o.Input(),i("design:type",Boolean)],Column.prototype,"expander",void 0),r([o.Input(),i("design:type",String)],Column.prototype,"selectionMode",void 0),r([o.Output(),i("design:type",o.EventEmitter)],Column.prototype,"sortFunction",void 0),r([o.ContentChild(o.TemplateRef),i("design:type",o.TemplateRef)],Column.prototype,"template",void 0),Column=r([a.Component({selector:"p-column",template:""}),i("design:paramtypes",[])],Column)}();t.Column=p;var d=function(){function ColumnTemplateLoader(e){this.viewContainer=e}return ColumnTemplateLoader.prototype.ngOnInit=function(){this.viewContainer.createEmbeddedView(this.column.template,{$implicit:this.column,rowData:this.rowData,rowIndex:this.rowIndex})},r([o.Input(),i("design:type",Object)],ColumnTemplateLoader.prototype,"column",void 0),r([o.Input(),i("design:type",Object)],ColumnTemplateLoader.prototype,"rowData",void 0),r([o.Input(),i("design:type",Number)],ColumnTemplateLoader.prototype,"rowIndex",void 0),ColumnTemplateLoader=r([a.Component({selector:"p-columnTemplateLoader",template:""}),i("design:paramtypes",[o.ViewContainerRef])],ColumnTemplateLoader)}();t.ColumnTemplateLoader=d;var h=function(){function SharedModule(){}return SharedModule=r([o.NgModule({imports:[s.CommonModule],exports:[l,c,p,u,d],declarations:[l,c,p,u,d]}),i("design:paramtypes",[])],SharedModule)}();t.SharedModule=h},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(1),o=n(6),s=n(41),a=n(899),l=n(215),c=n(517),u=n(317),p=function(e){function Subject(t,n){e.call(this),this.destination=t,this.source=n,this.observers=[],this.isUnsubscribed=!1,this.isStopped=!1,this.hasErrored=!1,this.dispatching=!1,this.hasCompleted=!1,this.source=n}return r(Subject,e),Subject.prototype.lift=function(e){var t=new Subject(this.destination||this,this);return t.operator=e,t},Subject.prototype.add=function(e){return s.Subscription.prototype.add.call(this,e)},Subject.prototype.remove=function(e){s.Subscription.prototype.remove.call(this,e)},Subject.prototype.unsubscribe=function(){s.Subscription.prototype.unsubscribe.call(this)},Subject.prototype._subscribe=function(e){if(this.source)return this.source.subscribe(e);if(!e.isUnsubscribed){if(this.hasErrored)return e.error(this.errorValue);if(this.hasCompleted)return e.complete();this.throwIfUnsubscribed();var t=new a.SubjectSubscription(this,e);return this.observers.push(e),t}},Subject.prototype._unsubscribe=function(){this.source=null,this.isStopped=!0,this.observers=null,this.destination=null},Subject.prototype.next=function(e){this.throwIfUnsubscribed(),this.isStopped||(this.dispatching=!0,this._next(e),this.dispatching=!1,this.hasErrored?this._error(this.errorValue):this.hasCompleted&&this._complete())},Subject.prototype.error=function(e){this.throwIfUnsubscribed(),this.isStopped||(this.isStopped=!0,this.hasErrored=!0,this.errorValue=e,this.dispatching||this._error(e))},Subject.prototype.complete=function(){this.throwIfUnsubscribed(),this.isStopped||(this.isStopped=!0,this.hasCompleted=!0,this.dispatching||this._complete())},Subject.prototype.asObservable=function(){var e=new d(this);return e},Subject.prototype._next=function(e){this.destination?this.destination.next(e):this._finalNext(e)},Subject.prototype._finalNext=function(e){for(var t=-1,n=this.observers.slice(0),r=n.length;++t"+i+""};e.exports=function(e,t){var n={};n[e]=t(a),r(r.P+r.F*i(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t,n){"use strict";var r=n(81),i=n(514),o=n(217),s=n(42),a=n(38),l=n(513),c=function(){function Subscription(e){this.isUnsubscribed=!1,e&&(this._unsubscribe=e)}return Subscription.prototype.unsubscribe=function(){var e,t=!1;if(!this.isUnsubscribed){this.isUnsubscribed=!0;var n=this,c=n._unsubscribe,u=n._subscriptions;if(this._subscriptions=null,o.isFunction(c)){var p=s.tryCatch(c).call(this);p===a.errorObject&&(t=!0,(e=e||[]).push(a.errorObject.e))}if(r.isArray(u))for(var d=-1,h=u.length;++d0?i(r(e),9007199254740991):0}},function(e,t,n){"use strict";var r=n(1082);t.async=new r.AsyncScheduler},function(e,t,n){"use strict";function __export(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}var r=n(86);t.HostMetadata=r.HostMetadata,t.InjectMetadata=r.InjectMetadata,t.InjectableMetadata=r.InjectableMetadata,t.OptionalMetadata=r.OptionalMetadata,t.SelfMetadata=r.SelfMetadata,t.SkipSelfMetadata=r.SkipSelfMetadata,__export(n(115));var i=n(162);t.forwardRef=i.forwardRef,t.resolveForwardRef=i.resolveForwardRef;var o=n(163);t.Injector=o.Injector;var s=n(571);t.ReflectiveInjector=s.ReflectiveInjector;var a=n(250);t.Binding=a.Binding,t.ProviderBuilder=a.ProviderBuilder,t.bind=a.bind,t.Provider=a.Provider,t.provide=a.provide;var l=n(253);t.ResolvedReflectiveFactory=l.ResolvedReflectiveFactory;var c=n(252);t.ReflectiveKey=c.ReflectiveKey;var u=n(251);t.NoProviderError=u.NoProviderError,t.AbstractProviderError=u.AbstractProviderError,t.CyclicDependencyError=u.CyclicDependencyError,t.InstantiationError=u.InstantiationError,t.InvalidProviderError=u.InvalidProviderError,t.NoAnnotationError=u.NoAnnotationError,t.OutOfBoundsError=u.OutOfBoundsError;var p=n(374);t.OpaqueToken=p.OpaqueToken},[1104,32],function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t,n){"use strict";var r=n(13);e.exports=function(e,t){return!!e&&r(function(){t?e.call(null,function(){},1):e.call(null)})}},function(e,t,n){var r=n(75);e.exports=function(e){return Object(r(e))}},function(e,t,n){"use strict";(function(e,n){var r={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1};t.root=r[typeof self]&&self||r[typeof window]&&window;var i=(r[typeof t]&&t&&!t.nodeType&&t,r[typeof e]&&e&&!e.nodeType&&e,r[typeof n]&&n);!i||i.global!==i&&i.window!==i||(t.root=i)}).call(t,n(1100)(e),n(82))},function(e,t,n){"use strict";var r=n(0);t.NG_VALUE_ACCESSOR=new r.OpaqueToken("NgValueAccessor")},52,function(e,t,n){"use strict";function _convertToPromise(e){return s.isPromise(e)?e:i.toPromise.call(e)}function _executeValidators(e,t){return t.map(function(t){return t(e)})}function _executeAsyncValidators(e,t){return t.map(function(t){return t(e)})}function _mergeErrors(e){var t=e.reduce(function(e,t){return s.isPresent(t)?o.StringMapWrapper.merge(e,t):e},{});return o.StringMapWrapper.isEmpty(t)?null:t}var r=n(0),i=n(313),o=n(47),s=n(32);t.NG_VALIDATORS=new r.OpaqueToken("NgValidators"),t.NG_ASYNC_VALIDATORS=new r.OpaqueToken("NgAsyncValidators");var a=function(){function Validators(){}return Validators.required=function(e){return s.isBlank(e.value)||s.isString(e.value)&&""==e.value?{required:!0}:null},Validators.minLength=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=t.value;return n.lengthe?{maxlength:{requiredLength:e,actualLength:n.length}}:null}},Validators.pattern=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=new RegExp("^"+e+"$"),r=t.value;return n.test(r)?null:{pattern:{requiredPattern:"^"+e+"$",actualValue:r}}}},Validators.nullValidator=function(e){return null},Validators.compose=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){return _mergeErrors(_executeValidators(e,t))}},Validators.composeAsync=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){var n=_executeAsyncValidators(e,t).map(_convertToPromise);return Promise.all(n).then(_mergeErrors)}},Validators}();t.Validators=a},function(e,t,n){"use strict";var r=n(0),i=n(123),o=n(72),s=n(16),a=n(126),l=n(278);t.PRIMITIVE=String;var c=function(){function Serializer(e){this._renderStore=e}return Serializer.prototype.serialize=function(e,n){var i=this;if(!s.isPresent(e))return null;if(s.isArray(e))return e.map(function(e){return i.serialize(e,n)});if(n==t.PRIMITIVE)return e;if(n==u)return this._renderStore.serialize(e);if(n===r.RenderComponentType)return this._serializeRenderComponentType(e);if(n===r.ViewEncapsulation)return s.serializeEnum(e);if(n===l.LocationType)return this._serializeLocation(e);throw new o.BaseException("No serializer for "+n.toString())},Serializer.prototype.deserialize=function(e,n,a){var c=this;if(!s.isPresent(e))return null;if(s.isArray(e)){var p=[];return e.forEach(function(e){return p.push(c.deserialize(e,n,a))}),p}if(n==t.PRIMITIVE)return e;if(n==u)return this._renderStore.deserialize(e);if(n===r.RenderComponentType)return this._deserializeRenderComponentType(e);if(n===r.ViewEncapsulation)return i.VIEW_ENCAPSULATION_VALUES[e];if(n===l.LocationType)return this._deserializeLocation(e);throw new o.BaseException("No deserializer for "+n.toString())},Serializer.prototype._serializeLocation=function(e){return{href:e.href,protocol:e.protocol,host:e.host,hostname:e.hostname,port:e.port,pathname:e.pathname,search:e.search,hash:e.hash,origin:e.origin}},Serializer.prototype._deserializeLocation=function(e){return new l.LocationType(e.href,e.protocol,e.host,e.hostname,e.port,e.pathname,e.search,e.hash,e.origin)},Serializer.prototype._serializeRenderComponentType=function(e){return{id:e.id,templateUrl:e.templateUrl,slotCount:e.slotCount,encapsulation:this.serialize(e.encapsulation,r.ViewEncapsulation),styles:this.serialize(e.styles,t.PRIMITIVE)}},Serializer.prototype._deserializeRenderComponentType=function(e){return new r.RenderComponentType(e.id,e.templateUrl,e.slotCount,this.deserialize(e.encapsulation,r.ViewEncapsulation),this.deserialize(e.styles,t.PRIMITIVE),{})},Serializer.decorators=[{type:r.Injectable}],Serializer.ctorParameters=[{type:a.RenderStore}],Serializer}();t.Serializer=c;var u=function(){function RenderStoreObject(){}return RenderStoreObject}();t.RenderStoreObject=u},function(e,t,n){var r=n(2),i=n(24),o=n(13);e.exports=function(e,t){var n=(i.Object||{})[e]||Object[e],s={};s[e]=t(n),r(r.S+r.F*o(function(){n(1)}),"Object",s)}},function(e,t,n){var r=n(133),i=n(75);e.exports=function(e){return r(i(e))}},function(e,t,n){"use strict";function _convertToPromise(e){return s.isPromise(e)?e:i.toPromise.call(e)}function _executeValidators(e,t){return t.map(function(t){return t(e)})}function _executeAsyncValidators(e,t){return t.map(function(t){return t(e)})}function _mergeErrors(e){var t=e.reduce(function(e,t){return s.isPresent(t)?o.StringMapWrapper.merge(e,t):e},{});return o.StringMapWrapper.isEmpty(t)?null:t}var r=n(0),i=n(313),o=n(34),s=n(7);t.NG_VALIDATORS=new r.OpaqueToken("NgValidators"),t.NG_ASYNC_VALIDATORS=new r.OpaqueToken("NgAsyncValidators");var a=function(){function Validators(){}return Validators.required=function(e){return s.isBlank(e.value)||s.isString(e.value)&&""==e.value?{required:!0}:null},Validators.minLength=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=t.value;return n.lengthe?{maxlength:{requiredLength:e,actualLength:n.length}}:null}},Validators.pattern=function(e){return function(t){if(s.isPresent(Validators.required(t)))return null;var n=new RegExp("^"+e+"$"),r=t.value;return n.test(r)?null:{pattern:{requiredPattern:"^"+e+"$",actualValue:r}}}},Validators.nullValidator=function(e){return null},Validators.compose=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){return _mergeErrors(_executeValidators(e,t))}},Validators.composeAsync=function(e){if(s.isBlank(e))return null;var t=e.filter(s.isPresent);return 0==t.length?null:function(e){var n=_executeAsyncValidators(e,t).map(_convertToPromise);return Promise.all(n).then(_mergeErrors)}},Validators}();t.Validators=a},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(83),o=n(7),s=function(e){function InvalidPipeArgumentException(t,n){e.call(this,"Invalid argument '"+n+"' for pipe '"+o.stringify(t)+"'")}return r(InvalidPipeArgumentException,e),InvalidPipeArgumentException}(i.BaseException);t.InvalidPipeArgumentException=s},function(e,t,n){"use strict";/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -var r=n(5),i=function(){function ParseLocation(e,t,n,r){this.file=e,this.offset=t,this.line=n,this.col=r}return ParseLocation.prototype.toString=function(){return r.isPresent(this.offset)?this.file.url+"@"+this.line+":"+this.col:this.file.url},ParseLocation}();t.ParseLocation=i;var o=function(){function ParseSourceFile(e,t){this.content=e,this.url=t}return ParseSourceFile}();t.ParseSourceFile=o;var s=function(){function ParseSourceSpan(e,t,n){void 0===n&&(n=null),this.start=e,this.end=t,this.details=n}return ParseSourceSpan.prototype.toString=function(){return this.start.file.content.substring(this.start.offset,this.end.offset)},ParseSourceSpan}();t.ParseSourceSpan=s,function(e){e[e.WARNING=0]="WARNING",e[e.FATAL=1]="FATAL"}(t.ParseErrorLevel||(t.ParseErrorLevel={}));var a=t.ParseErrorLevel,l=function(){function ParseError(e,t,n){void 0===n&&(n=a.FATAL),this.span=e,this.msg=t,this.level=n}return ParseError.prototype.toString=function(){var e=this.span.start.file.content,t=this.span.start.offset,n="",i="";if(r.isPresent(t)){t>e.length-1&&(t=e.length-1);for(var o=t,s=0,a=0;s<100&&t>0&&(t--,s++,"\n"!=e[t]||3!=++a););for(s=0,a=0;s<100&&o]"+e.substring(this.span.start.offset,o+1);n=' ("'+l+'")'}return this.span.details&&(i=", "+this.span.details),""+this.msg+n+": "+this.span.start+i},ParseError}();t.ParseError=l},function(e,t,n){"use strict";function templateVisitAll(e,t,n){void 0===n&&(n=null);var i=[];return t.forEach(function(t){var o=t.visit(e,n);r.isPresent(o)&&i.push(o)}),i}var r=n(5),i=function(){function TextAst(e,t,n){this.value=e,this.ngContentIndex=t,this.sourceSpan=n}return TextAst.prototype.visit=function(e,t){return e.visitText(this,t)},TextAst}();t.TextAst=i;var o=function(){function BoundTextAst(e,t,n){this.value=e,this.ngContentIndex=t,this.sourceSpan=n}return BoundTextAst.prototype.visit=function(e,t){return e.visitBoundText(this,t)},BoundTextAst}();t.BoundTextAst=o;var s=function(){function AttrAst(e,t,n){this.name=e,this.value=t,this.sourceSpan=n}return AttrAst.prototype.visit=function(e,t){return e.visitAttr(this,t)},AttrAst}();t.AttrAst=s;var a=function(){function BoundElementPropertyAst(e,t,n,r,i,o){this.name=e,this.type=t,this.securityContext=n,this.value=r,this.unit=i,this.sourceSpan=o}return BoundElementPropertyAst.prototype.visit=function(e,t){return e.visitElementProperty(this,t)},BoundElementPropertyAst}();t.BoundElementPropertyAst=a;var l=function(){function BoundEventAst(e,t,n,r){this.name=e,this.target=t,this.handler=n,this.sourceSpan=r}return BoundEventAst.prototype.visit=function(e,t){return e.visitEvent(this,t)},Object.defineProperty(BoundEventAst.prototype,"fullName",{get:function(){return r.isPresent(this.target)?this.target+":"+this.name:this.name},enumerable:!0,configurable:!0}),BoundEventAst}();t.BoundEventAst=l;var c=function(){function ReferenceAst(e,t,n){this.name=e,this.value=t,this.sourceSpan=n}return ReferenceAst.prototype.visit=function(e,t){return e.visitReference(this,t)},ReferenceAst}();t.ReferenceAst=c;var u=function(){function VariableAst(e,t,n){this.name=e,this.value=t,this.sourceSpan=n}return VariableAst.prototype.visit=function(e,t){return e.visitVariable(this,t)},VariableAst}();t.VariableAst=u;var p=function(){function ElementAst(e,t,n,r,i,o,s,a,l,c,u){this.name=e,this.attrs=t,this.inputs=n,this.outputs=r,this.references=i,this.directives=o,this.providers=s,this.hasViewContainer=a,this.children=l,this.ngContentIndex=c,this.sourceSpan=u}return ElementAst.prototype.visit=function(e,t){return e.visitElement(this,t)},ElementAst}();t.ElementAst=p;var d=function(){function EmbeddedTemplateAst(e,t,n,r,i,o,s,a,l,c){this.attrs=e,this.outputs=t,this.references=n,this.variables=r,this.directives=i,this.providers=o,this.hasViewContainer=s,this.children=a,this.ngContentIndex=l,this.sourceSpan=c}return EmbeddedTemplateAst.prototype.visit=function(e,t){return e.visitEmbeddedTemplate(this,t)},EmbeddedTemplateAst}();t.EmbeddedTemplateAst=d;var h=function(){function BoundDirectivePropertyAst(e,t,n,r){this.directiveName=e,this.templateName=t,this.value=n,this.sourceSpan=r}return BoundDirectivePropertyAst.prototype.visit=function(e,t){return e.visitDirectiveProperty(this,t)},BoundDirectivePropertyAst}();t.BoundDirectivePropertyAst=h;var f=function(){function DirectiveAst(e,t,n,r,i){this.directive=e,this.inputs=t,this.hostProperties=n,this.hostEvents=r,this.sourceSpan=i}return DirectiveAst.prototype.visit=function(e,t){return e.visitDirective(this,t)},DirectiveAst}();t.DirectiveAst=f;var m=function(){function ProviderAst(e,t,n,r,i,o,s){this.token=e,this.multiProvider=t,this.eager=n,this.providers=r,this.providerType=i,this.lifecycleHooks=o,this.sourceSpan=s}return ProviderAst.prototype.visit=function(e,t){return null},ProviderAst}();t.ProviderAst=m,function(e){e[e.PublicService=0]="PublicService",e[e.PrivateService=1]="PrivateService",e[e.Component=2]="Component",e[e.Directive=3]="Directive",e[e.Builtin=4]="Builtin"}(t.ProviderAstType||(t.ProviderAstType={}));var y=(t.ProviderAstType,function(){function NgContentAst(e,t,n){this.index=e,this.ngContentIndex=t,this.sourceSpan=n}return NgContentAst.prototype.visit=function(e,t){return e.visitNgContent(this,t)},NgContentAst}());t.NgContentAst=y,function(e){e[e.Property=0]="Property",e[e.Attribute=1]="Attribute",e[e.Class=2]="Class",e[e.Style=3]="Style",e[e.Animation=4]="Animation"}(t.PropertyBindingType||(t.PropertyBindingType={}));t.PropertyBindingType;t.templateVisitAll=templateVisitAll},function(e,t){"use strict";var n=function(){function MessageBus(){}return MessageBus}();t.MessageBus=n},function(e,t){"use strict";t.PRIMARY_OUTLET="primary"},function(e,t,n){var r=n(106),i=n(133),o=n(50),s=n(44),a=n(676);e.exports=function(e,t){var n=1==e,l=2==e,c=3==e,u=4==e,p=6==e,d=5==e||p,h=t||a;return function(t,a,f){for(var m,y,v=o(t),g=i(v),b=r(a,f,3),_=s(g.length),S=0,w=n?h(t,_):l?h(t,0):void 0;_>S;S++)if((d||S in g)&&(m=g[S],y=b(m,S,v),e))if(n)w[S]=y;else if(y)switch(e){case 3:return!0;case 5:return m;case 6:return S;case 2:w.push(m)}else if(u)return!1;return p?-1:c||u?u:w}}},function(e,t,n){var r=n(30),i=n(109);e.exports=n(35)?function(e,t,n){return r.f(e,t,i(1,n))}:function(e,t,n){return e[t]=n,e}},function(e,t,n){var r=n(472),i=n(2),o=n(199)("metadata"),s=o.store||(o.store=new(n(798))),a=function(e,t,n){var i=s.get(e);if(!i){if(!n)return;s.set(e,i=new r)}var o=i.get(t);if(!o){if(!n)return;i.set(t,o=new r)}return o},l=function(e,t,n){var r=a(t,n,!1);return void 0!==r&&r.has(e)},c=function(e,t,n){var r=a(t,n,!1);return void 0===r?void 0:r.get(e)},u=function(e,t,n,r){a(n,r,!0).set(e,t)},p=function(e,t){var n=a(e,t,!1),r=[];return n&&n.forEach(function(e,t){r.push(t)}),r},d=function(e){return void 0===e||"symbol"==typeof e?e:String(e)},h=function(e){i(i.S,"Reflect",e)};e.exports={store:s,map:a,has:l,get:c,set:u,keys:p,key:d,exp:h}},function(e,t,n){var r=n(48),i=n(50),o=n(300)("IE_PROTO"),s=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=i(e),r(e,o)?e[o]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?s:null}},function(e,t,n){"use strict";var r=n(347),i=function(){function InterpolationConfig(e,t){this.start=e,this.end=t}return InterpolationConfig.fromArray=function(e){return e?(r.assertInterpolationSymbols("interpolation",e),new InterpolationConfig(e[0],e[1])):t.DEFAULT_INTERPOLATION_CONFIG},InterpolationConfig}();t.InterpolationConfig=i,t.DEFAULT_INTERPOLATION_CONFIG=new i("{{","}}")},[1107,263],function(e,t,n){"use strict";function controlPath(e,t){var n=r.ListWrapper.clone(t.path);return n.push(e),n}function setUpControl(e,t){o.isBlank(e)&&_throwError(t,"Cannot find control with"),o.isBlank(t.valueAccessor)&&_throwError(t,"No value accessor for form control with"),e.validator=s.Validators.compose([e.validator,t.validator]),e.asyncValidator=s.Validators.composeAsync([e.asyncValidator,t.asyncValidator]),t.valueAccessor.writeValue(e.value),t.valueAccessor.registerOnChange(function(n){t.viewToModelUpdate(n),e.markAsDirty(),e.setValue(n,{emitModelToViewChange:!1})}),e.registerOnChange(function(e,n){t.valueAccessor.writeValue(e),n&&t.viewToModelUpdate(e)}),t.valueAccessor.registerOnTouched(function(){return e.markAsTouched()})}function setUpFormContainer(e,t){o.isBlank(e)&&_throwError(t,"Cannot find control with"),e.validator=s.Validators.compose([e.validator,t.validator]),e.asyncValidator=s.Validators.composeAsync([e.asyncValidator,t.asyncValidator])}function _throwError(e,t){var n;throw n=e.path.length>1?"path: '"+e.path.join(" -> ")+"'":e.path[0]?"name: '"+e.path+"'":"unspecified name attribute",new i.BaseException(t+" "+n)}function composeValidators(e){return o.isPresent(e)?s.Validators.compose(e.map(c.normalizeValidator)):null}function composeAsyncValidators(e){return o.isPresent(e)?s.Validators.composeAsync(e.map(c.normalizeAsyncValidator)):null}function isPropertyUpdated(e,t){if(!r.StringMapWrapper.contains(e,"model"))return!1;var n=e.model;return!!n.isFirstChange()||!o.looseIdentical(t,n.currentValue)}function selectValueAccessor(e,t){if(o.isBlank(t))return null;var n,r,i;return t.forEach(function(t){o.hasConstructor(t,l.DefaultValueAccessor)?n=t:o.hasConstructor(t,a.CheckboxControlValueAccessor)||o.hasConstructor(t,u.NumberValueAccessor)||o.hasConstructor(t,d.SelectControlValueAccessor)||o.hasConstructor(t,h.SelectMultipleControlValueAccessor)||o.hasConstructor(t,p.RadioControlValueAccessor)?(o.isPresent(r)&&_throwError(e,"More than one built-in value accessor matches form control with"),r=t):(o.isPresent(i)&&_throwError(e,"More than one custom value accessor matches form control with"),i=t)}),o.isPresent(i)?i:o.isPresent(r)?r:o.isPresent(n)?n:(_throwError(e,"No valid value accessor for form control with"),null)}var r=n(47),i=n(88),o=n(32),s=n(54),a=n(169),l=n(170),c=n(587),u=n(266),p=n(172),d=n(173),h=n(174);t.controlPath=controlPath,t.setUpControl=setUpControl,t.setUpFormContainer=setUpFormContainer,t.composeValidators=composeValidators,t.composeAsyncValidators=composeAsyncValidators,t.isPropertyUpdated=isPropertyUpdated,t.selectValueAccessor=selectValueAccessor},function(e,t){"use strict";!function(e){e[e.Get=0]="Get",e[e.Post=1]="Post",e[e.Put=2]="Put",e[e.Delete=3]="Delete",e[e.Options=4]="Options",e[e.Head=5]="Head",e[e.Patch=6]="Patch"}(t.RequestMethod||(t.RequestMethod={}));t.RequestMethod;!function(e){e[e.Unsent=0]="Unsent",e[e.Open=1]="Open",e[e.HeadersReceived=2]="HeadersReceived",e[e.Loading=3]="Loading",e[e.Done=4]="Done",e[e.Cancelled=5]="Cancelled"}(t.ReadyState||(t.ReadyState={}));t.ReadyState;!function(e){e[e.Basic=0]="Basic",e[e.Cors=1]="Cors",e[e.Default=2]="Default",e[e.Error=3]="Error",e[e.Opaque=4]="Opaque"}(t.ResponseType||(t.ResponseType={}));t.ResponseType;!function(e){e[e.NONE=0]="NONE",e[e.JSON=1]="JSON",e[e.FORM=2]="FORM",e[e.FORM_DATA=3]="FORM_DATA",e[e.TEXT=4]="TEXT",e[e.BLOB=5]="BLOB",e[e.ARRAY_BUFFER=6]="ARRAY_BUFFER"}(t.ContentType||(t.ContentType={}));t.ContentType;!function(e){e[e.Text=0]="Text",e[e.Json=1]="Json",e[e.ArrayBuffer=2]="ArrayBuffer",e[e.Blob=3]="Blob"}(t.ResponseContentType||(t.ResponseContentType={}));t.ResponseContentType},[1106,418,419,419],function(e,t,n){"use strict";function createEmptyUrlTree(){return new o(new s([],{}),{},null)}function containsTree(e,t,n){return n?equalSegmentGroups(e.root,t.root):containsSegmentGroup(e.root,t.root)}function equalSegmentGroups(e,t){if(!equalPath(e.segments,t.segments))return!1;if(e.numberOfChildren!==t.numberOfChildren)return!1;for(var n in t.children){if(!e.children[n])return!1;if(!equalSegmentGroups(e.children[n],t.children[n]))return!1}return!0}function containsSegmentGroup(e,t){return containsSegmentGroupHelper(e,t,t.segments)}function containsSegmentGroupHelper(e,t,n){if(e.segments.length>n.length){var i=e.segments.slice(0,n.length);return!!equalPath(i,n)&&!t.hasChildren()}if(e.segments.length===n.length){if(!equalPath(e.segments,n))return!1;for(var o in t.children){if(!e.children[o])return!1;if(!containsSegmentGroup(e.children[o],t.children[o]))return!1}return!0}var i=n.slice(0,e.segments.length),s=n.slice(e.segments.length);return!!equalPath(e.segments,i)&&(!!e.children[r.PRIMARY_OUTLET]&&containsSegmentGroupHelper(e.children[r.PRIMARY_OUTLET],t,s))}function equalSegments(e,t){if(e.length!==t.length)return!1;for(var n=0;n0?n+"("+o.join("//")+")":""+n}if(e.hasChildren()&&!t){var s=mapChildrenIntoArray(e,function(t,n){return n===r.PRIMARY_OUTLET?[serializeSegment(e.children[r.PRIMARY_OUTLET],!1)]:[n+":"+serializeSegment(t,!1)]});return serializePaths(e)+"/("+s.join("//")+")"}return serializePaths(e)}function encode(e){return encodeURIComponent(e)}function decode(e){return decodeURIComponent(e)}function serializePath(e){return""+encode(e.path)+serializeParams(e.parameters)}function serializeParams(e){return pairs(e).map(function(e){return";"+encode(e.first)+"="+encode(e.second)}).join("")}function serializeQueryParams(e){var t=pairs(e).map(function(e){return encode(e.first)+"="+encode(e.second)});return t.length>0?"?"+t.join("&"):""}function pairs(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(new u(n,e[n]));return t}function matchSegments(e){p.lastIndex=0;var t=e.match(p);return t?t[0]:""}function matchQueryParams(e){d.lastIndex=0;var t=e.match(p);return t?t[0]:""}function matchUrlQueryParamValue(e){h.lastIndex=0;var t=e.match(h);return t?t[0]:""}var r=n(63),i=n(74);t.createEmptyUrlTree=createEmptyUrlTree,t.containsTree=containsTree;var o=function(){function UrlTree(e,t,n){this.root=e,this.queryParams=t,this.fragment=n}return UrlTree.prototype.toString=function(){return(new c).serialize(this)},UrlTree}();t.UrlTree=o;var s=function(){function UrlSegmentGroup(e,t){var n=this;this.segments=e,this.children=t,this.parent=null,i.forEach(t,function(e,t){return e.parent=n})}return UrlSegmentGroup.prototype.hasChildren=function(){return this.numberOfChildren>0},Object.defineProperty(UrlSegmentGroup.prototype,"numberOfChildren",{get:function(){return Object.keys(this.children).length},enumerable:!0,configurable:!0}),UrlSegmentGroup.prototype.toString=function(){return serializePaths(this)},UrlSegmentGroup}();t.UrlSegmentGroup=s;var a=function(){function UrlSegment(e,t){this.path=e,this.parameters=t}return UrlSegment.prototype.toString=function(){return serializePath(this)},UrlSegment}();t.UrlSegment=a,t.equalSegments=equalSegments,t.equalPath=equalPath,t.mapChildrenIntoArray=mapChildrenIntoArray;var l=function(){function UrlSerializer(){}return UrlSerializer}();t.UrlSerializer=l;var c=function(){function DefaultUrlSerializer(){}return DefaultUrlSerializer.prototype.parse=function(e){var t=new f(e);return new o(t.parseRootSegment(),t.parseQueryParams(),t.parseFragment())},DefaultUrlSerializer.prototype.serialize=function(e){var t="/"+serializeSegment(e.root,!0),n=serializeQueryParams(e.queryParams),r=null!==e.fragment&&void 0!==e.fragment?"#"+encodeURIComponent(e.fragment):"";return""+t+n+r},DefaultUrlSerializer}();t.DefaultUrlSerializer=c,t.serializePaths=serializePaths,t.encode=encode,t.decode=decode,t.serializePath=serializePath;var u=function(){function Pair(e,t){this.first=e,this.second=t}return Pair}(),p=/^[^\/\(\)\?;=&#]+/,d=/^[^=\?&#]+/,h=/^[^\?&#]+/,f=function(){function UrlParser(e){this.url=e,this.remaining=e}return UrlParser.prototype.peekStartsWith=function(e){return this.remaining.startsWith(e)},UrlParser.prototype.capture=function(e){if(!this.remaining.startsWith(e))throw new Error('Expected "'+e+'".');this.remaining=this.remaining.substring(e.length)},UrlParser.prototype.parseRootSegment=function(){return this.remaining.startsWith("/")&&this.capture("/"),""===this.remaining||this.remaining.startsWith("?")||this.remaining.startsWith("#")?new s([],{}):new s([],this.parseChildren())},UrlParser.prototype.parseChildren=function(){if(0==this.remaining.length)return{};this.peekStartsWith("/")&&this.capture("/");var e=[];for(this.peekStartsWith("(")||e.push(this.parseSegments());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),e.push(this.parseSegments());var t={};this.peekStartsWith("/(")&&(this.capture("/"),t=this.parseParens(!0));var n={};return this.peekStartsWith("(")&&(n=this.parseParens(!1)),(e.length>0||Object.keys(t).length>0)&&(n[r.PRIMARY_OUTLET]=new s(e,t)),n},UrlParser.prototype.parseSegments=function(){var e=matchSegments(this.remaining);if(""===e&&this.peekStartsWith(";"))throw new Error("Empty path url segment cannot have parameters: '"+this.remaining+"'.");this.capture(e);var t={};return this.peekStartsWith(";")&&(t=this.parseMatrixParams()),new a(decode(e),t)},UrlParser.prototype.parseQueryParams=function(){var e={};if(this.peekStartsWith("?"))for(this.capture("?"),this.parseQueryParam(e);this.remaining.length>0&&this.peekStartsWith("&");)this.capture("&"),this.parseQueryParam(e);return e},UrlParser.prototype.parseFragment=function(){return this.peekStartsWith("#")?decode(this.remaining.substring(1)):null},UrlParser.prototype.parseMatrixParams=function(){for(var e={};this.remaining.length>0&&this.peekStartsWith(";");)this.capture(";"),this.parseParam(e);return e},UrlParser.prototype.parseParam=function(e){var t=matchSegments(this.remaining);if(t){this.capture(t);var n="true";if(this.peekStartsWith("=")){this.capture("=");var r=matchSegments(this.remaining);r&&(n=r,this.capture(n))}e[decode(t)]=decode(n)}},UrlParser.prototype.parseQueryParam=function(e){var t=matchQueryParams(this.remaining);if(t){this.capture(t);var n="";if(this.peekStartsWith("=")){this.capture("=");var r=matchUrlQueryParamValue(this.remaining);r&&(n=r,this.capture(n))}e[decode(t)]=decode(n)}},UrlParser.prototype.parseParens=function(e){var t={};for(this.capture("(");!this.peekStartsWith(")")&&this.remaining.length>0;){var n=matchSegments(this.remaining),i=this.remaining[n.length];if("/"!==i&&")"!==i&&";"!==i)throw new Error("Cannot parse url '"+this.url+"'");var o=void 0;n.indexOf(":")>-1?(o=n.substr(0,n.indexOf(":")),this.capture(o),this.capture(":")):e&&(o=r.PRIMARY_OUTLET);var a=this.parseChildren();t[o]=1===Object.keys(a).length?a[r.PRIMARY_OUTLET]:new s([],a),this.peekStartsWith("//")&&this.capture("//")}return this.capture(")"),t},UrlParser}()},function(e,t,n){"use strict";function shallowEqualArrays(e,t){if(e.length!==t.length)return!1;for(var n=0;n0?e[0]:null}function last(e){return e.length>0?e[e.length-1]:null}function and(e){return e.reduce(function(e,t){return e&&t},!0)}function merge(e,t){var n={};for(var r in e)e.hasOwnProperty(r)&&(n[r]=e[r]);for(var r in t)t.hasOwnProperty(r)&&(n[r]=t[r]);return n}function forEach(e,t){for(var n in e)e.hasOwnProperty(n)&&t(e[n],n)}function waitForMap(e,t){var n=[],r={};return forEach(e,function(e,i){i===s.PRIMARY_OUTLET&&n.push(t(i,e).map(function(e){return r[i]=e,e}))}),forEach(e,function(e,i){i!==s.PRIMARY_OUTLET&&n.push(t(i,e).map(function(e){return r[i]=e,e}))}),n.length>0?o.of.apply(void 0,n).concatAll().last().map(function(e){return r}):o.of(r)}function andObservables(e){return e.mergeAll().every(function(e){return e===!0})}function wrapIntoObservable(e){return e instanceof r.Observable?e:e instanceof Promise?i.fromPromise(e):o.of(e)}n(304),n(497);var r=n(1),i=n(211),o=n(141),s=n(63);t.shallowEqualArrays=shallowEqualArrays,t.shallowEqual=shallowEqual,t.flatten=flatten,t.first=first,t.last=last,t.and=and,t.merge=merge,t.forEach=forEach,t.waitForMap=waitForMap,t.andObservables=andObservables,t.wrapIntoObservable=wrapIntoObservable},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(137)("meta"),i=n(15),o=n(48),s=n(30).f,a=0,l=Object.isExtensible||function(){return!0},c=!n(13)(function(){return l(Object.preventExtensions({}))}),u=function(e){s(e,r,{value:{i:"O"+ ++a,w:{}}})},p=function(e,t){if(!i(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!o(e,r)){if(!l(e))return"F";if(!t)return"E";u(e)}return e[r].i},d=function(e,t){if(!o(e,r)){if(!l(e))return!0;if(!t)return!1;u(e)}return e[r].w},h=function(e){return c&&f.NEED&&l(e)&&!o(e,r)&&u(e),e},f=e.exports={KEY:r,NEED:!1,fastKey:p,getWeak:d,onFreeze:h}},function(e,t,n){var r=n(197),i=n(109),o=n(57),s=n(97),a=n(48),l=n(453),c=Object.getOwnPropertyDescriptor;t.f=n(35)?c:function(e,t){if(e=o(e),t=s(t,!0),l)try{return c(e,t)}catch(n){}if(a(e,t))return i(!r.f.call(e,t),e[t])}},function(e,t){e.exports=".vt-row {\n display: flex;\n flex-wrap: wrap;\n height: 100%;\n width: 100%;\n}\n\n.vt-card {\n display: inline-table;\n margin-left: 25px;\n margin-bottom: 10px;\n margin-top: 10px;\n}\n\n.stats-container {\n width: 100%;\n}\n\n.vt-padding{\n padding-left: 25px;\n padding-right: 25px;\n}\n\n>>> p-dialog .ui-dialog{\n position: fixed !important;\n top: 50% !important;\n left: 50% !important;\n transform: translate(-50%, -50%);\n margin: 0;\n width: auto !important;\n}\n\n.vt-popUpContainer{\n position: fixed;\n padding: 0;\n margin: 0;\n z-index: 0;\n bottom: 0;\n right: 0;\n top: 0;\n left: 0;\n min-height: 1000vh;\n min-width: 1000vw;\n height: 100%;\n width: 100%;\n background: rgba(0,0,0,0.6);\n}\n\n.vt-dark-link:link {\n text-decoration: none;\n color: black;\n}\n\n.vt-dark-link:visited {\n text-decoration: none;\n color: black;\n}\n\n.vt-dark-link:hover {\n text-decoration: none;\n color: black;\n}\n\n.vt-dark-link:active {\n text-decoration: none;\n color: black;\n}\n\n/* Toolbar */\n.vt-toolbar {\n width: 100%;\n text-align: center;\n}\n\n>>> p-accordiontab a {\n padding-left: 25px! important;\n}\n\n>>> .ui-accordion-content button {\n margin-top: 2px;\n}\n\n>>> p-menu .ui-menu {\n margin-top: 19px;\n display: inline-block;\n top: auto !important;\n left: auto !important;\n float: right;\n \n}\n\np-menu {\n display: inline-block;\n float: left;\n}\n\n.vt-toolbar .vt-menu {\n padding-top: 19px;\n float: left;\n}\n\n.vt-toolbar .vt-right-menu {\n padding-top: 19px;\n position: fixed;\n right: 25px;\n top: 19px;\n}\n\n.vt-card-toolbar {\n display: inline-block;\n width: 100%;\n}\n\n.vt-card-toolbar .vt-menu {\n float: left;\n}\n.vt-card-toolbar .vt-title {\n float: right;\n margin: 0;\n padding-left: 25px;\n}\n\nmd-list:hover {\n background: #E8E8E8\n}\n"},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(1),o=n(308),s=n(80),a=n(98),l=function(e){function ArrayObservable(t,n){e.call(this),this.array=t,this.scheduler=n,n||1!==t.length||(this._isScalar=!0,this.value=t[0])}return r(ArrayObservable,e),ArrayObservable.create=function(e,t){return new ArrayObservable(e,t)},ArrayObservable.of=function(){for(var e=[],t=0;t1?new ArrayObservable(e,n):1===r?new o.ScalarObservable(e[0],n):new s.EmptyObservable(n)},ArrayObservable.dispatch=function(e){var t=e.array,n=e.index,r=e.count,i=e.subscriber;return n>=r?void i.complete():(i.next(t[n]),void(i.isUnsubscribed||(e.index=n+1,this.schedule(e))))},ArrayObservable.prototype._subscribe=function(e){var t=0,n=this.array,r=n.length,i=this.scheduler;if(i)return i.schedule(ArrayObservable.dispatch,0,{array:n,index:t,count:r,subscriber:e});for(var o=0;o0?" { "+e.children.map(serializeNode).join(", ")+" } ":"";return""+e.value+t}function advanceActivatedRoute(e){e.snapshot?(a.shallowEqual(e.snapshot.queryParams,e._futureSnapshot.queryParams)||e.queryParams.next(e._futureSnapshot.queryParams),e.snapshot.fragment!==e._futureSnapshot.fragment&&e.fragment.next(e._futureSnapshot.fragment),a.shallowEqual(e.snapshot.params,e._futureSnapshot.params)||(e.params.next(e._futureSnapshot.params),e.data.next(e._futureSnapshot.data)),a.shallowEqualArrays(e.snapshot.url,e._futureSnapshot.url)||e.url.next(e._futureSnapshot.url),e.snapshot=e._futureSnapshot):(e.snapshot=e._futureSnapshot,e.data.next(e._futureSnapshot.data))}var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(207),o=n(63),s=n(73),a=n(74),l=n(281),c=function(e){function RouterState(t,n){e.call(this,t),this.snapshot=n,setRouterStateSnapshot(this,t)}return r(RouterState,e),Object.defineProperty(RouterState.prototype,"queryParams",{get:function(){return this.root.queryParams},enumerable:!0,configurable:!0}),Object.defineProperty(RouterState.prototype,"fragment",{get:function(){return this.root.fragment},enumerable:!0,configurable:!0}),RouterState.prototype.toString=function(){return this.snapshot.toString()},RouterState}(l.Tree);t.RouterState=c,t.createEmptyState=createEmptyState;var u=function(){function ActivatedRoute(e,t,n,r,i,o,s,a){this.url=e,this.params=t,this.queryParams=n,this.fragment=r,this.data=i,this.outlet=o,this.component=s,this._futureSnapshot=a}return Object.defineProperty(ActivatedRoute.prototype,"routeConfig",{get:function(){return this._futureSnapshot.routeConfig},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRoute.prototype,"root",{get:function(){return this._routerState.root},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRoute.prototype,"parent",{get:function(){return this._routerState.parent(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRoute.prototype,"firstChild",{get:function(){return this._routerState.firstChild(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRoute.prototype,"children",{get:function(){return this._routerState.children(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRoute.prototype,"pathFromRoot",{get:function(){return this._routerState.pathFromRoot(this)},enumerable:!0,configurable:!0}),ActivatedRoute.prototype.toString=function(){return this.snapshot?this.snapshot.toString():"Future("+this._futureSnapshot+")"},ActivatedRoute}();t.ActivatedRoute=u;var p=function(){function InheritedResolve(e,t){this.parent=e,this.current=t,this.resolvedData={}}return Object.defineProperty(InheritedResolve.prototype,"flattenedResolvedData",{get:function(){return this.parent?a.merge(this.parent.flattenedResolvedData,this.resolvedData):this.resolvedData},enumerable:!0,configurable:!0}),Object.defineProperty(InheritedResolve,"empty",{get:function(){return new InheritedResolve(null,{})},enumerable:!0,configurable:!0}),InheritedResolve}();t.InheritedResolve=p;var d=function(){function ActivatedRouteSnapshot(e,t,n,r,i,o,s,a,l,c,u){this.url=e,this.params=t,this.queryParams=n,this.fragment=r,this.data=i,this.outlet=o,this.component=s,this._routeConfig=a,this._urlSegment=l,this._lastPathIndex=c,this._resolve=u}return Object.defineProperty(ActivatedRouteSnapshot.prototype,"routeConfig",{get:function(){return this._routeConfig},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRouteSnapshot.prototype,"root",{get:function(){return this._routerState.root},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRouteSnapshot.prototype,"parent",{get:function(){return this._routerState.parent(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRouteSnapshot.prototype,"firstChild",{get:function(){return this._routerState.firstChild(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRouteSnapshot.prototype,"children",{get:function(){return this._routerState.children(this)},enumerable:!0,configurable:!0}),Object.defineProperty(ActivatedRouteSnapshot.prototype,"pathFromRoot",{get:function(){return this._routerState.pathFromRoot(this)},enumerable:!0,configurable:!0}),ActivatedRouteSnapshot.prototype.toString=function(){var e=this.url.map(function(e){return e.toString()}).join("/"),t=this._routeConfig?this._routeConfig.path:"";return"Route(url:'"+e+"', path:'"+t+"')"},ActivatedRouteSnapshot}();t.ActivatedRouteSnapshot=d;var h=function(e){function RouterStateSnapshot(t,n){e.call(this,n),this.url=t,setRouterStateSnapshot(this,n)}return r(RouterStateSnapshot,e),Object.defineProperty(RouterStateSnapshot.prototype,"queryParams",{get:function(){return this.root.queryParams},enumerable:!0,configurable:!0}),Object.defineProperty(RouterStateSnapshot.prototype,"fragment",{get:function(){return this.root.fragment},enumerable:!0,configurable:!0}),RouterStateSnapshot.prototype.toString=function(){return serializeNode(this._root)},RouterStateSnapshot}(l.Tree);t.RouterStateSnapshot=h,t.advanceActivatedRoute=advanceActivatedRoute},function(e,t,n){"use strict";var r=n(43),i=(n.n(r),n(0));n.n(i);n.d(t,"a",function(){return a});var o=this&&this.__decorate||function(e,t,n,r){var i,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},s=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},a=function(){function VtctlService(e){this.http=e,this.vtctlUrl="../api/vtctl/"}return VtctlService.prototype.sendPostRequest=function(e,t){var n=new r.Headers({"Content-Type":"application/json"}),i=new r.RequestOptions({headers:n});return this.http.post(e,JSON.stringify(t),i).map(function(e){return e.json()})},VtctlService.prototype.runCommand=function(e){return this.sendPostRequest(this.vtctlUrl,e)},VtctlService=o([n.i(i.Injectable)(),s("design:paramtypes",["function"==typeof(e="undefined"!=typeof r.Http&&r.Http)&&e||Object])],VtctlService);var e}()},function(e,t,n){"use strict";var r=n(192);n.d(t,"a",function(){return i});var i=function(){function DialogContent(e,t,n,r,i){void 0===e&&(e=""),void 0===t&&(t={}),void 0===n&&(n={}),void 0===r&&(r=void 0),void 0===i&&(i=""),this.nameId=e,this.flags=t,this.requiredFlags=n,this.prepareFunction=r,this.action=i}return DialogContent.prototype.getName=function(){return this.flags[this.nameId]?this.flags[this.nameId].getStrValue():""},DialogContent.prototype.setName=function(e){this.flags[this.nameId]&&this.flags[this.nameId].setValue(e)},DialogContent.prototype.getPostBody=function(e){void 0===e&&(e=void 0),e||(e=this.getFlags());var t=[],n=[];t.push(this.action);for(var r=0,i=e;r1?"path: '"+e.path.join(" -> ")+"'":e.path[0]?"name: '"+e.path+"'":"unspecified name",new i.BaseException(t+" "+n)}function composeValidators(e){return o.isPresent(e)?s.Validators.compose(e.map(c.normalizeValidator)):null}function composeAsyncValidators(e){return o.isPresent(e)?s.Validators.composeAsync(e.map(c.normalizeAsyncValidator)):null}function isPropertyUpdated(e,t){if(!r.StringMapWrapper.contains(e,"model"))return!1;var n=e.model;return!!n.isFirstChange()||!o.looseIdentical(t,n.currentValue)}function selectValueAccessor(e,t){if(o.isBlank(t))return null;var n,r,i;return t.forEach(function(t){o.hasConstructor(t,l.DefaultValueAccessor)?n=t:o.hasConstructor(t,a.CheckboxControlValueAccessor)||o.hasConstructor(t,u.NumberValueAccessor)||o.hasConstructor(t,d.SelectControlValueAccessor)||o.hasConstructor(t,h.SelectMultipleControlValueAccessor)||o.hasConstructor(t,p.RadioControlValueAccessor)?(o.isPresent(r)&&_throwError(e,"More than one built-in value accessor matches form control with"),r=t):(o.isPresent(i)&&_throwError(e,"More than one custom value accessor matches form control with"),i=t)}),o.isPresent(i)?i:o.isPresent(r)?r:o.isPresent(n)?n:(_throwError(e,"No valid value accessor for form control with"),null)}var r=n(34),i=n(83),o=n(7),s=n(58),a=n(144),l=n(145),c=n(526),u=n(227),p=n(146),d=n(147),h=n(228);t.controlPath=controlPath,t.setUpControl=setUpControl,t.setUpControlGroup=setUpControlGroup,t.composeValidators=composeValidators,t.composeAsyncValidators=composeAsyncValidators,t.isPropertyUpdated=isPropertyUpdated,t.selectValueAccessor=selectValueAccessor},function(e,t,n){"use strict";var r=n(0),i=n(18),o=n(28),s=function(){function CompilerConfig(e){var t=void 0===e?{}:e,n=t.renderTypes,i=void 0===n?new l:n,o=t.defaultEncapsulation,s=void 0===o?r.ViewEncapsulation.Emulated:o,a=t.genDebugInfo,c=t.logBindingUpdate,u=t.useJit,p=void 0===u||u,d=t.deprecatedPlatformDirectives,h=void 0===d?[]:d,f=t.deprecatedPlatformPipes,m=void 0===f?[]:f;this.renderTypes=i,this.defaultEncapsulation=s,this._genDebugInfo=a,this._logBindingUpdate=c,this.useJit=p,this.platformDirectives=h,this.platformPipes=m}return Object.defineProperty(CompilerConfig.prototype,"genDebugInfo",{get:function(){return void 0===this._genDebugInfo?r.isDevMode():this._genDebugInfo},enumerable:!0,configurable:!0}),Object.defineProperty(CompilerConfig.prototype,"logBindingUpdate",{get:function(){return void 0===this._logBindingUpdate?r.isDevMode():this._logBindingUpdate},enumerable:!0,configurable:!0}),CompilerConfig}();t.CompilerConfig=s;var a=function(){function RenderTypes(){}return Object.defineProperty(RenderTypes.prototype,"renderer",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),Object.defineProperty(RenderTypes.prototype,"renderText",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),Object.defineProperty(RenderTypes.prototype,"renderElement",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),Object.defineProperty(RenderTypes.prototype,"renderComment",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),Object.defineProperty(RenderTypes.prototype,"renderNode",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),Object.defineProperty(RenderTypes.prototype,"renderEvent",{get:function(){return i.unimplemented()},enumerable:!0,configurable:!0}),RenderTypes}();t.RenderTypes=a;var l=function(){function DefaultRenderTypes(){this.renderer=o.Identifiers.Renderer,this.renderText=null,this.renderElement=null,this.renderComment=null,this.renderNode=null,this.renderEvent=null}return DefaultRenderTypes}();t.DefaultRenderTypes=l},function(e,t){"use strict";function splitNsName(e){if(":"!=e[0])return[null,e];var t=e.indexOf(":",1);if(t==-1)throw new Error('Unsupported format "'+e+'" expecting ":namespace:name"');return[e.slice(1,t),e.slice(t+1)]}function getNsPrefix(e){return null===e?null:splitNsName(e)[0]}function mergeNsAndName(e,t){return e?":"+e+":"+t:t}!function(e){e[e.RAW_TEXT=0]="RAW_TEXT",e[e.ESCAPABLE_RAW_TEXT=1]="ESCAPABLE_RAW_TEXT",e[e.PARSABLE_DATA=2]="PARSABLE_DATA"}(t.TagContentType||(t.TagContentType={}));t.TagContentType;t.splitNsName=splitNsName,t.getNsPrefix=getNsPrefix,t.mergeNsAndName=mergeNsAndName,t.NAMED_ENTITIES={Aacute:"Á",aacute:"á",Acirc:"Â",acirc:"â",acute:"´",AElig:"Æ",aelig:"æ",Agrave:"À",agrave:"à",alefsym:"ℵ",Alpha:"Α",alpha:"α",amp:"&",and:"∧",ang:"∠",apos:"'",Aring:"Å",aring:"å",asymp:"≈",Atilde:"Ã",atilde:"ã",Auml:"Ä",auml:"ä",bdquo:"„",Beta:"Β",beta:"β",brvbar:"¦",bull:"•",cap:"∩",Ccedil:"Ç",ccedil:"ç",cedil:"¸",cent:"¢",Chi:"Χ",chi:"χ",circ:"ˆ",clubs:"♣",cong:"≅",copy:"©",crarr:"↵",cup:"∪",curren:"¤",dagger:"†",Dagger:"‡",darr:"↓",dArr:"⇓",deg:"°",Delta:"Δ",delta:"δ",diams:"♦",divide:"÷",Eacute:"É",eacute:"é",Ecirc:"Ê",ecirc:"ê",Egrave:"È",egrave:"è",empty:"∅",emsp:" ",ensp:" ",Epsilon:"Ε",epsilon:"ε",equiv:"≡",Eta:"Η",eta:"η",ETH:"Ð",eth:"ð",Euml:"Ë",euml:"ë",euro:"€",exist:"∃",fnof:"ƒ",forall:"∀",frac12:"½",frac14:"¼",frac34:"¾",frasl:"⁄",Gamma:"Γ",gamma:"γ",ge:"≥",gt:">",harr:"↔",hArr:"⇔",hearts:"♥",hellip:"…",Iacute:"Í",iacute:"í",Icirc:"Î",icirc:"î",iexcl:"¡",Igrave:"Ì",igrave:"ì",image:"ℑ",infin:"∞","int":"∫",Iota:"Ι",iota:"ι",iquest:"¿",isin:"∈",Iuml:"Ï",iuml:"ï",Kappa:"Κ",kappa:"κ",Lambda:"Λ",lambda:"λ",lang:"⟨",laquo:"«",larr:"←",lArr:"⇐",lceil:"⌈",ldquo:"“",le:"≤",lfloor:"⌊",lowast:"∗",loz:"◊",lrm:"‎",lsaquo:"‹",lsquo:"‘",lt:"<",macr:"¯",mdash:"—",micro:"µ",middot:"·",minus:"−",Mu:"Μ",mu:"μ",nabla:"∇",nbsp:" ",ndash:"–",ne:"≠",ni:"∋",not:"¬",notin:"∉",nsub:"⊄",Ntilde:"Ñ",ntilde:"ñ",Nu:"Ν",nu:"ν",Oacute:"Ó",oacute:"ó",Ocirc:"Ô",ocirc:"ô",OElig:"Œ",oelig:"œ",Ograve:"Ò",ograve:"ò",oline:"‾",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",oplus:"⊕",or:"∨",ordf:"ª",ordm:"º",Oslash:"Ø",oslash:"ø",Otilde:"Õ",otilde:"õ",otimes:"⊗",Ouml:"Ö",ouml:"ö",para:"¶",permil:"‰",perp:"⊥",Phi:"Φ",phi:"φ",Pi:"Π",pi:"π",piv:"ϖ",plusmn:"±",pound:"£",prime:"′",Prime:"″",prod:"∏",prop:"∝",Psi:"Ψ",psi:"ψ",quot:'"',radic:"√",rang:"⟩",raquo:"»",rarr:"→",rArr:"⇒",rceil:"⌉",rdquo:"”",real:"ℜ",reg:"®",rfloor:"⌋",Rho:"Ρ",rho:"ρ",rlm:"‏",rsaquo:"›",rsquo:"’",sbquo:"‚",Scaron:"Š",scaron:"š",sdot:"⋅",sect:"§",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sim:"∼",spades:"♠",sub:"⊂",sube:"⊆",sum:"∑",sup:"⊃",sup1:"¹",sup2:"²",sup3:"³",supe:"⊇",szlig:"ß",Tau:"Τ",tau:"τ",there4:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thinsp:" ",THORN:"Þ",thorn:"þ",tilde:"˜",times:"×",trade:"™",Uacute:"Ú",uacute:"ú",uarr:"↑",uArr:"⇑",Ucirc:"Û",ucirc:"û",Ugrave:"Ù",ugrave:"ù",uml:"¨",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",Uuml:"Ü",uuml:"ü",weierp:"℘",Xi:"Ξ",xi:"ξ",Yacute:"Ý",yacute:"ý",yen:"¥",yuml:"ÿ",Yuml:"Ÿ",Zeta:"Ζ",zeta:"ζ",zwj:"‍",zwnj:"‌"}},function(e,t,n){"use strict";function createUrlResolverWithoutPackagePrefix(){return new s}function createOfflineCompileUrlResolver(){return new s(o)}function getUrlScheme(e){var t=_split(e);return t&&t[a.Scheme]||""}function _buildFromEncodedParts(e,t,n,r,o,s,a){var l=[];return i.isPresent(e)&&l.push(e+":"),i.isPresent(n)&&(l.push("//"),i.isPresent(t)&&l.push(t+"@"),l.push(n),i.isPresent(r)&&l.push(":"+r)),i.isPresent(o)&&l.push(o),i.isPresent(s)&&l.push("?"+s),i.isPresent(a)&&l.push("#"+a),l.join("")}function _split(e){return e.match(l)}function _removeDotSegments(e){if("/"==e)return"/";for(var t="/"==e[0]?"/":"",n="/"===e[e.length-1]?"/":"",r=e.split("/"),i=[],o=0,s=0;s0?i.pop():o++;break;default:i.push(a)}}if(""==t){for(;o-- >0;)i.unshift("..");0===i.length&&i.push(".")}return t+i.join("/")+n}function _joinAndCanonicalizePath(e){var t=e[a.Path];return t=i.isBlank(t)?"":_removeDotSegments(t),e[a.Path]=t,_buildFromEncodedParts(e[a.Scheme],e[a.UserInfo],e[a.Domain],e[a.Port],t,e[a.QueryData],e[a.Fragment])}function _resolveUrl(e,t){var n=_split(encodeURI(t)),r=_split(e);if(i.isPresent(n[a.Scheme]))return _joinAndCanonicalizePath(n);n[a.Scheme]=r[a.Scheme];for(var o=a.Scheme;o<=a.Port;o++)i.isBlank(n[o])&&(n[o]=r[o]);if("/"==n[a.Path][0])return _joinAndCanonicalizePath(n);var s=r[a.Path];i.isBlank(s)&&(s="/");var l=s.lastIndexOf("/");return s=s.substring(0,l+1)+n[a.Path],n[a.Path]=s,_joinAndCanonicalizePath(n)}var r=n(0),i=n(5),o="asset:";t.createUrlResolverWithoutPackagePrefix=createUrlResolverWithoutPackagePrefix,t.createOfflineCompileUrlResolver=createOfflineCompileUrlResolver,t.DEFAULT_PACKAGE_URL_PROVIDER={provide:r.PACKAGE_ROOT_URL,useValue:"/"};var s=function(){function UrlResolver(e){void 0===e&&(e=null),this._packagePrefix=e}return UrlResolver.prototype.resolve=function(e,t){var n=t;i.isPresent(e)&&e.length>0&&(n=_resolveUrl(e,n));var r=_split(n),s=this._packagePrefix;if(i.isPresent(s)&&i.isPresent(r)&&"package"==r[a.Scheme]){var l=r[a.Path];if(this._packagePrefix!==o)return s=i.StringWrapper.stripRight(s,"/"),l=i.StringWrapper.stripLeft(l,"/"),s+"/"+l;var c=l.split(/\//);n="asset:"+c[0]+"/lib/"+c.slice(1).join("/")}return n},UrlResolver.decorators=[{type:r.Injectable}],UrlResolver.ctorParameters=[{type:void 0,decorators:[{type:r.Inject,args:[r.PACKAGE_ROOT_URL]}]}],UrlResolver}();t.UrlResolver=s,t.getUrlScheme=getUrlScheme;var a,l=new RegExp("^(?:([^:/?#.]+):)?(?://(?:([^/?#]*)@)?([\\w\\d\\-\\u0100-\\uffff.%]*)(?::([0-9]+))?)?([^?#]+)?(?:\\?([^#]*))?(?:#(.*))?$");!function(e){e[e.Scheme=1]="Scheme",e[e.UserInfo=2]="UserInfo",e[e.Domain=3]="Domain",e[e.Port=4]="Port",e[e.Path=5]="Path",e[e.QueryData=6]="QueryData",e[e.Fragment=7]="Fragment"}(a||(a={}))},function(e,t,n){"use strict";function _enumExpression(e,t){if(s.isBlank(t))return l.NULL_EXPR;var n=s.resolveEnumToken(e.runtime,t);return l.importExpr(new o.CompileIdentifierMetadata({name:e.name+"."+n,moduleUrl:e.moduleUrl,runtime:t}))}var r=n(0),i=n(27),o=n(31),s=n(5),a=n(28),l=n(17),c=function(){function ViewTypeEnum(){}return ViewTypeEnum.fromValue=function(e){return _enumExpression(a.Identifiers.ViewType,e)},ViewTypeEnum.HOST=ViewTypeEnum.fromValue(i.ViewType.HOST),ViewTypeEnum.COMPONENT=ViewTypeEnum.fromValue(i.ViewType.COMPONENT),ViewTypeEnum.EMBEDDED=ViewTypeEnum.fromValue(i.ViewType.EMBEDDED),ViewTypeEnum}();t.ViewTypeEnum=c;var u=function(){function ViewEncapsulationEnum(){}return ViewEncapsulationEnum.fromValue=function(e){return _enumExpression(a.Identifiers.ViewEncapsulation,e)},ViewEncapsulationEnum.Emulated=ViewEncapsulationEnum.fromValue(r.ViewEncapsulation.Emulated),ViewEncapsulationEnum.Native=ViewEncapsulationEnum.fromValue(r.ViewEncapsulation.Native),ViewEncapsulationEnum.None=ViewEncapsulationEnum.fromValue(r.ViewEncapsulation.None),ViewEncapsulationEnum}();t.ViewEncapsulationEnum=u;var p=function(){function ChangeDetectionStrategyEnum(){}return ChangeDetectionStrategyEnum.fromValue=function(e){return _enumExpression(a.Identifiers.ChangeDetectionStrategy,e)},ChangeDetectionStrategyEnum.OnPush=ChangeDetectionStrategyEnum.fromValue(r.ChangeDetectionStrategy.OnPush),ChangeDetectionStrategyEnum.Default=ChangeDetectionStrategyEnum.fromValue(r.ChangeDetectionStrategy.Default),ChangeDetectionStrategyEnum}();t.ChangeDetectionStrategyEnum=p;var d=function(){function ChangeDetectorStatusEnum(){}return ChangeDetectorStatusEnum.fromValue=function(e){return _enumExpression(a.Identifiers.ChangeDetectorStatus,e)},ChangeDetectorStatusEnum.CheckOnce=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.CheckOnce),ChangeDetectorStatusEnum.Checked=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.Checked),ChangeDetectorStatusEnum.CheckAlways=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.CheckAlways),ChangeDetectorStatusEnum.Detached=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.Detached),ChangeDetectorStatusEnum.Errored=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.Errored),ChangeDetectorStatusEnum.Destroyed=ChangeDetectorStatusEnum.fromValue(i.ChangeDetectorStatus.Destroyed),ChangeDetectorStatusEnum}();t.ChangeDetectorStatusEnum=d;var h=function(){function ViewConstructorVars(){}return ViewConstructorVars.viewUtils=l.variable("viewUtils"),ViewConstructorVars.parentInjector=l.variable("parentInjector"),ViewConstructorVars.declarationEl=l.variable("declarationEl"),ViewConstructorVars}();t.ViewConstructorVars=h;var f=function(){function ViewProperties(){}return ViewProperties.renderer=l.THIS_EXPR.prop("renderer"),ViewProperties.projectableNodes=l.THIS_EXPR.prop("projectableNodes"),ViewProperties.viewUtils=l.THIS_EXPR.prop("viewUtils"),ViewProperties}();t.ViewProperties=f;var m=function(){function EventHandlerVars(){}return EventHandlerVars.event=l.variable("$event"),EventHandlerVars}();t.EventHandlerVars=m;var y=function(){function InjectMethodVars(){}return InjectMethodVars.token=l.variable("token"),InjectMethodVars.requestNodeIndex=l.variable("requestNodeIndex"),InjectMethodVars.notFoundResult=l.variable("notFoundResult"),InjectMethodVars}();t.InjectMethodVars=y;var v=function(){function DetectChangesVars(){}return DetectChangesVars.throwOnChange=l.variable("throwOnChange"),DetectChangesVars.changes=l.variable("changes"),DetectChangesVars.changed=l.variable("changed"),DetectChangesVars.valUnwrapper=l.variable("valUnwrapper"),DetectChangesVars}();t.DetectChangesVars=v},99,function(e,t,n){var r=n(95);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){var r=n(8),i=n(462),o=n(288),s=n(300)("IE_PROTO"),a=function(){},l="prototype",c=function(){var e,t=n(451)("iframe"),r=o.length,i="<",s=">";for(t.style.display="none",n(452).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write(i+"script"+s+"document.F=Object"+i+"/script"+s),e.close(),c=e.F;r--;)delete c[l][o[r]];return c()};e.exports=Object.create||function(e,t){var n;return null!==e?(a[l]=r(e),n=new a,a[l]=null,n[s]=e):n=c(),void 0===t?n:i(n,t)}},function(e,t,n){var r=n(464),i=n(288);e.exports=Object.keys||function(e){return r(e,i)}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){"use strict";function multicast(e){var t;return t="function"==typeof e?e:function(){return e},new r.ConnectableObservable(this,t)}var r=n(502);t.multicast=multicast},[1107,219],function(e,t){"use strict";var n=function(){function ElementSchemaRegistry(){}return ElementSchemaRegistry}();t.ElementSchemaRegistry=n},function(e,t,n){"use strict";function getPropertyInView(e,t,n){if(t===n)return e;for(var o=s.THIS_EXPR,a=t;a!==n&&i.isPresent(a.declarationElement.view);)a=a.declarationElement.view,o=o.prop("parent");if(a!==n)throw new r.BaseException("Internal error: Could not calculate a property in a parent view: "+e);if(e instanceof s.ReadPropExpr){var l=e;(n.fields.some(function(e){return e.name==l.name})||n.getters.some(function(e){return e.name==l.name}))&&(o=o.cast(n.classType))}return s.replaceVarInExpression(s.THIS_EXPR.name,o,e)}function injectFromViewParentInjector(e,t){var n=[a.createDiTokenExpression(e)];return t&&n.push(s.NULL_EXPR),s.THIS_EXPR.prop("parentInjector").callMethod("get",n)}function getViewFactoryName(e,t){return"viewFactory_"+e.type.name+t}function createFlatArray(e){for(var t=[],n=s.literalArr([]),r=0;r0&&(n=n.callMethod(s.BuiltinMethod.ConcatArray,[s.literalArr(t)]),t=[]),n=n.callMethod(s.BuiltinMethod.ConcatArray,[i])):t.push(i)}return t.length>0&&(n=n.callMethod(s.BuiltinMethod.ConcatArray,[s.literalArr(t)])),n}function createPureProxy(e,t,n,a){a.fields.push(new s.ClassField(n.name,null));var l=t0){var r=e.substring(0,n),i=e.substring(n+1).trim();t.set(r,i)}}),t},Headers.prototype.append=function(e,t){e=normalize(e);var n=this._headersMap.get(e),i=r.isListLikeIterable(n)?n:[];i.push(t),this._headersMap.set(e,i)},Headers.prototype.delete=function(e){this._headersMap.delete(normalize(e))},Headers.prototype.forEach=function(e){this._headersMap.forEach(e)},Headers.prototype.get=function(e){return r.ListWrapper.first(this._headersMap.get(normalize(e)))},Headers.prototype.has=function(e){return this._headersMap.has(normalize(e))},Headers.prototype.keys=function(){return r.MapWrapper.keys(this._headersMap)},Headers.prototype.set=function(e,t){var n=[];if(r.isListLikeIterable(t)){var i=t.join(",");n.push(i)}else n.push(t);this._headersMap.set(normalize(e),n)},Headers.prototype.values=function(){return r.MapWrapper.values(this._headersMap)},Headers.prototype.toJSON=function(){var e={};return this._headersMap.forEach(function(t,n){var i=[];r.iterateListLike(t,function(e){return i=r.ListWrapper.concat(i,e.split(","))}),e[normalize(n)]=i}),e},Headers.prototype.getAll=function(e){var t=this._headersMap.get(normalize(e));return r.isListLikeIterable(t)?t:[]},Headers.prototype.entries=function(){throw new i.BaseException('"entries" method is not implemented on Headers class')},Headers}();t.Headers=s},function(e,t){"use strict";var n=function(){function ConnectionBackend(){}return ConnectionBackend}();t.ConnectionBackend=n;var r=function(){function Connection(){}return Connection}();t.Connection=r;var i=function(){function XSRFStrategy(){}return XSRFStrategy}();t.XSRFStrategy=i},function(e,t,n){"use strict";var r=n(0);t.RenderDebugInfo=r.__core_private__.RenderDebugInfo,t.wtfInit=r.__core_private__.wtfInit,t.ReflectionCapabilities=r.__core_private__.ReflectionCapabilities,t.VIEW_ENCAPSULATION_VALUES=r.__core_private__.VIEW_ENCAPSULATION_VALUES,t.DebugDomRootRenderer=r.__core_private__.DebugDomRootRenderer,t.reflector=r.__core_private__.reflector,t.NoOpAnimationPlayer=r.__core_private__.NoOpAnimationPlayer,t.AnimationPlayer=r.__core_private__.AnimationPlayer,t.AnimationSequencePlayer=r.__core_private__.AnimationSequencePlayer,t.AnimationGroupPlayer=r.__core_private__.AnimationGroupPlayer,t.AnimationKeyframe=r.__core_private__.AnimationKeyframe,t.AnimationStyles=r.__core_private__.AnimationStyles,t.prepareFinalAnimationStyles=r.__core_private__.prepareFinalAnimationStyles,t.balanceAnimationKeyframes=r.__core_private__.balanceAnimationKeyframes,t.flattenStyles=r.__core_private__.flattenStyles,t.clearStyles=r.__core_private__.clearStyles,t.collectAndResolveStyles=r.__core_private__.collectAndResolveStyles},function(e,t,n){"use strict";var r=n(0);t.DOCUMENT=new r.OpaqueToken("DocumentToken")},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(0),o=n(33),s=n(16),a=n(62),l=n(55),c=function(){function ClientMessageBrokerFactory(){}return ClientMessageBrokerFactory}();t.ClientMessageBrokerFactory=c;var u=function(e){function ClientMessageBrokerFactory_(t,n){e.call(this),this._messageBus=t,this._serializer=n}return r(ClientMessageBrokerFactory_,e),ClientMessageBrokerFactory_.prototype.createMessageBroker=function(e,t){return void 0===t&&(t=!0),this._messageBus.initChannel(e,t),new d(this._messageBus,this._serializer,e)},ClientMessageBrokerFactory_.decorators=[{type:i.Injectable}],ClientMessageBrokerFactory_.ctorParameters=[{type:a.MessageBus},{type:l.Serializer}],ClientMessageBrokerFactory_}(c);t.ClientMessageBrokerFactory_=u;var p=function(){function ClientMessageBroker(){}return ClientMessageBroker}();t.ClientMessageBroker=p;var d=function(e){function ClientMessageBroker_(t,n,r){var i=this;e.call(this),this.channel=r,this._pending=new Map,this._sink=t.to(r),this._serializer=n;var o=t.from(r);o.subscribe({next:function(e){return i._handleMessage(e)}})}return r(ClientMessageBroker_,e),ClientMessageBroker_.prototype._generateMessageId=function(e){for(var t=s.stringify(s.DateWrapper.toMillis(s.DateWrapper.now())),n=0,r=e+t+s.stringify(n);s.isPresent(this._pending[r]);)r=""+e+t+n,n++;return r},ClientMessageBroker_.prototype.runOnService=function(e,t){var n=this,r=[];s.isPresent(e.args)&&e.args.forEach(function(e){null!=e.type?r.push(n._serializer.serialize(e.value,e.type)):r.push(e.value)});var i,o=null;if(null!=t){var a;i=new Promise(function(e,t){a={resolve:e,reject:t}}),o=this._generateMessageId(e.method),this._pending.set(o,a),i.catch(function(e){s.print(e),a.reject(e)}),i=i.then(function(e){return null==n._serializer?e:n._serializer.deserialize(e,t)})}else i=null;var l={method:e.method,args:r};return null!=o&&(l.id=o),this._sink.emit(l),i},ClientMessageBroker_.prototype._handleMessage=function(e){var t=new h(e);if(s.StringWrapper.equals(t.type,"result")||s.StringWrapper.equals(t.type,"error")){var n=t.id;this._pending.has(n)&&(s.StringWrapper.equals(t.type,"result")?this._pending.get(n).resolve(t.value):this._pending.get(n).reject(t.value),this._pending.delete(n))}},ClientMessageBroker_}(p);t.ClientMessageBroker_=d;var h=function(){function MessageData(e){this.type=o.StringMapWrapper.get(e,"type"),this.id=this._getValueIfPresent(e,"id"),this.value=this._getValueIfPresent(e,"value")}return MessageData.prototype._getValueIfPresent=function(e,t){return o.StringMapWrapper.contains(e,t)?o.StringMapWrapper.get(e,t):null},MessageData}(),f=function(){function FnArg(e,t){this.value=e,this.type=t}return FnArg}();t.FnArg=f;var m=function(){function UiArguments(e,t){this.method=e,this.args=t}return UiArguments}();t.UiArguments=m},function(e,t,n){"use strict";var r=n(0),i=function(){function RenderStore(){this._nextIndex=0,this._lookupById=new Map,this._lookupByObject=new Map}return RenderStore.prototype.allocateId=function(){return this._nextIndex++},RenderStore.prototype.store=function(e,t){this._lookupById.set(t,e),this._lookupByObject.set(e,t)},RenderStore.prototype.remove=function(e){var t=this._lookupByObject.get(e);this._lookupByObject.delete(e),this._lookupById.delete(t)},RenderStore.prototype.deserialize=function(e){return null==e?null:this._lookupById.has(e)?this._lookupById.get(e):null},RenderStore.prototype.serialize=function(e){return null==e?null:this._lookupByObject.get(e)},RenderStore.decorators=[{type:r.Injectable}],RenderStore.ctorParameters=[],RenderStore}();t.RenderStore=i},function(e,t,n){"use strict";var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(0),o=n(33),s=n(16),a=n(62),l=n(55),c=function(){function ServiceMessageBrokerFactory(){}return ServiceMessageBrokerFactory}();t.ServiceMessageBrokerFactory=c;var u=function(e){function ServiceMessageBrokerFactory_(t,n){e.call(this),this._messageBus=t,this._serializer=n}return r(ServiceMessageBrokerFactory_,e),ServiceMessageBrokerFactory_.prototype.createMessageBroker=function(e,t){return void 0===t&&(t=!0),this._messageBus.initChannel(e,t),new d(this._messageBus,this._serializer,e)},ServiceMessageBrokerFactory_.decorators=[{type:i.Injectable}],ServiceMessageBrokerFactory_.ctorParameters=[{type:a.MessageBus},{type:l.Serializer}],ServiceMessageBrokerFactory_}(c);t.ServiceMessageBrokerFactory_=u;var p=function(){function ServiceMessageBroker(){}return ServiceMessageBroker}();t.ServiceMessageBroker=p;var d=function(e){function ServiceMessageBroker_(t,n,r){var i=this;e.call(this),this._serializer=n,this.channel=r,this._methods=new o.Map,this._sink=t.to(r);var s=t.from(r);s.subscribe({next:function(e){return i._handleMessage(e)}})}return r(ServiceMessageBroker_,e),ServiceMessageBroker_.prototype.registerMethod=function(e,t,n,r){var i=this;this._methods.set(e,function(e){for(var a=e.args,l=null===t?0:t.length,c=o.ListWrapper.createFixedSize(l),u=0;u0?n[n.length-1]._routeConfig._loadedConfig:null}function nodeChildrenAsMap(e){return e?e.children.reduce(function(e,t){return e[t.value.outlet]=t,e},{}):{}}function getOutlet(e,t){var n=e._outlets[t.outlet];if(!n){var r=t.component.name;throw t.outlet===y.PRIMARY_OUTLET?new Error("Cannot find primary outlet to load '"+r+"'"):new Error("Cannot find the outlet "+t.outlet+" to load '"+r+"'")}return n}n(140),n(499),n(305),n(500),n(493);var r=n(0),i=n(20),o=n(309),s=n(141),a=n(623),l=n(624),c=n(625),u=n(626),p=n(627),d=n(628),h=n(187),f=n(129),m=n(91),y=n(63),v=n(73),g=n(74),b=function(){function NavigationStart(e,t){this.id=e,this.url=t}return NavigationStart.prototype.toString=function(){return"NavigationStart(id: "+this.id+", url: '"+this.url+"')"},NavigationStart}();t.NavigationStart=b;var _=function(){function NavigationEnd(e,t,n){this.id=e,this.url=t,this.urlAfterRedirects=n}return NavigationEnd.prototype.toString=function(){return"NavigationEnd(id: "+this.id+", url: '"+this.url+"', urlAfterRedirects: '"+this.urlAfterRedirects+"')"},NavigationEnd}();t.NavigationEnd=_;var S=function(){function NavigationCancel(e,t){this.id=e,this.url=t}return NavigationCancel.prototype.toString=function(){return"NavigationCancel(id: "+this.id+", url: '"+this.url+"')"},NavigationCancel}();t.NavigationCancel=S;var w=function(){function NavigationError(e,t,n){this.id=e,this.url=t,this.error=n}return NavigationError.prototype.toString=function(){return"NavigationError(id: "+this.id+", url: '"+this.url+"', error: "+this.error+")"},NavigationError}();t.NavigationError=w;var C=function(){function RoutesRecognized(e,t,n,r){this.id=e,this.url=t,this.urlAfterRedirects=n,this.state=r}return RoutesRecognized.prototype.toString=function(){return"RoutesRecognized(id: "+this.id+", url: '"+this.url+"', urlAfterRedirects: '"+this.urlAfterRedirects+"', state: "+this.state+")"},RoutesRecognized}();t.RoutesRecognized=C;var E=function(){function Router(e,t,n,r,o,s,a,l){this.rootComponentType=e,this.resolver=t,this.urlSerializer=n,this.outletMap=r,this.location=o,this.injector=s,this.navigationId=0,this.navigated=!1,this.resetConfig(l),this.routerEvents=new i.Subject,this.currentUrlTree=v.createEmptyUrlTree(),this.configLoader=new h.RouterConfigLoader(a),this.currentRouterState=m.createEmptyState(this.currentUrlTree,this.rootComponentType)}return Router.prototype.initialNavigation=function(){this.setUpLocationChangeListener(),this.navigateByUrl(this.location.path(!0))},Object.defineProperty(Router.prototype,"routerState",{get:function(){return this.currentRouterState},enumerable:!0,configurable:!0}),Object.defineProperty(Router.prototype,"url",{get:function(){return this.serializeUrl(this.currentUrlTree)},enumerable:!0,configurable:!0}),Object.defineProperty(Router.prototype,"events",{get:function(){return this.routerEvents},enumerable:!0,configurable:!0}),Router.prototype.resetConfig=function(e){l.validateConfig(e),this.config=e},Router.prototype.ngOnDestroy=function(){this.dispose()},Router.prototype.dispose=function(){this.locationSubscription.unsubscribe()},Router.prototype.createUrlTree=function(e,t){var n=void 0===t?{}:t,r=n.relativeTo,i=n.queryParams,o=n.fragment,s=n.preserveQueryParams,a=n.preserveFragment,l=r?r:this.routerState.root,c=s?this.currentUrlTree.queryParams:i,p=a?this.currentUrlTree.fragment:o;return u.createUrlTree(l,this.currentUrlTree,e,c,p)},Router.prototype.navigateByUrl=function(e,t){if(void 0===t&&(t={skipLocationChange:!1}),e instanceof v.UrlTree)return this.scheduleNavigation(e,t);var n=this.urlSerializer.parse(e);return this.scheduleNavigation(n,t)},Router.prototype.navigate=function(e,t){return void 0===t&&(t={skipLocationChange:!1}),this.scheduleNavigation(this.createUrlTree(e,t),t)},Router.prototype.serializeUrl=function(e){return this.urlSerializer.serialize(e)},Router.prototype.parseUrl=function(e){return this.urlSerializer.parse(e)},Router.prototype.isActive=function(e,t){if(e instanceof v.UrlTree)return v.containsTree(this.currentUrlTree,e,t);var n=this.urlSerializer.parse(e);return v.containsTree(this.currentUrlTree,n,t)},Router.prototype.scheduleNavigation=function(e,t){var n=this,r=++this.navigationId;return this.routerEvents.next(new b(r,this.serializeUrl(e))),Promise.resolve().then(function(i){return n.runNavigate(e,t.skipLocationChange,r)})},Router.prototype.setUpLocationChangeListener=function(){var e=this;this.locationSubscription=this.location.subscribe(Zone.current.wrap(function(t){var n=e.urlSerializer.parse(t.url);return e.currentUrlTree.toString()!==n.toString()?e.scheduleNavigation(n,t.pop):null}))},Router.prototype.runNavigate=function(e,t,n){var r=this;return n!==this.navigationId?(this.location.go(this.urlSerializer.serialize(this.currentUrlTree)),this.routerEvents.next(new S(n,this.serializeUrl(e))),Promise.resolve(!1)):new Promise(function(i,o){var l,u,h,f,m=r.currentRouterState,y=r.currentUrlTree;a.applyRedirects(r.injector,r.configLoader,e,r.config).mergeMap(function(e){return f=e,p.recognize(r.rootComponentType,r.config,f,r.serializeUrl(f))}).mergeMap(function(t){return r.routerEvents.next(new C(n,r.serializeUrl(e),r.serializeUrl(f),t)),d.resolve(r.resolver,t)}).map(function(e){return c.createRouterState(e,r.currentRouterState)}).map(function(e){l=e,h=new P(l.snapshot,r.currentRouterState.snapshot,r.injector),h.traverse(r.outletMap)}).mergeMap(function(e){return h.checkGuards()}).mergeMap(function(e){return e?h.resolveData().map(function(){return e}):s.of(e)}).forEach(function(i){if(!i||n!==r.navigationId)return r.routerEvents.next(new S(n,r.serializeUrl(e))),void(u=!1);if(r.currentUrlTree=f,r.currentRouterState=l,new x(l,m).activate(r.outletMap),!t){var o=r.urlSerializer.serialize(f);r.location.isCurrentPathEqualTo(o)?r.location.replaceState(o):r.location.go(o)}u=!0}).then(function(){r.navigated=!0,r.routerEvents.next(new _(n,r.serializeUrl(e),r.serializeUrl(f))),i(u)},function(t){r.currentRouterState=m,r.currentUrlTree=y,r.routerEvents.next(new w(n,r.serializeUrl(e),t)),o(t)})})},Router}();t.Router=E;var T=function(){function CanActivate(e){this.path=e}return Object.defineProperty(CanActivate.prototype,"route",{get:function(){return this.path[this.path.length-1]},enumerable:!0,configurable:!0}),CanActivate}(),R=function(){function CanDeactivate(e,t){this.component=e,this.route=t}return CanDeactivate}(),P=function(){function PreActivation(e,t,n){this.future=e,this.curr=t,this.injector=n,this.checks=[]}return PreActivation.prototype.traverse=function(e){var t=this.future._root,n=this.curr?this.curr._root:null;this.traverseChildRoutes(t,n,e,[t.value])},PreActivation.prototype.checkGuards=function(){var e=this;return 0===this.checks.length?s.of(!0):o.from(this.checks).map(function(t){if(t instanceof T)return g.andObservables(o.from([e.runCanActivate(t.route),e.runCanActivateChild(t.path)]));if(t instanceof R){var n=t;return e.runCanDeactivate(n.component,n.route)}throw new Error("Cannot be reached")}).mergeAll().every(function(e){return e===!0})},PreActivation.prototype.resolveData=function(){var e=this;return 0===this.checks.length?s.of(null):o.from(this.checks).mergeMap(function(t){return t instanceof T?e.runResolve(t.route):s.of(null)}).reduce(function(e,t){return e})},PreActivation.prototype.traverseChildRoutes=function(e,t,n,r){var i=this,o=nodeChildrenAsMap(t);e.children.forEach(function(e){i.traverseRoutes(e,o[e.value.outlet],n,r.concat([e.value])),delete o[e.value.outlet]}),g.forEach(o,function(e,t){return i.deactivateOutletAndItChildren(e,n._outlets[t])})},PreActivation.prototype.traverseRoutes=function(e,t,n,r){var i=e.value,o=t?t.value:null,s=n?n._outlets[e.value.outlet]:null;o&&i._routeConfig===o._routeConfig?(g.shallowEqual(i.params,o.params)||this.checks.push(new R(s.component,o),new T(r)),i.component?this.traverseChildRoutes(e,t,s?s.outletMap:null,r):this.traverseChildRoutes(e,t,n,r)):(o&&(o.component?this.deactivateOutletAndItChildren(o,s):this.deactivateOutletMap(n)),this.checks.push(new T(r)),i.component?this.traverseChildRoutes(e,null,s?s.outletMap:null,r):this.traverseChildRoutes(e,null,n,r))},PreActivation.prototype.deactivateOutletAndItChildren=function(e,t){t&&t.isActivated&&(this.deactivateOutletMap(t.outletMap),this.checks.push(new R(t.component,e)))},PreActivation.prototype.deactivateOutletMap=function(e){var t=this;g.forEach(e._outlets,function(e){e.isActivated&&t.deactivateOutletAndItChildren(e.activatedRoute.snapshot,e)})},PreActivation.prototype.runCanActivate=function(e){var t=this,n=e._routeConfig?e._routeConfig.canActivate:null;if(!n||0===n.length)return s.of(!0);var r=o.from(n).map(function(n){var r=t.getToken(n,e,t.future);return r.canActivate?g.wrapIntoObservable(r.canActivate(e,t.future)):g.wrapIntoObservable(r(e,t.future))});return g.andObservables(r)},PreActivation.prototype.runCanActivateChild=function(e){var t=this,n=e[e.length-1],r=e.slice(0,e.length-1).reverse().map(function(e){return t.extractCanActivateChild(e)}).filter(function(e){return null!==e});return g.andObservables(o.from(r).map(function(e){var r=o.from(e.guards).map(function(e){var r=t.getToken(e,e.node,t.future);return r.canActivateChild?g.wrapIntoObservable(r.canActivateChild(n,t.future)):g.wrapIntoObservable(r(n,t.future))});return g.andObservables(r)}))},PreActivation.prototype.extractCanActivateChild=function(e){var t=e._routeConfig?e._routeConfig.canActivateChild:null;return t&&0!==t.length?{node:e,guards:t}:null},PreActivation.prototype.runCanDeactivate=function(e,t){var n=this,r=t&&t._routeConfig?t._routeConfig.canDeactivate:null;return r&&0!==r.length?o.from(r).map(function(r){var i=n.getToken(r,t,n.curr);return i.canDeactivate?g.wrapIntoObservable(i.canDeactivate(e,t,n.curr)):g.wrapIntoObservable(i(e,t,n.curr))}).mergeAll().every(function(e){return e===!0}):s.of(!0)},PreActivation.prototype.runResolve=function(e){var t=e._resolve;return this.resolveNode(t.current,e).map(function(n){return t.resolvedData=n,e.data=g.merge(e.data,t.flattenedResolvedData),null})},PreActivation.prototype.resolveNode=function(e,t){var n=this;return g.waitForMap(e,function(e,r){var i=n.getToken(r,t,n.future);return i.resolve?g.wrapIntoObservable(i.resolve(t,n.future)):g.wrapIntoObservable(i(t,n.future))})},PreActivation.prototype.getToken=function(e,t,n){var r=closestLoadedConfig(n,t),i=r?r.injector:this.injector;return i.get(e)},PreActivation}(),x=function(){function ActivateRoutes(e,t){this.futureState=e,this.currState=t}return ActivateRoutes.prototype.activate=function(e){var t=this.futureState._root,n=this.currState?this.currState._root:null;m.advanceActivatedRoute(this.futureState.root),this.activateChildRoutes(t,n,e)},ActivateRoutes.prototype.activateChildRoutes=function(e,t,n){var r=this,i=nodeChildrenAsMap(t);e.children.forEach(function(e){r.activateRoutes(e,i[e.value.outlet],n),delete i[e.value.outlet]}),g.forEach(i,function(e,t){return r.deactivateOutletAndItChildren(n._outlets[t])})},ActivateRoutes.prototype.activateRoutes=function(e,t,n){ -var r=e.value,i=t?t.value:null;if(r===i)if(m.advanceActivatedRoute(r),r.component){var o=getOutlet(n,e.value);this.activateChildRoutes(e,t,o.outletMap)}else this.activateChildRoutes(e,t,n);else{if(i)if(i.component){var o=getOutlet(n,e.value);this.deactivateOutletAndItChildren(o)}else this.deactivateOutletMap(n);if(r.component){m.advanceActivatedRoute(r);var o=getOutlet(n,e.value),s=new f.RouterOutletMap;this.placeComponentIntoOutlet(s,r,o),this.activateChildRoutes(e,null,s)}else m.advanceActivatedRoute(r),this.activateChildRoutes(e,null,n)}},ActivateRoutes.prototype.placeComponentIntoOutlet=function(e,t,n){var i=[{provide:m.ActivatedRoute,useValue:t},{provide:f.RouterOutletMap,useValue:e}],o=closestLoadedConfig(this.futureState.snapshot,t.snapshot),s=null,a=null;o&&(s=o.factoryResolver,a=o.injector,i.push({provide:r.ComponentFactoryResolver,useValue:s})),n.activate(t,s,a,r.ReflectiveInjector.resolve(i),e)},ActivateRoutes.prototype.deactivateOutletAndItChildren=function(e){e&&e.isActivated&&(this.deactivateOutletMap(e.outletMap),e.deactivate())},ActivateRoutes.prototype.deactivateOutletMap=function(e){var t=this;g.forEach(e._outlets,function(e){return t.deactivateOutletAndItChildren(e)})},ActivateRoutes}()},function(e,t){"use strict";var n=function(){function RouterOutletMap(){this._outlets={}}return RouterOutletMap.prototype.registerOutlet=function(e,t){this._outlets[e]=t},RouterOutletMap.prototype.removeOutlet=function(e){this._outlets[e]=void 0},RouterOutletMap}();t.RouterOutletMap=n},function(e,t,n){"use strict";var r=n(43),i=(n.n(r),n(0));n.n(i);n.d(t,"a",function(){return a});var o=this&&this.__decorate||function(e,t,n,r){var i,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},s=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},a=function(){function FeaturesService(e){var t=this;this.http=e,this.activeReparents=!1,this.showStatus=!1,this.showTopologyCRUD=!1,this.showWorkflows=!1,this.workflows=[],this.featuresUrl="../api/features",this.getFeatures().subscribe(function(e){t.activeReparents=e.activeReparents,t.showStatus=e.showStatus,t.showTopologyCRUD=e.showTopologyCRUD,t.showWorkflows=e.showWorkflows,t.workflows=e.workflows})}return FeaturesService.prototype.getFeatures=function(){return this.http.get(this.featuresUrl).map(function(e){return e.json()})},FeaturesService=o([n.i(i.Injectable)(),s("design:paramtypes",["function"==typeof(e="undefined"!=typeof r.Http&&r.Http)&&e||Object])],FeaturesService);var e}()},function(e,t,n){"use strict";var r=n(43),i=(n.n(r),n(0)),o=(n.n(i),n(484)),s=(n.n(o),n(283)),a=n(644),l=n(284);n.d(t,"a",function(){return p});var c=this&&this.__decorate||function(e,t,n,r){var i,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,n,r);else for(var a=e.length-1;a>=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},u=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},p=function(){function KeyspaceService(e,t){this.http=e,this.shardService=t,this.keyspacesUrl="../api/keyspaces/",this.srvKeyspaceUrl="../api/srv_keyspace/local/"}return KeyspaceService.prototype.getShards=function(e){return this.shardService.getShards(e)},KeyspaceService.prototype.getKeyspaceNames=function(){return this.http.get(this.keyspacesUrl).map(function(e){return e.json()})},KeyspaceService.prototype.getSrvKeyspaces=function(){return this.http.get(this.srvKeyspaceUrl).map(function(e){return e.json()})},KeyspaceService.prototype.SrvKeyspaceAndNamesObservable=function(){var e=this.getKeyspaceNames(),t=this.getSrvKeyspaces();return e.combineLatest(t)},KeyspaceService.prototype.getKeyspaceShardingData=function(e){return this.http.get(this.keyspacesUrl+e).map(function(e){return e.json()})},KeyspaceService.prototype.getShardsAndShardingData=function(e){var t=this.getShards(e),n=this.getKeyspaceShardingData(e);return t.combineLatest(n)},KeyspaceService.prototype.buildKeyspace=function(e,t){return this.getShardsAndShardingData(e).map(function(n){var r=n[0],i=n[1],o=new a.a(e);return t.forEach(function(e){return o.addServingShard(e)}),r.forEach(function(e){o.contains(e)||o.addNonservingShard(e)}),o.shardingColumnName=i.sharding_column_name||"",o.shardingColumnType=i.sharding_column_type||"",o})},KeyspaceService.prototype.getServingShards=function(e,t){if(t&&t[e]){var n=t[e].partitions;if(void 0===n)return[];for(var r=0;r=0;a--)(i=e[a])&&(s=(o<3?i(s):o>3?i(t,n,s):i(t,n))||s);return o>3&&s&&Object.defineProperty(t,n,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},o=n(0),s=n(9),a=n(3),l=function(){function Button(e,t){this.el=e,this.domHandler=t,this.iconPos="left"}return Button.prototype.ngAfterViewInit=function(){if(this.domHandler.addMultipleClasses(this.el.nativeElement,this.getStyleClass()),this.icon){var e=document.createElement("span"),t="right"==this.iconPos?"ui-button-icon-right":"ui-button-icon-left";e.className=t+" ui-c fa fa-fw "+this.icon,this.el.nativeElement.appendChild(e)}var n=document.createElement("span");n.className="ui-button-text ui-c",n.appendChild(document.createTextNode(this.label||"ui-button")),this.el.nativeElement.appendChild(n),this.initialized=!0},Button.prototype.onMouseenter=function(e){this.hover=!0},Button.prototype.onMouseleave=function(e){this.hover=!1,this.active=!1},Button.prototype.onMouseDown=function(e){this.active=!0},Button.prototype.onMouseUp=function(e){this.active=!1},Button.prototype.onFocus=function(e){this.focus=!0},Button.prototype.onBlur=function(e){this.focus=!1},Button.prototype.isDisabled=function(){return this.el.nativeElement.disabled},Button.prototype.getStyleClass=function(){var e="ui-button ui-widget ui-state-default ui-corner-all";return e+=this.icon?null!=this.label&&void 0!=this.label?"left"==this.iconPos?" ui-button-text-icon-left":" ui-button-text-icon-right":" ui-button-icon-only":" ui-button-text-only"},Object.defineProperty(Button.prototype,"label",{get:function(){return this._label},set:function(e){this._label=e,this.initialized&&(this.domHandler.findSingle(this.el.nativeElement,".ui-button-text").textContent=this._label)},enumerable:!0,configurable:!0}),Button.prototype.ngOnDestroy=function(){for(;this.el.nativeElement.hasChildNodes();)this.el.nativeElement.removeChild(this.el.nativeElement.lastChild);this.initialized=!1},r([o.Input(),i("design:type",String)],Button.prototype,"icon",void 0),r([o.Input(),i("design:type",String)],Button.prototype,"iconPos",void 0),r([o.HostListener("mouseenter",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onMouseenter",null),r([o.HostListener("mouseleave",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onMouseleave",null),r([o.HostListener("mousedown",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onMouseDown",null),r([o.HostListener("mouseup",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onMouseUp",null),r([o.HostListener("focus",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onFocus",null),r([o.HostListener("blur",["$event"]),i("design:type",Function),i("design:paramtypes",[Object]),i("design:returntype",void 0)],Button.prototype,"onBlur",null),r([o.Input(),i("design:type",String)],Button.prototype,"label",null),Button=r([o.Directive({selector:"[pButton]",host:{"[class.ui-state-hover]":"hover&&!isDisabled()","[class.ui-state-focus]":"focus","[class.ui-state-active]":"active","[class.ui-state-disabled]":"isDisabled()"},providers:[s.DomHandler]}),i("design:paramtypes",[o.ElementRef,s.DomHandler])],Button)}();t.Button=l;var c=function(){function ButtonModule(){}return ButtonModule=r([o.NgModule({imports:[a.CommonModule],exports:[l],declarations:[l]}),i("design:paramtypes",[])],ButtonModule)}();t.ButtonModule=c},function(e,t,n){"use strict";var r=n(1),i=n(505);r.Observable.prototype.map=i.map},function(e,t,n){"use strict";var r=n(79);t.of=r.ArrayObservable.of},function(e,t,n){"use strict";var r=n(51),i=r.root.Symbol;if("function"==typeof i)i.iterator?t.$$iterator=i.iterator:"function"==typeof i.for&&(t.$$iterator=i.for("iterator"));else if(r.root.Set&&"function"==typeof(new r.root.Set)["@@iterator"])t.$$iterator="@@iterator";else if(r.root.Map)for(var o=Object.getOwnPropertyNames(r.root.Map.prototype),s=0;s=this.length?i.$EOF:o.StringWrapper.charCodeAt(this.input,this.index)},_Scanner.prototype.scanToken=function(){for(var e=this.input,t=this.length,n=this.peek,r=this.index;n<=i.$SPACE;){if(++r>=t){n=i.$EOF;break}n=o.StringWrapper.charCodeAt(e,r)}if(this.peek=n,this.index=r,r>=t)return null;if(isIdentifierStart(n))return this.scanIdentifier();if(i.isDigit(n))return this.scanNumber(r);var s=r;switch(n){case i.$PERIOD:return this.advance(),i.isDigit(this.peek)?this.scanNumber(s):newCharacterToken(s,i.$PERIOD);case i.$LPAREN:case i.$RPAREN:case i.$LBRACE:case i.$RBRACE:case i.$LBRACKET:case i.$RBRACKET:case i.$COMMA:case i.$COLON:case i.$SEMICOLON:return this.scanCharacter(s,n);case i.$SQ:case i.$DQ:return this.scanString();case i.$HASH:case i.$PLUS:case i.$MINUS:case i.$STAR:case i.$SLASH:case i.$PERCENT:case i.$CARET:return this.scanOperator(s,o.StringWrapper.fromCharCode(n));case i.$QUESTION:return this.scanComplexOperator(s,"?",i.$PERIOD,".");case i.$LT:case i.$GT:return this.scanComplexOperator(s,o.StringWrapper.fromCharCode(n),i.$EQ,"=");case i.$BANG:case i.$EQ:return this.scanComplexOperator(s,o.StringWrapper.fromCharCode(n),i.$EQ,"=",i.$EQ,"=");case i.$AMPERSAND:return this.scanComplexOperator(s,"&",i.$AMPERSAND,"&");case i.$BAR:return this.scanComplexOperator(s,"|",i.$BAR,"|");case i.$NBSP:for(;i.isWhitespace(this.peek);)this.advance();return this.scanToken()}return this.advance(),this.error("Unexpected character ["+o.StringWrapper.fromCharCode(n)+"]",0)},_Scanner.prototype.scanCharacter=function(e,t){return this.advance(),newCharacterToken(e,t)},_Scanner.prototype.scanOperator=function(e,t){return this.advance(),newOperatorToken(e,t)},_Scanner.prototype.scanComplexOperator=function(e,t,n,r,i,s){this.advance();var a=t;return this.peek==n&&(this.advance(),a+=r),o.isPresent(i)&&this.peek==i&&(this.advance(),a+=s),newOperatorToken(e,a)},_Scanner.prototype.scanIdentifier=function(){var e=this.index;for(this.advance();isIdentifierPart(this.peek);)this.advance();var t=this.input.substring(e,this.index);return a.indexOf(t)>-1?newKeywordToken(e,t):newIdentifierToken(e,t)},_Scanner.prototype.scanNumber=function(e){var t=this.index===e;for(this.advance();;){if(i.isDigit(this.peek));else if(this.peek==i.$PERIOD)t=!1;else{if(!isExponentStart(this.peek))break;if(this.advance(),isExponentSign(this.peek)&&this.advance(),!i.isDigit(this.peek))return this.error("Invalid exponent",-1);t=!1}this.advance()}var n=this.input.substring(e,this.index),r=t?o.NumberWrapper.parseIntAutoRadix(n):o.NumberWrapper.parseFloat(n);return newNumberToken(e,r)},_Scanner.prototype.scanString=function(){var e=this.index,t=this.peek;this.advance();for(var n,r=this.index,s=this.input;this.peek!=t;)if(this.peek==i.$BACKSLASH){null==n&&(n=new o.StringJoiner),n.add(s.substring(r,this.index)),this.advance();var a;if(this.peek==i.$u){var l=s.substring(this.index+1,this.index+5);try{a=o.NumberWrapper.parseInt(l,16)}catch(c){return this.error("Invalid unicode escape [\\u"+l+"]",0)}for(var u=0;u<5;u++)this.advance()}else a=unescape(this.peek),this.advance();n.add(o.StringWrapper.fromCharCode(a)),r=this.index}else{if(this.peek==i.$EOF)return this.error("Unterminated quote",0);this.advance()}var p=s.substring(r,this.index);this.advance();var d=p;return null!=n&&(n.add(p),d=n.toString()),newStringToken(e,d)},_Scanner.prototype.error=function(e,t){var n=this.index+t;return newErrorToken(n,"Lexer Error: "+e+" at column "+n+" in expression ["+this.input+"]")},_Scanner}();t.isIdentifier=isIdentifier,t.isQuote=isQuote},function(e,t,n){"use strict";function _createInterpolateRegExp(e){var t=o.escapeRegExp(e.start)+"([\\s\\S]*?)"+o.escapeRegExp(e.end);return new RegExp(t,"g")}var r=n(0),i=n(233),o=n(5),s=n(68),a=n(236),l=n(151),c=function(){function SplitInterpolation(e,t){this.strings=e,this.expressions=t}return SplitInterpolation}();t.SplitInterpolation=c;var u=function(){function TemplateBindingParseResult(e,t,n){this.templateBindings=e,this.warnings=t,this.errors=n}return TemplateBindingParseResult}();t.TemplateBindingParseResult=u;var p=function(){function Parser(e){this._lexer=e,this.errors=[]}return Parser.prototype.parseAction=function(e,t,n){void 0===n&&(n=s.DEFAULT_INTERPOLATION_CONFIG),this._checkNoInterpolation(e,t,n);var r=this._lexer.tokenize(this._stripComments(e)),i=new d(e,t,r,(!0),this.errors).parseChain();return new a.ASTWithSource(i,e,t,this.errors)},Parser.prototype.parseBinding=function(e,t,n){void 0===n&&(n=s.DEFAULT_INTERPOLATION_CONFIG);var r=this._parseBindingAst(e,t,n);return new a.ASTWithSource(r,e,t,this.errors)},Parser.prototype.parseSimpleBinding=function(e,t,n){void 0===n&&(n=s.DEFAULT_INTERPOLATION_CONFIG);var r=this._parseBindingAst(e,t,n);return h.check(r)||this._reportError("Host binding expression can only contain field access and constants",e,t),new a.ASTWithSource(r,e,t,this.errors)},Parser.prototype._reportError=function(e,t,n,r){this.errors.push(new a.ParserError(e,t,n,r))},Parser.prototype._parseBindingAst=function(e,t,n){var r=this._parseQuote(e,t);if(o.isPresent(r))return r;this._checkNoInterpolation(e,t,n);var i=this._lexer.tokenize(this._stripComments(e));return new d(e,t,i,(!1),this.errors).parseChain()},Parser.prototype._parseQuote=function(e,t){if(o.isBlank(e))return null;var n=e.indexOf(":");if(n==-1)return null;var r=e.substring(0,n).trim();if(!l.isIdentifier(r))return null;var i=e.substring(n+1);return new a.Quote(new a.ParseSpan(0,e.length),r,i,t)},Parser.prototype.parseTemplateBindings=function(e,t){var n=this._lexer.tokenize(e);return new d(e,t,n,(!1),this.errors).parseTemplateBindings()},Parser.prototype.parseInterpolation=function(e,t,n){void 0===n&&(n=s.DEFAULT_INTERPOLATION_CONFIG);var r=this.splitInterpolation(e,t,n);if(null==r)return null;for(var i=[],l=0;l0?l.push(p):this._reportError("Blank expressions are not allowed in interpolated strings",e,"at column "+this._findInterpolationErrorColumn(i,u,n)+" in",t)}return new c(a,l)},Parser.prototype.wrapLiteralPrimitive=function(e,t){return new a.ASTWithSource(new a.LiteralPrimitive(new a.ParseSpan(0,o.isBlank(e)?0:e.length),e),e,t,this.errors)},Parser.prototype._stripComments=function(e){var t=this._commentStart(e);return o.isPresent(t)?e.substring(0,t).trim():e},Parser.prototype._commentStart=function(e){for(var t=null,n=0;n1&&this._reportError("Got interpolation ("+n.start+n.end+") where expression was expected",e,"at column "+this._findInterpolationErrorColumn(i,1,n)+" in",t)},Parser.prototype._findInterpolationErrorColumn=function(e,t,n){for(var r="",i=0;i":case"<=":case">=":this.advance();var n=this.parseAdditive();e=new a.Binary(this.span(e.span.start),t,e,n);continue}break}return e},_ParseAST.prototype.parseAdditive=function(){for(var e=this.parseMultiplicative();this.next.type==l.TokenType.Operator;){var t=this.next.strValue;switch(t){case"+":case"-":this.advance();var n=this.parseMultiplicative();e=new a.Binary(this.span(e.span.start),t,e,n);continue}break}return e},_ParseAST.prototype.parseMultiplicative=function(){for(var e=this.parsePrefix();this.next.type==l.TokenType.Operator;){var t=this.next.strValue;switch(t){case"*":case"%":case"/":this.advance();var n=this.parsePrefix();e=new a.Binary(this.span(e.span.start),t,e,n);continue}break}return e},_ParseAST.prototype.parsePrefix=function(){if(this.next.type==l.TokenType.Operator){var e=this.inputIndex,t=this.next.strValue,n=void 0;switch(t){case"+":return this.advance(),this.parsePrefix();case"-":return this.advance(),n=this.parsePrefix(),new a.Binary(this.span(e),t,new a.LiteralPrimitive(new a.ParseSpan(e,e),0),n);case"!":return this.advance(),n=this.parsePrefix(),new a.PrefixNot(this.span(e),n)}}return this.parseCallChain()},_ParseAST.prototype.parseCallChain=function(){for(var e=this.parsePrimary();;)if(this.optionalCharacter(i.$PERIOD))e=this.parseAccessMemberOrMethodCall(e,!1);else if(this.optionalOperator("?."))e=this.parseAccessMemberOrMethodCall(e,!0);else if(this.optionalCharacter(i.$LBRACKET)){this.rbracketsExpected++;var t=this.parsePipe();if(this.rbracketsExpected--,this.expectCharacter(i.$RBRACKET),this.optionalOperator("=")){var n=this.parseConditional();e=new a.KeyedWrite(this.span(e.span.start),e,t,n)}else e=new a.KeyedRead(this.span(e.span.start),e,t)}else{if(!this.optionalCharacter(i.$LPAREN))return e;this.rparensExpected++;var r=this.parseCallArguments();this.rparensExpected--,this.expectCharacter(i.$RPAREN),e=new a.FunctionCall(this.span(e.span.start),e,r)}},_ParseAST.prototype.parsePrimary=function(){var e=this.inputIndex;if(this.optionalCharacter(i.$LPAREN)){this.rparensExpected++;var t=this.parsePipe();return this.rparensExpected--,this.expectCharacter(i.$RPAREN),t}if(this.next.isKeywordNull())return this.advance(),new a.LiteralPrimitive(this.span(e),null);if(this.next.isKeywordUndefined())return this.advance(),new a.LiteralPrimitive(this.span(e),(void 0));if(this.next.isKeywordTrue())return this.advance(),new a.LiteralPrimitive(this.span(e),(!0));if(this.next.isKeywordFalse())return this.advance(),new a.LiteralPrimitive(this.span(e),(!1));if(this.next.isKeywordThis())return this.advance(),new a.ImplicitReceiver(this.span(e));if(this.optionalCharacter(i.$LBRACKET)){this.rbracketsExpected++;var n=this.parseExpressionList(i.$RBRACKET);return this.rbracketsExpected--,this.expectCharacter(i.$RBRACKET),new a.LiteralArray(this.span(e),n)}if(this.next.isCharacter(i.$LBRACE))return this.parseLiteralMap();if(this.next.isIdentifier())return this.parseAccessMemberOrMethodCall(new a.ImplicitReceiver(this.span(e)),!1);if(this.next.isNumber()){var r=this.next.toNumber();return this.advance(),new a.LiteralPrimitive(this.span(e),r)}if(this.next.isString()){var o=this.next.toString();return this.advance(),new a.LiteralPrimitive(this.span(e),o)}return this.index>=this.tokens.length?(this.error("Unexpected end of expression: "+this.input),new a.EmptyExpr(this.span(e))):(this.error("Unexpected token "+this.next),new a.EmptyExpr(this.span(e)))},_ParseAST.prototype.parseExpressionList=function(e){var t=[];if(!this.next.isCharacter(e))do t.push(this.parsePipe());while(this.optionalCharacter(i.$COMMA));return t},_ParseAST.prototype.parseLiteralMap=function(){var e=[],t=[],n=this.inputIndex;if(this.expectCharacter(i.$LBRACE),!this.optionalCharacter(i.$RBRACE)){this.rbracesExpected++;do{var r=this.expectIdentifierOrKeywordOrString();e.push(r),this.expectCharacter(i.$COLON),t.push(this.parsePipe())}while(this.optionalCharacter(i.$COMMA));this.rbracesExpected--,this.expectCharacter(i.$RBRACE)}return new a.LiteralMap(this.span(n),e,t)},_ParseAST.prototype.parseAccessMemberOrMethodCall=function(e,t){void 0===t&&(t=!1);var n=e.span.start,r=this.expectIdentifierOrKeyword();if(this.optionalCharacter(i.$LPAREN)){this.rparensExpected++;var o=this.parseCallArguments();this.expectCharacter(i.$RPAREN),this.rparensExpected--;var s=this.span(n);return t?new a.SafeMethodCall(s,e,r,o):new a.MethodCall(s,e,r,o)}if(t)return this.optionalOperator("=")?(this.error("The '?.' operator cannot be used in the assignment"),new a.EmptyExpr(this.span(n))):new a.SafePropertyRead(this.span(n),e,r);if(this.optionalOperator("=")){if(!this.parseAction)return this.error("Bindings cannot contain assignments"),new a.EmptyExpr(this.span(n));var l=this.parseConditional();return new a.PropertyWrite(this.span(n),e,r,l)}return new a.PropertyRead(this.span(n),e,r)},_ParseAST.prototype.parseCallArguments=function(){if(this.next.isCharacter(i.$RPAREN))return[];var e=[];do e.push(this.parsePipe());while(this.optionalCharacter(i.$COMMA));return e},_ParseAST.prototype.expectTemplateBindingKey=function(){var e="",t=!1;do e+=this.expectIdentifierOrKeywordOrString(),t=this.optionalOperator("-"),t&&(e+="-");while(t);return e.toString()},_ParseAST.prototype.parseTemplateBindings=function(){for(var e=[],t=null,n=[];this.index0&&e[e.length-1]===t}var r=this&&this.__extends||function(e,t){function __(){this.constructor=e}for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);e.prototype=null===t?Object.create(t):(__.prototype=t.prototype,new __)},i=n(10),o=n(5),s=n(60),a=n(85),l=n(68),c=n(546),u=n(102),p=function(e){function TreeError(t,n,r){e.call(this,n,r),this.elementName=t}return r(TreeError,e),TreeError.create=function(e,t,n){return new TreeError(e,t,n)},TreeError}(s.ParseError);t.TreeError=p;var d=function(){function ParseTreeResult(e,t){this.rootNodes=e,this.errors=t}return ParseTreeResult}();t.ParseTreeResult=d;var h=function(){function Parser(e){this._getTagDefinition=e}return Parser.prototype.parse=function(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r=l.DEFAULT_INTERPOLATION_CONFIG);var i=c.tokenize(e,t,this._getTagDefinition,n,r),o=new f(i.tokens,this._getTagDefinition).build();return new d(o.rootNodes,i.errors.concat(o.errors))},Parser}();t.Parser=h;var f=function(){function _TreeBuilder(e,t){this.tokens=e,this.getTagDefinition=t,this._index=-1,this._rootNodes=[],this._errors=[],this._elementStack=[],this._advance()}return _TreeBuilder.prototype.build=function(){for(;this._peek.type!==c.TokenType.EOF;)this._peek.type===c.TokenType.TAG_OPEN_START?this._consumeStartTag(this._advance()):this._peek.type===c.TokenType.TAG_CLOSE?this._consumeEndTag(this._advance()):this._peek.type===c.TokenType.CDATA_START?(this._closeVoidElement(),this._consumeCdata(this._advance())):this._peek.type===c.TokenType.COMMENT_START?(this._closeVoidElement(),this._consumeComment(this._advance())):this._peek.type===c.TokenType.TEXT||this._peek.type===c.TokenType.RAW_TEXT||this._peek.type===c.TokenType.ESCAPABLE_RAW_TEXT?(this._closeVoidElement(),this._consumeText(this._advance())):this._peek.type===c.TokenType.EXPANSION_FORM_START?this._consumeExpansion(this._advance()):this._advance();return new d(this._rootNodes,this._errors)},_TreeBuilder.prototype._advance=function(){var e=this._peek;return this._index0)return this._errors=this._errors.concat(i.errors),null;var l=new s.ParseSourceSpan(e.sourceSpan.start,r.sourceSpan.end),u=new s.ParseSourceSpan(t.sourceSpan.start,r.sourceSpan.end);return new a.ExpansionCase(e.parts[0],i.rootNodes,l,e.sourceSpan,u)},_TreeBuilder.prototype._collectExpansionExpTokens=function(e){for(var t=[],n=[c.TokenType.EXPANSION_CASE_EXP_START];;){if(this._peek.type!==c.TokenType.EXPANSION_FORM_START&&this._peek.type!==c.TokenType.EXPANSION_CASE_EXP_START||n.push(this._peek.type),this._peek.type===c.TokenType.EXPANSION_CASE_EXP_END){if(!lastOnStack(n,c.TokenType.EXPANSION_CASE_EXP_START))return this._errors.push(p.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;if(n.pop(),0==n.length)return t}if(this._peek.type===c.TokenType.EXPANSION_FORM_END){if(!lastOnStack(n,c.TokenType.EXPANSION_FORM_START))return this._errors.push(p.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;n.pop()}if(this._peek.type===c.TokenType.EOF)return this._errors.push(p.create(null,e.sourceSpan,"Invalid ICU message. Missing '}'.")),null;t.push(this._advance())}},_TreeBuilder.prototype._consumeText=function(e){var t=e.parts[0];if(t.length>0&&"\n"==t[0]){var n=this._getParentElement();o.isPresent(n)&&0==n.children.length&&this.getTagDefinition(n.name).ignoreFirstLf&&(t=t.substring(1))}t.length>0&&this._addToParent(new a.Text(t,e.sourceSpan))},_TreeBuilder.prototype._closeVoidElement=function(){if(this._elementStack.length>0){var e=i.ListWrapper.last(this._elementStack);this.getTagDefinition(e.name).isVoid&&this._elementStack.pop()}},_TreeBuilder.prototype._consumeStartTag=function(e){for(var t=e.parts[0],n=e.parts[1],r=[];this._peek.type===c.TokenType.ATTR_NAME;)r.push(this._consumeAttr(this._advance()));var i=this._getElementFullName(t,n,this._getParentElement()),o=!1;if(this._peek.type===c.TokenType.TAG_OPEN_END_VOID){this._advance(),o=!0;var l=this.getTagDefinition(i);l.canSelfClose||null!==u.getNsPrefix(i)||l.isVoid||this._errors.push(p.create(i,e.sourceSpan,'Only void and foreign elements can be self closed "'+e.parts[1]+'"'))}else this._peek.type===c.TokenType.TAG_OPEN_END&&(this._advance(),o=!1);var d=this._peek.sourceSpan.start,h=new s.ParseSourceSpan(e.sourceSpan.start,d),f=new a.Element(i,r,[],h,h,null);this._pushElement(f),o&&(this._popElement(i),f.endSourceSpan=h)},_TreeBuilder.prototype._pushElement=function(e){if(this._elementStack.length>0){var t=i.ListWrapper.last(this._elementStack);this.getTagDefinition(t.name).isClosedByChild(e.name)&&this._elementStack.pop()}var n=this.getTagDefinition(e.name),r=this._getParentElementSkippingContainers(),s=r.parent,l=r.container;if(o.isPresent(s)&&n.requireExtraParent(s.name)){var c=new a.Element(n.parentToAdd,[],[],e.sourceSpan,e.startSourceSpan,e.endSourceSpan);this._insertBeforeContainer(s,l,c)}this._addToParent(e),this._elementStack.push(e)},_TreeBuilder.prototype._consumeEndTag=function(e){var t=this._getElementFullName(e.parts[0],e.parts[1],this._getParentElement());this._getParentElement()&&(this._getParentElement().endSourceSpan=e.sourceSpan),this.getTagDefinition(t).isVoid?this._errors.push(p.create(t,e.sourceSpan,'Void elements do not have end tags "'+e.parts[1]+'"')):this._popElement(t)||this._errors.push(p.create(t,e.sourceSpan,'Unexpected closing tag "'+e.parts[1]+'"'))},_TreeBuilder.prototype._popElement=function(e){for(var t=this._elementStack.length-1;t>=0;t--){var n=this._elementStack[t];if(n.name==e)return i.ListWrapper.splice(this._elementStack,t,this._elementStack.length-t),!0;if(!this.getTagDefinition(n.name).closedByParent)return!1}return!1},_TreeBuilder.prototype._consumeAttr=function(e){var t=u.mergeNsAndName(e.parts[0],e.parts[1]),n=e.sourceSpan.end,r="";if(this._peek.type===c.TokenType.ATTR_VALUE){var i=this._advance();r=i.parts[0],n=i.sourceSpan.end}return new a.Attribute(t,r,new s.ParseSourceSpan(e.sourceSpan.start,n))},_TreeBuilder.prototype._getParentElement=function(){return this._elementStack.length>0?i.ListWrapper.last(this._elementStack):null},_TreeBuilder.prototype._getParentElementSkippingContainers=function(){for(var e=null,t=this._elementStack.length-1;t>=0;t--){if("ng-container"!==this._elementStack[t].name)return{parent:this._elementStack[t],container:e};e=this._elementStack[t]}return{parent:i.ListWrapper.last(this._elementStack),container:e}},_TreeBuilder.prototype._addToParent=function(e){var t=this._getParentElement();o.isPresent(t)?t.children.push(e):this._rootNodes.push(e)},_TreeBuilder.prototype._insertBeforeContainer=function(e,t,n){if(t){if(e){var r=e.children.indexOf(t);e.children[r]=n}else this._rootNodes.push(n);n.children.push(t),this._elementStack.splice(this._elementStack.indexOf(t),0,n)}else this._addToParent(n),this._elementStack.push(n)},_TreeBuilder.prototype._getElementFullName=function(e,t,n){return o.isBlank(e)&&(e=this.getTagDefinition(t).implicitNamespacePrefix,o.isBlank(e)&&o.isPresent(n)&&(e=u.getNsPrefix(n.name))),u.mergeNsAndName(e,t)},_TreeBuilder}()},function(e,t,n){"use strict";function splitClasses(e){return e.trim().split(/\s+/g)}function createElementCssSelector(e,t){var n=new S.CssSelector,r=v.splitNsName(e)[1];n.setElement(r);for(var i=0;i0&&this._console.warn("Template parse warnings:\n"+a.join("\n")),l.length>0){var c=l.join("\n");throw new u.BaseException("Template parse errors:\n"+c)}return s.templateAst},TemplateParser.prototype.tryParse=function(e,t,n,r,i,o){var a;e.template&&(a=y.InterpolationConfig.fromArray(e.template.interpolation));var l,c=this._htmlParser.parse(t,o,!0,a),u=c.errors;if(0==u.length){var d=m.expandNodes(c.rootNodes);u.push.apply(u,d.errors),c=new f.ParseTreeResult(d.nodes,u)}if(c.rootNodes.length>0){var v=s.removeIdentifierDuplicates(n),g=s.removeIdentifierDuplicates(r),_=new b.ProviderViewContext(e,c.rootNodes[0].sourceSpan),S=new j(_,v,g,i,this._exprParser,this._schemaRegistry);l=h.visitAll(S,c.rootNodes,z),u.push.apply(u,S.errors.concat(_.errors))}else l=[];return this._assertNoReferenceDuplicationOnTemplate(l,u),u.length>0?new L(l,u):(p.isPresent(this.transforms)&&this.transforms.forEach(function(e){l=E.templateVisitAll(e,l)}),new L(l,u))},TemplateParser.prototype._assertNoReferenceDuplicationOnTemplate=function(e,t){var n=[];e.filter(function(e){return!!e.references}).forEach(function(e){return e.references.forEach(function(e){var r=e.name;if(n.indexOf(r)<0)n.push(r);else{var i=new V('Reference "#'+r+'" is defined several times',e.sourceSpan,g.ParseErrorLevel.FATAL);t.push(i)}})})},TemplateParser.decorators=[{type:i.Injectable}],TemplateParser.ctorParameters=[{type:l.Parser},{type:_.ElementSchemaRegistry},{type:f.HtmlParser},{type:o.Console},{type:Array,decorators:[{type:i.Optional},{type:i.Inject,args:[t.TEMPLATE_TRANSFORMS]}]}],TemplateParser}();t.TemplateParser=F;var j=function(){function TemplateParseVisitor(e,t,n,r,i,o){var s=this;this.providerViewContext=e,this._schemas=r,this._exprParser=i,this._schemaRegistry=o,this.errors=[],this.directivesIndex=new Map,this.ngContentCount=0,this.selectorMatcher=new S.SelectorMatcher;var a=e.component.template;p.isPresent(a)&&p.isPresent(a.interpolation)&&(this._interpolationConfig={start:a.interpolation[0],end:a.interpolation[1]}),c.ListWrapper.forEachWithIndex(t,function(e,t){var n=S.CssSelector.parse(e.selector);s.selectorMatcher.addSelectables(n,e),s.directivesIndex.set(e,t)}),this.pipesByName=new Map,n.forEach(function(e){return s.pipesByName.set(e.name,e)})}return TemplateParseVisitor.prototype._reportError=function(e,t,n){void 0===n&&(n=g.ParseErrorLevel.FATAL),this.errors.push(new V(e,t,n))},TemplateParseVisitor.prototype._reportParserErors=function(e,t){for(var n=0,r=e;no.MAX_INTERPOLATION_VALUES)throw new u.BaseException("Only support at most "+o.MAX_INTERPOLATION_VALUES+" interpolation values!");return r}catch(i){return this._reportError(""+i,t),this._exprParser.wrapLiteralPrimitive("ERROR",n)}},TemplateParseVisitor.prototype._parseAction=function(e,t){var n=t.start.toString();try{var r=this._exprParser.parseAction(e,n,this._interpolationConfig);return r&&this._reportParserErors(r.errors,t),!r||r.ast instanceof a.EmptyExpr?(this._reportError("Empty expressions are not allowed",t),this._exprParser.wrapLiteralPrimitive("ERROR",n)):(this._checkPipes(r,t),r)}catch(i){return this._reportError(""+i,t),this._exprParser.wrapLiteralPrimitive("ERROR",n)}},TemplateParseVisitor.prototype._parseBinding=function(e,t){var n=t.start.toString();try{var r=this._exprParser.parseBinding(e,n,this._interpolationConfig);return r&&this._reportParserErors(r.errors,t),this._checkPipes(r,t),r}catch(i){return this._reportError(""+i,t),this._exprParser.wrapLiteralPrimitive("ERROR",n)}},TemplateParseVisitor.prototype._parseTemplateBindings=function(e,t){var n=this,r=t.start.toString();try{var i=this._exprParser.parseTemplateBindings(e,r);return this._reportParserErors(i.errors,t),i.templateBindings.forEach(function(e){p.isPresent(e.expression)&&n._checkPipes(e.expression,t)}),i.warnings.forEach(function(e){n._reportError(e,t,g.ParseErrorLevel.WARNING)}),i.templateBindings}catch(o){return this._reportError(""+o,t),[]}},TemplateParseVisitor.prototype._checkPipes=function(e,t){var n=this;if(p.isPresent(e)){var r=new q;e.visit(r),r.pipes.forEach(function(e){n.pipesByName.has(e)||n._reportError("The pipe '"+e+"' could not be found",t)})}},TemplateParseVisitor.prototype.visitExpansion=function(e,t){return null},TemplateParseVisitor.prototype.visitExpansionCase=function(e,t){return null},TemplateParseVisitor.prototype.visitText=function(e,t){var n=t.findNgContentIndex(N),r=this._parseInterpolation(e.value,e.sourceSpan);return p.isPresent(r)?new E.BoundTextAst(r,n,e.sourceSpan):new E.TextAst(e.value,n,e.sourceSpan)},TemplateParseVisitor.prototype.visitAttribute=function(e,t){return new E.AttrAst(e.name,e.value,e.sourceSpan)},TemplateParseVisitor.prototype.visitComment=function(e,t){return null},TemplateParseVisitor.prototype.visitElement=function(e,t){var n=this,r=e.name,i=T.preparseElement(e);if(i.type===T.PreparsedElementType.SCRIPT||i.type===T.PreparsedElementType.STYLE)return null;if(i.type===T.PreparsedElementType.STYLESHEET&&w.isStyleUrlResolvable(i.hrefAttr))return null;var o=[],s=[],a=[],l=[],c=[],u=[],d=[],f=[],m=[],y=!1,g=[],_=v.splitNsName(r.toLowerCase())[1],C=_==P;e.attrs.forEach(function(e){var t=n._parseAttr(C,e,o,s,c,u,a,l),r=n._parseInlineTemplateBinding(e,f,d,m);r&&y&&n._reportError("Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *",e.sourceSpan),t||r||(g.push(n.visitAttribute(e,null)),o.push([e.name,e.value])),r&&(y=!0)});var R=createElementCssSelector(r,o),x=this._parseDirectives(this.selectorMatcher,R),M=[],I=this._createDirectiveAsts(C,e.name,x,s,a,e.sourceSpan,M),A=this._createElementPropertyAsts(e.name,s,I).concat(c),k=t.isTemplateElement||y,O=new b.ProviderElementContext(this.providerViewContext,t.providerContext,k,I,g,M,e.sourceSpan),D=h.visitAll(i.nonBindable?G:this,e.children,U.create(C,I,C?t.providerContext:O));O.afterElement();var N,V=p.isPresent(i.projectAs)?S.CssSelector.parse(i.projectAs)[0]:R,L=t.findNgContentIndex(V);if(i.type===T.PreparsedElementType.NG_CONTENT)p.isPresent(e.children)&&e.children.length>0&&this._reportError(" element cannot have content. must be immediately followed by ",e.sourceSpan),N=new E.NgContentAst((this.ngContentCount++),y?null:L,e.sourceSpan);else if(C)this._assertAllEventsPublishedByDirectives(I,u),this._assertNoComponentsNorElementBindingsOnTemplate(I,A,e.sourceSpan),N=new E.EmbeddedTemplateAst(g,u,M,l,O.transformedDirectiveAsts,O.transformProviders,O.transformedHasViewContainer,D,y?null:L,e.sourceSpan);else{this._assertOnlyOneComponent(I,e.sourceSpan);var F=y?null:t.findNgContentIndex(V);N=new E.ElementAst(r,g,A,u,M,O.transformedDirectiveAsts,O.transformProviders,O.transformedHasViewContainer,D,y?null:F,e.sourceSpan)}if(y){var j=createElementCssSelector(P,f),B=this._parseDirectives(this.selectorMatcher,j),W=this._createDirectiveAsts(!0,e.name,B,d,[],e.sourceSpan,[]),H=this._createElementPropertyAsts(e.name,d,W);this._assertNoComponentsNorElementBindingsOnTemplate(W,H,e.sourceSpan);var z=new b.ProviderElementContext(this.providerViewContext,t.providerContext,t.isTemplateElement,W,[],[],e.sourceSpan);z.afterElement(),N=new E.EmbeddedTemplateAst([],[],[],m,z.transformedDirectiveAsts,z.transformProviders,z.transformedHasViewContainer,[N],L,e.sourceSpan)}return N},TemplateParseVisitor.prototype._parseInlineTemplateBinding=function(e,t,n,r){var i=null;if(this._normalizeAttributeName(e.name)==x)i=e.value;else if(e.name.startsWith(M)){var o=e.name.substring(M.length);i=0==e.value.length?o:o+" "+e.value}if(p.isPresent(i)){for(var s=this._parseTemplateBindings(i,e.sourceSpan),a=0;a elements is deprecated. Use "let-" instead!',t.sourceSpan,g.ParseErrorLevel.WARNING),this._parseVariable(h,c,t.sourceSpan,a)):(this._reportError('"var-" on non