Repository: vitessio/vitess
Pull request #6892 (2020-10-16 10:06:39)

VReplication: Tool to diagnose vreplication issues in production
Tool developed while researching a issue faced during a migration. More details in the doc which is part of this PR

Signed-off-by: Rohit Nayak <rohit@planetscale.com>



Patch:
diff --git a/MAINTAINERS.md b/MAINTAINERS.md
index d991a272f2..f40497cf09 100644
--- a/MAINTAINERS.md
+++ b/MAINTAINERS.md
@@ -16,7 +16,6 @@ The following is the full list, alphabetically ordered.
 * Morgan Tocker ([morgo](https://github.com/morgo)) morgan@planetscale.com
 * Paul Hemberger ([pH14](https://github.com/pH14)) phemberger@hubspot.com
 * Rafael Chacon ([rafael](https://github.com/rafael)) rchacon@slack-corp.com
-* Rohit Nayak ([rohit-nayak-ps](https://github.com/rohit-nayak-ps)) rohit@planetscale.com
 * Shlomi Noach ([shlomi-noach](https://github.com/shlomi-noach)) shlomi@planetscale.com
 * Sugu Sougoumarane ([sougou](https://github.com/sougou)) sougou@planetscale.com
 
diff --git a/bootstrap.sh b/bootstrap.sh
index ff8f702c0a..c539809bc8 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -27,9 +27,6 @@ BUILD_JAVA=${BUILD_JAVA:-1}
 BUILD_CONSUL=${BUILD_CONSUL:-1}
 BUILD_CHROME=${BUILD_CHROME:-1}
 
-VITESS_RESOURCES_DOWNLOAD_BASE_URL="https://github.com/vitessio/vitess-resources/releases/download"
-VITESS_RESOURCES_RELEASE="v1.0"
-VITESS_RESOURCES_DOWNLOAD_URL="${VITESS_RESOURCES_DOWNLOAD_BASE_URL}/${VITESS_RESOURCES_RELEASE}"
 #
 # 0. Initialization and helper methods.
 #
@@ -41,7 +38,7 @@ VITESS_RESOURCES_DOWNLOAD_URL="${VITESS_RESOURCES_DOWNLOAD_BASE_URL}/${VITESS_RE
 # If the installation is successful, it puts the installed version string into
 # the $dist/.installed_version file. If the version has not changed, bootstrap
 # will skip future installations.
-install_dep() {
+function install_dep() {
   if [[ $# != 4 ]]; then
     fail "install_dep function requires exactly 4 parameters (and not $#). Parameters: $*"
   fi
@@ -88,12 +85,12 @@ install_dep() {
 # We should not use the arch command, since it is not reliably
 # available on macOS or some linuxes:
 # https://www.gnu.org/software/coreutils/manual/html_node/arch-invocation.html
-get_arch() {
+function get_arch() {
   uname -m
 }
 
 # Install protoc.
-install_protoc() {
+function install_protoc() {
   local version="$1"
   local dist="$2"
 
@@ -108,23 +105,21 @@ install_protoc() {
       *)   echo "ERROR: unsupported architecture"; exit 1;;
   esac
 
-  # This is how we'd download directly from source:
-  # wget https://github.com/protocolbuffers/protobuf/releases/download/v$version/protoc-$version-$platform-${target}.zip
-  wget "${VITESS_RESOURCES_DOWNLOAD_URL}/protoc-$version-$platform-${target}.zip"
+  wget https://github.com/protocolbuffers/protobuf/releases/download/v$version/protoc-$version-$platform-${target}.zip
   unzip "protoc-$version-$platform-${target}.zip"
   ln -snf "$dist/bin/protoc" "$VTROOT/bin/protoc"
 }
+protoc_ver=3.6.1
+install_dep "protoc" "$protoc_ver" "$VTROOT/dist/vt-protoc-$protoc_ver" install_protoc
 
 
 # Install Zookeeper.
-install_zookeeper() {
+function install_zookeeper() {
   local version="$1"
   local dist="$2"
 
   zk="zookeeper-$version"
-  # This is how we'd download directly from source:
-  # wget "https://archive.apache.org/dist/zookeeper/$zk/$zk.tar.gz"
-  wget "${VITESS_RESOURCES_DOWNLOAD_URL}/${zk}.tar.gz"
+  wget "https://archive.apache.org/dist/zookeeper/$zk/$zk.tar.gz"
   tar -xzf "$zk.tar.gz"
   ant -f "$zk/build.xml" package
   ant -f "$zk/zookeeper-contrib/zookeeper-contrib-fatjar/build.xml" jar
@@ -134,9 +129,13 @@ install_zookeeper() {
   rm -rf "$zk" "$zk.tar.gz"
 }
 
+zk_ver=${ZK_VERSION:-3.4.14}
+if [ "$BUILD_JAVA" == 1 ] ; then
+  install_dep "Zookeeper" "$zk_ver" "$VTROOT/dist/vt-zookeeper-$zk_ver" install_zookeeper
+fi
 
 # Download and install etcd, link etcd binary into our root.
-install_etcd() {
+function install_etcd() {
   local version="$1"
   local dist="$2"
 
@@ -151,12 +150,10 @@ install_etcd() {
       *)   echo "ERROR: unsupported architecture"; exit 1;;
   esac
 
+  download_url=https://github.com/coreos/etcd/releases/download
   file="etcd-${version}-${platform}-${target}.${ext}"
 
-  # This is how we'd download directly from source:
-  # download_url=https://github.com/etcd-io/etcd/releases/download
-  # wget "$download_url/$version/$file"
-  wget "${VITESS_RESOURCES_DOWNLOAD_URL}/${file}"
+  wget "$download_url/$version/$file"
   if [ "$ext" = "tar.gz" ]; then
     tar xzf "$file"
   else
@@ -166,10 +163,11 @@ install_etcd() {
   ln -snf "$dist/etcd-${version}-${platform}-${target}/etcd" "$VTROOT/bin/etcd"
   ln -snf "$dist/etcd-${version}-${platform}-${target}/etcdctl" "$VTROOT/bin/etcdctl"
 }
+command -v etcd && echo "etcd already installed" || install_dep "etcd" "v3.3.10" "$VTROOT/dist/etcd" install_etcd
 
 
 # Download and install k3s, link k3s binary into our root
-install_k3s() {
+function install_k3s() {
   local version="$1"
   local dist="$2"
 
@@ -184,20 +182,18 @@ install_k3s() {
       *)   echo "WARNING: unsupported architecture, the k8s topology will not be available for local examples."; return;;
   esac
 
+  download_url=https://github.com/rancher/k3s/releases/download
   file="k3s${target}"
 
   local dest="$dist/k3s${target}-${version}-${platform}"
-  # This is how we'd download directly from source:
-  # download_url=https://github.com/rancher/k3s/releases/download
-  # wget -O  $dest "$download_url/$version/$file"
-  wget -O  $dest "${VITESS_RESOURCES_DOWNLOAD_URL}/$file-$version"
+  wget -O  $dest "$download_url/$version/$file"
   chmod +x $dest
   ln -snf  $dest "$VTROOT/bin/k3s"
 }
-
+command -v  k3s || install_dep "k3s" "v1.0.0" "$VTROOT/dist/k3s" install_k3s
 
 # Download and install consul, link consul binary into our root.
-install_consul() {
+function install_consul() {
   local version="$1"
   local dist="$2"
 
@@ -212,17 +208,18 @@ install_consul() {
       *)   echo "ERROR: unsupported architecture"; exit 1;;
   esac
 
-  # This is how we'd download directly from source:
-  # download_url=https://releases.hashicorp.com/consul
-  # wget "${download_url}/${version}/consul_${version}_${platform}_${target}.zip"
-  wget "${VITESS_RESOURCES_DOWNLOAD_URL}/consul_${version}_${platform}_${target}.zip"
+  download_url=https://releases.hashicorp.com/consul
+  wget "${download_url}/${version}/consul_${version}_${platform}_${target}.zip"
   unzip "consul_${version}_${platform}_${target}.zip"
   ln -snf "$dist/consul" "$VTROOT/bin/consul"
 }
 
+if [ "$BUILD_CONSUL" == 1 ] ; then
+  install_dep "Consul" "1.4.0" "$VTROOT/dist/consul" install_consul
+fi
 
 # Download chromedriver
-install_chromedriver() {
+function install_chromedriver() {
   local version="$1"
   local dist="$2"
 
@@ -234,12 +231,12 @@ install_chromedriver() {
   if [ "$(arch)" == "aarch64" ] ; then
       os=$(cat /etc/*release | grep "^ID=" | cut -d '=' -f 2)
       case $os in
-        ubuntu|debian)
-          sudo apt-get update -y && sudo apt install -y --no-install-recommends unzip libglib2.0-0 libnss3 libx11-6
-        ;;
-        centos|fedora)
-          sudo yum update -y && yum install -y libX11 unzip wget
-        ;;
+          ubuntu|debian)
+              sudo apt-get update -y && sudo apt install -y --no-install-recommends unzip libglib2.0-0 libnss3 libx11-6
+	      ;;
+	  centos|fedora)
+	      sudo yum update -y && yum install -y libX11 unzip wget
+	      ;;
       esac
       echo "For Arm64, using prebuilt binary from electron (https://github.com/electron/electron/) of version 76.0.3809.126"
       wget https://github.com/electron/electron/releases/download/v6.0.3/chromedriver-v6.0.3-linux-arm64.zip
@@ -252,35 +249,9 @@ install_chromedriver() {
   fi
 }
 
-install_all() {
-  # protoc
-  protoc_ver=3.6.1
-  install_dep "protoc" "$protoc_ver" "$VTROOT/dist/vt-protoc-$protoc_ver" install_protoc
-
-  # zk
-  zk_ver=${ZK_VERSION:-3.4.14}
-  if [ "$BUILD_JAVA" == 1 ] ; then
-    install_dep "Zookeeper" "$zk_ver" "$VTROOT/dist/vt-zookeeper-$zk_ver" install_zookeeper
-  fi
-
-  # etcd
-  command -v etcd && echo "etcd already installed" || install_dep "etcd" "v3.3.10" "$VTROOT/dist/etcd" install_etcd
-
-  # k3s
-  command -v  k3s || install_dep "k3s" "v1.0.0" "$VTROOT/dist/k3s" install_k3s
-
-  # consul
-  if [ "$BUILD_CONSUL" == 1 ] ; then
-    install_dep "Consul" "1.4.0" "$VTROOT/dist/consul" install_consul
-  fi
-
-  # chromedriver
-  if [ "$BUILD_CHROME" == 1 ] ; then
-    install_dep "chromedriver" "73.0.3683.20" "$VTROOT/dist/chromedriver" install_chromedriver
-  fi
-
-  echo
-  echo "bootstrap finished - run 'make build' to compile"
-}
+if [ "$BUILD_CHROME" == 1 ] ; then
+	install_dep "chromedriver" "73.0.3683.20" "$VTROOT/dist/chromedriver" install_chromedriver
+fi
 
-install_all
+echo
+echo "bootstrap finished - run 'make build' to compile"
diff --git a/go.mod b/go.mod
index b2d92b4f95..066b5775bd 100644
--- a/go.mod
+++ b/go.mod
@@ -34,7 +34,6 @@ require (
 	github.com/golang/protobuf v1.3.2
 	github.com/golang/snappy v0.0.1
 	github.com/google/go-cmp v0.4.0
-	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
 	github.com/google/uuid v1.1.1
 	github.com/googleapis/gnostic v0.2.0 // indirect
 	github.com/gorilla/websocket v1.4.0
@@ -61,7 +60,6 @@ require (
 	github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11
 	github.com/mattn/go-sqlite3 v1.14.0
 	github.com/minio/minio-go v0.0.0-20190131015406-c8a261de75c1
-	github.com/mitchellh/go-ps v1.0.0 // indirect
 	github.com/mitchellh/go-testing-interface v1.14.0 // indirect
 	github.com/mitchellh/mapstructure v1.2.3 // indirect
 	github.com/montanaflynn/stats v0.6.3
diff --git a/go.sum b/go.sum
index 23a318542b..a357895fb7 100644
--- a/go.sum
+++ b/go.sum
@@ -273,8 +273,6 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
@@ -459,8 +457,6 @@ github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg=
 github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
-github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI=
 github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go
index 58821c4d11..d517547564 100644
--- a/go/cmd/vtcombo/main.go
+++ b/go/cmd/vtcombo/main.go
@@ -167,7 +167,7 @@ func main() {
 
 	// Now that we have fully initialized the tablets, rebuild the keyspace graph.
 	for _, ks := range tpb.Keyspaces {
-		err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, ks.GetName(), tpb.Cells, false)
+		err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, ks.GetName(), tpb.Cells)
 		if err != nil {
 			if *startMysql {
 				mysqld.Shutdown(context.TODO(), cnf, true)
diff --git a/go/mysql/constants.go b/go/mysql/constants.go
index 9554166642..f731e7d7c3 100644
--- a/go/mysql/constants.go
+++ b/go/mysql/constants.go
@@ -605,20 +605,3 @@ func IsConnErr(err error) bool {
 	}
 	return false
 }
-
-// IsSchemaApplyError returns true when given error is a MySQL error applying schema change
-func IsSchemaApplyError(err error) bool {
-	merr, isSQLErr := err.(*SQLError)
-	if !isSQLErr {
-		return false
-	}
-	switch merr.Num {
-	case
-		ERDupKeyName,
-		ERCantDropFieldOrKey,
-		ERTableExists,
-		ERDupFieldName:
-		return true
-	}
-	return false
-}
diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go
index 263a0d62c9..c9ce887067 100644
--- a/go/vt/discovery/healthcheck.go
+++ b/go/vt/discovery/healthcheck.go
@@ -386,8 +386,8 @@ func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) {
 		log.Infof("We have no health data for tablet: %v, it might have been deleted already", tabletAlias)
 		return
 	}
-	// Calling this will end the context associated with th.checkConn,
-	// which will call finalizeConn, which will close the connection.
+	// calling this will end the context associated with th.checkConn
+	// which will call finalizeConn, which will close the connection
 	th.cancelFunc()
 	delete(hc.healthByAlias, tabletAlias)
 	// delete from map by keyspace.shard.tabletType
@@ -442,27 +442,24 @@ func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, shr *query.StreamHealt
 		}
 	}
 	if !trivialNonMasterUpdate {
-		// We re-sort the healthy tablet list whenever we get a health update for tablets we can route to.
-		// Tablets from other cells for non-master targets should not trigger a re-sort;
-		// they should also be excluded from healthy list.
-		if shr.Target.TabletType != topodata.TabletType_MASTER && hc.isIncluded(shr.Target.TabletType, shr.TabletAlias) {
+		if shr.Target.TabletType != topodata.TabletType_MASTER {
 			all := hc.healthData[targetKey]
 			allArray := make([]*TabletHealth, 0, len(all))
 			for _, s := range all {
-				// Only tablets in same cell / cellAlias are included in healthy list.
-				if hc.isIncluded(s.Tablet.Type, s.Tablet.Alias) {
+				// only tablets in same cell / cellAlias are included in healthy list
+				if hc.isIncluded(shr) {
 					allArray = append(allArray, s)
 				}
 			}
 			hc.healthy[targetKey] = FilterStatsByReplicationLag(allArray)
 		}
-		if targetChanged && currentTarget.TabletType != topodata.TabletType_MASTER && hc.isIncluded(shr.Target.TabletType, shr.TabletAlias) { // also recompute old target's healthy list
+		if targetChanged && currentTarget.TabletType != topodata.TabletType_MASTER { // also recompute old target's healthy list
 			oldTargetKey := hc.keyFromTarget(currentTarget)
 			all := hc.healthData[oldTargetKey]
 			allArray := make([]*TabletHealth, 0, len(all))
 			for _, s := range all {
-				// Only tablets in same cell / cellAlias are included in healthy list.
-				if hc.isIncluded(s.Tablet.Type, s.Tablet.Alias) {
+				// only tablets in same cell / cellAlias are included in healthy list
+				if hc.isIncluded(shr) {
 					allArray = append(allArray, s)
 				}
 			}
@@ -719,14 +716,14 @@ func (hc *HealthCheckImpl) getAliasByCell(cell string) string {
 	return alias
 }
 
-func (hc *HealthCheckImpl) isIncluded(tabletType topodata.TabletType, tabletAlias *topodata.TabletAlias) bool {
-	if tabletType == topodata.TabletType_MASTER {
+func (hc *HealthCheckImpl) isIncluded(shr *query.StreamHealthResponse) bool {
+	if shr.Target.TabletType == topodata.TabletType_MASTER {
 		return true
 	}
-	if tabletAlias.Cell == hc.cell {
+	if shr.TabletAlias.Cell == hc.cell {
 		return true
 	}
-	if hc.getAliasByCell(tabletAlias.Cell) == hc.getAliasByCell(hc.cell) {
+	if hc.getAliasByCell(shr.TabletAlias.Cell) == hc.getAliasByCell(hc.cell) {
 		return true
 	}
 	return false
diff --git a/go/vt/hook/hook.go b/go/vt/hook/hook.go
index 6cee35e424..0215a14382 100644
--- a/go/vt/hook/hook.go
+++ b/go/vt/hook/hook.go
@@ -18,8 +18,6 @@ package hook
 
 import (
 	"bytes"
-	"context"
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -27,7 +25,6 @@ import (
 	"path"
 	"strings"
 	"syscall"
-	"time"
 
 	vtenv "vitess.io/vitess/go/vt/env"
 	"vitess.io/vitess/go/vt/log"
@@ -72,10 +69,6 @@ const (
 
 	// HOOK_GENERIC_ERROR is returned for unknown errors.
 	HOOK_GENERIC_ERROR = -6
-
-	// HOOK_TIMEOUT_ERROR is returned when a CommandContext has its context
-	// become done before the command terminates.
-	HOOK_TIMEOUT_ERROR = -7
 )
 
 // WaitFunc is a return type for the Pipe methods.
@@ -97,8 +90,8 @@ func NewHookWithEnv(name string, params []string, env map[string]string) *Hook {
 	return &Hook{Name: name, Parameters: params, ExtraEnv: env}
 }
 
-// findHook tries to locate the hook, and returns the exec.Cmd for it.
-func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) {
+// findHook trie to locate the hook, and returns the exec.Cmd for it.
+func (hook *Hook) findHook() (*exec.Cmd, int, error) {
 	// Check the hook path.
 	if strings.Contains(hook.Name, "/") {
 		return nil, HOOK_INVALID_NAME, fmt.Errorf("hook cannot contain '/'")
@@ -123,7 +116,7 @@ func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) {
 
 	// Configure the command.
 	log.Infof("hook: executing hook: %v %v", vthook, strings.Join(hook.Parameters, " "))
-	cmd := exec.CommandContext(ctx, vthook, hook.Parameters...)
+	cmd := exec.Command(vthook, hook.Parameters...)
 	if len(hook.ExtraEnv) > 0 {
 		cmd.Env = os.Environ()
 		for key, value := range hook.ExtraEnv {
@@ -134,12 +127,12 @@ func (hook *Hook) findHook(ctx context.Context) (*exec.Cmd, int, error) {
 	return cmd, HOOK_SUCCESS, nil
 }
 
-// ExecuteContext tries to execute the Hook with the given context and returns a HookResult.
-func (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) {
+// Execute tries to execute the Hook and returns a HookResult.
+func (hook *Hook) Execute() (result *HookResult) {
 	result = &HookResult{}
 
 	// Find the hook.
-	cmd, status, err := hook.findHook(ctx)
+	cmd, status, err := hook.findHook()
 	if err != nil {
 		result.ExitStatus = status
 		result.Stderr = err.Error() + "\n"
@@ -150,52 +143,23 @@ func (hook *Hook) ExecuteContext(ctx context.Context) (result *HookResult) {
 	var stdout, stderr bytes.Buffer
 	cmd.Stdout = &stdout
 	cmd.Stderr = &stderr
-
-	start := time.Now()
 	err = cmd.Run()
-	duration := time.Since(start)
-
 	result.Stdout = stdout.String()
 	result.Stderr = stderr.String()
-
-	defer func() {
-		log.Infof("hook: result is %v", result.String())
-	}()
-
 	if err == nil {
 		result.ExitStatus = HOOK_SUCCESS
-		return result
-	}
-
-	if ctx.Err() != nil && errors.Is(ctx.Err(), context.DeadlineExceeded) {
-		// When (exec.Cmd).Run hits a context cancelled, the process is killed via SIGTERM.
-		// This means:
-		// 	1. cmd.ProcessState.Exited() is false.
-		//	2. cmd.ProcessState.ExitCode() is -1.
-		// [ref]: https://golang.org/pkg/os/#ProcessState.ExitCode
-		//
-		// Therefore, we need to catch this error specifically, and set result.ExitStatus to
-		// HOOK_TIMEOUT_ERROR, because just using ExitStatus will result in HOOK_DOES_NOT_EXIST,
-		// which would be wrong. Since we're already doing some custom handling, we'll also include
-		// the amount of time the command was running in the error string, in case that is helpful.
-		result.ExitStatus = HOOK_TIMEOUT_ERROR
-		result.Stderr += fmt.Sprintf("ERROR: (after %s) %s\n", duration, err)
-		return result
-	}
-
-	if cmd.ProcessState != nil && cmd.ProcessState.Sys() != nil {
-		result.ExitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
 	} else {
-		result.ExitStatus = HOOK_CANNOT_GET_EXIT_STATUS
+		if cmd.ProcessState != nil && cmd.ProcessState.Sys() != nil {
+			result.ExitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
+		} else {
+			result.ExitStatus = HOOK_CANNOT_GET_EXIT_STATUS
+		}
+		result.Stderr += "ERROR: " + err.Error() + "\n"
 	}
-	result.Stderr += "ERROR: " + err.Error() + "\n"
 
-	return result
-}
+	log.Infof("hook: result is %v", result.String())
 
-// Execute tries to execute the Hook and returns a HookResult.
-func (hook *Hook) Execute() (result *HookResult) {
-	return hook.ExecuteContext(context.Background())
+	return result
 }
 
 // ExecuteOptional executes an optional hook, logs if it doesn't
@@ -223,7 +187,7 @@ func (hook *Hook) ExecuteOptional() error {
 // - an error code and an error if anything fails.
 func (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, int, error) {
 	// Find the hook.
-	cmd, status, err := hook.findHook(context.Background())
+	cmd, status, err := hook.findHook()
 	if err != nil {
 		return nil, nil, status, err
 	}
@@ -262,7 +226,7 @@ func (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, i
 // - an error code and an error if anything fails.
 func (hook *Hook) ExecuteAsReadPipe(in io.Reader) (io.Reader, WaitFunc, int, error) {
 	// Find the hook.
-	cmd, status, err := hook.findHook(context.Background())
+	cmd, status, err := hook.findHook()
 	if err != nil {
 		return nil, nil, status, err
 	}
diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go
index a1db9af510..cc077bb661 100644
--- a/go/vt/mysqlctl/builtinbackupengine.go
+++ b/go/vt/mysqlctl/builtinbackupengine.go
@@ -20,7 +20,6 @@ import (
 	"bufio"
 	"context"
 	"encoding/json"
-	"flag"
 	"fmt"
 	"io"
 	"os"
@@ -48,13 +47,6 @@ const (
 	dataDictionaryFile      = "mysql.ibd"
 )
 
-var (
-	// BuiltinBackupMysqldTimeout is how long ExecuteBackup should wait for response from mysqld.Shutdown.
-	// It can later be extended for other calls to mysqld during backup functions.
-	// Exported for testing.
-	BuiltinBackupMysqldTimeout = flag.Duration("builtinbackup_mysqld_timeout", 10*time.Minute, "how long to wait for mysqld to shutdown at the start of the backup")
-)
-
 // BuiltinBackupEngine encapsulates the logic of the builtin engine
 // it implements the BackupEngine interface and contains all the logic
 // required to implement a backup/restore by copying files from and to
@@ -190,9 +182,7 @@ func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, params BackupP
 	params.Logger.Infof("using replication position: %v", replicationPosition)
 
 	// shutdown mysqld
-	shutdownCtx, cancel := context.WithTimeout(ctx, *BuiltinBackupMysqldTimeout)
-	err = params.Mysqld.Shutdown(shutdownCtx, params.Cnf, true)
-	defer cancel()
+	err = params.Mysqld.Shutdown(ctx, params.Cnf, true)
 	if err != nil {
 		return false, vterrors.Wrap(err, "can't shutdown mysqld")
 	}
diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go
index 84e933dfa6..f4142ffee2 100644
--- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go
+++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go
@@ -48,14 +48,6 @@ type FakeMysqlDaemon struct {
 	// Running is used by Start / Shutdown
 	Running bool
 
-	// StartupTime is used to simulate mysqlds that take some time to respond
-	// to a "start" command. It is used by Start.
-	StartupTime time.Duration
-
-	// ShutdownTime is used to simulate mysqlds that take some time to respond
-	// to a "stop" request (i.e. a wedged systemd unit). It is used by Shutdown.
-	ShutdownTime time.Duration
-
 	// MysqlPort will be returned by GetMysqlPort(). Set to -1 to
 	// return an error.
 	MysqlPort sync2.AtomicInt32
@@ -189,15 +181,6 @@ func (fmd *FakeMysqlDaemon) Start(ctx context.Context, cnf *mysqlctl.Mycnf, mysq
 	if fmd.Running {
 		return fmt.Errorf("fake mysql daemon already running")
 	}
-
-	if fmd.StartupTime > 0 {
-		select {
-		case <-time.After(fmd.StartupTime):
-		case <-ctx.Done():
-			return ctx.Err()
-		}
-	}
-
 	fmd.Running = true
 	return nil
 }
@@ -207,15 +190,6 @@ func (fmd *FakeMysqlDaemon) Shutdown(ctx context.Context, cnf *mysqlctl.Mycnf, w
 	if !fmd.Running {
 		return fmt.Errorf("fake mysql daemon not running")
 	}
-
-	if fmd.ShutdownTime > 0 {
-		select {
-		case <-time.After(fmd.ShutdownTime):
-		case <-ctx.Done():
-			return ctx.Err()
-		}
-	}
-
 	fmd.Running = false
 	return nil
 }
diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go
index fc6fce373b..7abd1da7a7 100644
--- a/go/vt/mysqlctl/mysqld.go
+++ b/go/vt/mysqlctl/mysqld.go
@@ -512,7 +512,7 @@ func (mysqld *Mysqld) Shutdown(ctx context.Context, cnf *Mycnf, waitForMysqld bo
 
 	// try the mysqld shutdown hook, if any
 	h := hook.NewSimpleHook("mysqld_shutdown")
-	hr := h.ExecuteContext(ctx)
+	hr := h.Execute()
 	switch hr.ExitStatus {
 	case hook.HOOK_SUCCESS:
 		// hook exists and worked, we can keep going
diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go
index 74c8049e50..057ac0a562 100644
--- a/go/vt/topotools/rebuild_keyspace.go
+++ b/go/vt/topotools/rebuild_keyspace.go
@@ -30,14 +30,14 @@ import (
 )
 
 // RebuildKeyspace rebuilds the serving graph data while locking out other changes.
-func RebuildKeyspace(ctx context.Context, log logutil.Logger, ts *topo.Server, keyspace string, cells []string, allowPartial bool) (err error) {
+func RebuildKeyspace(ctx context.Context, log logutil.Logger, ts *topo.Server, keyspace string, cells []string) (err error) {
 	ctx, unlock, lockErr := ts.LockKeyspace(ctx, keyspace, "RebuildKeyspace")
 	if lockErr != nil {
 		return lockErr
 	}
 	defer unlock(&err)
 
-	return RebuildKeyspaceLocked(ctx, log, ts, keyspace, cells, allowPartial)
+	return RebuildKeyspaceLocked(ctx, log, ts, keyspace, cells)
 }
 
 // RebuildKeyspaceLocked should only be used with an action lock on the keyspace
@@ -46,7 +46,7 @@ func RebuildKeyspace(ctx context.Context, log logutil.Logger, ts *topo.Server, k
 //
 // Take data from the global keyspace and rebuild the local serving
 // copies in each cell.
-func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Server, keyspace string, cells []string, allowPartial bool) error {
+func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Server, keyspace string, cells []string) error {
 	if err := topo.CheckKeyspaceLocked(ctx, keyspace); err != nil {
 		return err
 	}
@@ -131,11 +131,8 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser
 			}
 		}
 
-		if !(ki.KeyspaceType == topodatapb.KeyspaceType_SNAPSHOT && allowPartial) {
-			// skip this check for SNAPSHOT keyspaces so that incomplete keyspaces can still serve
-			if err := topo.OrderAndCheckPartitions(cell, srvKeyspace); err != nil {
-				return err
-			}
+		if err := topo.OrderAndCheckPartitions(cell, srvKeyspace); err != nil {
+			return err
 		}
 
 	}
diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go
index 5f364585c2..406407cd04 100644
--- a/go/vt/vtcombo/tablet_map.go
+++ b/go/vt/vtcombo/tablet_map.go
@@ -280,7 +280,7 @@ func InitTabletMap(ts *topo.Server, tpb *vttestpb.VTTestTopology, mysqld mysqlct
 
 		// Rebuild the SrvKeyspace object, so we can support
 		// range-based sharding queries, and export the redirects.
-		if err := wr.RebuildKeyspaceGraph(ctx, keyspace, nil, false); err != nil {
+		if err := wr.RebuildKeyspaceGraph(ctx, keyspace, nil); err != nil {
 			return fmt.Errorf("cannot rebuild %v: %v", keyspace, err)
 		}
 	}
diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go
index 9137fbe179..2c9f733395 100644
--- a/go/vt/vtctl/vtctl.go
+++ b/go/vt/vtctl/vtctl.go
@@ -87,7 +87,6 @@ import (
 	"flag"
 	"fmt"
 	"io/ioutil"
-	"math"
 	"sort"
 	"strconv"
 	"strings"
@@ -306,7 +305,7 @@ var commands = []commandGroup{
 				"[-source=<source keyspace name>] [-remove] [-cells=c1,c2,...] <keyspace name> <tablet type>",
 				"Changes the ServedFromMap manually. This command is intended for emergency fixes. This field is automatically set when you call the *MigrateServedFrom* command. This command does not rebuild the serving graph."},
 			{"RebuildKeyspaceGraph", commandRebuildKeyspaceGraph,
-				"[-cells=c1,c2,...] [-allow_partial] <keyspace> ...",
+				"[-cells=c1,c2,...] <keyspace> ...",
 				"Rebuilds the serving data for the keyspace. This command may trigger an update to all connected clients."},
 			{"ValidateKeyspace", commandValidateKeyspace,
 				"[-ping-tablets] <keyspace name>",
@@ -1848,7 +1847,6 @@ func commandSetKeyspaceServedFrom(ctx context.Context, wr *wrangler.Wrangler, su
 
 func commandRebuildKeyspaceGraph(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
 	cells := subFlags.String("cells", "", "Specifies a comma-separated list of cells to update")
-	allowPartial := subFlags.Bool("allow_partial", false, "Specifies whether a SNAPSHOT keyspace is allowed to serve with an incomplete set of shards. Ignored for all other types of keyspaces")
 	if err := subFlags.Parse(args); err != nil {
 		return err
 	}
@@ -1866,7 +1864,7 @@ func commandRebuildKeyspaceGraph(ctx context.Context, wr *wrangler.Wrangler, sub
 		return err
 	}
 	for _, keyspace := range keyspaces {
-		if err := wr.RebuildKeyspaceGraph(ctx, keyspace, cellArray, *allowPartial); err != nil {
+		if err := wr.RebuildKeyspaceGraph(ctx, keyspace, cellArray); err != nil {
 			return err
 		}
 	}
@@ -1996,8 +1994,8 @@ func commandVDiff(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.Fla
 	targetCell := subFlags.String("target_cell", "", "The target cell to compare with")
 	tabletTypes := subFlags.String("tablet_types", "master,replica,rdonly", "Tablet types for source and target")
 	filteredReplicationWaitTime := subFlags.Duration("filtered_replication_wait_time", 30*time.Second, "Specifies the maximum time to wait, in seconds, for filtered replication to catch up on master migrations. The migration will be aborted on timeout.")
-	maxRows := subFlags.Int64("limit", math.MaxInt64, "Max rows to stop comparing after")
 	format := subFlags.String("format", "", "Format of report") //"json" or ""
+
 	if err := subFlags.Parse(args); err != nil {
 		return err
 	}
@@ -2009,10 +2007,8 @@ func commandVDiff(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.Fla
 	if err != nil {
 		return err
 	}
-	if *maxRows <= 0 {
-		return fmt.Errorf("maximum number of rows to compare needs to be greater than 0")
-	}
-	_, err = wr.VDiff(ctx, keyspace, workflow, *sourceCell, *targetCell, *tabletTypes, *filteredReplicationWaitTime, *format, *maxRows)
+
+	_, err = wr.VDiff(ctx, keyspace, workflow, *sourceCell, *targetCell, *tabletTypes, *filteredReplicationWaitTime, *format)
 	if err != nil {
 		log.Errorf("vdiff returning with error: %v", err)
 	}
diff --git a/go/vt/vtgate/evalengine/arithmetic.go b/go/vt/vtgate/evalengine/arithmetic.go
index bf34797276..f40e9d5c45 100644
--- a/go/vt/vtgate/evalengine/arithmetic.go
+++ b/go/vt/vtgate/evalengine/arithmetic.go
@@ -209,7 +209,7 @@ func isByteComparable(v sqltypes.Value) bool {
 		return true
 	}
 	switch v.Type() {
-	case sqltypes.Timestamp, sqltypes.Date, sqltypes.Time, sqltypes.Datetime, sqltypes.Enum:
+	case sqltypes.Timestamp, sqltypes.Date, sqltypes.Time, sqltypes.Datetime:
 		return true
 	}
 	return false
diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go
index d2410a0ebb..092476d790 100644
--- a/go/vt/vtgate/planbuilder/select.go
+++ b/go/vt/vtgate/planbuilder/select.go
@@ -331,11 +331,6 @@ func (r *rewriter) rewriteTableSchema(cursor *sqlparser.Cursor) bool {
 
 					evalExpr, err := sqlparser.Convert(parent.Right)
 					if err != nil {
-						if err == sqlparser.ErrExprNotSupported {
-							// This just means we can't rewrite this particular expression,
-							// not that we have to exit altogether
-							return true
-						}
 						r.err = err
 						return false
 					}
diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go
index 3eb6bb3f23..f8483dea36 100644
--- a/go/vt/vttablet/onlineddl/executor.go
+++ b/go/vt/vttablet/onlineddl/executor.go
@@ -32,7 +32,6 @@ import (
 	"syscall"
 	"time"
 
-	"vitess.io/vitess/go/mysql"
 	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/textutil"
 	"vitess.io/vitess/go/timer"
@@ -50,8 +49,6 @@ import (
 	querypb "vitess.io/vitess/go/vt/proto/query"
 	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
-
-	"github.com/google/shlex"
 )
 
 var (
@@ -120,9 +117,8 @@ type Executor struct {
 	migrationRunning  int64
 	lastMigrationUUID string
 
-	ticks             *timer.Timer
-	isOpen            bool
-	schemaInitialized bool
+	ticks  *timer.Timer
+	isOpen bool
 }
 
 // GhostBinaryFileName returns the full path+name of the gh-ost binary
@@ -169,13 +165,6 @@ func (e *Executor) execQuery(ctx context.Context, query string) (result *sqltype
 }
 
 func (e *Executor) initSchema(ctx context.Context) error {
-	e.initMutex.Lock()
-	defer e.initMutex.Unlock()
-
-	if e.schemaInitialized {
-		return nil
-	}
-
 	defer e.env.LogError()
 
 	conn, err := e.pool.Get(ctx)
@@ -183,18 +172,9 @@ func (e *Executor) initSchema(ctx context.Context) error {
 		return err
 	}
 	defer conn.Recycle()
-
-	for _, ddl := range applyDDL {
-		_, err := conn.Exec(ctx, ddl, math.MaxInt32, false)
-		if mysql.IsSchemaApplyError(err) {
-			continue
-		}
-		if err != nil {
-			return err
-		}
-	}
-	e.schemaInitialized = true
-	return nil
+	parsed := sqlparser.BuildParsedQuery(sqlValidationQuery, "_vt")
+	_, err = withDDL.Exec(ctx, parsed.Query, conn.Exec)
+	return err
 }
 
 // InitDBConfig initializes keysapce
@@ -212,6 +192,7 @@ func (e *Executor) Open() error {
 		return nil
 	}
 	e.pool.Open(e.env.Config().DB.AppWithDB(), e.env.Config().DB.DbaWithDB(), e.env.Config().DB.AppDebugWithDB())
+	e.initSchema(context.Background())
 	e.ticks.Start(e.onMigrationCheckTick)
 
 	if _, err := sqlparser.QueryMatchesTemplates("select 1 from dual", vexecUpdateTemplates); err != nil {
@@ -493,8 +474,7 @@ curl -s 'http://localhost:%d/schema-migration/report-status?uuid=%s&status=%s&dr
 			fmt.Sprintf(`--panic-flag-file=%s`, e.ghostPanicFlagFileName(onlineDDL.UUID)),
 			fmt.Sprintf(`--execute=%t`, execute),
 		}
-		opts, _ := shlex.Split(onlineDDL.Options)
-		args = append(args, opts...)
+		args = append(args, strings.Fields(onlineDDL.Options)...)
 		_, err := execCmd("bash", args, os.Environ(), "/tmp", nil, nil)
 		return err
 	}
@@ -721,8 +701,7 @@ export MYSQL_PWD
 				`--no-drop-old-table`,
 			)
 		}
-		opts, _ := shlex.Split(onlineDDL.Options)
-		args = append(args, opts...)
+		args = append(args, strings.Fields(onlineDDL.Options)...)
 		_, err = execCmd("bash", args, os.Environ(), "/tmp", nil, nil)
 		return err
 	}
@@ -1157,10 +1136,6 @@ func (e *Executor) onMigrationCheckTick() {
 	}
 	ctx := context.Background()
 
-	if err := e.initSchema(ctx); err != nil {
-		log.Error(err)
-		return
-	}
 	if err := e.scheduleNextMigration(ctx); err != nil {
 		log.Error(err)
 	}
diff --git a/go/vt/vttablet/onlineddl/schema.go b/go/vt/vttablet/onlineddl/schema.go
index 24602cb6b3..ef145320ff 100644
--- a/go/vt/vttablet/onlineddl/schema.go
+++ b/go/vt/vttablet/onlineddl/schema.go
@@ -18,6 +18,8 @@ package onlineddl
 
 import (
 	"fmt"
+
+	"vitess.io/vitess/go/vt/withddl"
 )
 
 const (
@@ -50,6 +52,7 @@ const (
 		KEY status_idx (migration_status, liveness_timestamp),
 		KEY cleanup_status_idx (cleanup_timestamp, migration_status)
 	) engine=InnoDB DEFAULT CHARSET=utf8mb4`
+	sqlValidationQuery         = `select 1 from %s.schema_migrations limit 1`
 	sqlScheduleSingleMigration = `UPDATE %s.schema_migrations
 		SET
 			migration_status='ready',
@@ -198,7 +201,7 @@ var (
 	sqlDropOnlineDDLUser = `DROP USER IF EXISTS %s`
 )
 
-var applyDDL = []string{
+var withDDL = withddl.New([]string{
 	fmt.Sprintf(sqlCreateSidecarDB, "_vt"),
 	fmt.Sprintf(sqlCreateSchemaMigrationsTable, "_vt"),
-}
+})
diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go
index 2a5b9f69b9..8c88333bc4 100644
--- a/go/vt/vttablet/tabletmanager/tm_init.go
+++ b/go/vt/vttablet/tabletmanager/tm_init.go
@@ -429,7 +429,7 @@ func (tm *TabletManager) rebuildKeyspace(keyspace string, retryInterval time.Dur
 				return
 			}
 		}
-		err = topotools.RebuildKeyspace(tm.BatchCtx, logutil.NewConsoleLogger(), tm.TopoServer, keyspace, []string{tm.tabletAlias.Cell}, false)
+		err = topotools.RebuildKeyspace(tm.BatchCtx, logutil.NewConsoleLogger(), tm.TopoServer, keyspace, []string{tm.tabletAlias.Cell})
 		if err == nil {
 			srvKeyspace, err = tm.TopoServer.GetSrvKeyspace(tm.BatchCtx, tm.tabletAlias.Cell, keyspace)
 			if err == nil {
diff --git a/go/vt/vttablet/tabletserver/health_streamer.go b/go/vt/vttablet/tabletserver/health_streamer.go
index 4eaf80fddc..85393c76ad 100644
--- a/go/vt/vttablet/tabletserver/health_streamer.go
+++ b/go/vt/vttablet/tabletserver/health_streamer.go
@@ -17,7 +17,6 @@ limitations under the License.
 package tabletserver
 
 import (
-	"flag"
 	"fmt"
 	"io"
 	"sync"
@@ -26,7 +25,6 @@ import (
 	"github.com/golang/protobuf/proto"
 	"golang.org/x/net/context"
 	"vitess.io/vitess/go/history"
-	"vitess.io/vitess/go/vt/log"
 	querypb "vitess.io/vitess/go/vt/proto/query"
 	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
@@ -41,8 +39,6 @@ var (
 	blpFunc = vreplication.StatusSummary
 
 	errUnintialized = "tabletserver uninitialized"
-
-	streamHealthBufferSize = flag.Uint("stream_health_buffer_size", 20, "max streaming health entries to buffer per streaming health client")
 )
 
 // healthStreamer streams health information to callers.
@@ -119,10 +115,7 @@ func (hs *healthStreamer) Stream(ctx context.Context, callback func(*querypb.Str
 			return nil
 		case <-hsCtx.Done():
 			return vterrors.Errorf(vtrpcpb.Code_UNAVAILABLE, "tabletserver is shutdown")
-		case shr, ok := <-ch:
-			if !ok {
-				return vterrors.Errorf(vtrpcpb.Code_RESOURCE_EXHAUSTED, "stream health buffer overflowed. client should reconnect for up-to-date status")
-			}
+		case shr := <-ch:
 			if err := callback(shr); err != nil {
 				if err == io.EOF {
 					return nil
@@ -141,7 +134,7 @@ func (hs *healthStreamer) register() (chan *querypb.StreamHealthResponse, contex
 		return nil, nil
 	}
 
-	ch := make(chan *querypb.StreamHealthResponse, *streamHealthBufferSize)
+	ch := make(chan *querypb.StreamHealthResponse, 1)
 	hs.clients[ch] = struct{}{}
 
 	// Send the current state immediately.
@@ -183,21 +176,6 @@ func (hs *healthStreamer) ChangeState(tabletType topodatapb.TabletType, terTimes
 		select {
 		case ch <- shr:
 		default:
-			// We can't block this state change on broadcasting to a streaming health client, but we
-			// also don't want to silently fail to inform a streaming health client of a state change
-			// because it can allow a vtgate to get wedged in a state where it's wrong about whether
-			// a tablet is healthy and can't automatically recover (see
-			//  https://github.com/vitessio/vitess/issues/5445). If we can't send a health update
-			// to this client we'll close() the channel which will ultimate fail the streaming health
-			// RPC and cause vtgates to reconnect.
-			//
-			// An alternative approach for streaming health would be to force a periodic broadcast even
-			// when there hasn't been an update and/or move away from using channels toward a model where
-			// old updates can be purged from the buffer in favor of more recent updates (since only the
-			// most recent health state really matters to gates).
-			log.Warning("A streaming health buffer is full. Closing the channel")
-			close(ch)
-			delete(hs.clients, ch)
 		}
 	}
 	hs.history.Add(&historyRecord{
@@ -209,7 +187,7 @@ func (hs *healthStreamer) ChangeState(tabletType topodatapb.TabletType, terTimes
 	})
 }
 
-func (hs *healthStreamer) AppendDetails(details []*kv) []*kv {
+func (hs *healthStreamer) ApppendDetails(details []*kv) []*kv {
 	hs.mu.Lock()
 	defer hs.mu.Unlock()
 	if hs.state.Target.TabletType == topodatapb.TabletType_MASTER {
diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go
index 06ea4e8ff6..2cf8235b8b 100644
--- a/go/vt/vttablet/tabletserver/query_executor.go
+++ b/go/vt/vttablet/tabletserver/query_executor.go
@@ -655,8 +655,8 @@ func (qre *QueryExecutor) generateFinalSQL(parsedQuery *sqlparser.ParsedQuery, b
 	if err != nil {
 		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%s", err)
 	}
-	withoutComments := query
 	buf.WriteString(query)
+	withoutComments := buf.String()
 	buf.WriteString(qre.marginComments.Trailing)
 	fullSQL := buf.String()
 	return fullSQL, withoutComments, nil
diff --git a/go/vt/vttablet/tabletserver/state_manager.go b/go/vt/vttablet/tabletserver/state_manager.go
index 272340217e..4a43be11ef 100644
--- a/go/vt/vttablet/tabletserver/state_manager.go
+++ b/go/vt/vttablet/tabletserver/state_manager.go
@@ -654,7 +654,7 @@ func (sm *stateManager) isServingLocked() bool {
 	return sm.state == StateServing && sm.wantState == StateServing && sm.replHealthy && !sm.lameduck
 }
 
-func (sm *stateManager) AppendDetails(details []*kv) []*kv {
+func (sm *stateManager) ApppendDetails(details []*kv) []*kv {
 	sm.mu.Lock()
 	defer sm.mu.Unlock()
 
diff --git a/go/vt/vttablet/tabletserver/status.go b/go/vt/vttablet/tabletserver/status.go
index ca95a2c2c4..d8d1244f0f 100644
--- a/go/vt/vttablet/tabletserver/status.go
+++ b/go/vt/vttablet/tabletserver/status.go
@@ -246,8 +246,8 @@ func (tsv *TabletServer) AddStatusPart() {
 		} else {
 			status.Latest = &historyRecord{}
 		}
-		status.Details = tsv.sm.AppendDetails(nil)
-		status.Details = tsv.hs.AppendDetails(status.Details)
+		status.Details = tsv.sm.ApppendDetails(nil)
+		status.Details = tsv.hs.ApppendDetails(status.Details)
 		rates := tsv.stats.QPSRates.Get()
 		if qps, ok := rates["All"]; ok && len(qps) > 0 {
 			status.CurrentQPS = qps[0]
@@ -257,8 +257,8 @@ func (tsv *TabletServer) AddStatusPart() {
 
 	tsv.exporter.HandleFunc("/debug/status_details", func(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Content-Type", "application/json; charset=utf-8")
-		details := tsv.sm.AppendDetails(nil)
-		details = tsv.hs.AppendDetails(details)
+		details := tsv.sm.ApppendDetails(nil)
+		details = tsv.hs.ApppendDetails(details)
 		b, err := json.MarshalIndent(details, "", " ")
 		if err != nil {
 			w.Write([]byte(err.Error()))
diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go
index e57086015c..280416e218 100644
--- a/go/vt/vttablet/tabletserver/tabletserver.go
+++ b/go/vt/vttablet/tabletserver/tabletserver.go
@@ -353,7 +353,8 @@ func (tsv *TabletServer) StopService() {
 // connect to the database and serving traffic), or an error explaining
 // the unhealthiness otherwise.
 func (tsv *TabletServer) IsHealthy() error {
-	if tsv.IsServingType() {
+	switch tsv.sm.Target().TabletType {
+	case topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_BATCH, topodatapb.TabletType_EXPERIMENTAL:
 		_, err := tsv.Execute(
 			tabletenv.LocalContext(),
 			nil,
@@ -364,18 +365,8 @@ func (tsv *TabletServer) IsHealthy() error {
 			nil,
 		)
 		return err
-	}
-	return nil
-}
-
-// IsServingType returns true if the tablet type is one that should be serving to be healthy, or false if the tablet type
-// should not be serving in it's healthy state.
-func (tsv *TabletServer) IsServingType() bool {
-	switch tsv.sm.Target().TabletType {
-	case topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_BATCH, topodatapb.TabletType_EXPERIMENTAL:
-		return true
 	default:
-		return false
+		return nil
 	}
 }
 
@@ -1473,7 +1464,7 @@ func (tsv *TabletServer) registerHealthzHealthHandler() {
 			acl.SendError(w, err)
 			return
 		}
-		if tsv.sm.Target().TabletType != topodatapb.TabletType_SPARE && !tsv.sm.IsServing() {
+		if !tsv.sm.IsServing() {
 			http.Error(w, "500 internal server error: vttablet is not serving", http.StatusInternalServerError)
 			return
 		}
diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go
index d6ecaee211..6d59cbc60d 100644
--- a/go/vt/wrangler/keyspace.go
+++ b/go/vt/wrangler/keyspace.go
@@ -1184,7 +1184,7 @@ func (wr *Wrangler) MigrateServedFrom(ctx context.Context, keyspace, shard strin
 
 	// rebuild the keyspace serving graph if there was no error
 	if err == nil {
-		err = topotools.RebuildKeyspaceLocked(ctx, wr.logger, wr.ts, keyspace, cells, false)
+		err = topotools.RebuildKeyspaceLocked(ctx, wr.logger, wr.ts, keyspace, cells)
 	}
 
 	return err
diff --git a/go/vt/wrangler/rebuild.go b/go/vt/wrangler/rebuild.go
index c1c3b6eea3..f942f1d582 100644
--- a/go/vt/wrangler/rebuild.go
+++ b/go/vt/wrangler/rebuild.go
@@ -22,6 +22,6 @@ import (
 )
 
 // RebuildKeyspaceGraph rebuilds the serving graph data while locking out other changes.
-func (wr *Wrangler) RebuildKeyspaceGraph(ctx context.Context, keyspace string, cells []string, allowPartial bool) error {
-	return topotools.RebuildKeyspace(ctx, wr.logger, wr.ts, keyspace, cells, allowPartial)
+func (wr *Wrangler) RebuildKeyspaceGraph(ctx context.Context, keyspace string, cells []string) error {
+	return topotools.RebuildKeyspace(ctx, wr.logger, wr.ts, keyspace, cells)
 }
diff --git a/go/vt/wrangler/vdiff.go b/go/vt/wrangler/vdiff.go
index 70b5ab3da6..087963cdf1 100644
--- a/go/vt/wrangler/vdiff.go
+++ b/go/vt/wrangler/vdiff.go
@@ -116,7 +116,8 @@ type shardStreamer struct {
 
 // VDiff reports differences between the sources and targets of a vreplication workflow.
 func (wr *Wrangler) VDiff(ctx context.Context, targetKeyspace, workflow, sourceCell, targetCell, tabletTypesStr string,
-	filteredReplicationWaitTime time.Duration, format string, maxRows int64) (map[string]*DiffReport, error) {
+	filteredReplicationWaitTime time.Duration,
+	format string) (map[string]*DiffReport, error) {
 	log.Infof("Starting VDiff for %s.%s, sourceCell %s, targetCell %s, tabletTypes %s, timeout %s",
 		targetKeyspace, workflow, sourceCell, targetCell, tabletTypesStr, filteredReplicationWaitTime.String())
 	// Assign defaults to sourceCell and targetCell if not specified.
@@ -201,7 +202,6 @@ func (wr *Wrangler) VDiff(ctx context.Context, targetKeyspace, workflow, sourceC
 	defer cancel()
 
 	// TODO(sougou): parallelize
-	rowsToCompare := maxRows
 	diffReports := make(map[string]*DiffReport)
 	jsonOutput := ""
 	for table, td := range df.differs {
@@ -226,7 +226,7 @@ func (wr *Wrangler) VDiff(ctx context.Context, targetKeyspace, workflow, sourceC
 			return nil, vterrors.Wrap(err, "restartTargets")
 		}
 		// Perform the diff of source and target streams.
-		dr, err := td.diff(ctx, df.ts.wr, &rowsToCompare)
+		dr, err := td.diff(ctx, df.ts.wr)
 		if err != nil {
 			return nil, vterrors.Wrap(err, "diff")
 		}
@@ -804,7 +804,7 @@ func logSteps(n int64) string {
 //-----------------------------------------------------------------
 // tableDiffer
 
-func (td *tableDiffer) diff(ctx context.Context, wr *Wrangler, rowsToCompare *int64) (*DiffReport, error) {
+func (td *tableDiffer) diff(ctx context.Context, wr *Wrangler) (*DiffReport, error) {
 	sourceExecutor := newPrimitiveExecutor(ctx, td.sourcePrimitive)
 	targetExecutor := newPrimitiveExecutor(ctx, td.targetPrimitive)
 	dr := &DiffReport{}
@@ -814,12 +814,7 @@ func (td *tableDiffer) diff(ctx context.Context, wr *Wrangler, rowsToCompare *in
 	advanceTarget := true
 	for {
 		if s := logSteps(int64(dr.ProcessedRows)); s != "" {
-			log.Infof("VDiff processed %s rows", td.targetTable, s)
-		}
-		*rowsToCompare--
-		if *rowsToCompare < 0 {
-			log.Infof("Stopping vdiff, specified limit reached")
-			return dr, nil
+			log.Infof("VDiff processed %s rows", s)
 		}
 		if advanceSource {
 			sourceRow, err = sourceExecutor.next()
diff --git a/go/vt/wrangler/vexec.go b/go/vt/wrangler/vexec.go
index 36839316f1..8f6008d893 100644
--- a/go/vt/wrangler/vexec.go
+++ b/go/vt/wrangler/vexec.go
@@ -561,9 +561,6 @@ func dumpStreamListAsJSON(replStatus *ReplicationStatusResult, wr *Wrangler) err
 
 func (wr *Wrangler) printWorkflowList(workflows []string) {
 	list := strings.Join(workflows, ", ")
-	if list == "" {
-		return
-	}
 	wr.Logger().Printf("Workflows: %v", list)
 }
 
diff --git a/java/client/pom.xml b/java/client/pom.xml
index e2f100bf74..69d2bf8b12 100644
--- a/java/client/pom.xml
+++ b/java/client/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.vitess</groupId>
     <artifactId>vitess-parent</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
+    <version>8.0.0-SNAPSHOT</version>
   </parent>
   <artifactId>vitess-client</artifactId>
 
diff --git a/java/example/pom.xml b/java/example/pom.xml
index 803073c9ee..da0487e8bf 100644
--- a/java/example/pom.xml
+++ b/java/example/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.vitess</groupId>
     <artifactId>vitess-parent</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
+    <version>8.0.0-SNAPSHOT</version>
   </parent>
   <artifactId>vitess-example</artifactId>
 
diff --git a/java/grpc-client/pom.xml b/java/grpc-client/pom.xml
index faa9207894..0984783dd2 100644
--- a/java/grpc-client/pom.xml
+++ b/java/grpc-client/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.vitess</groupId>
     <artifactId>vitess-parent</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
+    <version>8.0.0-SNAPSHOT</version>
   </parent>
   <artifactId>vitess-grpc-client</artifactId>
 
diff --git a/java/jdbc/pom.xml b/java/jdbc/pom.xml
index da3d41e23b..8a8126cdcd 100644
--- a/java/jdbc/pom.xml
+++ b/java/jdbc/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>io.vitess</groupId>
     <artifactId>vitess-parent</artifactId>
-    <version>9.0.0-SNAPSHOT</version>
+    <version>8.0.0-SNAPSHOT</version>
   </parent>
   <artifactId>vitess-jdbc</artifactId>
 
diff --git a/java/pom.xml b/java/pom.xml
index 7bdd5f3bf6..15ece71613 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -11,7 +11,7 @@
 
   <groupId>io.vitess</groupId>
   <artifactId>vitess-parent</artifactId>
-  <version>9.0.0-SNAPSHOT</version>
+  <version>8.0.0-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>Vitess Java Client libraries [Parent]</name>
diff --git a/tools/rowlog/rowlog.go b/tools/rowlog/rowlog.go
new file mode 100644
index 0000000000..09f041c60d
--- /dev/null
+++ b/tools/rowlog/rowlog.go
@@ -0,0 +1,502 @@
+package main
+
+import (
+	"context"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+	"vitess.io/vitess/go/mysql"
+	"vitess.io/vitess/go/sqltypes"
+	"vitess.io/vitess/go/vt/discovery"
+	"vitess.io/vitess/go/vt/log"
+	"vitess.io/vitess/go/vt/logutil"
+	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
+	logutilpb "vitess.io/vitess/go/vt/proto/logutil"
+	"vitess.io/vitess/go/vt/proto/query"
+	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
+	"vitess.io/vitess/go/vt/topo"
+	_ "vitess.io/vitess/go/vt/topo/etcd2topo"
+	_ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn"
+	_ "vitess.io/vitess/go/vt/vttablet/grpctabletconn"
+
+	_ "vitess.io/vitess/go/vt/vtctl/grpcvtctlclient"
+	"vitess.io/vitess/go/vt/vtctl/vtctlclient"
+	"vitess.io/vitess/go/vt/vtgate/vtgateconn"
+)
+
+type RowLogConfig struct {
+	ids, cells []string
+
+	sourceKeyspace, targetKeyspace, table, vtgate, vtctld, pk string
+}
+
+func (rlc *RowLogConfig) String() string {
+	s := fmt.Sprintf("\tsource:%s, target:%s, table:%s, ids:%s, pk:%s\n",
+		rlc.sourceKeyspace, rlc.targetKeyspace, rlc.table, strings.Join(rlc.ids, ","), rlc.pk)
+	s += fmt.Sprintf("\tvtgate:%s, vtctld:%s, cells:%s", rlc.vtgate, rlc.vtctld, strings.Join(rlc.cells, ","))
+	return s
+}
+
+func (rlc *RowLogConfig) Validate() bool {
+	if rlc.table == "" || len(rlc.cells) == 0 || rlc.vtctld == "" || rlc.vtgate == "" || len(rlc.ids) == 0 || rlc.targetKeyspace == "" || rlc.sourceKeyspace == "" || rlc.pk == "" {
+		return false
+	}
+	return true
+}
+
+func usage() {
+	logger := logutil.NewConsoleLogger()
+	flag.CommandLine.SetOutput(logutil.NewLoggerWriter(logger))
+	flag.Usage = func() {
+		logger.Printf("Rowlog Usage:\n")
+		s := "rowlog -ids <id list csv> -table <table_name> -pk <primary_key_only_ints> -source <source_keyspace> -target <target_keyspace> "
+		s += "-vtctld <vtctl url> -vtgate <vtgate url> -cells <cell names csv> -topo_implementation <topo type, eg: etcd2> "
+		s += "-topo_global_server_address <top url> -topo_global_root <topo root dir>\n"
+		logger.Printf(s)
+	}
+}
+
+func main() {
+	usage()
+	defer log.Flush()
+	ctx := context.Background()
+	config := parseCommandLine()
+	if !config.Validate() {
+		flag.Usage()
+		return
+	}
+	log.Infof("Starting rowlogger with config: %s", config)
+	fmt.Printf("Starting rowlogger with\n%v\n", config)
+	ts := topo.Open()
+	sourceTablet := getTablet(ctx, ts, config.cells, config.sourceKeyspace)
+	targetTablet := getTablet(ctx, ts, config.cells, config.targetKeyspace)
+	log.Infof("Using tablets %s and %s to get positions", sourceTablet, targetTablet)
+
+	var wg sync.WaitGroup
+	var stream = func(keyspace, tablet string) {
+		defer wg.Done()
+		var startPos, stopPos string
+		var i int
+		var done, fieldsPrinted bool
+		var err error
+		for {
+			i++
+			if i > 100 {
+				log.Errorf("returning without completion : Timing out for keyspace %s", keyspace)
+				return
+			}
+			log.Infof("%s Iteration:%d", keyspace, i)
+			startPos, stopPos, done, fieldsPrinted, err = startStreaming(ctx, config.vtgate, config.vtctld, keyspace, tablet, config.table, config.pk, config.ids, startPos, stopPos, fieldsPrinted)
+			if done {
+				log.Infof("Finished streaming all events for keyspace %s", keyspace)
+				fmt.Printf("Finished streaming all events for keyspace %s\n", keyspace)
+				return
+			}
+			if startPos != "" {
+				log.Infof("resuming streaming from %s, error received was %v", startPos, err)
+			} else {
+				log.Errorf("returning without completion of keyspace %s because of error %v", keyspace, err)
+				return
+			}
+		}
+	}
+
+	wg.Add(1)
+	go stream(config.sourceKeyspace, sourceTablet)
+
+	wg.Add(1)
+	go stream(config.targetKeyspace, targetTablet)
+
+	wg.Wait()
+
+	log.Infof("rowlog done streaming from both source and target")
+	fmt.Printf("\n\nRowlog completed\nIf the program worked you should see two log files with the related binlog entries: %s.log and %s.log\n",
+		config.sourceKeyspace, config.targetKeyspace)
+}
+
+func startStreaming(ctx context.Context, vtgate, vtctld, keyspace, tablet, table, pk string, ids []string, startPos, stopPos string, fieldsPrinted bool) (string, string, bool, bool, error) {
+	var err error
+	if startPos == "" {
+		flavor := getFlavor(ctx, vtctld, keyspace)
+		if flavor == "" {
+			log.Errorf("Invalid flavor for %s", keyspace)
+			return "", "", false, false, nil
+		}
+		startPos, stopPos, err = getPositions(ctx, vtctld, tablet)
+		startPos = flavor + "/" + startPos
+		stopPos = flavor + "/" + stopPos
+	}
+	log.Infof("Streaming keyspace %s from %s upto %s", keyspace, startPos, stopPos)
+	fmt.Printf("Streaming keyspace %s from %s upto %s\n", keyspace, startPos, stopPos)
+	vgtid := &binlogdatapb.VGtid{
+		ShardGtids: []*binlogdatapb.ShardGtid{{
+			Keyspace: keyspace,
+			Shard:    "0",
+			Gtid:     startPos,
+		}},
+	}
+	filter := &binlogdatapb.Filter{
+		Rules: []*binlogdatapb.Rule{{
+			Match:  table,
+			Filter: "select * from " + table,
+		}},
+		FieldEventMode: 1,
+	}
+	conn, err := vtgateconn.Dial(ctx, vtgate)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer conn.Close()
+	reader, err := conn.VStream(ctx, topodatapb.TabletType_MASTER, vgtid, filter)
+	var fields []*query.Field
+	var gtid string
+	var plan *TablePlan
+	var lastLoggedAt int64
+	var totalRowsForTable, filteredRows int
+	for {
+		evs, err := reader.Recv()
+		//fmt.Printf("events received: %d\n",len(evs))
+		switch err {
+		case nil:
+			for _, ev := range evs {
+				now := time.Now().Unix()
+				if now-lastLoggedAt > 60 && ev.Timestamp != 0 { //every minute
+					lastLoggedAt = now
+					log.Infof("%s Progress: %d/%d rows, %s: %s", keyspace, filteredRows, totalRowsForTable,
+						time.Unix(ev.Timestamp, 0).Format(time.RFC3339), gtid)
+					fmt.Printf(".")
+				}
+				switch ev.Type {
+				case binlogdatapb.VEventType_VGTID:
+					gtid = ev.Vgtid.ShardGtids[0].Gtid
+					//fmt.Printf("gtid %s\n", gtid)
+				case binlogdatapb.VEventType_FIELD:
+					fields = ev.FieldEvent.Fields
+					//fmt.Printf("field %s\n", fields)
+					plan = getTablePlan(keyspace, fields, ev.FieldEvent.TableName, pk, ids)
+					if !fieldsPrinted {
+						outputHeader(plan)
+						fieldsPrinted = true
+					}
+				case binlogdatapb.VEventType_ROW:
+					totalRowsForTable += len(ev.RowEvent.RowChanges)
+					rows := processRowEvent(plan, gtid, ev)
+					if len(rows) > 0 {
+						//fmt.Printf("#rows %d\n", len(rows))
+						filteredRows += len(rows)
+						outputRows(plan, rows)
+					}
+				default:
+					//fmt.Printf("event type %v\n",ev.Type)
+				}
+			}
+			//fmt.Printf("stopPos %s\n", stopPos)
+			var err error
+			var currentPosition, stopPosition mysql.Position
+			currentPosition, err = mysql.DecodePosition(gtid)
+			if err != nil {
+				fmt.Errorf("Error decoding position for %s:%vs\n", gtid, err.Error())
+			}
+			stopPosition, err = mysql.DecodePosition(stopPos)
+			if err != nil {
+				fmt.Errorf("Error decoding position for %s:%vs\n", stopPos, err.Error())
+			}
+			if currentPosition.AtLeast(stopPosition) {
+				log.Infof("Finished streaming keyspace %s from %s upto %s, total rows seen %d", keyspace, startPos, stopPos, totalRowsForTable)
+				return "", "", true, true, nil
+			}
+			// return gtid, stopPos, false, fieldsPrinted, nil //uncomment for testing resumability
+		case io.EOF:
+			log.Infof("stream ended before reaching stop pos")
+			fmt.Printf("stream ended before reaching stop pos\n")
+			return "", "", false, fieldsPrinted, nil
+		default:
+			log.Errorf("remote error: %s, returning gtid %s, stopPos %s", err, gtid, stopPos)
+			fmt.Printf("remote error: %s, returning gtid %s, stopPos %s\n", err.Error(), gtid, stopPos)
+			return gtid, stopPos, false, fieldsPrinted, err
+		}
+	}
+}
+
+func output(filename, s string) {
+	f, err := os.OpenFile(filename+".log",
+		os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+	if err != nil {
+		log.Errorf(err.Error())
+	}
+	defer f.Close()
+	if _, err := f.WriteString(s + "\n"); err != nil {
+		log.Errorf(err.Error())
+	}
+	log.Infof("Writing to %s.log: %s", filename, s)
+}
+
+func outputHeader(plan *TablePlan) {
+	s := getHeader(plan)
+	output(plan.keyspace, s)
+}
+
+func getHeader(plan *TablePlan) string {
+	s := ""
+	for _, field := range plan.fields {
+		s += field.Name + "\t"
+	}
+	s += fmt.Sprintf("op\ttimestamp\tgtid")
+	return s
+}
+
+func outputRows(plan *TablePlan, rows []*RowLog) {
+	for _, row := range rows {
+		s := ""
+		for _, val := range row.values {
+			s += val + "\t"
+		}
+		s += fmt.Sprintf("%s\t%s\t%s", row.op, row.when, row.gtid)
+		output(plan.keyspace, s)
+	}
+}
+
+func mustSend(plan *TablePlan, afterVals, beforeVals []string) bool {
+	if len(afterVals) > 0 {
+		if _, ok := plan.allowedIds[afterVals[plan.pkIndex]]; ok {
+			return true
+		}
+	}
+	if len(beforeVals) > 0 {
+		if _, ok := plan.allowedIds[beforeVals[plan.pkIndex]]; ok {
+			return true
+		}
+	}
+	return false
+}
+
+type RowLog struct {
+	op     string
+	values []string
+	when   string
+	gtid   string
+}
+
+func processRowEvent(plan *TablePlan, gtid string, ev *binlogdatapb.VEvent) []*RowLog {
+	op := "insert"
+	var rowLogs []*RowLog
+	for _, change := range ev.RowEvent.RowChanges {
+		var after, before []sqltypes.Value
+		var afterVals, beforeVals []string
+		if change.After != nil {
+			after = sqltypes.MakeRowTrusted(plan.fields, change.After)
+		}
+		if change.Before != nil {
+			before = sqltypes.MakeRowTrusted(plan.fields, change.Before)
+		}
+		for _, val := range after {
+			afterVals = append(afterVals, string(val.ToBytes()))
+		}
+		for _, val := range before {
+			beforeVals = append(beforeVals, string(val.ToBytes()))
+		}
+		if !mustSend(plan, afterVals, beforeVals) {
+			continue
+		}
+
+		if len(after) > 0 && len(before) > 0 {
+			op = "update"
+		} else if len(before) > 0 {
+			op = "delete"
+			afterVals = beforeVals
+		}
+
+		rowLog := &RowLog{
+			op:     op,
+			values: afterVals,
+			when:   time.Unix(ev.Timestamp, 0).Format(time.RFC3339),
+			gtid:   gtid,
+		}
+		rowLogs = append(rowLogs, rowLog)
+	}
+	return rowLogs
+}
+
+func getTablePlan(keyspace string, fields []*query.Field, table, pk string, ids []string) *TablePlan {
+	allowedIds := make(map[string]bool)
+	for _, id := range ids {
+		allowedIds[id] = true
+	}
+	var pkIndex int64
+	for i, field := range fields {
+		if field.Name == pk {
+			pkIndex = int64(i)
+			break
+		}
+	}
+	return &TablePlan{
+		table:      table,
+		pk:         pk,
+		allowedIds: allowedIds,
+		pkIndex:    pkIndex,
+		fields:     fields,
+		keyspace:   keyspace,
+	}
+}
+
+type TablePlan struct {
+	table, pk  string
+	allowedIds map[string]bool
+	pkIndex    int64
+	fields     []*query.Field
+	keyspace   string
+}
+
+func getFlavor(ctx context.Context, server, keyspace string) string {
+	curPos, err := getPosition(ctx, server, keyspace, "0")
+	//fmt.Printf("curpos is %s\n", curPos)
+	if err != nil {
+		return ""
+	}
+	if curPos == "" {
+		return ""
+	}
+	flavor := strings.Split(curPos, "/")[0]
+	return flavor
+}
+
+func getTablet(ctx context.Context, ts *topo.Server, cells []string, keyspace string) string {
+	picker, err := discovery.NewTabletPicker(ts, cells, keyspace, "0", "master")
+	if err != nil {
+		return ""
+	}
+	tab, err := picker.PickForStreaming(ctx)
+	if err != nil {
+		return ""
+	}
+	tabletId := fmt.Sprintf("%s-%d", tab.Alias.Cell, tab.Alias.Uid)
+	return tabletId
+
+}
+func parseCommandLine() *RowLogConfig {
+	sourceKeyspace := flag.String("source", "", "")
+	targetKeyspace := flag.String("target", "", "")
+	ids := flag.String("ids", "", "")
+	pk := flag.String("pk", "", "")
+	table := flag.String("table", "", "")
+	vtgate := flag.String("vtgate", "", "")
+	vtctld := flag.String("vtctld", "", "")
+	cells := flag.String("cells", "", "")
+
+	flag.Parse()
+
+	return &RowLogConfig{
+		sourceKeyspace: *sourceKeyspace,
+		targetKeyspace: *targetKeyspace,
+		table:          *table,
+		pk:             *pk,
+		ids:            strings.Split(*ids, ","),
+		vtctld:         *vtctld,
+		vtgate:         *vtgate,
+		cells:          strings.Split(*cells, ","),
+	}
+}
+
+func processPositionResult(gtidset string) (string, string) {
+	gtids := strings.Trim(strings.Replace(gtidset, "|", "", 10), " \n")
+	arr := strings.Split(gtids, ":")
+	subs := strings.Split(arr[1], "-")
+	id, err := strconv.Atoi(subs[0])
+	if err != nil {
+		fmt.Errorf(err.Error())
+		return "", ""
+	}
+	firstPos := arr[0] + ":" + strconv.Itoa(id) //subs[0]
+	lastPos := gtids
+	return firstPos, lastPos
+}
+
+// hack, should read json in a structured manner
+func parseExecOutput(result string) string {
+	resultMap := make(map[string]interface{})
+	err := json.Unmarshal([]byte(result), &resultMap)
+	if err != nil {
+		fmt.Errorf("error parsing result json %s", result)
+		return ""
+	}
+	rows := reflect.ValueOf(resultMap["rows"])
+	s := fmt.Sprintf("%v", rows)
+	s = strings.Trim(s, "[]")
+	//fmt.Printf("gtidset %s", s)
+	return s
+}
+
+func getPositions(ctx context.Context, server, tablet string) (string, string, error) {
+	query := "select GTID_SUBTRACT(@@GLOBAL.gtid_executed, GTID_SUBTRACT(@@GLOBAL.gtid_executed, @@GLOBAL.gtid_purged));"
+	results, err := execVtctl(ctx, server, []string{"ExecuteFetchAsDba", "-json", tablet, query})
+	if err != nil {
+		fmt.Println(err)
+		log.Errorf(err.Error())
+		return "", "", err
+	}
+	//fmt.Printf("results are %v\n", results)
+	firstPos := parseExecOutput(strings.Join(results, ""))
+
+	query = "select @@GLOBAL.gtid_executed;"
+	results, err = execVtctl(ctx, server, []string{"ExecuteFetchAsDba", "-json", tablet, query})
+	if err != nil {
+		fmt.Println(err)
+		log.Errorf(err.Error())
+		return "", "", err
+	}
+	//fmt.Printf("results are %v\n", results)
+	lastPos := parseExecOutput(strings.Join(results, ""))
+	//fmt.Printf("firstPos %s, lastPos %s\n", firstPos, lastPos)
+	return firstPos, lastPos, nil
+}
+
+func getPosition(ctx context.Context, server, keyspace, shard string) (string, error) {
+	results, err := execVtctl(ctx, server, []string{"ShardReplicationPositions", fmt.Sprintf("%s:%s", keyspace, shard)})
+	if err != nil {
+		fmt.Println(err)
+		return "", err
+	}
+	splits := strings.Split(results[0], " ")
+	return splits[8], nil
+}
+
+func execVtctl(ctx context.Context, server string, args []string) ([]string, error) {
+	client, err := vtctlclient.New(server)
+	if err != nil {
+		fmt.Println(err)
+		return nil, err
+	}
+	if client == nil {
+		fmt.Printf("Unable to contact %s\n", server)
+		return nil, fmt.Errorf("unable to contact %s\n", server)
+	}
+	defer client.Close()
+
+	stream, err := client.ExecuteVtctlCommand(ctx, args, 10*time.Second)
+	if err != nil {
+		return nil, fmt.Errorf("cannot execute remote command: %v", err)
+	}
+
+	var results []string
+	for {
+		e, err := stream.Recv()
+		switch err {
+		case nil:
+			if e.Level == logutilpb.Level_CONSOLE {
+				results = append(results, e.Value)
+			}
+		case io.EOF:
+			return results, nil
+		default:
+			log.Errorf("remote error: %v", err)
+			return nil, fmt.Errorf("remote error: %v", err)
+		}
+	}
+}
diff --git a/tools/rowlog/rowlog.md b/tools/rowlog/rowlog.md
new file mode 100644
index 0000000000..1564dfeac8
--- /dev/null
+++ b/tools/rowlog/rowlog.md
@@ -0,0 +1,35 @@
+#rowlog
+
+`rowlog` is a diagnostic tool for researching issues reported by users in vreplication workflows. These are usually
+reported as data mismatches or loss and are not reproducible because of the huge amounts of data involved and 
+data privacy reasons. Also, the database configurations vary greatly: number/type/size of columns, collations, 
+keys/indexes etc.
+
+In order to rule out that the problem is not related to the core vreplication algorithm this tool has been built.
+
+`rowlog` is a standalone command-line tool. For a given set of primary keys for a table (only non-composite 
+integer primary keys are supported) it outputs the binlogs associated with these ids, both on the source and
+on the target. 
+
+The binlogs on the source and target will usually not be identical because vreplication can "merge" multiple 
+binlog entries during the initial copy phase. 
+
+`rowlog` uses the vstream API to stream events for the specified table from both the source and target keyspaces.
+
+Here is an example of how to invoke it:
+
+```
+go build
+./rowlog -ids 1,3,4 -table customer -pk customer_id -source commerce -target customer -vtctld localhost:15999 
+        -vtgate localhost:15991 -cells zone1 -topo_implementation etcd2 -topo_global_server_address localhost:2379 
+        -topo_global_root /vitess/global
+```
+
+The resulting binlog entries are output to two tab-separated files which can be inspected to validate if 
+data being copied is consistent.
+
+Initial version is for unsharded keyspaces but can be easily extended for sharded. 
+
+Another possible enhancement is to also stream the events to the _vt.vreplication table so that we can track the 
+source gtid positions related to the sql applied on the target. However this requires changes in vreplication: 
+currently the sidecar _vt database is not streamed.


Test patch:
diff --git a/go/test/endtoend/vreplication/config.go b/go/test/endtoend/vreplication/config.go
index 2f031b329f..cd06ff3cee 100644
--- a/go/test/endtoend/vreplication/config.go
+++ b/go/test/endtoend/vreplication/config.go
@@ -3,7 +3,7 @@ package vreplication
 var (
 	initialProductSchema = `
 create table product(pid int, description varbinary(128), primary key(pid));
-create table customer(cid int, name varbinary(128), typ enum('individual','soho','enterprise'), primary key(cid));
+create table customer(cid int, name varbinary(128),	primary key(cid));
 create table merchant(mname varchar(128), category varchar(128), primary key(mname)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 create table orders(oid int, cid int, pid int, mname varchar(128), price int, primary key(oid));
 create table customer_seq(id int, next_id bigint, cache bigint, primary key(id)) comment 'vitess_sequence';
diff --git a/go/test/endtoend/vreplication/unsharded_init_data.sql b/go/test/endtoend/vreplication/unsharded_init_data.sql
index 9b405e76b8..955392b075 100644
--- a/go/test/endtoend/vreplication/unsharded_init_data.sql
+++ b/go/test/endtoend/vreplication/unsharded_init_data.sql
@@ -1,6 +1,6 @@
-insert into customer(cid, name, typ) values(1, 'john',1);
-insert into customer(cid, name, typ) values(2, 'paul','soho');
-insert into customer(cid, name, typ) values(3, 'ringo','enterprise');
+insert into customer(cid, name) values(1, 'john');
+insert into customer(cid, name) values(2, 'paul');
+insert into customer(cid, name) values(3, 'ringo');
 insert into merchant(mname, category) values('monoprice', 'electronics');
 insert into merchant(mname, category) values('newegg', 'electronics');
 insert into product(pid, description) values(1, 'keyboard');
diff --git a/go/vt/hook/hook_test.go b/go/vt/hook/hook_test.go
deleted file mode 100644
index fd9235f14b..0000000000
--- a/go/vt/hook/hook_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package hook
-
-import (
-	"context"
-	"os"
-	"os/exec"
-	"path"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	vtenv "vitess.io/vitess/go/vt/env"
-)
-
-func TestExecuteContext(t *testing.T) {
-	vtroot, err := vtenv.VtRoot()
-	require.NoError(t, err)
-
-	sleep, err := exec.LookPath("sleep")
-	require.NoError(t, err)
-
-	sleepHookPath := path.Join(vtroot, "vthook", "sleep")
-	require.NoError(t, os.Symlink(sleep, sleepHookPath))
-	defer func() {
-		require.NoError(t, os.Remove(sleepHookPath))
-	}()
-
-	h := NewHook("sleep", []string{"5"})
-	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*10)
-	defer cancel()
-
-	hr := h.ExecuteContext(ctx)
-	assert.Equal(t, HOOK_TIMEOUT_ERROR, hr.ExitStatus)
-
-	h.Parameters = []string{"0.1"}
-	hr = h.Execute()
-	assert.Equal(t, HOOK_SUCCESS, hr.ExitStatus)
-}
diff --git a/go/vt/mysqlctl/builtinbackupengine_test.go b/go/vt/mysqlctl/builtinbackupengine_test.go
deleted file mode 100644
index 3e9b739839..0000000000
--- a/go/vt/mysqlctl/builtinbackupengine_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Package mysqlctl_test is the blackbox tests for package mysqlctl.
-// Tests that need to use fakemysqldaemon must be written as blackbox tests;
-// since fakemysqldaemon imports mysqlctl, importing fakemysqldaemon in
-// a `package mysqlctl` test would cause a circular import.
-package mysqlctl_test
-
-import (
-	"context"
-	"os"
-	"path"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"vitess.io/vitess/go/mysql/fakesqldb"
-	"vitess.io/vitess/go/vt/logutil"
-	"vitess.io/vitess/go/vt/mysqlctl"
-	"vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon"
-	"vitess.io/vitess/go/vt/mysqlctl/filebackupstorage"
-	"vitess.io/vitess/go/vt/proto/topodata"
-	"vitess.io/vitess/go/vt/proto/vttime"
-	"vitess.io/vitess/go/vt/topo"
-	"vitess.io/vitess/go/vt/topo/memorytopo"
-	"vitess.io/vitess/go/vt/vttablet/faketmclient"
-	"vitess.io/vitess/go/vt/vttablet/tmclient"
-)
-
-func setBuiltinBackupMysqldDeadline(t time.Duration) time.Duration {
-	old := *mysqlctl.BuiltinBackupMysqldTimeout
-	mysqlctl.BuiltinBackupMysqldTimeout = &t
-
-	return old
-}
-
-func createBackupDir(root string, dirs ...string) error {
-	for _, dir := range dirs {
-		if err := os.MkdirAll(path.Join(root, dir), 0755); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func TestExecuteBackup(t *testing.T) {
-	// Set up local backup directory
-	backupRoot := "testdata/builtinbackup_test"
-	*filebackupstorage.FileBackupStorageRoot = backupRoot
-	require.NoError(t, createBackupDir(backupRoot, "innodb", "log", "datadir"))
-	defer os.RemoveAll(backupRoot)
-
-	ctx := context.Background()
-
-	// Set up topo
-	keyspace, shard := "mykeyspace", "-80"
-	ts := memorytopo.NewServer("cell1")
-	defer ts.Close()
-
-	require.NoError(t, ts.CreateKeyspace(ctx, keyspace, &topodata.Keyspace{}))
-	require.NoError(t, ts.CreateShard(ctx, keyspace, shard))
-
-	tablet := topo.NewTablet(100, "cell1", "mykeyspace-00-80-0100")
-	tablet.Keyspace = keyspace
-	tablet.Shard = shard
-
-	require.NoError(t, ts.CreateTablet(ctx, tablet))
-
-	_, err := ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error {
-		si.MasterAlias = &topodata.TabletAlias{Uid: 100, Cell: "cell1"}
-
-		now := time.Now()
-		si.MasterTermStartTime = &vttime.Time{Seconds: int64(now.Second()), Nanoseconds: int32(now.Nanosecond())}
-
-		return nil
-	})
-	require.NoError(t, err)
-
-	// Set up tm client
-	// Note that using faketmclient.NewFakeTabletManagerClient will cause infinite recursion :shrug:
-	tmclient.RegisterTabletManagerClientFactory("grpc",
-		func() tmclient.TabletManagerClient { return &faketmclient.FakeTabletManagerClient{} },
-	)
-
-	be := &mysqlctl.BuiltinBackupEngine{}
-
-	// Configure a tight deadline to force a timeout
-	oldDeadline := setBuiltinBackupMysqldDeadline(time.Second)
-	defer setBuiltinBackupMysqldDeadline(oldDeadline)
-
-	bh := filebackupstorage.FileBackupHandle{}
-
-	// Spin up a fake daemon to be used in backups. It needs to be allowed to receive:
-	//  "STOP SLAVE", "START SLAVE", in that order.
-	mysqld := fakemysqldaemon.NewFakeMysqlDaemon(fakesqldb.New(t))
-	mysqld.ExpectedExecuteSuperQueryList = []string{"STOP SLAVE", "START SLAVE"}
-	// mysqld.ShutdownTime = time.Minute
-
-	ok, err := be.ExecuteBackup(ctx, mysqlctl.BackupParams{
-		Logger: logutil.NewConsoleLogger(),
-		Mysqld: mysqld,
-		Cnf: &mysqlctl.Mycnf{
-			InnodbDataHomeDir:     path.Join(backupRoot, "innodb"),
-			InnodbLogGroupHomeDir: path.Join(backupRoot, "log"),
-			DataDir:               path.Join(backupRoot, "datadir"),
-		},
-		HookExtraEnv: map[string]string{},
-		TopoServer:   ts,
-		Keyspace:     keyspace,
-		Shard:        shard,
-	}, &bh)
-
-	require.NoError(t, err)
-	assert.True(t, ok)
-
-	mysqld.ExpectedExecuteSuperQueryCurrent = 0 // resest the index of what queries we've run
-	mysqld.ShutdownTime = time.Minute           // reminder that shutdownDeadline is 1s
-
-	ok, err = be.ExecuteBackup(ctx, mysqlctl.BackupParams{
-		Logger: logutil.NewConsoleLogger(),
-		Mysqld: mysqld,
-		Cnf: &mysqlctl.Mycnf{
-			InnodbDataHomeDir:     path.Join(backupRoot, "innodb"),
-			InnodbLogGroupHomeDir: path.Join(backupRoot, "log"),
-			DataDir:               path.Join(backupRoot, "datadir"),
-		},
-		HookExtraEnv: map[string]string{},
-		TopoServer:   ts,
-		Keyspace:     keyspace,
-		Shard:        shard,
-	}, &bh)
-
-	assert.Error(t, err)
-	assert.False(t, ok)
-}
diff --git a/go/vt/srvtopo/resolver_test.go b/go/vt/srvtopo/resolver_test.go
index 938fe8cf03..0cc6ce5a9a 100644
--- a/go/vt/srvtopo/resolver_test.go
+++ b/go/vt/srvtopo/resolver_test.go
@@ -19,8 +19,6 @@ package srvtopo
 import (
 	"testing"
 
-	"github.com/stretchr/testify/require"
-
 	"golang.org/x/net/context"
 
 	"vitess.io/vitess/go/sqltypes"
@@ -65,34 +63,11 @@ func initResolver(t *testing.T, name string) *Resolver {
 
 	// And rebuild both.
 	for _, keyspace := range []string{"sks", "uks"} {
-		if err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, keyspace, []string{cell}, false); err != nil {
+		if err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, keyspace, []string{cell}); err != nil {
 			t.Fatalf("RebuildKeyspace(%v) failed: %v", keyspace, err)
 		}
 	}
 
-	// Create snapshot keyspace and shard.
-	err = ts.CreateKeyspace(ctx, "rks", &topodatapb.Keyspace{KeyspaceType: topodatapb.KeyspaceType_SNAPSHOT})
-	require.NoError(t, err, "CreateKeyspace(rks) failed: %v")
-	err = ts.CreateShard(ctx, "rks", "-80")
-	require.NoError(t, err, "CreateShard(-80) failed: %v")
-
-	// Rebuild should error because allowPartial is false and shard does not cover full keyrange
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "rks", []string{cell}, false)
-	require.Error(t, err, "RebuildKeyspace(rks) failed")
-	require.EqualError(t, err, "keyspace partition for MASTER in cell cell1 does not end with max key")
-
-	// Rebuild should succeed with allowPartial true
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "rks", []string{cell}, true)
-	require.NoError(t, err, "RebuildKeyspace(rks) failed")
-
-	// Create missing shard
-	err = ts.CreateShard(ctx, "rks", "80-")
-	require.NoError(t, err, "CreateShard(80-) failed: %v")
-
-	// Rebuild should now succeed even with allowPartial false
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "rks", []string{cell}, false)
-	require.NoError(t, err, "RebuildKeyspace(rks) failed")
-
 	return NewResolver(rs, &tabletconntest.FakeQueryService{}, cell)
 }
 
diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
index 67195e515f..bdf90d1151 100644
--- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
@@ -2115,20 +2115,3 @@
 # non-existent table on right of join
 "select c from user join t"
 "table t not found"
-
-# information schema query that uses table_schema
-"select column_name from information_schema.columns where table_schema = (select schema())"
-{
-  "QueryType": "SELECT",
-  "Original": "select column_name from information_schema.columns where table_schema = (select schema())",
-  "Instructions": {
-    "OperatorType": "Route",
-    "Variant": "SelectDBA",
-    "Keyspace": {
-      "Name": "main",
-      "Sharded": false
-    },
-    "FieldQuery": "select column_name from information_schema.`columns` where 1 != 1",
-    "Query": "select column_name from information_schema.`columns` where table_schema = schema()"
-  }
-}
diff --git a/go/vt/vtgate/vindexes/consistent_lookup_test.go b/go/vt/vtgate/vindexes/consistent_lookup_test.go
index 4c496be158..b0ec78081b 100644
--- a/go/vt/vtgate/vindexes/consistent_lookup_test.go
+++ b/go/vt/vtgate/vindexes/consistent_lookup_test.go
@@ -451,6 +451,7 @@ func TestConsistentLookupUpdateBecauseUncomparableTypes(t *testing.T) {
 		{querypb.Type_VARCHAR, "some string"},
 		{querypb.Type_CHAR, "some string"},
 		{querypb.Type_BIT, "some string"},
+		{querypb.Type_ENUM, "some string"},
 		{querypb.Type_SET, "some string"},
 		{querypb.Type_GEOMETRY, "some string"},
 		{querypb.Type_JSON, "some string"},
diff --git a/go/vt/vttablet/endtoend/misc_test.go b/go/vt/vttablet/endtoend/misc_test.go
index da82b2669e..770f81781e 100644
--- a/go/vt/vttablet/endtoend/misc_test.go
+++ b/go/vt/vttablet/endtoend/misc_test.go
@@ -279,12 +279,12 @@ func TestConsolidation(t *testing.T) {
 		var wg sync.WaitGroup
 		wg.Add(2)
 		go func() {
-			query := fmt.Sprintf("/* query: 1 */ select sleep(%v) from dual /* query: 1 */", sleep)
+			query := fmt.Sprintf("select sleep(%v) from dual /* query: 1 */", sleep)
 			framework.NewClient().Execute(query, nil)
 			wg.Done()
 		}()
 		go func() {
-			query := fmt.Sprintf("/* query: 2 */ select sleep(%v) from dual /* query: 2 */", sleep)
+			query := fmt.Sprintf("select sleep(%v) from dual /* query: 2 */", sleep)
 			framework.NewClient().Execute(query, nil)
 			wg.Done()
 		}()
diff --git a/go/vt/vttablet/tabletmanager/tm_init_test.go b/go/vt/vttablet/tabletmanager/tm_init_test.go
index f2c653e376..4ff49654c3 100644
--- a/go/vt/vttablet/tabletmanager/tm_init_test.go
+++ b/go/vt/vttablet/tabletmanager/tm_init_test.go
@@ -149,7 +149,7 @@ func TestStartCreateKeyspaceShard(t *testing.T) {
 	// srvKeyspace already created
 	_, err = ts.GetOrCreateShard(ctx, "ks2", "0")
 	require.NoError(t, err)
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "ks2", []string{cell}, false)
+	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "ks2", []string{cell})
 	require.NoError(t, err)
 	tm = newTestTM(t, ts, 3, "ks2", "0")
 	defer tm.Stop()
@@ -164,7 +164,7 @@ func TestStartCreateKeyspaceShard(t *testing.T) {
 	// srvVSchema already created
 	_, err = ts.GetOrCreateShard(ctx, "ks3", "0")
 	require.NoError(t, err)
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "ks3", []string{cell}, false)
+	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, "ks3", []string{cell})
 	require.NoError(t, err)
 	err = ts.RebuildSrvVSchema(ctx, []string{cell})
 	require.NoError(t, err)
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
index c3850807a3..be492e75ca 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
@@ -259,8 +259,6 @@ func TestPlayerFilters(t *testing.T) {
 		fmt.Sprintf("create table %s.dst4(id1 int, val varbinary(128), primary key(id1))", vrepldb),
 		"create table src5(id1 int, id2 int, val varbinary(128), primary key(id1))",
 		fmt.Sprintf("create table %s.dst5(id1 int, val varbinary(128), primary key(id1))", vrepldb),
-		"create table srcCharset(id1 int, val varchar(128) character set utf8mb4 collate utf8mb4_bin, primary key(id1))",
-		fmt.Sprintf("create table %s.dstCharset(id1 int, val varchar(128) character set utf8mb4 collate utf8mb4_bin, primary key(id1))", vrepldb),
 	})
 	defer execStatements(t, []string{
 		"drop table src1",
@@ -278,8 +276,6 @@ func TestPlayerFilters(t *testing.T) {
 		fmt.Sprintf("drop table %s.dst4", vrepldb),
 		"drop table src5",
 		fmt.Sprintf("drop table %s.dst5", vrepldb),
-		"drop table srcCharset",
-		fmt.Sprintf("drop table %s.dstCharset", vrepldb),
 	})
 	env.SchemaEngine.Reload(context.Background())
 
@@ -303,9 +299,6 @@ func TestPlayerFilters(t *testing.T) {
 		}, {
 			Match:  "dst5",
 			Filter: "select id1, val from src5 where val = 'abc'",
-		}, {
-			Match:  "dstCharset",
-			Filter: "select id1, concat(substr(_utf8mb4 val collate utf8mb4_bin,1,1),'abcxyz') val from srcCharset",
 		}},
 	}
 	bls := &binlogdatapb.BinlogSource{
@@ -551,17 +544,6 @@ func TestPlayerFilters(t *testing.T) {
 		},
 		table: "dst5",
 		data:  [][]string{{"1", "abc"}, {"4", "abc"}},
-	}, {
-		// test collation + filter
-		input: "insert into srcCharset values (1,'木元')",
-		output: []string{
-			"begin",
-			"insert into dstCharset(id1,val) values (1,concat(substr(_utf8mb4 '木元' collate utf8mb4_bin, 1, 1), 'abcxyz'))",
-			"/update _vt.vreplication set pos=",
-			"commit",
-		},
-		table: "dstCharset",
-		data:  [][]string{{"1", "木abcxyz"}},
 	}}
 
 	for _, tcase := range testcases {
diff --git a/go/vt/worker/legacy_split_clone_test.go b/go/vt/worker/legacy_split_clone_test.go
index 524a66a782..5084273fd7 100644
--- a/go/vt/worker/legacy_split_clone_test.go
+++ b/go/vt/worker/legacy_split_clone_test.go
@@ -151,7 +151,7 @@ func (tc *legacySplitCloneTestCase) setUp(v3 bool) {
 	if err := tc.wi.wr.SetKeyspaceShardingInfo(ctx, "ks", "keyspace_id", topodatapb.KeyspaceIdType_UINT64, false); err != nil {
 		tc.t.Fatalf("SetKeyspaceShardingInfo failed: %v", err)
 	}
-	if err := tc.wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil, false); err != nil {
+	if err := tc.wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil); err != nil {
 		tc.t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/worker/multi_split_diff_test.go b/go/vt/worker/multi_split_diff_test.go
index 667747da07..6561ccffeb 100644
--- a/go/vt/worker/multi_split_diff_test.go
+++ b/go/vt/worker/multi_split_diff_test.go
@@ -245,7 +245,7 @@ func testMultiSplitDiff(t *testing.T, v3 bool) {
 	if err := wi.wr.SetKeyspaceShardingInfo(ctx, "ks", "keyspace_id", topodatapb.KeyspaceIdType_UINT64, false); err != nil {
 		t.Fatalf("SetKeyspaceShardingInfo failed: %v", err)
 	}
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/worker/split_clone_flaky_test.go b/go/vt/worker/split_clone_flaky_test.go
index 0cfe93788b..ff2b9b8af4 100644
--- a/go/vt/worker/split_clone_flaky_test.go
+++ b/go/vt/worker/split_clone_flaky_test.go
@@ -191,7 +191,7 @@ func (tc *splitCloneTestCase) setUpWithConcurrency(v3 bool, concurrency, writeQu
 	if err := tc.wi.wr.SetKeyspaceShardingInfo(ctx, "ks", "keyspace_id", topodatapb.KeyspaceIdType_UINT64, false); err != nil {
 		tc.t.Fatalf("SetKeyspaceShardingInfo failed: %v", err)
 	}
-	if err := tc.wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil, false); err != nil {
+	if err := tc.wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil); err != nil {
 		tc.t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/worker/split_diff_test.go b/go/vt/worker/split_diff_test.go
index 489d741104..3dc938c0da 100644
--- a/go/vt/worker/split_diff_test.go
+++ b/go/vt/worker/split_diff_test.go
@@ -239,7 +239,7 @@ func testSplitDiff(t *testing.T, v3 bool, destinationTabletType topodatapb.Table
 	if err := wi.wr.SetKeyspaceShardingInfo(ctx, "ks", "keyspace_id", topodatapb.KeyspaceIdType_UINT64, false); err != nil {
 		t.Fatalf("SetKeyspaceShardingInfo failed: %v", err)
 	}
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/worker/vertical_split_clone_test.go b/go/vt/worker/vertical_split_clone_test.go
index 272701e90b..fd096d967a 100644
--- a/go/vt/worker/vertical_split_clone_test.go
+++ b/go/vt/worker/vertical_split_clone_test.go
@@ -113,10 +113,10 @@ func TestVerticalSplitClone(t *testing.T) {
 		topodatapb.TabletType_RDONLY, nil, testlib.TabletKeyspaceShard(t, "destination_ks", "0"))
 
 	// add the topo and schema data we'll need
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "source_ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "source_ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "destination_ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "destination_ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/worker/vertical_split_diff_test.go b/go/vt/worker/vertical_split_diff_test.go
index 3074adec96..c0d494b162 100644
--- a/go/vt/worker/vertical_split_diff_test.go
+++ b/go/vt/worker/vertical_split_diff_test.go
@@ -140,10 +140,10 @@ func TestVerticalSplitDiff(t *testing.T) {
 	wi.wr.SetSourceShards(ctx, "destination_ks", "0", []*topodatapb.TabletAlias{sourceRdonly1.Tablet.Alias}, []string{"moving.*", "view1"})
 
 	// add the topo and schema data we'll need
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "source_ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "source_ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
-	if err := wi.wr.RebuildKeyspaceGraph(ctx, "destination_ks", nil, false); err != nil {
+	if err := wi.wr.RebuildKeyspaceGraph(ctx, "destination_ks", nil); err != nil {
 		t.Fatalf("RebuildKeyspaceGraph failed: %v", err)
 	}
 
diff --git a/go/vt/wrangler/testlib/external_reparent_test.go b/go/vt/wrangler/testlib/external_reparent_test.go
index 708f68aa1f..f6612f3fa2 100644
--- a/go/vt/wrangler/testlib/external_reparent_test.go
+++ b/go/vt/wrangler/testlib/external_reparent_test.go
@@ -57,7 +57,7 @@ func TestTabletExternallyReparentedBasic(t *testing.T) {
 	newMaster := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -149,7 +149,7 @@ func TestTabletExternallyReparentedToReplica(t *testing.T) {
 	newMaster.FakeMysqlDaemon.Replicating = true
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -230,7 +230,7 @@ func TestTabletExternallyReparentedWithDifferentMysqlPort(t *testing.T) {
 	goodReplica := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -315,7 +315,7 @@ func TestTabletExternallyReparentedContinueOnUnexpectedMaster(t *testing.T) {
 	goodReplica := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -393,7 +393,7 @@ func TestTabletExternallyReparentedRerun(t *testing.T) {
 	goodReplica := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -494,7 +494,7 @@ func TestRPCTabletExternallyReparentedDemotesMasterToConfiguredTabletType(t *tes
 	defer newMaster.StopActionLoop(t)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1"})
 	assert.NoError(t, err, "RebuildKeyspaceLocked failed: %v", err)
 
 	// Reparent to new master
diff --git a/go/vt/wrangler/testlib/find_tablet_test.go b/go/vt/wrangler/testlib/find_tablet_test.go
index e77321ec2b..1f037cec0a 100644
--- a/go/vt/wrangler/testlib/find_tablet_test.go
+++ b/go/vt/wrangler/testlib/find_tablet_test.go
@@ -43,7 +43,7 @@ func TestFindTablet(t *testing.T) {
 	goodReplica2 := NewFakeTablet(t, wr, "cell2", 3, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1", "cell2"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1", "cell2"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked 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 d25c44f1f2..fa34f1cb91 100644
--- a/go/vt/wrangler/testlib/migrate_served_types_test.go
+++ b/go/vt/wrangler/testlib/migrate_served_types_test.go
@@ -111,7 +111,7 @@ func TestMigrateServedTypes(t *testing.T) {
 		TabletKeyspaceShard(t, "ks", "80-"))
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
@@ -317,7 +317,7 @@ func TestMultiShardMigrateServedTypes(t *testing.T) {
 		TabletKeyspaceShard(t, "ks", "c0-"))
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
diff --git a/go/vt/wrangler/testlib/shard_test.go b/go/vt/wrangler/testlib/shard_test.go
index 7bdc96e27a..790ccd5f17 100644
--- a/go/vt/wrangler/testlib/shard_test.go
+++ b/go/vt/wrangler/testlib/shard_test.go
@@ -45,7 +45,7 @@ func TestDeleteShardCleanup(t *testing.T) {
 	remoteReplica := NewFakeTablet(t, wr, "cell2", 2, topodatapb.TabletType_REPLICA, nil)
 
 	// Build keyspace graph
-	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, master.Tablet.Keyspace, []string{"cell1", "cell2"}, false)
+	err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, master.Tablet.Keyspace, []string{"cell1", "cell2"})
 	if err != nil {
 		t.Fatalf("RebuildKeyspaceLocked failed: %v", err)
 	}
diff --git a/go/vt/wrangler/traffic_switcher_env_test.go b/go/vt/wrangler/traffic_switcher_env_test.go
index 28d032b2d4..4ac1c0742d 100644
--- a/go/vt/wrangler/traffic_switcher_env_test.go
+++ b/go/vt/wrangler/traffic_switcher_env_test.go
@@ -153,11 +153,11 @@ func newTestTableMigraterCustom(ctx context.Context, t *testing.T, sourceShards,
 	if err := tme.ts.RebuildSrvVSchema(ctx, nil); err != nil {
 		t.Fatal(err)
 	}
-	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks1", []string{"cell1"}, false)
+	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks1", []string{"cell1"})
 	if err != nil {
 		t.Fatal(err)
 	}
-	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks2", []string{"cell1"}, false)
+	err = topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks2", []string{"cell1"})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -276,7 +276,7 @@ func newTestShardMigrater(ctx context.Context, t *testing.T, sourceShards, targe
 	if err := tme.ts.RebuildSrvVSchema(ctx, nil); err != nil {
 		t.Fatal(err)
 	}
-	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks", nil, false)
+	err := topotools.RebuildKeyspace(ctx, logutil.NewConsoleLogger(), tme.ts, "ks", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/go/vt/wrangler/vdiff_test.go b/go/vt/wrangler/vdiff_test.go
index 44a7aba8bd..decce4f3de 100644
--- a/go/vt/wrangler/vdiff_test.go
+++ b/go/vt/wrangler/vdiff_test.go
@@ -560,7 +560,7 @@ func TestVDiffUnsharded(t *testing.T) {
 		env.tablets[101].setResults("select c1, c2 from t1 order by c1 asc", vdiffSourceGtid, tcase.source)
 		env.tablets[201].setResults("select c1, c2 from t1 order by c1 asc", vdiffTargetMasterPosition, tcase.target)
 
-		dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "", 100)
+		dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "")
 		require.NoError(t, err)
 		assert.Equal(t, tcase.dr, dr["t1"], tcase.id)
 	}
@@ -622,7 +622,7 @@ func TestVDiffSharded(t *testing.T) {
 		),
 	)
 
-	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "", 100)
+	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "")
 	require.NoError(t, err)
 	wantdr := &DiffReport{
 		ProcessedRows: 3,
@@ -688,7 +688,7 @@ func TestVDiffAggregates(t *testing.T) {
 		),
 	)
 
-	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "", 100)
+	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "")
 	require.NoError(t, err)
 	wantdr := &DiffReport{
 		ProcessedRows: 5,
@@ -752,7 +752,7 @@ func TestVDiffPKWeightString(t *testing.T) {
 		),
 	)
 
-	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "", 100)
+	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "")
 	require.NoError(t, err)
 	wantdr := &DiffReport{
 		ProcessedRows: 4,
@@ -816,7 +816,7 @@ func TestVDiffNoPKWeightString(t *testing.T) {
 		),
 	)
 
-	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "", 100)
+	dr, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 30*time.Second, "")
 	require.NoError(t, err)
 	wantdr := &DiffReport{
 		ProcessedRows: 4,
@@ -854,20 +854,12 @@ func TestVDiffDefaults(t *testing.T) {
 	env.tablets[101].setResults("select c1, c2 from t1 order by c1 asc", vdiffSourceGtid, source)
 	env.tablets[201].setResults("select c1, c2 from t1 order by c1 asc", vdiffTargetMasterPosition, target)
 
-	_, err := env.wr.VDiff(context.Background(), "target", env.workflow, "", "", "replica", 30*time.Second, "", 100)
+	_, err := env.wr.VDiff(context.Background(), "target", env.workflow, "", "", "replica", 30*time.Second, "")
 	require.NoError(t, err)
-	_, err = env.wr.VDiff(context.Background(), "target", env.workflow, "", env.cell, "replica", 30*time.Second, "", 100)
+	_, err = env.wr.VDiff(context.Background(), "target", env.workflow, "", env.cell, "replica", 30*time.Second, "")
 	require.NoError(t, err)
-	var df map[string]*DiffReport
-	df, err = env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, "", "replica", 30*time.Second, "", 100)
+	_, err = env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, "", "replica", 30*time.Second, "")
 	require.NoError(t, err)
-	require.Equal(t, df["t1"].ProcessedRows, 3)
-	df, err = env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, "", "replica", 30*time.Second, "", 1)
-	require.NoError(t, err)
-	require.Equal(t, df["t1"].ProcessedRows, 1)
-	df, err = env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, "", "replica", 30*time.Second, "", 0)
-	require.NoError(t, err)
-	require.Equal(t, df["t1"].ProcessedRows, 0)
 }
 
 func TestVDiffReplicationWait(t *testing.T) {
@@ -899,7 +891,7 @@ func TestVDiffReplicationWait(t *testing.T) {
 	env.tablets[101].setResults("select c1, c2 from t1 order by c1 asc", vdiffSourceGtid, source)
 	env.tablets[201].setResults("select c1, c2 from t1 order by c1 asc", vdiffTargetMasterPosition, target)
 
-	_, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 0*time.Second, "", 100)
+	_, err := env.wr.VDiff(context.Background(), "target", env.workflow, env.cell, env.cell, "replica", 0*time.Second, "")
 	require.EqualError(t, err, "startQueryStreams(sources): VDiff timed out for tablet cell-0000000101: you may want to increase it with the flag -filtered_replication_wait_time=<timeoutSeconds>")
 }
 
diff --git a/go/vt/wrangler/vexec_test.go b/go/vt/wrangler/vexec_test.go
index 3a176bee29..6af98a62ad 100644
--- a/go/vt/wrangler/vexec_test.go
+++ b/go/vt/wrangler/vexec_test.go
@@ -177,12 +177,9 @@ func TestWorkflowListStreams(t *testing.T) {
 	logger := logutil.NewMemoryLogger()
 	wr := New(logger, env.topoServ, env.tmc)
 
-	_, err := wr.WorkflowAction(ctx, workflow, keyspace, "listall", false)
+	_, err := wr.WorkflowAction(ctx, workflow, keyspace, "show", false)
 	require.Nil(t, err)
-	_, err = wr.WorkflowAction(ctx, workflow, keyspace, "show", false)
-	require.Nil(t, err)
-	want := `Workflows: wrWorkflow
-{
+	want := `{
 	"Workflow": "wrWorkflow",
 	"SourceLocation": {
 		"Keyspace": "source",