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  }