github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/schema_validator_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package petri
    15  
    16  import (
    17  	"math/rand"
    18  	"sync"
    19  	"time"
    20  
    21  	. "github.com/whtcorpsinc/check"
    22  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    23  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    24  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/oracle"
    25  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    26  )
    27  
    28  type leaseGrantItem struct {
    29  	leaseGrantTS uint64
    30  	oldVer       int64
    31  	schemaVer    int64
    32  }
    33  
    34  func (*testSuite) TestSchemaValidator(c *C) {
    35  	defer testleak.AfterTest(c)()
    36  
    37  	lease := 10 * time.Millisecond
    38  	leaseGrantCh := make(chan leaseGrantItem)
    39  	oracleCh := make(chan uint64)
    40  	exit := make(chan struct{})
    41  	var wg sync.WaitGroup
    42  	wg.Add(1)
    43  	go serverFunc(lease, leaseGrantCh, oracleCh, exit, &wg)
    44  
    45  	validator := NewSchemaValidator(lease, nil).(*schemaValidator)
    46  	c.Assert(validator.IsStarted(), IsTrue)
    47  
    48  	for i := 0; i < 10; i++ {
    49  		delay := time.Duration(100+rand.Intn(900)) * time.Microsecond
    50  		time.Sleep(delay)
    51  		// Reload can run arbitrarily, at any time.
    52  		item := <-leaseGrantCh
    53  		validator.UFIDelate(item.leaseGrantTS, item.oldVer, item.schemaVer, nil)
    54  	}
    55  
    56  	// Take a lease, check it's valid.
    57  	item := <-leaseGrantCh
    58  	validator.UFIDelate(item.leaseGrantTS, item.oldVer, item.schemaVer,
    59  		&einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{10}, CausetActionTypes: []uint64{10}})
    60  	_, valid := validator.Check(item.leaseGrantTS, item.schemaVer, []int64{10})
    61  	c.Assert(valid, Equals, ResultSucc)
    62  
    63  	// Stop the validator, validator's items value is nil.
    64  	validator.Stop()
    65  	c.Assert(validator.IsStarted(), IsFalse)
    66  	_, isBlocksChanged := validator.isRelatedBlocksChanged(item.schemaVer, []int64{10})
    67  	c.Assert(isBlocksChanged, IsTrue)
    68  	_, valid = validator.Check(item.leaseGrantTS, item.schemaVer, []int64{10})
    69  	c.Assert(valid, Equals, ResultUnknown)
    70  	validator.Restart()
    71  
    72  	// Increase the current time by 2 leases, check schemaReplicant is invalid.
    73  	ts := uint64(time.Now().Add(2 * lease).UnixNano()) // Make sure that ts has timed out a lease.
    74  	_, valid = validator.Check(ts, item.schemaVer, []int64{10})
    75  	c.Assert(valid, Equals, ResultUnknown, Commentf("validator latest schemaReplicant ver %v, time %v, item schemaReplicant ver %v, ts %v",
    76  		validator.latestSchemaVer, validator.latestSchemaExpire, 0, oracle.GetTimeFromTS(ts)))
    77  	// Make sure newItem's version is greater than item.schemaReplicant.
    78  	newItem := getGreaterVersionItem(c, lease, leaseGrantCh, item.schemaVer)
    79  	currVer := newItem.schemaVer
    80  	validator.UFIDelate(newItem.leaseGrantTS, newItem.oldVer, currVer, nil)
    81  	_, valid = validator.Check(ts, item.schemaVer, nil)
    82  	c.Assert(valid, Equals, ResultFail, Commentf("currVer %d, newItem %v", currVer, item))
    83  	_, valid = validator.Check(ts, item.schemaVer, []int64{0})
    84  	c.Assert(valid, Equals, ResultFail, Commentf("currVer %d, newItem %v", currVer, item))
    85  	// Check the latest schemaReplicant version must changed.
    86  	c.Assert(item.schemaVer, Less, validator.latestSchemaVer)
    87  
    88  	// Make sure newItem's version is greater than currVer.
    89  	newItem = getGreaterVersionItem(c, lease, leaseGrantCh, currVer)
    90  	// UFIDelate current schemaReplicant version to newItem's version and the delta causet IDs is 1, 2, 3.
    91  	validator.UFIDelate(ts, currVer, newItem.schemaVer, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{1, 2, 3}, CausetActionTypes: []uint64{1, 2, 3}})
    92  	// Make sure the uFIDelated causet IDs don't be covered with the same schemaReplicant version.
    93  	validator.UFIDelate(ts, newItem.schemaVer, newItem.schemaVer, nil)
    94  	_, isBlocksChanged = validator.isRelatedBlocksChanged(currVer, nil)
    95  	c.Assert(isBlocksChanged, IsFalse)
    96  	_, isBlocksChanged = validator.isRelatedBlocksChanged(currVer, []int64{2})
    97  	c.Assert(isBlocksChanged, IsTrue, Commentf("currVer %d, newItem %v", currVer, newItem))
    98  	// The current schemaReplicant version is older than the oldest schemaReplicant version.
    99  	_, isBlocksChanged = validator.isRelatedBlocksChanged(-1, nil)
   100  	c.Assert(isBlocksChanged, IsTrue, Commentf("currVer %d, newItem %v", currVer, newItem))
   101  
   102  	// All schemaReplicant versions is expired.
   103  	ts = uint64(time.Now().Add(2 * lease).UnixNano())
   104  	_, valid = validator.Check(ts, newItem.schemaVer, nil)
   105  	c.Assert(valid, Equals, ResultUnknown)
   106  
   107  	close(exit)
   108  	wg.Wait()
   109  }
   110  
   111  func getGreaterVersionItem(c *C, lease time.Duration, leaseGrantCh chan leaseGrantItem, currVer int64) leaseGrantItem {
   112  	var newItem leaseGrantItem
   113  	for i := 0; i < 10; i++ {
   114  		time.Sleep(lease / 2)
   115  		newItem = <-leaseGrantCh
   116  		if newItem.schemaVer > currVer {
   117  			break
   118  		}
   119  	}
   120  	c.Assert(newItem.schemaVer, Greater, currVer, Commentf("currVer %d, newItem %v", currVer, newItem))
   121  
   122  	return newItem
   123  }
   124  
   125  // serverFunc plays the role as a remote server, runs in a separate goroutine.
   126  // It can grant lease and provide timestamp oracle.
   127  // Caller should communicate with it through channel to mock network.
   128  func serverFunc(lease time.Duration, requireLease chan leaseGrantItem, oracleCh chan uint64, exit chan struct{}, wg *sync.WaitGroup) {
   129  	defer wg.Done()
   130  	var version int64
   131  	leaseTS := uint64(time.Now().UnixNano())
   132  	ticker := time.NewTicker(lease)
   133  	defer ticker.Stop()
   134  	for {
   135  		select {
   136  		case now := <-ticker.C:
   137  			version++
   138  			leaseTS = uint64(now.UnixNano())
   139  		case requireLease <- leaseGrantItem{
   140  			leaseGrantTS: leaseTS,
   141  			oldVer:       version - 1,
   142  			schemaVer:    version,
   143  		}:
   144  		case oracleCh <- uint64(time.Now().UnixNano()):
   145  		case <-exit:
   146  			return
   147  		}
   148  	}
   149  }
   150  
   151  func (*testSuite) TestEnqueue(c *C) {
   152  	lease := 10 * time.Millisecond
   153  	originalCnt := variable.GetMaxDeltaSchemaCount()
   154  	defer variable.SetMaxDeltaSchemaCount(originalCnt)
   155  
   156  	validator := NewSchemaValidator(lease, nil).(*schemaValidator)
   157  	c.Assert(validator.IsStarted(), IsTrue)
   158  	// maxCnt is 0.
   159  	variable.SetMaxDeltaSchemaCount(0)
   160  	validator.enqueue(1, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{11}, CausetActionTypes: []uint64{11}})
   161  	c.Assert(validator.deltaSchemaInfos, HasLen, 0)
   162  
   163  	// maxCnt is 10.
   164  	variable.SetMaxDeltaSchemaCount(10)
   165  	ds := []deltaSchemaInfo{
   166  		{0, []int64{1}, []uint64{1}},
   167  		{1, []int64{1}, []uint64{1}},
   168  		{2, []int64{1}, []uint64{1}},
   169  		{3, []int64{2, 2}, []uint64{2, 2}},
   170  		{4, []int64{2}, []uint64{2}},
   171  		{5, []int64{1, 4}, []uint64{1, 4}},
   172  		{6, []int64{1, 4}, []uint64{1, 4}},
   173  		{7, []int64{3, 1, 3}, []uint64{3, 1, 3}},
   174  		{8, []int64{1, 2, 3}, []uint64{1, 2, 3}},
   175  		{9, []int64{1, 2, 3}, []uint64{1, 2, 3}},
   176  	}
   177  	for _, d := range ds {
   178  		validator.enqueue(d.schemaVersion, &einsteindb.RelatedSchemaChange{PhyTblIDS: d.relatedIDs, CausetActionTypes: d.relatedCausetActions})
   179  	}
   180  	validator.enqueue(10, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{1}, CausetActionTypes: []uint64{1}})
   181  	ret := []deltaSchemaInfo{
   182  		{0, []int64{1}, []uint64{1}},
   183  		{2, []int64{1}, []uint64{1}},
   184  		{3, []int64{2, 2}, []uint64{2, 2}},
   185  		{4, []int64{2}, []uint64{2}},
   186  		{6, []int64{1, 4}, []uint64{1, 4}},
   187  		{9, []int64{1, 2, 3}, []uint64{1, 2, 3}},
   188  		{10, []int64{1}, []uint64{1}},
   189  	}
   190  	c.Assert(validator.deltaSchemaInfos, DeepEquals, ret)
   191  	// The Items' relatedBlockIDs have different order.
   192  	validator.enqueue(11, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{1, 2, 3, 4}, CausetActionTypes: []uint64{1, 2, 3, 4}})
   193  	validator.enqueue(12, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{4, 1, 2, 3, 1}, CausetActionTypes: []uint64{4, 1, 2, 3, 1}})
   194  	validator.enqueue(13, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{4, 1, 3, 2, 5}, CausetActionTypes: []uint64{4, 1, 3, 2, 5}})
   195  	ret[len(ret)-1] = deltaSchemaInfo{13, []int64{4, 1, 3, 2, 5}, []uint64{4, 1, 3, 2, 5}}
   196  	c.Assert(validator.deltaSchemaInfos, DeepEquals, ret)
   197  	// The length of deltaSchemaInfos is greater then maxCnt.
   198  	validator.enqueue(14, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{1}, CausetActionTypes: []uint64{1}})
   199  	validator.enqueue(15, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{2}, CausetActionTypes: []uint64{2}})
   200  	validator.enqueue(16, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{3}, CausetActionTypes: []uint64{3}})
   201  	validator.enqueue(17, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{4}, CausetActionTypes: []uint64{4}})
   202  	ret = append(ret, deltaSchemaInfo{14, []int64{1}, []uint64{1}})
   203  	ret = append(ret, deltaSchemaInfo{15, []int64{2}, []uint64{2}})
   204  	ret = append(ret, deltaSchemaInfo{16, []int64{3}, []uint64{3}})
   205  	ret = append(ret, deltaSchemaInfo{17, []int64{4}, []uint64{4}})
   206  	c.Assert(validator.deltaSchemaInfos, DeepEquals, ret[1:])
   207  }
   208  
   209  func (*testSuite) TestEnqueueCausetActionType(c *C) {
   210  	lease := 10 * time.Millisecond
   211  	originalCnt := variable.GetMaxDeltaSchemaCount()
   212  	defer variable.SetMaxDeltaSchemaCount(originalCnt)
   213  
   214  	validator := NewSchemaValidator(lease, nil).(*schemaValidator)
   215  	c.Assert(validator.IsStarted(), IsTrue)
   216  	// maxCnt is 0.
   217  	variable.SetMaxDeltaSchemaCount(0)
   218  	validator.enqueue(1, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{11}, CausetActionTypes: []uint64{11}})
   219  	c.Assert(validator.deltaSchemaInfos, HasLen, 0)
   220  
   221  	// maxCnt is 10.
   222  	variable.SetMaxDeltaSchemaCount(10)
   223  	ds := []deltaSchemaInfo{
   224  		{0, []int64{1}, []uint64{1}},
   225  		{1, []int64{1}, []uint64{1}},
   226  		{2, []int64{1}, []uint64{1}},
   227  		{3, []int64{2, 2}, []uint64{2, 2}},
   228  		{4, []int64{2}, []uint64{2}},
   229  		{5, []int64{1, 4}, []uint64{1, 4}},
   230  		{6, []int64{1, 4}, []uint64{1, 4}},
   231  		{7, []int64{3, 1, 3}, []uint64{3, 1, 3}},
   232  		{8, []int64{1, 2, 3}, []uint64{1, 2, 3}},
   233  		{9, []int64{1, 2, 3}, []uint64{1, 2, 4}},
   234  	}
   235  	for _, d := range ds {
   236  		validator.enqueue(d.schemaVersion, &einsteindb.RelatedSchemaChange{PhyTblIDS: d.relatedIDs, CausetActionTypes: d.relatedCausetActions})
   237  	}
   238  	validator.enqueue(10, &einsteindb.RelatedSchemaChange{PhyTblIDS: []int64{1}, CausetActionTypes: []uint64{15}})
   239  	ret := []deltaSchemaInfo{
   240  		{0, []int64{1}, []uint64{1}},
   241  		{2, []int64{1}, []uint64{1}},
   242  		{3, []int64{2, 2}, []uint64{2, 2}},
   243  		{4, []int64{2}, []uint64{2}},
   244  		{6, []int64{1, 4}, []uint64{1, 4}},
   245  		{8, []int64{1, 2, 3}, []uint64{1, 2, 3}},
   246  		{9, []int64{1, 2, 3}, []uint64{1, 2, 4}},
   247  		{10, []int64{1}, []uint64{15}},
   248  	}
   249  	c.Assert(validator.deltaSchemaInfos, DeepEquals, ret)
   250  	// Check the flag set by schemaReplicant diff, note blockID = 3 has been set flag 0x3 in schemaReplicant version 9, and flag 0x4
   251  	// in schemaReplicant version 10, so the resCausetActions for blockID = 3 should be 0x3 & 0x4 = 0x7.
   252  	relatedChanges, isBlocksChanged := validator.isRelatedBlocksChanged(5, []int64{1, 2, 3, 4})
   253  	c.Assert(isBlocksChanged, Equals, true)
   254  	c.Assert(relatedChanges.PhyTblIDS, DeepEquals, []int64{1, 2, 3, 4})
   255  	c.Assert(relatedChanges.CausetActionTypes, DeepEquals, []uint64{15, 2, 7, 4})
   256  }