github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/core/upgradelock_internal_test.go (about)

     1  // Package core provides core metadata and in-cluster API
     2  /*
     3   * Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package core
     6  
     7  import (
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/NVIDIA/aistore/cmn/atomic"
    13  	"github.com/NVIDIA/aistore/cmn/cos"
    14  	"github.com/NVIDIA/aistore/tools/tassert"
    15  	"github.com/NVIDIA/aistore/tools/trand"
    16  )
    17  
    18  func TestUpgradeLock(t *testing.T) {
    19  	if testing.Short() {
    20  		t.Skipf("skipping %s in short mode", t.Name())
    21  	}
    22  	for _, test := range []string{"downgrade", "unlock"} {
    23  		t.Run(test, func(t *testing.T) {
    24  			const threadCnt = 10000
    25  			var (
    26  				n       = &nlc{}
    27  				wg      = &sync.WaitGroup{}
    28  				sema    = cos.NewDynSemaphore(threadCnt)
    29  				counter = atomic.NewInt32(0)
    30  				uname   = trand.String(10)
    31  			)
    32  			n.init()
    33  
    34  			// Additional stray reader which forces the other to block on `UpgradeLock`.
    35  			n.Lock(uname, false)
    36  
    37  			sema.Acquire(threadCnt)
    38  			wg.Add(threadCnt)
    39  			for range threadCnt {
    40  				go func() {
    41  					defer wg.Done()
    42  
    43  					n.Lock(uname, false)
    44  
    45  					sema.Acquire()
    46  					if finished := n.UpgradeLock(uname); finished {
    47  						tassert.Fatalf(t, counter.Load() > 0, "counter should be already updated")
    48  						n.Unlock(uname, false)
    49  						return
    50  					}
    51  
    52  					// Imitate doing job.
    53  					counter.Inc()
    54  					time.Sleep(time.Second)
    55  
    56  					switch test {
    57  					case "downgrade":
    58  						n.DowngradeLock(uname)
    59  						n.Unlock(uname, false)
    60  					case "unlock":
    61  						n.Unlock(uname, true)
    62  					default:
    63  						panic(test)
    64  					}
    65  				}()
    66  			}
    67  
    68  			// Make sure all other threads are past `n.Lock` and blocked on `sema.Acquire`.
    69  			time.Sleep(500 * time.Millisecond)
    70  
    71  			sema.Release(threadCnt)
    72  			// Wait a while to make sure that all goroutines started and blocked on `UpgradeLock`.
    73  			time.Sleep(500 * time.Millisecond)
    74  
    75  			// Should wake up one of the waiter which should start doing job.
    76  			n.Unlock(uname, false)
    77  
    78  			wg.Wait()
    79  			tassert.Fatalf(t, counter.Load() == 1, "counter should be equal to 1 (counter: %d)", counter.Load())
    80  		})
    81  	}
    82  }