vitess.io/vitess@v0.16.2/go/test/endtoend/vreplication/vschema_load_test.go (about)

     1  /*
     2  Copyright 2022 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package vreplication
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"net"
    23  	"strconv"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/test/endtoend/cluster"
    30  	"vitess.io/vitess/go/vt/log"
    31  	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
    32  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    33  	vtgatepb "vitess.io/vitess/go/vt/proto/vtgate"
    34  	"vitess.io/vitess/go/vt/vtgate/vtgateconn"
    35  )
    36  
    37  // TestVSchemaChangesUnderLoad tests vstreamer under a load of high binlog events and simultaneous multiple vschema changes
    38  // see https://github.com/vitessio/vitess/issues/11169
    39  func TestVSchemaChangesUnderLoad(t *testing.T) {
    40  
    41  	extendedTimeout := defaultTimeout * 4
    42  
    43  	defaultCellName := "zone1"
    44  	allCells := []string{"zone1"}
    45  	allCellNames = "zone1"
    46  	vc = NewVitessCluster(t, "TestVSchemaChanges", allCells, mainClusterConfig)
    47  
    48  	require.NotNil(t, vc)
    49  
    50  	defer vc.TearDown(t)
    51  
    52  	defaultCell = vc.Cells[defaultCellName]
    53  	vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, 1, 0, 100, sourceKsOpts)
    54  	vtgate = defaultCell.Vtgates[0]
    55  	require.NotNil(t, vtgate)
    56  	err := cluster.WaitForHealthyShard(vc.VtctldClient, "product", "0")
    57  	require.NoError(t, err)
    58  	vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.replica", "product", "0"), 1, 30*time.Second)
    59  	vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort)
    60  	defer vtgateConn.Close()
    61  
    62  	// ch is used to signal that there is significant data inserted into the tables and when a lot of vschema changes have been applied
    63  	ch := make(chan bool, 1)
    64  
    65  	ctx := context.Background()
    66  	initialDataInserted := false
    67  	startCid := 100
    68  	warmupRowCount := startCid + 2000
    69  	insertData := func() {
    70  		timer := time.NewTimer(extendedTimeout)
    71  		defer timer.Stop()
    72  		log.Infof("Inserting data into customer")
    73  		cid := startCid
    74  		for {
    75  			if !initialDataInserted && cid > warmupRowCount {
    76  				log.Infof("Done inserting initial data into customer")
    77  				initialDataInserted = true
    78  				ch <- true
    79  			}
    80  			query := fmt.Sprintf("insert into customer(cid, name) values (%d, 'a')", cid)
    81  			_, _ = vtgateConn.ExecuteFetch(query, 1, false)
    82  			cid++
    83  			query = "update customer set name = concat(name, 'a')"
    84  			_, _ = vtgateConn.ExecuteFetch(query, 10000, false)
    85  			select {
    86  			case <-timer.C:
    87  				log.Infof("Done inserting data into customer")
    88  				return
    89  			default:
    90  			}
    91  		}
    92  	}
    93  	go func() {
    94  		log.Infof("Starting to vstream from replica")
    95  		vgtid := &binlogdatapb.VGtid{
    96  			ShardGtids: []*binlogdatapb.ShardGtid{{
    97  				Keyspace: "product",
    98  				Shard:    "0",
    99  				Gtid:     "",
   100  			}}}
   101  
   102  		filter := &binlogdatapb.Filter{
   103  			Rules: []*binlogdatapb.Rule{{
   104  				Match:  "customer",
   105  				Filter: "select * from customer",
   106  			}},
   107  		}
   108  		conn, err := vtgateconn.Dial(ctx, net.JoinHostPort("localhost", strconv.Itoa(vc.ClusterConfig.vtgateGrpcPort)))
   109  		require.NoError(t, err)
   110  		defer conn.Close()
   111  
   112  		flags := &vtgatepb.VStreamFlags{}
   113  
   114  		ctx2, cancel := context.WithTimeout(ctx, extendedTimeout/2)
   115  		defer cancel()
   116  		reader, err := conn.VStream(ctx2, topodatapb.TabletType_REPLICA, vgtid, filter, flags)
   117  		require.NoError(t, err)
   118  		_, err = reader.Recv()
   119  		require.NoError(t, err)
   120  		log.Infof("About to sleep in vstreaming to block the vstream Recv() channel")
   121  		time.Sleep(extendedTimeout)
   122  		log.Infof("Done vstreaming")
   123  	}()
   124  
   125  	go insertData()
   126  	<-ch // wait for enough data to be inserted before ApplyVSchema
   127  	const maxApplyVSchemas = 20
   128  	go func() {
   129  		numApplyVSchema := 0
   130  		timer := time.NewTimer(extendedTimeout)
   131  		defer timer.Stop()
   132  		log.Infof("Started ApplyVSchema")
   133  		for {
   134  			if err := vc.VtctlClient.ExecuteCommand("ApplyVSchema", "--", "--vschema={}", "product"); err != nil {
   135  				log.Errorf("ApplyVSchema command failed with %+v\n", err)
   136  				return
   137  			}
   138  			numApplyVSchema++
   139  			if numApplyVSchema > maxApplyVSchemas {
   140  				ch <- true
   141  			}
   142  			select {
   143  			case <-timer.C:
   144  				log.Infof("Done ApplyVSchema")
   145  				ch <- true
   146  				return
   147  			default:
   148  				time.Sleep(defaultTick)
   149  			}
   150  		}
   151  	}()
   152  
   153  	<-ch // wait for enough ApplyVSchema calls before doing a PRS
   154  	if err := vc.VtctlClient.ExecuteCommand("PlannedReparentShard", "--", "--keyspace_shard", "product/0",
   155  		"--new_primary", "zone1-101", "--wait_replicas_timeout", defaultTimeout.String()); err != nil {
   156  		require.NoError(t, err, "PlannedReparentShard command failed")
   157  	}
   158  }