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