github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/utils/filesys/lock.go (about) 1 // Copyright 2019 Dolthub, Inc. 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 filesys 16 17 import ( 18 "errors" 19 "sync/atomic" 20 21 "github.com/dolthub/fslock" 22 ) 23 24 const unlockedStateValue int32 = 0 25 const lockedStateValue int32 = 1 26 27 // errLockUnlock occurs if there is an error unlocking the lock 28 var errLockUnlock = errors.New("unable to unlock the lock") 29 30 // FilesysLock is an interface for locking and unlocking filesystems 31 type FilesysLock interface { 32 TryLock() (bool, error) 33 Unlock() error 34 } 35 36 // CreateFilesysLock creates a new FilesysLock 37 func CreateFilesysLock(fs Filesys, filename string) FilesysLock { 38 switch fs.(type) { 39 case *InMemFS: 40 return NewInMemFileLock(fs) 41 case *localFS: 42 return NewLocalFileLock(fs, filename) 43 default: 44 panic("Unsupported file system") 45 } 46 } 47 48 // InMemFileLock is a lock for the InMemFS 49 type InMemFileLock struct { 50 state int32 51 } 52 53 // NewInMemFileLock creates a new InMemFileLock 54 func NewInMemFileLock(fs Filesys) *InMemFileLock { 55 return &InMemFileLock{unlockedStateValue} 56 } 57 58 // TryLock attempts to lock the lock or fails if it is already locked 59 func (memLock *InMemFileLock) TryLock() (bool, error) { 60 if atomic.CompareAndSwapInt32(&memLock.state, unlockedStateValue, lockedStateValue) { 61 return true, nil 62 } 63 return false, nil 64 } 65 66 // Unlock unlocks the lock 67 func (memLock *InMemFileLock) Unlock() error { 68 if memLock.state == 0 { 69 return nil 70 } 71 72 new := atomic.AddInt32(&memLock.state, -lockedStateValue) 73 74 if new != 0 { 75 return errLockUnlock 76 } 77 78 return nil 79 } 80 81 // LocalFileLock is the lock for the localFS 82 type LocalFileLock struct { 83 lck *fslock.Lock 84 } 85 86 // NewLocalFileLock creates a new LocalFileLock 87 func NewLocalFileLock(fs Filesys, filename string) *LocalFileLock { 88 lck := fslock.New(filename) 89 90 return &LocalFileLock{lck: lck} 91 } 92 93 // TryLock attempts to lock the lock or fails if it is already locked 94 func (locLock *LocalFileLock) TryLock() (bool, error) { 95 err := locLock.lck.TryLock() 96 if err != nil { 97 return false, err 98 } 99 return true, nil 100 } 101 102 // Unlock unlocks the lock 103 func (locLock *LocalFileLock) Unlock() error { 104 err := locLock.lck.Unlock() 105 if err != nil { 106 return err 107 } 108 return nil 109 }