github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/master/scheduler/latch_test.go (about) 1 // Copyright 2021 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 scheduler 15 16 import ( 17 "sort" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/require" 23 ) 24 25 func TestOneAcquireSuccess(t *testing.T) { 26 t.Parallel() 27 28 var ( 29 l = newLatches() 30 fire = make(chan struct{}) 31 success = make(chan string, 2) 32 fail = make(chan struct{}, 8) 33 group1 = "group1" 34 group2 = "group2" 35 wg sync.WaitGroup 36 ) 37 38 for i := 0; i < 10; i++ { 39 var group string 40 if i < 5 { 41 group = group1 42 } else { 43 group = group2 44 } 45 46 wg.Add(1) 47 go func(name string) { 48 defer wg.Done() 49 <-fire 50 _, err := l.tryAcquire(name) 51 if err != nil { 52 fail <- struct{}{} 53 } else { 54 success <- name 55 } 56 }(group) 57 } 58 59 for i := 0; i < 10; i++ { 60 fire <- struct{}{} 61 } 62 wg.Wait() 63 64 require.Len(t, fail, 8) 65 66 var succNames []string 67 succNames = append(succNames, <-success) 68 succNames = append(succNames, <-success) 69 sort.Strings(succNames) 70 require.Equal(t, []string{group1, group2}, succNames) 71 } 72 73 func TestAcquireAfterRelease(t *testing.T) { 74 t.Parallel() 75 76 var ( 77 l = newLatches() 78 fire = make(chan struct{}) 79 success int 80 group = "group1" 81 wg sync.WaitGroup 82 ) 83 84 for i := 0; i < 5; i++ { 85 wg.Add(1) 86 go func() { 87 defer wg.Done() 88 <-fire 89 90 for { 91 release, err := l.tryAcquire(group) 92 if err != nil { 93 time.Sleep(10 * time.Millisecond) 94 } else { 95 time.Sleep(20 * time.Millisecond) 96 success++ 97 release() 98 return 99 } 100 } 101 }() 102 } 103 104 for i := 0; i < 5; i++ { 105 fire <- struct{}{} 106 } 107 108 wg.Wait() 109 require.Equal(t, 5, success) 110 } 111 112 func TestMultiRelease(t *testing.T) { 113 t.Parallel() 114 115 var ( 116 l = newLatches() 117 names = []string{"name1", "name2", "name3"} 118 fire = make(chan struct{}, len(names)) 119 wg sync.WaitGroup 120 ) 121 122 for repeat := 0; repeat < 3; repeat++ { 123 for i := range names { 124 wg.Add(1) 125 go func(name string) { 126 defer wg.Done() 127 <-fire 128 release, err := l.tryAcquire(name) 129 require.NoError(t, err) 130 release() 131 // will not panic or cause other error 132 release() 133 }(names[i]) 134 } 135 136 for range names { 137 fire <- struct{}{} 138 } 139 wg.Wait() 140 } 141 } 142 143 func TestWontReleaseOther(t *testing.T) { 144 t.Parallel() 145 146 var ( 147 l = newLatches() 148 group = "group1" 149 ) 150 151 release1, err := l.tryAcquire(group) 152 require.NoError(t, err) 153 release1() 154 155 // because release1 is called, another tryAcquire should succeed 156 release2, err := l.tryAcquire(group) 157 require.NoError(t, err) 158 159 // release1 should not release the latch of release2, we test this by tryAcquire 160 release1() 161 _, err = l.tryAcquire(group) 162 require.Error(t, err) 163 164 release2() 165 _, err = l.tryAcquire(group) 166 require.NoError(t, err) 167 }