github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/pkg/regionspan/region_range_lock_test.go (about) 1 // Copyright 2020 PingCAP, 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 regionspan 15 16 import ( 17 "context" 18 "math" 19 "time" 20 21 "github.com/pingcap/check" 22 "github.com/pingcap/ticdc/pkg/util/testleak" 23 ) 24 25 type regionRangeLockSuite struct{} 26 27 var _ = check.Suite(®ionRangeLockSuite{}) 28 29 func mustSuccess(c *check.C, res LockRangeResult, expectedCheckpointTs uint64) { 30 c.Assert(res.Status, check.Equals, LockRangeStatusSuccess) 31 c.Assert(res.CheckpointTs, check.Equals, expectedCheckpointTs) 32 } 33 34 func mustStale(c *check.C, res LockRangeResult, expectedRetryRanges ...ComparableSpan) { 35 c.Assert(res.Status, check.Equals, LockRangeStatusStale) 36 c.Assert(res.RetryRanges, check.DeepEquals, expectedRetryRanges) 37 } 38 39 func mustWaitFn(c *check.C, res LockRangeResult) func() LockRangeResult { 40 c.Assert(res.Status, check.Equals, LockRangeStatusWait) 41 return res.WaitFn 42 } 43 44 func mustLockRangeSuccess( 45 ctx context.Context, 46 c *check.C, 47 l *RegionRangeLock, 48 startKey, endKey string, 49 regionID, version, expectedCheckpointTs uint64, 50 ) { 51 res := l.LockRange(ctx, []byte(startKey), []byte(endKey), regionID, version) 52 mustSuccess(c, res, expectedCheckpointTs) 53 } 54 55 //nolint:unparam 56 func mustLockRangeStale( 57 ctx context.Context, 58 c *check.C, 59 l *RegionRangeLock, 60 startKey, endKey string, 61 regionID, version uint64, 62 expectRetrySpans ...string, 63 ) { 64 res := l.LockRange(ctx, []byte(startKey), []byte(endKey), regionID, version) 65 spans := make([]ComparableSpan, 0) 66 for i := 0; i < len(expectRetrySpans); i += 2 { 67 spans = append(spans, ComparableSpan{Start: []byte(expectRetrySpans[i]), End: []byte(expectRetrySpans[i+1])}) 68 } 69 mustStale(c, res, spans...) 70 } 71 72 //nolint:unparam 73 func mustLockRangeWait( 74 ctx context.Context, 75 c *check.C, 76 l *RegionRangeLock, 77 startKey, endKey string, 78 regionID, version uint64, 79 ) func() LockRangeResult { 80 res := l.LockRange(ctx, []byte(startKey), []byte(endKey), regionID, version) 81 return mustWaitFn(c, res) 82 } 83 84 func unlockRange(l *RegionRangeLock, startKey, endKey string, regionID, version uint64, checkpointTs uint64) { 85 l.UnlockRange([]byte(startKey), []byte(endKey), regionID, version, checkpointTs) 86 } 87 88 func (s *regionRangeLockSuite) TestRegionRangeLock(c *check.C) { 89 defer testleak.AfterTest(c)() 90 ctx := context.TODO() 91 l := NewRegionRangeLock([]byte("a"), []byte("h"), math.MaxUint64) 92 mustLockRangeSuccess(ctx, c, l, "a", "e", 1, 1, math.MaxUint64) 93 unlockRange(l, "a", "e", 1, 1, 100) 94 95 mustLockRangeSuccess(ctx, c, l, "a", "e", 1, 2, 100) 96 mustLockRangeStale(ctx, c, l, "a", "e", 1, 2) 97 wait := mustLockRangeWait(ctx, c, l, "a", "h", 1, 3) 98 99 unlockRange(l, "a", "e", 1, 2, 110) 100 res := wait() 101 mustSuccess(c, res, 110) 102 unlockRange(l, "a", "h", 1, 3, 120) 103 } 104 105 func (s *regionRangeLockSuite) TestRegionRangeLockStale(c *check.C) { 106 defer testleak.AfterTest(c)() 107 l := NewRegionRangeLock([]byte("a"), []byte("z"), math.MaxUint64) 108 ctx := context.TODO() 109 mustLockRangeSuccess(ctx, c, l, "c", "g", 1, 10, math.MaxUint64) 110 mustLockRangeSuccess(ctx, c, l, "j", "n", 2, 8, math.MaxUint64) 111 112 mustLockRangeStale(ctx, c, l, "c", "g", 1, 10) 113 mustLockRangeStale(ctx, c, l, "c", "i", 1, 9, "g", "i") 114 mustLockRangeStale(ctx, c, l, "a", "z", 1, 9, "a", "c", "g", "j", "n", "z") 115 mustLockRangeStale(ctx, c, l, "a", "e", 1, 9, "a", "c") 116 mustLockRangeStale(ctx, c, l, "e", "h", 1, 9, "g", "h") 117 mustLockRangeStale(ctx, c, l, "e", "k", 1, 9, "g", "j") 118 mustLockRangeSuccess(ctx, c, l, "g", "j", 3, 1, math.MaxUint64) 119 unlockRange(l, "g", "j", 3, 1, 2) 120 unlockRange(l, "c", "g", 1, 10, 5) 121 unlockRange(l, "j", "n", 2, 8, 8) 122 mustLockRangeSuccess(ctx, c, l, "a", "z", 1, 11, 2) 123 unlockRange(l, "a", "z", 1, 11, 2) 124 } 125 126 func (s *regionRangeLockSuite) TestRegionRangeLockLockingRegionID(c *check.C) { 127 defer testleak.AfterTest(c)() 128 ctx := context.TODO() 129 l := NewRegionRangeLock([]byte("a"), []byte("z"), math.MaxUint64) 130 mustLockRangeSuccess(ctx, c, l, "c", "d", 1, 10, math.MaxUint64) 131 132 mustLockRangeStale(ctx, c, l, "e", "f", 1, 5, "e", "f") 133 mustLockRangeStale(ctx, c, l, "e", "f", 1, 10, "e", "f") 134 wait := mustLockRangeWait(ctx, c, l, "e", "f", 1, 11) 135 unlockRange(l, "c", "d", 1, 10, 10) 136 mustSuccess(c, wait(), math.MaxUint64) 137 // Now ["e", "f") is locked by region 1 at version 11 and ts 11. 138 139 mustLockRangeSuccess(ctx, c, l, "g", "h", 2, 10, math.MaxUint64) 140 wait = mustLockRangeWait(ctx, c, l, "g", "h", 1, 12) 141 ch := make(chan LockRangeResult, 1) 142 go func() { 143 ch <- wait() 144 }() 145 unlockRange(l, "g", "h", 2, 10, 20) 146 // Locking should still be blocked because the regionID 1 is still locked. 147 select { 148 case <-ch: 149 c.Fatalf("locking finished unexpectedly") 150 case <-time.After(time.Millisecond * 50): 151 } 152 153 unlockRange(l, "e", "f", 1, 11, 11) 154 res := <-ch 155 // CheckpointTS calculation should still be based on range and do not consider the regionID. So 156 // the result's checkpointTs should be 20 from of range ["g", "h"), instead of 11 from min(11, 20). 157 mustSuccess(c, res, 20) 158 unlockRange(l, "g", "h", 1, 12, 30) 159 } 160 161 func (s *regionRangeLockSuite) TestRegionRangeLockCanBeCancelled(c *check.C) { 162 defer testleak.AfterTest(c)() 163 ctx, cancel := context.WithCancel(context.Background()) 164 l := NewRegionRangeLock([]byte("a"), []byte("z"), math.MaxUint64) 165 mustLockRangeSuccess(ctx, c, l, "g", "h", 1, 10, math.MaxUint64) 166 wait := mustLockRangeWait(ctx, c, l, "g", "h", 1, 12) 167 cancel() 168 lockResult := wait() 169 c.Assert(lockResult.Status, check.Equals, LockRangeStatusCancel) 170 } 171 172 func (s *regionRangeLockSuite) TestRangeTsMap(c *check.C) { 173 defer testleak.AfterTest(c)() 174 m := NewRangeTsMap([]byte("a"), []byte("z"), math.MaxUint64) 175 176 mustGetMin := func(startKey, endKey string, expectedTs uint64) { 177 ts := m.GetMin([]byte(startKey), []byte(endKey)) 178 c.Assert(ts, check.Equals, expectedTs) 179 } 180 set := func(startKey, endKey string, ts uint64) { 181 m.Set([]byte(startKey), []byte(endKey), ts) 182 } 183 184 mustGetMin("a", "z", math.MaxUint64) 185 set("b", "e", 100) 186 mustGetMin("a", "z", 100) 187 mustGetMin("b", "e", 100) 188 mustGetMin("a", "c", 100) 189 mustGetMin("d", "f", 100) 190 mustGetMin("a", "b", math.MaxUint64) 191 mustGetMin("e", "f", math.MaxUint64) 192 mustGetMin("a", "b\x00", 100) 193 194 set("d", "g", 80) 195 mustGetMin("d", "g", 80) 196 mustGetMin("a", "z", 80) 197 mustGetMin("d", "e", 80) 198 mustGetMin("a", "d", 100) 199 200 set("c", "f", 120) 201 mustGetMin("c", "f", 120) 202 mustGetMin("c", "d", 120) 203 mustGetMin("d", "e", 120) 204 mustGetMin("e", "f", 120) 205 mustGetMin("b", "e", 100) 206 mustGetMin("a", "z", 80) 207 208 set("c", "f", 130) 209 mustGetMin("c", "f", 130) 210 mustGetMin("c", "d", 130) 211 mustGetMin("d", "e", 130) 212 mustGetMin("e", "f", 130) 213 mustGetMin("b", "e", 100) 214 mustGetMin("a", "z", 80) 215 }