vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/twopc_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 tabletserver
    18  
    19  import (
    20  	"encoding/json"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tx"
    26  
    27  	"context"
    28  
    29  	"vitess.io/vitess/go/sqltypes"
    30  
    31  	querypb "vitess.io/vitess/go/vt/proto/query"
    32  )
    33  
    34  func TestReadAllRedo(t *testing.T) {
    35  	// Reuse code from tx_executor_test.
    36  	_, tsv, db := newTestTxExecutor(t)
    37  	defer db.Close()
    38  	defer tsv.StopService()
    39  	tpc := tsv.te.twoPC
    40  	ctx := context.Background()
    41  
    42  	conn, err := tsv.qe.conns.Get(ctx, nil)
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	defer conn.Recycle()
    47  
    48  	db.AddQuery(tpc.readAllRedo, &sqltypes.Result{})
    49  	prepared, failed, err := tpc.ReadAllRedo(ctx)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	var want []*tx.PreparedTx
    54  	if !reflect.DeepEqual(prepared, want) {
    55  		t.Errorf("ReadAllRedo: %s, want %s", jsonStr(prepared), jsonStr(want))
    56  	}
    57  	if len(failed) != 0 {
    58  		t.Errorf("ReadAllRedo (failed): %v, must be empty", jsonStr(failed))
    59  	}
    60  
    61  	db.AddQuery(tpc.readAllRedo, &sqltypes.Result{
    62  		Fields: []*querypb.Field{
    63  			{Type: sqltypes.VarChar},
    64  			{Type: sqltypes.Int64},
    65  			{Type: sqltypes.Int64},
    66  			{Type: sqltypes.VarChar},
    67  		},
    68  		Rows: [][]sqltypes.Value{{
    69  			sqltypes.NewVarBinary("dtid0"),
    70  			sqltypes.NewInt64(RedoStatePrepared),
    71  			sqltypes.NewVarBinary("1"),
    72  			sqltypes.NewVarBinary("stmt01"),
    73  		}},
    74  	})
    75  	prepared, failed, err = tpc.ReadAllRedo(ctx)
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	want = []*tx.PreparedTx{{
    80  		Dtid:    "dtid0",
    81  		Queries: []string{"stmt01"},
    82  		Time:    time.Unix(0, 1),
    83  	}}
    84  	if !reflect.DeepEqual(prepared, want) {
    85  		t.Errorf("ReadAllRedo: %s, want %s", jsonStr(prepared), jsonStr(want))
    86  	}
    87  	if len(failed) != 0 {
    88  		t.Errorf("ReadAllRedo (failed): %v, must be empty", jsonStr(failed))
    89  	}
    90  
    91  	db.AddQuery(tpc.readAllRedo, &sqltypes.Result{
    92  		Fields: []*querypb.Field{
    93  			{Type: sqltypes.VarChar},
    94  			{Type: sqltypes.Int64},
    95  			{Type: sqltypes.Int64},
    96  			{Type: sqltypes.VarChar},
    97  		},
    98  		Rows: [][]sqltypes.Value{{
    99  			sqltypes.NewVarBinary("dtid0"),
   100  			sqltypes.NewInt64(RedoStatePrepared),
   101  			sqltypes.NewVarBinary("1"),
   102  			sqltypes.NewVarBinary("stmt01"),
   103  		}, {
   104  			sqltypes.NewVarBinary("dtid0"),
   105  			sqltypes.NewInt64(RedoStatePrepared),
   106  			sqltypes.NewVarBinary("1"),
   107  			sqltypes.NewVarBinary("stmt02"),
   108  		}},
   109  	})
   110  	prepared, failed, err = tpc.ReadAllRedo(ctx)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	want = []*tx.PreparedTx{{
   115  		Dtid:    "dtid0",
   116  		Queries: []string{"stmt01", "stmt02"},
   117  		Time:    time.Unix(0, 1),
   118  	}}
   119  	if !reflect.DeepEqual(prepared, want) {
   120  		t.Errorf("ReadAllRedo: %s, want %s", jsonStr(prepared), jsonStr(want))
   121  	}
   122  	if len(failed) != 0 {
   123  		t.Errorf("ReadAllRedo (failed): %v, must be empty", jsonStr(failed))
   124  	}
   125  
   126  	db.AddQuery(tpc.readAllRedo, &sqltypes.Result{
   127  		Fields: []*querypb.Field{
   128  			{Type: sqltypes.VarChar},
   129  			{Type: sqltypes.Int64},
   130  			{Type: sqltypes.Int64},
   131  			{Type: sqltypes.VarChar},
   132  		},
   133  		Rows: [][]sqltypes.Value{{
   134  			sqltypes.NewVarBinary("dtid0"),
   135  			sqltypes.NewInt64(RedoStatePrepared),
   136  			sqltypes.NewVarBinary("1"),
   137  			sqltypes.NewVarBinary("stmt01"),
   138  		}, {
   139  			sqltypes.NewVarBinary("dtid0"),
   140  			sqltypes.NewInt64(RedoStatePrepared),
   141  			sqltypes.NewVarBinary("1"),
   142  			sqltypes.NewVarBinary("stmt02"),
   143  		}, {
   144  			sqltypes.NewVarBinary("dtid1"),
   145  			sqltypes.NewInt64(RedoStatePrepared),
   146  			sqltypes.NewVarBinary("1"),
   147  			sqltypes.NewVarBinary("stmt11"),
   148  		}},
   149  	})
   150  	prepared, failed, err = tpc.ReadAllRedo(ctx)
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	want = []*tx.PreparedTx{{
   155  		Dtid:    "dtid0",
   156  		Queries: []string{"stmt01", "stmt02"},
   157  		Time:    time.Unix(0, 1),
   158  	}, {
   159  		Dtid:    "dtid1",
   160  		Queries: []string{"stmt11"},
   161  		Time:    time.Unix(0, 1),
   162  	}}
   163  	if !reflect.DeepEqual(prepared, want) {
   164  		t.Errorf("ReadAllRedo: %s, want %s", jsonStr(prepared), jsonStr(want))
   165  	}
   166  	if len(failed) != 0 {
   167  		t.Errorf("ReadAllRedo (failed): %v, must be empty", jsonStr(failed))
   168  	}
   169  
   170  	db.AddQuery(tpc.readAllRedo, &sqltypes.Result{
   171  		Fields: []*querypb.Field{
   172  			{Type: sqltypes.VarChar},
   173  			{Type: sqltypes.Int64},
   174  			{Type: sqltypes.Int64},
   175  			{Type: sqltypes.VarChar},
   176  		},
   177  		Rows: [][]sqltypes.Value{{
   178  			sqltypes.NewVarBinary("dtid0"),
   179  			sqltypes.NewInt64(RedoStatePrepared),
   180  			sqltypes.NewVarBinary("1"),
   181  			sqltypes.NewVarBinary("stmt01"),
   182  		}, {
   183  			sqltypes.NewVarBinary("dtid0"),
   184  			sqltypes.NewInt64(RedoStatePrepared),
   185  			sqltypes.NewVarBinary("1"),
   186  			sqltypes.NewVarBinary("stmt02"),
   187  		}, {
   188  			sqltypes.NewVarBinary("dtid1"),
   189  			sqltypes.NewVarBinary("Failed"),
   190  			sqltypes.NewVarBinary("1"),
   191  			sqltypes.NewVarBinary("stmt11"),
   192  		}, {
   193  			sqltypes.NewVarBinary("dtid2"),
   194  			sqltypes.NewVarBinary("Failed"),
   195  			sqltypes.NewVarBinary("1"),
   196  			sqltypes.NewVarBinary("stmt21"),
   197  		}, {
   198  			sqltypes.NewVarBinary("dtid2"),
   199  			sqltypes.NewVarBinary("Failed"),
   200  			sqltypes.NewVarBinary("1"),
   201  			sqltypes.NewVarBinary("stmt22"),
   202  		}, {
   203  			sqltypes.NewVarBinary("dtid3"),
   204  			sqltypes.NewInt64(RedoStatePrepared),
   205  			sqltypes.NewVarBinary("1"),
   206  			sqltypes.NewVarBinary("stmt31"),
   207  		}},
   208  	})
   209  	prepared, failed, err = tpc.ReadAllRedo(ctx)
   210  	if err != nil {
   211  		t.Fatal(err)
   212  	}
   213  	want = []*tx.PreparedTx{{
   214  		Dtid:    "dtid0",
   215  		Queries: []string{"stmt01", "stmt02"},
   216  		Time:    time.Unix(0, 1),
   217  	}, {
   218  		Dtid:    "dtid3",
   219  		Queries: []string{"stmt31"},
   220  		Time:    time.Unix(0, 1),
   221  	}}
   222  	if !reflect.DeepEqual(prepared, want) {
   223  		t.Errorf("ReadAllRedo: %s, want %s", jsonStr(prepared), jsonStr(want))
   224  	}
   225  	wantFailed := []*tx.PreparedTx{{
   226  		Dtid:    "dtid1",
   227  		Queries: []string{"stmt11"},
   228  		Time:    time.Unix(0, 1),
   229  	}, {
   230  		Dtid:    "dtid2",
   231  		Queries: []string{"stmt21", "stmt22"},
   232  		Time:    time.Unix(0, 1),
   233  	}}
   234  	if !reflect.DeepEqual(failed, wantFailed) {
   235  		t.Errorf("ReadAllRedo failed): %s, want %s", jsonStr(failed), jsonStr(wantFailed))
   236  	}
   237  }
   238  
   239  func TestReadAllTransactions(t *testing.T) {
   240  	_, tsv, db := newTestTxExecutor(t)
   241  	defer db.Close()
   242  	defer tsv.StopService()
   243  	tpc := tsv.te.twoPC
   244  	ctx := context.Background()
   245  
   246  	conn, err := tsv.qe.conns.Get(ctx, nil)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	defer conn.Recycle()
   251  
   252  	db.AddQuery(tpc.readAllTransactions, &sqltypes.Result{})
   253  	distributed, err := tpc.ReadAllTransactions(ctx)
   254  	if err != nil {
   255  		t.Fatal(err)
   256  	}
   257  	var want []*tx.DistributedTx
   258  	if !reflect.DeepEqual(distributed, want) {
   259  		t.Errorf("ReadAllTransactions: %s, want %s", jsonStr(distributed), jsonStr(want))
   260  	}
   261  
   262  	db.AddQuery(tpc.readAllTransactions, &sqltypes.Result{
   263  		Fields: []*querypb.Field{
   264  			{Type: sqltypes.VarChar},
   265  			{Type: sqltypes.Int64},
   266  			{Type: sqltypes.Int64},
   267  			{Type: sqltypes.VarChar},
   268  			{Type: sqltypes.VarChar},
   269  		},
   270  		Rows: [][]sqltypes.Value{{
   271  			sqltypes.NewVarBinary("dtid0"),
   272  			sqltypes.NewInt64(RedoStatePrepared),
   273  			sqltypes.NewVarBinary("1"),
   274  			sqltypes.NewVarBinary("ks01"),
   275  			sqltypes.NewVarBinary("shard01"),
   276  		}},
   277  	})
   278  	distributed, err = tpc.ReadAllTransactions(ctx)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	want = []*tx.DistributedTx{{
   283  		Dtid:    "dtid0",
   284  		State:   "PREPARE",
   285  		Created: time.Unix(0, 1),
   286  		Participants: []querypb.Target{{
   287  			Keyspace: "ks01",
   288  			Shard:    "shard01",
   289  		}},
   290  	}}
   291  	if !reflect.DeepEqual(distributed, want) {
   292  		t.Errorf("ReadAllTransactions:\n%s, want\n%s", jsonStr(distributed), jsonStr(want))
   293  	}
   294  
   295  	db.AddQuery(tpc.readAllTransactions, &sqltypes.Result{
   296  		Fields: []*querypb.Field{
   297  			{Type: sqltypes.VarChar},
   298  			{Type: sqltypes.Int64},
   299  			{Type: sqltypes.Int64},
   300  			{Type: sqltypes.VarChar},
   301  			{Type: sqltypes.VarChar},
   302  		},
   303  		Rows: [][]sqltypes.Value{{
   304  			sqltypes.NewVarBinary("dtid0"),
   305  			sqltypes.NewInt64(RedoStatePrepared),
   306  			sqltypes.NewVarBinary("1"),
   307  			sqltypes.NewVarBinary("ks01"),
   308  			sqltypes.NewVarBinary("shard01"),
   309  		}, {
   310  			sqltypes.NewVarBinary("dtid0"),
   311  			sqltypes.NewInt64(RedoStatePrepared),
   312  			sqltypes.NewVarBinary("1"),
   313  			sqltypes.NewVarBinary("ks02"),
   314  			sqltypes.NewVarBinary("shard02"),
   315  		}},
   316  	})
   317  	distributed, err = tpc.ReadAllTransactions(ctx)
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	want = []*tx.DistributedTx{{
   322  		Dtid:    "dtid0",
   323  		State:   "PREPARE",
   324  		Created: time.Unix(0, 1),
   325  		Participants: []querypb.Target{{
   326  			Keyspace: "ks01",
   327  			Shard:    "shard01",
   328  		}, {
   329  			Keyspace: "ks02",
   330  			Shard:    "shard02",
   331  		}},
   332  	}}
   333  	if !reflect.DeepEqual(distributed, want) {
   334  		t.Errorf("ReadAllTransactions:\n%s, want\n%s", jsonStr(distributed), jsonStr(want))
   335  	}
   336  
   337  	db.AddQuery(tpc.readAllTransactions, &sqltypes.Result{
   338  		Fields: []*querypb.Field{
   339  			{Type: sqltypes.VarChar},
   340  			{Type: sqltypes.Int64},
   341  			{Type: sqltypes.Int64},
   342  			{Type: sqltypes.VarChar},
   343  			{Type: sqltypes.VarChar},
   344  		},
   345  		Rows: [][]sqltypes.Value{{
   346  			sqltypes.NewVarBinary("dtid0"),
   347  			sqltypes.NewInt64(RedoStatePrepared),
   348  			sqltypes.NewVarBinary("1"),
   349  			sqltypes.NewVarBinary("ks01"),
   350  			sqltypes.NewVarBinary("shard01"),
   351  		}, {
   352  			sqltypes.NewVarBinary("dtid0"),
   353  			sqltypes.NewInt64(RedoStatePrepared),
   354  			sqltypes.NewVarBinary("1"),
   355  			sqltypes.NewVarBinary("ks02"),
   356  			sqltypes.NewVarBinary("shard02"),
   357  		}, {
   358  			sqltypes.NewVarBinary("dtid1"),
   359  			sqltypes.NewInt64(RedoStatePrepared),
   360  			sqltypes.NewVarBinary("1"),
   361  			sqltypes.NewVarBinary("ks11"),
   362  			sqltypes.NewVarBinary("shard11"),
   363  		}},
   364  	})
   365  	distributed, err = tpc.ReadAllTransactions(ctx)
   366  	if err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	want = []*tx.DistributedTx{{
   370  		Dtid:    "dtid0",
   371  		State:   "PREPARE",
   372  		Created: time.Unix(0, 1),
   373  		Participants: []querypb.Target{{
   374  			Keyspace: "ks01",
   375  			Shard:    "shard01",
   376  		}, {
   377  			Keyspace: "ks02",
   378  			Shard:    "shard02",
   379  		}},
   380  	}, {
   381  		Dtid:    "dtid1",
   382  		State:   "PREPARE",
   383  		Created: time.Unix(0, 1),
   384  		Participants: []querypb.Target{{
   385  			Keyspace: "ks11",
   386  			Shard:    "shard11",
   387  		}},
   388  	}}
   389  	if !reflect.DeepEqual(distributed, want) {
   390  		t.Errorf("ReadAllTransactions:\n%s, want\n%s", jsonStr(distributed), jsonStr(want))
   391  	}
   392  }
   393  
   394  func jsonStr(v any) string {
   395  	out, _ := json.Marshal(v)
   396  	return string(out)
   397  }