vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/schema/engine_test.go (about)

     1  /*
     2  Copyright 2019 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 schema
    18  
    19  import (
    20  	"context"
    21  	"expvar"
    22  	"fmt"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"sort"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	"vitess.io/vitess/go/test/utils"
    31  
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  
    35  	"vitess.io/vitess/go/mysql"
    36  	"vitess.io/vitess/go/mysql/fakesqldb"
    37  	"vitess.io/vitess/go/sqltypes"
    38  	"vitess.io/vitess/go/vt/dbconfigs"
    39  	"vitess.io/vitess/go/vt/sqlparser"
    40  	"vitess.io/vitess/go/vt/vttablet/tabletserver/schema/schematest"
    41  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    42  
    43  	querypb "vitess.io/vitess/go/vt/proto/query"
    44  )
    45  
    46  const baseShowTablesPattern = `SELECT t\.table_name.*`
    47  
    48  var mustMatch = utils.MustMatchFn(".Mutex")
    49  
    50  func TestOpenAndReload(t *testing.T) {
    51  	db := fakesqldb.New(t)
    52  	defer db.Close()
    53  	schematest.AddDefaultQueries(db)
    54  	db.AddQueryPattern(baseShowTablesPattern,
    55  		&sqltypes.Result{
    56  			Fields:       mysql.BaseShowTablesFields,
    57  			RowsAffected: 0,
    58  			InsertID:     0,
    59  			Rows: [][]sqltypes.Value{
    60  				mysql.BaseShowTablesRow("test_table_01", false, ""),
    61  				mysql.BaseShowTablesRow("test_table_02", false, ""),
    62  				mysql.BaseShowTablesRow("test_table_03", false, ""),
    63  				mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
    64  				mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"),
    65  			},
    66  			SessionStateChanges: "",
    67  			StatusFlags:         0,
    68  		})
    69  
    70  	// advance to one second after the default 1427325875.
    71  	db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields(
    72  		"t",
    73  		"int64"),
    74  		"1427325876",
    75  	))
    76  	firstReadRowsValue := 12
    77  	AddFakeInnoDBReadRowsResult(db, firstReadRowsValue)
    78  	se := newEngine(10, 10*time.Second, 10*time.Second, db)
    79  	se.Open()
    80  	defer se.Close()
    81  
    82  	want := initialSchema()
    83  	mustMatch(t, want, se.GetSchema())
    84  	assert.Equal(t, int64(100), se.tableFileSizeGauge.Counts()["msg"])
    85  	assert.Equal(t, int64(150), se.tableAllocatedSizeGauge.Counts()["msg"])
    86  
    87  	// Advance time some more.
    88  	db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields(
    89  		"t",
    90  		"int64"),
    91  		"1427325877",
    92  	))
    93  	assert.EqualValues(t, firstReadRowsValue, se.innoDbReadRowsCounter.Get())
    94  
    95  	// Modify test_table_03
    96  	// Add test_table_04
    97  	// Drop msg
    98  	db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{
    99  		Fields: mysql.BaseShowTablesFields,
   100  		Rows: [][]sqltypes.Value{
   101  			mysql.BaseShowTablesRow("test_table_01", false, ""),
   102  			mysql.BaseShowTablesRow("test_table_02", false, ""),
   103  			{
   104  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_03")), // table_name
   105  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")),    // table_type
   106  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")),      // unix_timestamp(t.create_time)
   107  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")),              // table_comment
   108  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")),             // file_size
   109  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")),             // allocated_size
   110  			},
   111  			// test_table_04 will in spite of older timestamp because it doesn't exist yet.
   112  			mysql.BaseShowTablesRow("test_table_04", false, ""),
   113  			mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   114  		},
   115  	})
   116  	db.MockQueriesForTable("test_table_03", &sqltypes.Result{
   117  		Fields: []*querypb.Field{{
   118  			Name: "pk1",
   119  			Type: sqltypes.Int32,
   120  		}, {
   121  			Name: "pk2",
   122  			Type: sqltypes.Int32,
   123  		}, {
   124  			Name: "val",
   125  			Type: sqltypes.Int32,
   126  		}},
   127  	})
   128  
   129  	db.MockQueriesForTable("test_table_04", &sqltypes.Result{
   130  		Fields: []*querypb.Field{{
   131  			Name: "pk",
   132  			Type: sqltypes.Int32,
   133  		}},
   134  	})
   135  
   136  	db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{
   137  		Fields: mysql.ShowPrimaryFields,
   138  		Rows: [][]sqltypes.Value{
   139  			mysql.ShowPrimaryRow("test_table_01", "pk"),
   140  			mysql.ShowPrimaryRow("test_table_02", "pk"),
   141  			mysql.ShowPrimaryRow("test_table_03", "pk1"),
   142  			mysql.ShowPrimaryRow("test_table_03", "pk2"),
   143  			mysql.ShowPrimaryRow("test_table_04", "pk"),
   144  			mysql.ShowPrimaryRow("seq", "id"),
   145  		},
   146  	})
   147  	secondReadRowsValue := 123
   148  	AddFakeInnoDBReadRowsResult(db, secondReadRowsValue)
   149  
   150  	firstTime := true
   151  	notifier := func(full map[string]*Table, created, altered, dropped []string) {
   152  		if firstTime {
   153  			firstTime = false
   154  			sort.Strings(created)
   155  			assert.Equal(t, []string{"dual", "msg", "seq", "test_table_01", "test_table_02", "test_table_03"}, created)
   156  			assert.Equal(t, []string(nil), altered)
   157  			assert.Equal(t, []string(nil), dropped)
   158  		} else {
   159  			assert.Equal(t, []string{"test_table_04"}, created)
   160  			assert.Equal(t, []string{"test_table_03"}, altered)
   161  			sort.Strings(dropped)
   162  			assert.Equal(t, []string{"msg"}, dropped)
   163  		}
   164  	}
   165  	se.RegisterNotifier("test", notifier)
   166  	err := se.Reload(context.Background())
   167  	require.NoError(t, err)
   168  
   169  	assert.EqualValues(t, secondReadRowsValue, se.innoDbReadRowsCounter.Get())
   170  
   171  	want["test_table_03"] = &Table{
   172  		Name: sqlparser.NewIdentifierCS("test_table_03"),
   173  		Fields: []*querypb.Field{{
   174  			Name: "pk1",
   175  			Type: sqltypes.Int32,
   176  		}, {
   177  			Name: "pk2",
   178  			Type: sqltypes.Int32,
   179  		}, {
   180  			Name: "val",
   181  			Type: sqltypes.Int32,
   182  		}},
   183  		PKColumns:     []int{0, 1},
   184  		CreateTime:    1427325877,
   185  		FileSize:      128,
   186  		AllocatedSize: 256,
   187  	}
   188  	want["test_table_04"] = &Table{
   189  		Name: sqlparser.NewIdentifierCS("test_table_04"),
   190  		Fields: []*querypb.Field{{
   191  			Name: "pk",
   192  			Type: sqltypes.Int32,
   193  		}},
   194  		PKColumns:     []int{0},
   195  		CreateTime:    1427325875,
   196  		FileSize:      100,
   197  		AllocatedSize: 150,
   198  	}
   199  	delete(want, "msg")
   200  	assert.Equal(t, want, se.GetSchema())
   201  	assert.Equal(t, int64(0), se.tableAllocatedSizeGauge.Counts()["msg"])
   202  	assert.Equal(t, int64(0), se.tableFileSizeGauge.Counts()["msg"])
   203  
   204  	//ReloadAt tests
   205  	pos1, err := mysql.DecodePosition("MariaDB/0-41983-20")
   206  	require.NoError(t, err)
   207  	pos2, err := mysql.DecodePosition("MariaDB/0-41983-40")
   208  	require.NoError(t, err)
   209  	se.UnregisterNotifier("test")
   210  
   211  	err = se.ReloadAt(context.Background(), mysql.Position{})
   212  	require.NoError(t, err)
   213  	assert.Equal(t, want, se.GetSchema())
   214  
   215  	err = se.ReloadAt(context.Background(), pos1)
   216  	require.NoError(t, err)
   217  	assert.Equal(t, want, se.GetSchema())
   218  
   219  	db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{
   220  		Fields: mysql.BaseShowTablesFields,
   221  		Rows: [][]sqltypes.Value{
   222  			mysql.BaseShowTablesRow("test_table_01", false, ""),
   223  			mysql.BaseShowTablesRow("test_table_02", false, ""),
   224  			mysql.BaseShowTablesRow("test_table_04", false, ""),
   225  			mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   226  		},
   227  	})
   228  	db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{
   229  		Fields: mysql.ShowPrimaryFields,
   230  		Rows: [][]sqltypes.Value{
   231  			mysql.ShowPrimaryRow("test_table_01", "pk"),
   232  			mysql.ShowPrimaryRow("test_table_02", "pk"),
   233  			mysql.ShowPrimaryRow("test_table_04", "pk"),
   234  			mysql.ShowPrimaryRow("seq", "id"),
   235  		},
   236  	})
   237  	err = se.ReloadAt(context.Background(), pos1)
   238  	require.NoError(t, err)
   239  	assert.Equal(t, want, se.GetSchema())
   240  
   241  	delete(want, "test_table_03")
   242  	err = se.ReloadAt(context.Background(), pos2)
   243  	require.NoError(t, err)
   244  	assert.Equal(t, want, se.GetSchema())
   245  }
   246  
   247  func TestReloadWithSwappedTables(t *testing.T) {
   248  	db := fakesqldb.New(t)
   249  	defer db.Close()
   250  	schematest.AddDefaultQueries(db)
   251  	db.AddQueryPattern(baseShowTablesPattern,
   252  		&sqltypes.Result{
   253  			Fields:       mysql.BaseShowTablesFields,
   254  			RowsAffected: 0,
   255  			InsertID:     0,
   256  			Rows: [][]sqltypes.Value{
   257  				mysql.BaseShowTablesRow("test_table_01", false, ""),
   258  				mysql.BaseShowTablesRow("test_table_02", false, ""),
   259  				mysql.BaseShowTablesRow("test_table_03", false, ""),
   260  				mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   261  				mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"),
   262  			},
   263  			SessionStateChanges: "",
   264  			StatusFlags:         0,
   265  		})
   266  	firstReadRowsValue := 12
   267  	AddFakeInnoDBReadRowsResult(db, firstReadRowsValue)
   268  
   269  	se := newEngine(10, 10*time.Second, 10*time.Second, db)
   270  	se.Open()
   271  	defer se.Close()
   272  	want := initialSchema()
   273  	mustMatch(t, want, se.GetSchema())
   274  
   275  	// Add test_table_04 with a newer timestamp
   276  	// Advance time some more.
   277  	db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   278  		"t",
   279  		"int64"),
   280  		"1427325876",
   281  	))
   282  	db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{
   283  		Fields: mysql.BaseShowTablesFields,
   284  		Rows: [][]sqltypes.Value{
   285  			mysql.BaseShowTablesRow("test_table_01", false, ""),
   286  			mysql.BaseShowTablesRow("test_table_02", false, ""),
   287  			mysql.BaseShowTablesRow("test_table_03", false, ""),
   288  			{
   289  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_04")),
   290  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")),
   291  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(create_time)
   292  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")),
   293  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")), // file_size
   294  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")), // allocated_size
   295  			},
   296  			mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   297  			mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"),
   298  		},
   299  	})
   300  	db.MockQueriesForTable("test_table_04", &sqltypes.Result{
   301  		Fields: []*querypb.Field{{
   302  			Name: "mypk",
   303  			Type: sqltypes.Int32,
   304  		}},
   305  	})
   306  	db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{
   307  		Fields: mysql.ShowPrimaryFields,
   308  		Rows: [][]sqltypes.Value{
   309  			mysql.ShowPrimaryRow("test_table_01", "pk"),
   310  			mysql.ShowPrimaryRow("test_table_02", "pk"),
   311  			mysql.ShowPrimaryRow("test_table_03", "pk"),
   312  			mysql.ShowPrimaryRow("test_table_04", "mypk"),
   313  			mysql.ShowPrimaryRow("seq", "id"),
   314  			mysql.ShowPrimaryRow("msg", "id"),
   315  		},
   316  	})
   317  	err := se.Reload(context.Background())
   318  	require.NoError(t, err)
   319  	want["test_table_04"] = &Table{
   320  		Name: sqlparser.NewIdentifierCS("test_table_04"),
   321  		Fields: []*querypb.Field{{
   322  			Name: "mypk",
   323  			Type: sqltypes.Int32,
   324  		}},
   325  		PKColumns:     []int{0},
   326  		CreateTime:    1427325877,
   327  		FileSize:      128,
   328  		AllocatedSize: 256,
   329  	}
   330  
   331  	mustMatch(t, want, se.GetSchema())
   332  
   333  	// swap test_table_03 and test_table_04
   334  	// Advance time some more.
   335  	db.AddQuery("select unix_timestamp()", sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   336  		"t",
   337  		"int64"),
   338  		"1427325877",
   339  	))
   340  	db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{
   341  		Fields: mysql.BaseShowTablesFields,
   342  		Rows: [][]sqltypes.Value{
   343  			mysql.BaseShowTablesRow("test_table_01", false, ""),
   344  			mysql.BaseShowTablesRow("test_table_02", false, ""),
   345  			{
   346  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("test_table_03")),
   347  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("BASE TABLE")),
   348  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("1427325877")), // unix_timestamp(create_time)
   349  				sqltypes.MakeTrusted(sqltypes.VarChar, []byte("")),
   350  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("128")), // file_size
   351  				sqltypes.MakeTrusted(sqltypes.Int64, []byte("256")), // allocated_size
   352  			},
   353  			mysql.BaseShowTablesRow("test_table_04", false, ""),
   354  			mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   355  			mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"),
   356  		},
   357  	})
   358  	db.MockQueriesForTable("test_table_03", &sqltypes.Result{
   359  		Fields: []*querypb.Field{{
   360  			Name: "mypk",
   361  			Type: sqltypes.Int32,
   362  		}},
   363  	})
   364  
   365  	db.MockQueriesForTable("test_table_04", &sqltypes.Result{
   366  		Fields: []*querypb.Field{{
   367  			Name: "pk",
   368  			Type: sqltypes.Int32,
   369  		}},
   370  	})
   371  
   372  	db.AddQuery(mysql.BaseShowPrimary, &sqltypes.Result{
   373  		Fields: mysql.ShowPrimaryFields,
   374  		Rows: [][]sqltypes.Value{
   375  			mysql.ShowPrimaryRow("test_table_01", "pk"),
   376  			mysql.ShowPrimaryRow("test_table_02", "pk"),
   377  			mysql.ShowPrimaryRow("test_table_03", "mypk"),
   378  			mysql.ShowPrimaryRow("test_table_04", "pk"),
   379  			mysql.ShowPrimaryRow("seq", "id"),
   380  			mysql.ShowPrimaryRow("msg", "id"),
   381  		},
   382  	})
   383  	err = se.Reload(context.Background())
   384  	require.NoError(t, err)
   385  
   386  	delete(want, "test_table_03")
   387  	delete(want, "test_table_04")
   388  	want["test_table_03"] = &Table{
   389  		Name: sqlparser.NewIdentifierCS("test_table_03"),
   390  		Fields: []*querypb.Field{{
   391  			Name: "mypk",
   392  			Type: sqltypes.Int32,
   393  		}},
   394  		PKColumns:     []int{0},
   395  		CreateTime:    1427325877,
   396  		FileSize:      128,
   397  		AllocatedSize: 256,
   398  	}
   399  	want["test_table_04"] = &Table{
   400  		Name: sqlparser.NewIdentifierCS("test_table_04"),
   401  		Fields: []*querypb.Field{{
   402  			Name: "pk",
   403  			Type: sqltypes.Int32,
   404  		}},
   405  		PKColumns:     []int{0},
   406  		CreateTime:    1427325875,
   407  		FileSize:      100,
   408  		AllocatedSize: 150,
   409  	}
   410  	mustMatch(t, want, se.GetSchema())
   411  }
   412  
   413  func TestOpenFailedDueToExecErr(t *testing.T) {
   414  	db := fakesqldb.New(t)
   415  	defer db.Close()
   416  	schematest.AddDefaultQueries(db)
   417  	want := "injected error"
   418  	db.RejectQueryPattern(baseShowTablesPattern, want)
   419  	se := newEngine(10, 1*time.Second, 1*time.Second, db)
   420  	err := se.Open()
   421  	if err == nil || !strings.Contains(err.Error(), want) {
   422  		t.Errorf("se.Open: %v, want %s", err, want)
   423  	}
   424  }
   425  
   426  func TestOpenFailedDueToTableErr(t *testing.T) {
   427  	db := fakesqldb.New(t)
   428  	defer db.Close()
   429  	schematest.AddDefaultQueries(db)
   430  	db.AddQueryPattern(baseShowTablesPattern, &sqltypes.Result{
   431  		Fields: mysql.BaseShowTablesFields,
   432  		Rows: [][]sqltypes.Value{
   433  			mysql.BaseShowTablesRow("test_table", false, ""),
   434  		},
   435  	})
   436  	db.MockQueriesForTable("test_table", &sqltypes.Result{
   437  		// this will cause NewTable error, as it expects zero rows.
   438  		Fields: []*querypb.Field{
   439  			{
   440  				Type: querypb.Type_VARCHAR,
   441  			},
   442  		},
   443  		Rows: [][]sqltypes.Value{
   444  			{sqltypes.NewVarBinary("")},
   445  		},
   446  	})
   447  
   448  	AddFakeInnoDBReadRowsResult(db, 0)
   449  	se := newEngine(10, 1*time.Second, 1*time.Second, db)
   450  	err := se.Open()
   451  	want := "Row count exceeded"
   452  	if err == nil || !strings.Contains(err.Error(), want) {
   453  		t.Errorf("se.Open: %v, want %s", err, want)
   454  	}
   455  }
   456  
   457  func TestExportVars(t *testing.T) {
   458  	db := fakesqldb.New(t)
   459  	defer db.Close()
   460  	schematest.AddDefaultQueries(db)
   461  	se := newEngine(10, 1*time.Second, 1*time.Second, db)
   462  	se.Open()
   463  	defer se.Close()
   464  	expvar.Do(func(kv expvar.KeyValue) {
   465  		_ = kv.Value.String()
   466  	})
   467  }
   468  
   469  func TestStatsURL(t *testing.T) {
   470  	db := fakesqldb.New(t)
   471  	defer db.Close()
   472  	schematest.AddDefaultQueries(db)
   473  	se := newEngine(10, 1*time.Second, 1*time.Second, db)
   474  	se.Open()
   475  	defer se.Close()
   476  
   477  	request, _ := http.NewRequest("GET", "/debug/schema", nil)
   478  	response := httptest.NewRecorder()
   479  	se.handleDebugSchema(response, request)
   480  }
   481  
   482  func TestSchemaEngineCloseTickRace(t *testing.T) {
   483  	db := fakesqldb.New(t)
   484  	defer db.Close()
   485  	schematest.AddDefaultQueries(db)
   486  	db.AddQueryPattern(baseShowTablesPattern,
   487  		&sqltypes.Result{
   488  			Fields:       mysql.BaseShowTablesFields,
   489  			RowsAffected: 0,
   490  			InsertID:     0,
   491  			Rows: [][]sqltypes.Value{
   492  				mysql.BaseShowTablesRow("test_table_01", false, ""),
   493  				mysql.BaseShowTablesRow("test_table_02", false, ""),
   494  				mysql.BaseShowTablesRow("test_table_03", false, ""),
   495  				mysql.BaseShowTablesRow("seq", false, "vitess_sequence"),
   496  				mysql.BaseShowTablesRow("msg", false, "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30"),
   497  			},
   498  			SessionStateChanges: "",
   499  			StatusFlags:         0,
   500  		})
   501  	AddFakeInnoDBReadRowsResult(db, 12)
   502  	// Start the engine with a small reload tick
   503  	se := newEngine(10, 100*time.Millisecond, 1*time.Second, db)
   504  	err := se.Open()
   505  	require.NoError(t, err)
   506  
   507  	finished := make(chan bool)
   508  	go func() {
   509  		{
   510  			// Emulate the command of se.Close(), but with a wait in between
   511  			// to ensure that a reload-tick happens after locking the mutex but before
   512  			// stopping the ticks
   513  			se.mu.Lock()
   514  			// We wait for 200 milliseconds to be sure that the timer tick happens after acquiring the lock
   515  			// before we call closeLocked function
   516  			time.Sleep(200 * time.Millisecond)
   517  			se.closeLocked()
   518  		}
   519  		finished <- true
   520  	}()
   521  	// Wait until the ticks are stopped or 2 seonds have expired.
   522  	select {
   523  	case <-finished:
   524  		return
   525  	case <-time.After(2 * time.Second):
   526  		t.Fatal("Could not stop the ticks after 2 seconds")
   527  	}
   528  }
   529  
   530  func newEngine(queryCacheSize int, reloadTime time.Duration, idleTimeout time.Duration, db *fakesqldb.DB) *Engine {
   531  	config := tabletenv.NewDefaultConfig()
   532  	config.QueryCacheSize = queryCacheSize
   533  	config.SchemaReloadIntervalSeconds.Set(reloadTime)
   534  	config.OltpReadPool.IdleTimeoutSeconds.Set(idleTimeout)
   535  	config.OlapReadPool.IdleTimeoutSeconds.Set(idleTimeout)
   536  	config.TxPool.IdleTimeoutSeconds.Set(idleTimeout)
   537  	se := NewEngine(tabletenv.NewEnv(config, "SchemaTest"))
   538  	se.InitDBConfig(newDBConfigs(db).DbaWithDB())
   539  	return se
   540  }
   541  
   542  func newDBConfigs(db *fakesqldb.DB) *dbconfigs.DBConfigs {
   543  	params, _ := db.ConnParams().MysqlParams()
   544  	cp := *params
   545  	return dbconfigs.NewTestDBConfigs(cp, cp, "fakesqldb")
   546  }
   547  
   548  func initialSchema() map[string]*Table {
   549  	return map[string]*Table{
   550  		"dual": {
   551  			Name: sqlparser.NewIdentifierCS("dual"),
   552  		},
   553  		"test_table_01": {
   554  			Name: sqlparser.NewIdentifierCS("test_table_01"),
   555  			Fields: []*querypb.Field{{
   556  				Name: "pk",
   557  				Type: sqltypes.Int32,
   558  			}},
   559  			PKColumns:     []int{0},
   560  			CreateTime:    1427325875,
   561  			FileSize:      0x64,
   562  			AllocatedSize: 0x96,
   563  		},
   564  		"test_table_02": {
   565  			Name: sqlparser.NewIdentifierCS("test_table_02"),
   566  			Fields: []*querypb.Field{{
   567  				Name: "pk",
   568  				Type: sqltypes.Int32,
   569  			}},
   570  			PKColumns:     []int{0},
   571  			CreateTime:    1427325875,
   572  			FileSize:      0x64,
   573  			AllocatedSize: 0x96,
   574  		},
   575  		"test_table_03": {
   576  			Name: sqlparser.NewIdentifierCS("test_table_03"),
   577  			Fields: []*querypb.Field{{
   578  				Name: "pk",
   579  				Type: sqltypes.Int32,
   580  			}},
   581  			PKColumns:     []int{0},
   582  			CreateTime:    1427325875,
   583  			FileSize:      0x64,
   584  			AllocatedSize: 0x96,
   585  		},
   586  		"seq": {
   587  			Name: sqlparser.NewIdentifierCS("seq"),
   588  			Type: Sequence,
   589  			Fields: []*querypb.Field{{
   590  				Name: "id",
   591  				Type: sqltypes.Int32,
   592  			}, {
   593  				Name: "next_id",
   594  				Type: sqltypes.Int64,
   595  			}, {
   596  				Name: "cache",
   597  				Type: sqltypes.Int64,
   598  			}, {
   599  				Name: "increment",
   600  				Type: sqltypes.Int64,
   601  			}},
   602  			PKColumns:     []int{0},
   603  			CreateTime:    1427325875,
   604  			FileSize:      0x64,
   605  			AllocatedSize: 0x96,
   606  			SequenceInfo:  &SequenceInfo{},
   607  		},
   608  		"msg": {
   609  			Name: sqlparser.NewIdentifierCS("msg"),
   610  			Type: Message,
   611  			Fields: []*querypb.Field{{
   612  				Name: "id",
   613  				Type: sqltypes.Int64,
   614  			}, {
   615  				Name: "priority",
   616  				Type: sqltypes.Int64,
   617  			}, {
   618  				Name: "time_next",
   619  				Type: sqltypes.Int64,
   620  			}, {
   621  				Name: "epoch",
   622  				Type: sqltypes.Int64,
   623  			}, {
   624  				Name: "time_acked",
   625  				Type: sqltypes.Int64,
   626  			}, {
   627  				Name: "message",
   628  				Type: sqltypes.Int64,
   629  			}},
   630  			PKColumns:     []int{0},
   631  			CreateTime:    1427325875,
   632  			FileSize:      0x64,
   633  			AllocatedSize: 0x96,
   634  			MessageInfo: &MessageInfo{
   635  				Fields: []*querypb.Field{{
   636  					Name: "id",
   637  					Type: sqltypes.Int64,
   638  				}, {
   639  					Name: "message",
   640  					Type: sqltypes.Int64,
   641  				}},
   642  				AckWaitDuration:    30 * time.Second,
   643  				PurgeAfterDuration: 120 * time.Second,
   644  				MinBackoff:         30 * time.Second,
   645  				BatchSize:          1,
   646  				CacheSize:          10,
   647  				PollInterval:       30 * time.Second,
   648  			},
   649  		},
   650  	}
   651  }
   652  
   653  func AddFakeInnoDBReadRowsResult(db *fakesqldb.DB, value int) *fakesqldb.ExpectedResult {
   654  	return db.AddQuery("show status like 'Innodb_rows_read'", sqltypes.MakeTestResult(sqltypes.MakeTestFields(
   655  		"Variable_name|Value",
   656  		"varchar|int64"),
   657  		fmt.Sprintf("Innodb_rows_read|%d", value),
   658  	))
   659  }