github.com/swiftstack/proxyfs@v0.0.0-20201223034610-5434d919416e/fs/utils.go (about) 1 package fs 2 3 import ( 4 "container/list" 5 "crypto/rand" 6 "fmt" 7 "math/big" 8 "time" 9 10 "github.com/swiftstack/ProxyFS/stats" 11 ) 12 13 func (tryLockBackoffContext *tryLockBackoffContextStruct) backoff() { 14 var ( 15 serializedBackoffListElement *list.Element 16 ) 17 18 stats.IncrementOperations(&stats.InodeTryLockBackoffOps) 19 20 if 0 < tryLockBackoffContext.backoffsCompleted { 21 if tryLockBackoffContext.backoffsCompleted < globals.tryLockSerializationThreshhold { 22 // Just do normal delay backoff 23 24 stats.IncrementOperations(&stats.InodeTryLockDelayedBackoffOps) 25 26 backoffSleep() 27 } else { 28 stats.IncrementOperations(&stats.InodeTryLockSerializedBackoffOps) 29 30 // Push us onto the serializedBackoffList 31 32 globals.Lock() 33 34 serializedBackoffListElement = globals.serializedBackoffList.PushBack(tryLockBackoffContext) 35 36 if 1 == globals.serializedBackoffList.Len() { 37 // Nobody else is currently serialized... so just delay 38 39 globals.Unlock() 40 41 backoffSleep() 42 } else { 43 // We are not the only one on serializedBackoffList... so we must wait 44 45 tryLockBackoffContext.Add(1) 46 47 globals.Unlock() 48 49 tryLockBackoffContext.Wait() 50 51 // Now delay to get prior tryLockBackoffContext a chance to complete 52 53 backoffSleep() 54 } 55 56 // Now remove us from the front of serializedBackoffList 57 58 globals.Lock() 59 60 _ = globals.serializedBackoffList.Remove(serializedBackoffListElement) 61 62 // Now check if there is a tryLockBackoffContext "behind" us 63 64 serializedBackoffListElement = globals.serializedBackoffList.Front() 65 66 globals.Unlock() 67 68 if nil != serializedBackoffListElement { 69 // Awake the tryLockBackoffContext "behind" us 70 71 serializedBackoffListElement.Value.(*tryLockBackoffContextStruct).Done() 72 } 73 } 74 } 75 76 tryLockBackoffContext.backoffsCompleted++ 77 } 78 79 func backoffSleep() { 80 var ( 81 err error 82 randomBigInt *big.Int 83 thisDelay time.Duration 84 ) 85 86 randomBigInt, err = rand.Int(rand.Reader, big.NewInt(int64(globals.tryLockBackoffMax)-int64(globals.tryLockBackoffMin))) 87 if nil != err { 88 err = fmt.Errorf("fs.backoffSleep() failed in call to rand.Int(): %v", err) 89 panic(err) 90 } 91 92 thisDelay = time.Duration(int64(globals.tryLockBackoffMin) + randomBigInt.Int64()) 93 94 time.Sleep(thisDelay) 95 }