github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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  	"github.com/metacubex/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  }