gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/fsimpl/lock/lock_test.go (about) 1 // Copyright 2018 The gVisor Authors. 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lock 16 17 import ( 18 "reflect" 19 "testing" 20 21 "gvisor.dev/gvisor/pkg/errors/linuxerr" 22 ) 23 24 type entry struct { 25 Lock 26 LockRange 27 } 28 29 func equals(e0, e1 []entry) bool { 30 if len(e0) != len(e1) { 31 return false 32 } 33 for i := range e0 { 34 for k := range e0[i].Lock.Readers { 35 if _, ok := e1[i].Lock.Readers[k]; !ok { 36 return false 37 } 38 } 39 for k := range e1[i].Lock.Readers { 40 if _, ok := e0[i].Lock.Readers[k]; !ok { 41 return false 42 } 43 } 44 if !reflect.DeepEqual(e0[i].LockRange, e1[i].LockRange) { 45 return false 46 } 47 if e0[i].Lock.Writer != e1[i].Lock.Writer { 48 return false 49 } 50 } 51 return true 52 } 53 54 // fill a LockSet with consecutive region locks. Will panic if 55 // LockRanges are not consecutive. 56 func fill(entries []entry) LockSet { 57 l := LockSet{} 58 for _, e := range entries { 59 if e.Readers == nil { 60 e.Readers = make(map[UniqueID]OwnerInfo) 61 } 62 gap := l.FindGap(e.LockRange.Start) 63 if !gap.Ok() { 64 panic("cannot insert into existing segment") 65 } 66 l.Insert(gap, e.LockRange, e.Lock) 67 } 68 return l 69 } 70 71 func TestCanLockEmpty(t *testing.T) { 72 l := LockSet{} 73 74 // Expect to be able to take any locks given that the set is empty. 75 eof := l.FirstGap().End() 76 r := LockRange{0, eof} 77 if !l.canLock(1, ReadLock, r) { 78 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", ReadLock, r, 1) 79 } 80 if !l.canLock(2, ReadLock, r) { 81 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", ReadLock, r, 2) 82 } 83 if !l.canLock(1, WriteLock, r) { 84 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 1) 85 } 86 if !l.canLock(2, WriteLock, r) { 87 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 2) 88 } 89 } 90 91 func TestCanLock(t *testing.T) { 92 // + -------------- + ---------- + -------------- + --------- + 93 // | Readers 1 & 2 | Readers 1 | Readers 1 & 3 | Writer 1 | 94 // + ------------- + ---------- + -------------- + --------- + 95 // 0 1024 2048 3072 4096 96 l := fill([]entry{ 97 { 98 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 2: {}}}, 99 LockRange: LockRange{0, 1024}, 100 }, 101 { 102 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}}}, 103 LockRange: LockRange{1024, 2048}, 104 }, 105 { 106 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 3: {}}}, 107 LockRange: LockRange{2048, 3072}, 108 }, 109 { 110 Lock: Lock{Writer: 1}, 111 LockRange: LockRange{3072, 4096}, 112 }, 113 }) 114 115 // Now that we have a mildly interesting layout, try some checks on different 116 // ranges, uids, and lock types. 117 // 118 // Expect to be able to extend the read lock, despite the writer lock, because 119 // the writer has the same uid as the requested read lock. 120 r := LockRange{0, 8192} 121 if !l.canLock(1, ReadLock, r) { 122 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", ReadLock, r, 1) 123 } 124 // Expect to *not* be able to extend the read lock since there is an overlapping 125 // writer region locked by someone other than the uid. 126 if l.canLock(2, ReadLock, r) { 127 t.Fatalf("canLock type %d for range %v and uid %d got true, want false", ReadLock, r, 2) 128 } 129 // Expect to be able to extend the read lock if there are only other readers in 130 // the way. 131 r = LockRange{64, 3072} 132 if !l.canLock(2, ReadLock, r) { 133 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", ReadLock, r, 2) 134 } 135 // Expect to be able to set a read lock beyond the range of any existing locks. 136 r = LockRange{4096, 10240} 137 if !l.canLock(2, ReadLock, r) { 138 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", ReadLock, r, 2) 139 } 140 141 // Expect to not be able to take a write lock with other readers in the way. 142 r = LockRange{0, 8192} 143 if l.canLock(1, WriteLock, r) { 144 t.Fatalf("canLock type %d for range %v and uid %d got true, want false", WriteLock, r, 1) 145 } 146 // Expect to be able to extend the write lock for the same uid. 147 r = LockRange{3072, 8192} 148 if !l.canLock(1, WriteLock, r) { 149 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 1) 150 } 151 // Expect to not be able to overlap a write lock for two different uids. 152 if l.canLock(2, WriteLock, r) { 153 t.Fatalf("canLock type %d for range %v and uid %d got true, want false", WriteLock, r, 2) 154 } 155 // Expect to be able to set a write lock that is beyond the range of any 156 // existing locks. 157 r = LockRange{8192, 10240} 158 if !l.canLock(2, WriteLock, r) { 159 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 2) 160 } 161 // Expect to be able to upgrade a read lock (any portion of it). 162 r = LockRange{1024, 2048} 163 if !l.canLock(1, WriteLock, r) { 164 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 1) 165 } 166 r = LockRange{1080, 2000} 167 if !l.canLock(1, WriteLock, r) { 168 t.Fatalf("canLock type %d for range %v and uid %d got false, want true", WriteLock, r, 1) 169 } 170 } 171 172 func TestSetLock(t *testing.T) { 173 tests := []struct { 174 // description of test. 175 name string 176 177 // LockSet entries to pre-fill. 178 before []entry 179 180 // Description of region to lock: 181 // 182 // start is the file offset of the lock. 183 start uint64 184 // end is the end file offset of the lock. 185 end uint64 186 // uid of lock attempter. 187 uid UniqueID 188 // lock type requested. 189 lockType LockType 190 // err is the expected results. 191 err error 192 193 // Expected layout of the set after locking 194 // if err is nil. 195 after []entry 196 }{ 197 { 198 name: "set zero length ReadLock on empty set", 199 start: 0, 200 end: 0, 201 uid: 0, 202 lockType: ReadLock, 203 }, 204 { 205 name: "set zero length WriteLock on empty set", 206 start: 0, 207 end: 0, 208 uid: 0, 209 lockType: WriteLock, 210 }, 211 { 212 name: "set ReadLock on empty set", 213 start: 0, 214 end: LockEOF, 215 uid: 0, 216 lockType: ReadLock, 217 // + ----------------------------------------- + 218 // | Readers 0 | 219 // + ----------------------------------------- + 220 // 0 max uint64 221 after: []entry{ 222 { 223 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 224 LockRange: LockRange{0, LockEOF}, 225 }, 226 }, 227 }, 228 { 229 name: "set WriteLock on empty set", 230 start: 0, 231 end: LockEOF, 232 uid: 0, 233 lockType: WriteLock, 234 // + ----------------------------------------- + 235 // | Writer 0 | 236 // + ----------------------------------------- + 237 // 0 max uint64 238 after: []entry{ 239 { 240 Lock: Lock{Writer: 0}, 241 LockRange: LockRange{0, LockEOF}, 242 }, 243 }, 244 }, 245 { 246 name: "set ReadLock on WriteLock same uid", 247 // + ----------------------------------------- + 248 // | Writer 0 | 249 // + ----------------------------------------- + 250 // 0 max uint64 251 before: []entry{ 252 { 253 Lock: Lock{Writer: 0}, 254 LockRange: LockRange{0, LockEOF}, 255 }, 256 }, 257 start: 0, 258 end: 4096, 259 uid: 0, 260 lockType: ReadLock, 261 // + ----------- + --------------------------- + 262 // | Readers 0 | Writer 0 | 263 // + ----------- + --------------------------- + 264 // 0 4096 max uint64 265 after: []entry{ 266 { 267 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 268 LockRange: LockRange{0, 4096}, 269 }, 270 { 271 Lock: Lock{Writer: 0}, 272 LockRange: LockRange{4096, LockEOF}, 273 }, 274 }, 275 }, 276 { 277 name: "set WriteLock on ReadLock same uid", 278 // + ----------------------------------------- + 279 // | Readers 0 | 280 // + ----------------------------------------- + 281 // 0 max uint64 282 before: []entry{ 283 { 284 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 285 LockRange: LockRange{0, LockEOF}, 286 }, 287 }, 288 start: 0, 289 end: 4096, 290 uid: 0, 291 lockType: WriteLock, 292 // + ----------- + --------------------------- + 293 // | Writer 0 | Readers 0 | 294 // + ----------- + --------------------------- + 295 // 0 4096 max uint64 296 after: []entry{ 297 { 298 Lock: Lock{Writer: 0}, 299 LockRange: LockRange{0, 4096}, 300 }, 301 { 302 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 303 LockRange: LockRange{4096, LockEOF}, 304 }, 305 }, 306 }, 307 { 308 name: "set ReadLock on WriteLock different uid", 309 // + ----------------------------------------- + 310 // | Writer 0 | 311 // + ----------------------------------------- + 312 // 0 max uint64 313 before: []entry{ 314 { 315 Lock: Lock{Writer: 0}, 316 LockRange: LockRange{0, LockEOF}, 317 }, 318 }, 319 start: 0, 320 end: 4096, 321 uid: 1, 322 lockType: ReadLock, 323 err: linuxerr.ErrWouldBlock, 324 }, 325 { 326 name: "set WriteLock on ReadLock different uid", 327 // + ----------------------------------------- + 328 // | Readers 0 | 329 // + ----------------------------------------- + 330 // 0 max uint64 331 before: []entry{ 332 { 333 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 334 LockRange: LockRange{0, LockEOF}, 335 }, 336 }, 337 start: 0, 338 end: 4096, 339 uid: 1, 340 lockType: WriteLock, 341 err: linuxerr.ErrWouldBlock, 342 }, 343 { 344 name: "split ReadLock for overlapping lock at start 0", 345 // + ----------------------------------------- + 346 // | Readers 0 | 347 // + ----------------------------------------- + 348 // 0 max uint64 349 before: []entry{ 350 { 351 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 352 LockRange: LockRange{0, LockEOF}, 353 }, 354 }, 355 start: 0, 356 end: 4096, 357 uid: 1, 358 lockType: ReadLock, 359 // + -------------- + --------------------------- + 360 // | Readers 0 & 1 | Readers 0 | 361 // + -------------- + --------------------------- + 362 // 0 4096 max uint64 363 after: []entry{ 364 { 365 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 366 LockRange: LockRange{0, 4096}, 367 }, 368 { 369 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 370 LockRange: LockRange{4096, LockEOF}, 371 }, 372 }, 373 }, 374 { 375 name: "split ReadLock for overlapping lock at non-zero start", 376 // + ----------------------------------------- + 377 // | Readers 0 | 378 // + ----------------------------------------- + 379 // 0 max uint64 380 before: []entry{ 381 { 382 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 383 LockRange: LockRange{0, LockEOF}, 384 }, 385 }, 386 start: 4096, 387 end: 8192, 388 uid: 1, 389 lockType: ReadLock, 390 // + ---------- + -------------- + ----------- + 391 // | Readers 0 | Readers 0 & 1 | Readers 0 | 392 // + ---------- + -------------- + ----------- + 393 // 0 4096 8192 max uint64 394 after: []entry{ 395 { 396 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 397 LockRange: LockRange{0, 4096}, 398 }, 399 { 400 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 401 LockRange: LockRange{4096, 8192}, 402 }, 403 { 404 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 405 LockRange: LockRange{8192, LockEOF}, 406 }, 407 }, 408 }, 409 { 410 name: "fill front gap with ReadLock", 411 // + --------- + ---------------------------- + 412 // | gap | Readers 0 | 413 // + --------- + ---------------------------- + 414 // 0 1024 max uint64 415 before: []entry{ 416 { 417 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 418 LockRange: LockRange{1024, LockEOF}, 419 }, 420 }, 421 start: 0, 422 end: 8192, 423 uid: 0, 424 lockType: ReadLock, 425 // + ----------------------------------------- + 426 // | Readers 0 | 427 // + ----------------------------------------- + 428 // 0 max uint64 429 after: []entry{ 430 { 431 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 432 LockRange: LockRange{0, LockEOF}, 433 }, 434 }, 435 }, 436 { 437 name: "fill end gap with ReadLock", 438 // + ---------------------------- + 439 // | Readers 0 | 440 // + ---------------------------- + 441 // 0 4096 442 before: []entry{ 443 { 444 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 445 LockRange: LockRange{0, 4096}, 446 }, 447 }, 448 start: 1024, 449 end: LockEOF, 450 uid: 0, 451 lockType: ReadLock, 452 // Note that this is not merged after lock does a Split. This is 453 // fine because the two locks will still *behave* as one. In other 454 // words we can fragment any lock all we want and semantically it 455 // makes no difference. 456 // 457 // + ----------- + --------------------------- + 458 // | Readers 0 | Readers 0 | 459 // + ----------- + --------------------------- + 460 // 0 max uint64 461 after: []entry{ 462 { 463 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 464 LockRange: LockRange{0, 1024}, 465 }, 466 { 467 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 468 LockRange: LockRange{1024, LockEOF}, 469 }, 470 }, 471 }, 472 { 473 name: "fill gap with ReadLock and split", 474 // + --------- + ---------------------------- + 475 // | gap | Readers 0 | 476 // + --------- + ---------------------------- + 477 // 0 1024 max uint64 478 before: []entry{ 479 { 480 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 481 LockRange: LockRange{1024, LockEOF}, 482 }, 483 }, 484 start: 0, 485 end: 4096, 486 uid: 1, 487 lockType: ReadLock, 488 // + --------- + ------------- + ------------- + 489 // | Reader 1 | Readers 0 & 1 | Reader 0 | 490 // + ----------+ ------------- + ------------- + 491 // 0 1024 4096 max uint64 492 after: []entry{ 493 { 494 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}}}, 495 LockRange: LockRange{0, 1024}, 496 }, 497 { 498 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 499 LockRange: LockRange{1024, 4096}, 500 }, 501 { 502 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 503 LockRange: LockRange{4096, LockEOF}, 504 }, 505 }, 506 }, 507 { 508 name: "upgrade ReadLock to WriteLock for single uid fill gap", 509 // + ------------- + --------- + --- + ------------- + 510 // | Readers 0 & 1 | Readers 0 | gap | Readers 0 & 2 | 511 // + ------------- + --------- + --- + ------------- + 512 // 0 1024 2048 4096 max uint64 513 before: []entry{ 514 { 515 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 516 LockRange: LockRange{0, 1024}, 517 }, 518 { 519 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 520 LockRange: LockRange{1024, 2048}, 521 }, 522 { 523 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 2: {}}}, 524 LockRange: LockRange{4096, LockEOF}, 525 }, 526 }, 527 start: 1024, 528 end: 4096, 529 uid: 0, 530 lockType: WriteLock, 531 // + ------------- + -------- + ------------- + 532 // | Readers 0 & 1 | Writer 0 | Readers 0 & 2 | 533 // + ------------- + -------- + ------------- + 534 // 0 1024 4096 max uint64 535 after: []entry{ 536 { 537 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 538 LockRange: LockRange{0, 1024}, 539 }, 540 { 541 Lock: Lock{Writer: 0}, 542 LockRange: LockRange{1024, 4096}, 543 }, 544 { 545 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 2: {}}}, 546 LockRange: LockRange{4096, LockEOF}, 547 }, 548 }, 549 }, 550 { 551 name: "upgrade ReadLock to WriteLock for single uid keep gap", 552 // + ------------- + --------- + --- + ------------- + 553 // | Readers 0 & 1 | Readers 0 | gap | Readers 0 & 2 | 554 // + ------------- + --------- + --- + ------------- + 555 // 0 1024 2048 4096 max uint64 556 before: []entry{ 557 { 558 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 559 LockRange: LockRange{0, 1024}, 560 }, 561 { 562 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 563 LockRange: LockRange{1024, 2048}, 564 }, 565 { 566 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 2: {}}}, 567 LockRange: LockRange{4096, LockEOF}, 568 }, 569 }, 570 start: 1024, 571 end: 3072, 572 uid: 0, 573 lockType: WriteLock, 574 // + ------------- + -------- + --- + ------------- + 575 // | Readers 0 & 1 | Writer 0 | gap | Readers 0 & 2 | 576 // + ------------- + -------- + --- + ------------- + 577 // 0 1024 3072 4096 max uint64 578 after: []entry{ 579 { 580 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 581 LockRange: LockRange{0, 1024}, 582 }, 583 { 584 Lock: Lock{Writer: 0}, 585 LockRange: LockRange{1024, 3072}, 586 }, 587 { 588 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 2: {}}}, 589 LockRange: LockRange{4096, LockEOF}, 590 }, 591 }, 592 }, 593 { 594 name: "fail to upgrade ReadLock to WriteLock with conflicting Reader", 595 // + ------------- + --------- + 596 // | Readers 0 & 1 | Readers 0 | 597 // + ------------- + --------- + 598 // 0 1024 2048 599 before: []entry{ 600 { 601 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 602 LockRange: LockRange{0, 1024}, 603 }, 604 { 605 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 606 LockRange: LockRange{1024, 2048}, 607 }, 608 }, 609 start: 0, 610 end: 2048, 611 uid: 0, 612 lockType: WriteLock, 613 err: linuxerr.ErrWouldBlock, 614 }, 615 { 616 name: "take WriteLock on whole file if all uids are the same", 617 // + ------------- + --------- + --------- + ---------- + 618 // | Writer 0 | Readers 0 | Readers 0 | Readers 0 | 619 // + ------------- + --------- + --------- + ---------- + 620 // 0 1024 2048 4096 max uint64 621 before: []entry{ 622 { 623 Lock: Lock{Writer: 0}, 624 LockRange: LockRange{0, 1024}, 625 }, 626 { 627 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 628 LockRange: LockRange{1024, 2048}, 629 }, 630 { 631 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 632 LockRange: LockRange{2048, 4096}, 633 }, 634 { 635 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 636 LockRange: LockRange{4096, LockEOF}, 637 }, 638 }, 639 start: 0, 640 end: LockEOF, 641 uid: 0, 642 lockType: WriteLock, 643 // We do not manually merge locks. Semantically a fragmented lock 644 // held by the same uid will behave as one lock so it makes no difference. 645 // 646 // + ------------- + ---------------------------- + 647 // | Writer 0 | Writer 0 | 648 // + ------------- + ---------------------------- + 649 // 0 1024 max uint64 650 after: []entry{ 651 { 652 Lock: Lock{Writer: 0}, 653 LockRange: LockRange{0, 1024}, 654 }, 655 { 656 Lock: Lock{Writer: 0}, 657 LockRange: LockRange{1024, LockEOF}, 658 }, 659 }, 660 }, 661 } 662 663 for _, test := range tests { 664 t.Run(test.name, func(t *testing.T) { 665 l := fill(test.before) 666 667 r := LockRange{Start: test.start, End: test.end} 668 err := l.lock(test.uid, 0 /* ownerPID */, test.lockType, r, false) 669 var got []entry 670 for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 671 got = append(got, entry{ 672 Lock: seg.Value(), 673 LockRange: seg.Range(), 674 }) 675 } 676 677 if err != test.err { 678 t.Errorf("setlock(%v, %+v, %d, %d) got err %v, want %v", test.before, r, test.uid, test.lockType, err, test.err) 679 return 680 } 681 682 if err == nil { 683 if !equals(got, test.after) { 684 t.Errorf("got set %+v, want %+v", got, test.after) 685 } 686 } 687 }) 688 } 689 } 690 691 func TestUnlock(t *testing.T) { 692 tests := []struct { 693 // description of test. 694 name string 695 696 // LockSet entries to pre-fill. 697 before []entry 698 699 // Description of region to unlock: 700 // 701 // start is the file start of the lock. 702 start uint64 703 // end is the end file start of the lock. 704 end uint64 705 // uid of lock holder. 706 uid UniqueID 707 708 // Expected layout of the set after unlocking. 709 after []entry 710 }{ 711 { 712 name: "unlock zero length on empty set", 713 start: 0, 714 end: 0, 715 uid: 0, 716 }, 717 { 718 name: "unlock on empty set (no-op)", 719 start: 0, 720 end: LockEOF, 721 uid: 0, 722 }, 723 { 724 name: "unlock uid not locked (no-op)", 725 // + --------------------------- + 726 // | Readers 1 & 2 | 727 // + --------------------------- + 728 // 0 max uint64 729 before: []entry{ 730 { 731 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 2: {}}}, 732 LockRange: LockRange{0, LockEOF}, 733 }, 734 }, 735 start: 1024, 736 end: 4096, 737 uid: 0, 738 // + --------------------------- + 739 // | Readers 1 & 2 | 740 // + --------------------------- + 741 // 0 max uint64 742 after: []entry{ 743 { 744 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 2: {}}}, 745 LockRange: LockRange{0, LockEOF}, 746 }, 747 }, 748 }, 749 { 750 name: "unlock ReadLock over entire file", 751 // + ----------------------------------------- + 752 // | Readers 0 | 753 // + ----------------------------------------- + 754 // 0 max uint64 755 before: []entry{ 756 { 757 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 758 LockRange: LockRange{0, LockEOF}, 759 }, 760 }, 761 start: 0, 762 end: LockEOF, 763 uid: 0, 764 }, 765 { 766 name: "unlock WriteLock over entire file", 767 // + ----------------------------------------- + 768 // | Writer 0 | 769 // + ----------------------------------------- + 770 // 0 max uint64 771 before: []entry{ 772 { 773 Lock: Lock{Writer: 0}, 774 LockRange: LockRange{0, LockEOF}, 775 }, 776 }, 777 start: 0, 778 end: LockEOF, 779 uid: 0, 780 }, 781 { 782 name: "unlock partial ReadLock (start)", 783 // + ----------------------------------------- + 784 // | Readers 0 | 785 // + ----------------------------------------- + 786 // 0 max uint64 787 before: []entry{ 788 { 789 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 790 LockRange: LockRange{0, LockEOF}, 791 }, 792 }, 793 start: 0, 794 end: 4096, 795 uid: 0, 796 // + ------ + --------------------------- + 797 // | gap | Readers 0 | 798 // +------- + --------------------------- + 799 // 0 4096 max uint64 800 after: []entry{ 801 { 802 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 803 LockRange: LockRange{4096, LockEOF}, 804 }, 805 }, 806 }, 807 { 808 name: "unlock partial WriteLock (start)", 809 // + ----------------------------------------- + 810 // | Writer 0 | 811 // + ----------------------------------------- + 812 // 0 max uint64 813 before: []entry{ 814 { 815 Lock: Lock{Writer: 0}, 816 LockRange: LockRange{0, LockEOF}, 817 }, 818 }, 819 start: 0, 820 end: 4096, 821 uid: 0, 822 // + ------ + --------------------------- + 823 // | gap | Writer 0 | 824 // +------- + --------------------------- + 825 // 0 4096 max uint64 826 after: []entry{ 827 { 828 Lock: Lock{Writer: 0}, 829 LockRange: LockRange{4096, LockEOF}, 830 }, 831 }, 832 }, 833 { 834 name: "unlock partial ReadLock (end)", 835 // + ----------------------------------------- + 836 // | Readers 0 | 837 // + ----------------------------------------- + 838 // 0 max uint64 839 before: []entry{ 840 { 841 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 842 LockRange: LockRange{0, LockEOF}, 843 }, 844 }, 845 start: 4096, 846 end: LockEOF, 847 uid: 0, 848 // + --------------------------- + 849 // | Readers 0 | 850 // +---------------------------- + 851 // 0 4096 852 after: []entry{ 853 { 854 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}}}, 855 LockRange: LockRange{0, 4096}, 856 }, 857 }, 858 }, 859 { 860 name: "unlock partial WriteLock (end)", 861 // + ----------------------------------------- + 862 // | Writer 0 | 863 // + ----------------------------------------- + 864 // 0 max uint64 865 before: []entry{ 866 { 867 Lock: Lock{Writer: 0}, 868 LockRange: LockRange{0, LockEOF}, 869 }, 870 }, 871 start: 4096, 872 end: LockEOF, 873 uid: 0, 874 // + --------------------------- + 875 // | Writer 0 | 876 // +---------------------------- + 877 // 0 4096 878 after: []entry{ 879 { 880 Lock: Lock{Writer: 0}, 881 LockRange: LockRange{0, 4096}, 882 }, 883 }, 884 }, 885 { 886 name: "unlock for single uid", 887 // + ------------- + --------- + ------------------- + 888 // | Readers 0 & 1 | Writer 0 | Readers 0 & 1 & 2 | 889 // + ------------- + --------- + ------------------- + 890 // 0 1024 4096 max uint64 891 before: []entry{ 892 { 893 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 894 LockRange: LockRange{0, 1024}, 895 }, 896 { 897 Lock: Lock{Writer: 0}, 898 LockRange: LockRange{1024, 4096}, 899 }, 900 { 901 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}, 2: {}}}, 902 LockRange: LockRange{4096, LockEOF}, 903 }, 904 }, 905 start: 0, 906 end: LockEOF, 907 uid: 0, 908 // + --------- + --- + --------------- + 909 // | Readers 1 | gap | Readers 1 & 2 | 910 // + --------- + --- + --------------- + 911 // 0 1024 4096 max uint64 912 after: []entry{ 913 { 914 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}}}, 915 LockRange: LockRange{0, 1024}, 916 }, 917 { 918 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 2: {}}}, 919 LockRange: LockRange{4096, LockEOF}, 920 }, 921 }, 922 }, 923 { 924 name: "unlock subsection locked", 925 // + ------------------------------- + 926 // | Readers 0 & 1 & 2 | 927 // + ------------------------------- + 928 // 0 max uint64 929 before: []entry{ 930 { 931 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}, 2: {}}}, 932 LockRange: LockRange{0, LockEOF}, 933 }, 934 }, 935 start: 1024, 936 end: 4096, 937 uid: 0, 938 // + ----------------- + ------------- + ----------------- + 939 // | Readers 0 & 1 & 2 | Readers 1 & 2 | Readers 0 & 1 & 2 | 940 // + ----------------- + ------------- + ----------------- + 941 // 0 1024 4096 max uint64 942 after: []entry{ 943 { 944 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}, 2: {}}}, 945 LockRange: LockRange{0, 1024}, 946 }, 947 { 948 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}, 2: {}}}, 949 LockRange: LockRange{1024, 4096}, 950 }, 951 { 952 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}, 2: {}}}, 953 LockRange: LockRange{4096, LockEOF}, 954 }, 955 }, 956 }, 957 { 958 name: "unlock mid-gap to increase gap", 959 // + --------- + ----- + ------------------- + 960 // | Writer 0 | gap | Readers 0 & 1 | 961 // + --------- + ----- + ------------------- + 962 // 0 1024 4096 max uint64 963 before: []entry{ 964 { 965 Lock: Lock{Writer: 0}, 966 LockRange: LockRange{0, 1024}, 967 }, 968 { 969 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 970 LockRange: LockRange{4096, LockEOF}, 971 }, 972 }, 973 start: 8, 974 end: 2048, 975 uid: 0, 976 // + --------- + ----- + ------------------- + 977 // | Writer 0 | gap | Readers 0 & 1 | 978 // + --------- + ----- + ------------------- + 979 // 0 8 4096 max uint64 980 after: []entry{ 981 { 982 Lock: Lock{Writer: 0}, 983 LockRange: LockRange{0, 8}, 984 }, 985 { 986 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 987 LockRange: LockRange{4096, LockEOF}, 988 }, 989 }, 990 }, 991 { 992 name: "unlock split region on uid mid-gap", 993 // + --------- + ----- + ------------------- + 994 // | Writer 0 | gap | Readers 0 & 1 | 995 // + --------- + ----- + ------------------- + 996 // 0 1024 4096 max uint64 997 before: []entry{ 998 { 999 Lock: Lock{Writer: 0}, 1000 LockRange: LockRange{0, 1024}, 1001 }, 1002 { 1003 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 1004 LockRange: LockRange{4096, LockEOF}, 1005 }, 1006 }, 1007 start: 2048, 1008 end: 8192, 1009 uid: 0, 1010 // + --------- + ----- + --------- + ------------- + 1011 // | Writer 0 | gap | Readers 1 | Readers 0 & 1 | 1012 // + --------- + ----- + --------- + ------------- + 1013 // 0 1024 4096 8192 max uint64 1014 after: []entry{ 1015 { 1016 Lock: Lock{Writer: 0}, 1017 LockRange: LockRange{0, 1024}, 1018 }, 1019 { 1020 Lock: Lock{Readers: map[UniqueID]OwnerInfo{1: {}}}, 1021 LockRange: LockRange{4096, 8192}, 1022 }, 1023 { 1024 Lock: Lock{Readers: map[UniqueID]OwnerInfo{0: {}, 1: {}}}, 1025 LockRange: LockRange{8192, LockEOF}, 1026 }, 1027 }, 1028 }, 1029 } 1030 1031 for _, test := range tests { 1032 t.Run(test.name, func(t *testing.T) { 1033 l := fill(test.before) 1034 1035 r := LockRange{Start: test.start, End: test.end} 1036 l.unlock(test.uid, r) 1037 var got []entry 1038 for seg := l.FirstSegment(); seg.Ok(); seg = seg.NextSegment() { 1039 got = append(got, entry{ 1040 Lock: seg.Value(), 1041 LockRange: seg.Range(), 1042 }) 1043 } 1044 if !equals(got, test.after) { 1045 t.Errorf("got set %+v, want %+v", got, test.after) 1046 } 1047 }) 1048 } 1049 }