github.com/m3db/m3@v1.5.0/src/dbnode/storage/block/lease_test.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package block 22 23 import ( 24 "errors" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/m3db/m3/src/x/ident" 30 xtest "github.com/m3db/m3/src/x/test" 31 xtime "github.com/m3db/m3/src/x/time" 32 33 "github.com/golang/mock/gomock" 34 "github.com/stretchr/testify/require" 35 ) 36 37 func TestRegisterLeaser(t *testing.T) { 38 ctrl := xtest.NewController(t) 39 defer ctrl.Finish() 40 41 var ( 42 leaser = NewMockLeaser(ctrl) 43 leaseMgr = NewLeaseManager(nil) 44 ) 45 46 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 47 require.Equal(t, errLeaserAlreadyRegistered, leaseMgr.RegisterLeaser(leaser)) 48 } 49 50 func TestUnregisterLeaser(t *testing.T) { 51 ctrl := xtest.NewController(t) 52 defer ctrl.Finish() 53 54 var ( 55 leaser1 = NewMockLeaser(ctrl) 56 leaser2 = NewMockLeaser(ctrl) 57 leaseMgr = NewLeaseManager(nil) 58 ) 59 60 // Cant unregister if not registered. 61 require.Equal(t, errLeaserNotRegistered, leaseMgr.UnregisterLeaser(leaser1)) 62 require.Equal(t, errLeaserNotRegistered, leaseMgr.UnregisterLeaser(leaser2)) 63 64 // Register. 65 require.NoError(t, leaseMgr.RegisterLeaser(leaser1)) 66 require.NoError(t, leaseMgr.RegisterLeaser(leaser2)) 67 68 // Ensure registered. 69 require.Equal(t, errLeaserAlreadyRegistered, leaseMgr.RegisterLeaser(leaser1)) 70 require.Equal(t, errLeaserAlreadyRegistered, leaseMgr.RegisterLeaser(leaser2)) 71 72 // Ensure unregistering works. 73 require.NoError(t, leaseMgr.UnregisterLeaser(leaser1)) 74 require.NoError(t, leaseMgr.RegisterLeaser(leaser1)) 75 76 // Ensure unregistering leaser1 does not unregister leaser2. 77 require.Equal(t, errLeaserAlreadyRegistered, leaseMgr.RegisterLeaser(leaser2)) 78 } 79 80 func TestOpenLease(t *testing.T) { 81 ctrl := xtest.NewController(t) 82 defer ctrl.Finish() 83 84 var ( 85 leaser = NewMockLeaser(ctrl) 86 verifier = NewMockLeaseVerifier(ctrl) 87 leaseMgr = NewLeaseManager(verifier) 88 leaseDesc = LeaseDescriptor{ 89 Namespace: ident.StringID("test-ns"), 90 Shard: 1, 91 BlockStart: xtime.Now().Truncate(2 * time.Hour), 92 } 93 leaseState = LeaseState{ 94 Volume: 1, 95 } 96 ) 97 verifier.EXPECT().VerifyLease(leaseDesc, leaseState) 98 99 require.Equal(t, errLeaserNotRegistered, leaseMgr.OpenLease(leaser, leaseDesc, leaseState)) 100 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 101 require.NoError(t, leaseMgr.OpenLease(leaser, leaseDesc, leaseState)) 102 } 103 104 func TestOpenLeaseErrorIfNoVerifier(t *testing.T) { 105 ctrl := xtest.NewController(t) 106 defer ctrl.Finish() 107 108 var ( 109 leaser = NewMockLeaser(ctrl) 110 leaseMgr = NewLeaseManager(nil) 111 leaseDesc = LeaseDescriptor{ 112 Namespace: ident.StringID("test-ns"), 113 Shard: 1, 114 BlockStart: xtime.Now().Truncate(2 * time.Hour), 115 } 116 leaseState = LeaseState{ 117 Volume: 1, 118 } 119 ) 120 121 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 122 require.Equal(t, errOpenLeaseVerifierNotSet, leaseMgr.OpenLease(leaser, leaseDesc, leaseState)) 123 124 verifier := NewMockLeaseVerifier(ctrl) 125 verifier.EXPECT().VerifyLease(leaseDesc, leaseState) 126 require.NoError(t, leaseMgr.SetLeaseVerifier(verifier)) 127 require.NoError(t, leaseMgr.OpenLease(leaser, leaseDesc, leaseState)) 128 } 129 130 func TestOpenLatestLease(t *testing.T) { 131 ctrl := xtest.NewController(t) 132 defer ctrl.Finish() 133 134 var ( 135 leaser = NewMockLeaser(ctrl) 136 verifier = NewMockLeaseVerifier(ctrl) 137 leaseMgr = NewLeaseManager(verifier) 138 leaseDesc = LeaseDescriptor{ 139 Namespace: ident.StringID("test-ns"), 140 Shard: 1, 141 BlockStart: xtime.Now().Truncate(2 * time.Hour), 142 } 143 leaseState = LeaseState{ 144 Volume: 1, 145 } 146 ) 147 verifier.EXPECT().LatestState(leaseDesc).Return(leaseState, nil) 148 149 require.Equal(t, errLeaserNotRegistered, leaseMgr.OpenLease(leaser, leaseDesc, leaseState)) 150 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 151 latestState, err := leaseMgr.OpenLatestLease(leaser, leaseDesc) 152 require.NoError(t, err) 153 require.Equal(t, leaseState, latestState) 154 } 155 156 func TestOpenLatestLeaseErrorIfNoVerifier(t *testing.T) { 157 ctrl := xtest.NewController(t) 158 defer ctrl.Finish() 159 160 var ( 161 leaser = NewMockLeaser(ctrl) 162 leaseMgr = NewLeaseManager(nil) 163 leaseDesc = LeaseDescriptor{ 164 Namespace: ident.StringID("test-ns"), 165 Shard: 1, 166 BlockStart: xtime.Now().Truncate(2 * time.Hour), 167 } 168 leaseState = LeaseState{ 169 Volume: 1, 170 } 171 ) 172 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 173 _, err := leaseMgr.OpenLatestLease(leaser, leaseDesc) 174 require.Equal(t, errOpenLeaseVerifierNotSet, err) 175 176 verifier := NewMockLeaseVerifier(ctrl) 177 verifier.EXPECT().LatestState(leaseDesc).Return(leaseState, nil) 178 require.NoError(t, leaseMgr.SetLeaseVerifier(verifier)) 179 latestState, err := leaseMgr.OpenLatestLease(leaser, leaseDesc) 180 require.NoError(t, err) 181 require.Equal(t, leaseState, latestState) 182 } 183 184 func TestUpdateOpenLeases(t *testing.T) { 185 ctrl := xtest.NewController(t) 186 defer ctrl.Finish() 187 188 var ( 189 verifier = NewMockLeaseVerifier(ctrl) 190 leaseMgr = NewLeaseManager(verifier) 191 192 leaseDesc = LeaseDescriptor{ 193 Namespace: ident.StringID("test-ns"), 194 Shard: 1, 195 BlockStart: xtime.Now().Truncate(2 * time.Hour), 196 } 197 leaseState = LeaseState{ 198 Volume: 1, 199 } 200 leasers = []*MockLeaser{NewMockLeaser(ctrl), NewMockLeaser(ctrl)} 201 ) 202 verifier.EXPECT().VerifyLease(leaseDesc, leaseState).Times(len(leasers)) 203 204 // Expect that the leasers return NoOpenLease the first time to simulate the situation 205 // where they don't have an open lease on the LeaseDescriptor that should be updated. 206 leasers[0].EXPECT(). 207 UpdateOpenLease(leaseDesc, leaseState). 208 Return(NoOpenLease, nil) 209 leasers[1].EXPECT(). 210 UpdateOpenLease(leaseDesc, leaseState). 211 Return(NoOpenLease, nil) 212 213 // Expect that the leasers return UpdateOpenLease the second time to simulate the situation 214 // where they do have an open lease on the LeaseDescriptor that should be updated. 215 leasers[0].EXPECT(). 216 UpdateOpenLease(leaseDesc, leaseState). 217 Return(UpdateOpenLease, nil) 218 leasers[1].EXPECT(). 219 UpdateOpenLease(leaseDesc, leaseState). 220 Return(UpdateOpenLease, nil) 221 222 // Expect that the first leaser returns an error the third time to simulate the situation 223 // where one of the leasers returns an error and make sure that UpdateOpenLeases() bails out 224 // early and returns an error. 225 leasers[0].EXPECT(). 226 UpdateOpenLease(leaseDesc, leaseState). 227 Return(UpdateOpenLeaseResult(0), errors.New("some-error")) 228 229 for _, leaser := range leasers { 230 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 231 } 232 233 // First time the leasers will return that they didn't have an open lease. 234 result, err := leaseMgr.UpdateOpenLeases(leaseDesc, leaseState) 235 require.NoError(t, err) 236 require.Equal(t, result, UpdateLeasesResult{LeasersNoOpenLease: 2}) 237 238 for _, leaser := range leasers { 239 err := leaseMgr.OpenLease(leaser, leaseDesc, leaseState) 240 require.NoError(t, err) 241 } 242 243 // Second time the leasers will return that they did have an open lease. 244 result, err = leaseMgr.UpdateOpenLeases(leaseDesc, leaseState) 245 require.NoError(t, err) 246 require.Equal(t, result, UpdateLeasesResult{LeasersUpdatedLease: 2}) 247 248 // Third time the first leaser will return an error. 249 result, err = leaseMgr.UpdateOpenLeases(leaseDesc, leaseState) 250 require.Error(t, err) 251 } 252 253 func TestUpdateOpenLeasesErrorIfNoVerifier(t *testing.T) { 254 ctrl := xtest.NewController(t) 255 defer ctrl.Finish() 256 257 var ( 258 leaseMgr = NewLeaseManager(nil) 259 leaseDesc = LeaseDescriptor{ 260 Namespace: ident.StringID("test-ns"), 261 Shard: 1, 262 BlockStart: xtime.Now().Truncate(2 * time.Hour), 263 } 264 leaseState = LeaseState{ 265 Volume: 1, 266 } 267 leasers = []*MockLeaser{NewMockLeaser(ctrl), NewMockLeaser(ctrl)} 268 ) 269 270 for _, leaser := range leasers { 271 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 272 } 273 274 // First time the leasers will return that they didn't have an open lease. 275 _, err := leaseMgr.UpdateOpenLeases(leaseDesc, leaseState) 276 require.Equal(t, errUpdateOpenLeasesVerifierNotSet, err) 277 } 278 279 // TestUpdateOpenLeasesDoesNotDeadlockIfLeasersCallsBack verifies that a deadlock does 280 // not occur if a Leaser calls OpenLease or OpenLatestLease while the LeaseManager is 281 // waiting for a call to UpdateOpenLease() to complete on the same leaser. 282 func TestUpdateOpenLeasesDoesNotDeadlockIfLeasersCallsBack(t *testing.T) { 283 ctrl := xtest.NewController(t) 284 defer ctrl.Finish() 285 286 var ( 287 leaser = NewMockLeaser(ctrl) 288 verifier = NewMockLeaseVerifier(ctrl) 289 leaseMgr = NewLeaseManager(verifier) 290 ) 291 verifier.EXPECT().VerifyLease(gomock.Any(), gomock.Any()).AnyTimes() 292 verifier.EXPECT().LatestState(gomock.Any()).AnyTimes() 293 leaser.EXPECT().UpdateOpenLease(gomock.Any(), gomock.Any()).Do(func(_ LeaseDescriptor, _ LeaseState) { 294 require.NoError(t, leaseMgr.OpenLease(leaser, LeaseDescriptor{}, LeaseState{})) 295 _, err := leaseMgr.OpenLatestLease(leaser, LeaseDescriptor{}) 296 require.NoError(t, err) 297 }) 298 299 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 300 _, err := leaseMgr.UpdateOpenLeases(LeaseDescriptor{}, LeaseState{}) 301 require.NoError(t, err) 302 } 303 304 // TestUpdateOpenLeasesConcurrentNotAllowed verifies that concurrent calls to UpdateOpenLeases() 305 // with the same descriptor are not allowed which ensures that leasers receive all 306 // updates and in the correct order. 307 func TestUpdateOpenLeasesConcurrentNotAllowed(t *testing.T) { 308 ctrl := xtest.NewController(t) 309 defer ctrl.Finish() 310 311 var ( 312 leaser = NewMockLeaser(ctrl) 313 verifier = NewMockLeaseVerifier(ctrl) 314 leaseMgr = NewLeaseManager(verifier) 315 wg sync.WaitGroup 316 317 descriptor LeaseDescriptor 318 ) 319 320 wg.Add(1) 321 leaser.EXPECT().UpdateOpenLease(descriptor, gomock.Any()).Do(func(_ LeaseDescriptor, _ LeaseState) { 322 go func() { 323 defer wg.Done() 324 _, err := leaseMgr.UpdateOpenLeases(descriptor, LeaseState{}) 325 require.Equal(t, errConcurrentUpdateOpenLeases, err) 326 }() 327 wg.Wait() 328 }) 329 330 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 331 _, err := leaseMgr.UpdateOpenLeases(descriptor, LeaseState{}) 332 require.NoError(t, err) 333 } 334 335 func TestUpdateOpenLeasesDifferentDescriptorsConcurrent(t *testing.T) { 336 ctrl := xtest.NewController(t) 337 defer ctrl.Finish() 338 339 var ( 340 leaser = NewMockLeaser(ctrl) 341 verifier = NewMockLeaseVerifier(ctrl) 342 leaseMgr = NewLeaseManager(verifier) 343 wg sync.WaitGroup 344 345 blockStart = xtime.Now().Truncate(time.Hour) 346 descriptor1 = LeaseDescriptor{Namespace: ident.StringID("ns"), BlockStart: blockStart, Shard: 1} 347 descriptor2 = LeaseDescriptor{Namespace: ident.StringID("ns"), BlockStart: blockStart, Shard: 2} 348 ) 349 350 wg.Add(1) 351 leaser.EXPECT().UpdateOpenLease(descriptor1, gomock.Any()).Do(func(descriptor LeaseDescriptor, _ LeaseState) { 352 go func() { 353 defer wg.Done() 354 _, err := leaseMgr.UpdateOpenLeases(descriptor2, LeaseState{}) 355 require.NoError(t, err) 356 }() 357 wg.Wait() 358 }) 359 leaser.EXPECT().UpdateOpenLease(descriptor2, gomock.Any()) 360 361 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 362 _, err := leaseMgr.UpdateOpenLeases(descriptor1, LeaseState{}) 363 require.NoError(t, err) 364 } 365 366 // TestUpdateOpenLeasesConcurrencyTest spins up a number of goroutines to call UpdateOpenLeases(), 367 // OpenLease(), and OpenLatestLease() concurrently and ensure there are no deadlocks. 368 func TestUpdateOpenLeasesConcurrencyTest(t *testing.T) { 369 ctrl := xtest.NewController(t) 370 defer ctrl.Finish() 371 372 var ( 373 leaser = NewMockLeaser(ctrl) 374 verifier = NewMockLeaseVerifier(ctrl) 375 leaseMgr = NewLeaseManager(verifier) 376 wg sync.WaitGroup 377 doneCh = make(chan struct{}, 1) 378 numWorkers = 1 379 ) 380 verifier.EXPECT().VerifyLease(gomock.Any(), gomock.Any()).AnyTimes() 381 verifier.EXPECT().LatestState(gomock.Any()).AnyTimes() 382 leaser.EXPECT().UpdateOpenLease(gomock.Any(), gomock.Any()).Do(func(_ LeaseDescriptor, _ LeaseState) { 383 // Call back into the LeaseManager from the Leaser on each call to UpdateOpenLease to ensure there 384 // are no deadlocks there. 385 require.NoError(t, leaseMgr.OpenLease(leaser, LeaseDescriptor{}, LeaseState{})) 386 _, err := leaseMgr.OpenLatestLease(leaser, LeaseDescriptor{}) 387 require.NoError(t, err) 388 }).AnyTimes() 389 require.NoError(t, leaseMgr.RegisterLeaser(leaser)) 390 391 // One goroutine calling UpdateOpenLeases in a loop. 392 wg.Add(1) 393 go func() { 394 for { 395 select { 396 case <-doneCh: 397 wg.Done() 398 return 399 default: 400 _, err := leaseMgr.UpdateOpenLeases(LeaseDescriptor{}, LeaseState{}) 401 if err != nil { 402 panic(err) 403 } 404 } 405 } 406 }() 407 408 // Several goroutines calling OpenLease and OpenLatestLease. 409 for i := 0; i < numWorkers; i++ { 410 wg.Add(2) 411 go func() { 412 for { 413 select { 414 case <-doneCh: 415 wg.Done() 416 return 417 default: 418 if err := leaseMgr.OpenLease(leaser, LeaseDescriptor{}, LeaseState{}); err != nil { 419 panic(err) 420 } 421 } 422 } 423 }() 424 425 go func() { 426 for { 427 select { 428 case <-doneCh: 429 wg.Done() 430 return 431 default: 432 if _, err := leaseMgr.OpenLatestLease(leaser, LeaseDescriptor{}); err != nil { 433 panic(err) 434 } 435 } 436 } 437 }() 438 } 439 440 time.Sleep(100 * time.Millisecond) 441 close(doneCh) 442 wg.Wait() 443 }