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 }