github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/locker.go (about)

     1  package inode
     2  
     3  // Lock-related wrappers for inodes
     4  //
     5  // These APIs wrap calls to package DLM, which is a generic locking package.
     6  //
     7  // These wrappers enforce a naming convention for lock IDs.
     8  //
     9  
    10  import (
    11  	"fmt"
    12  
    13  	"github.com/swiftstack/ProxyFS/dlm"
    14  )
    15  
    16  // MakeLockID creates the ID of an inode used in volume
    17  func (vS *volumeStruct) MakeLockID(inodeNumber InodeNumber) (lockID string, err error) {
    18  	myLockID := fmt.Sprintf("vol.%s:ino.%d", vS.volumeName, inodeNumber)
    19  
    20  	return myLockID, nil
    21  }
    22  
    23  // InitInodeLock creates an inode lock. If callerID is non-nil, it is used.
    24  // Otherwise a new callerID is allocated.
    25  func (vS *volumeStruct) InitInodeLock(inodeNumber InodeNumber, callerID dlm.CallerID) (lock *dlm.RWLockStruct, err error) {
    26  	lockID, err := vS.MakeLockID(inodeNumber)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	if callerID == nil {
    32  		callerID = dlm.GenerateCallerID()
    33  	}
    34  
    35  	return &dlm.RWLockStruct{LockID: lockID,
    36  		Notify:       nil,
    37  		LockCallerID: callerID,
    38  	}, nil
    39  }
    40  
    41  // GetReadLock is a convenience function to create and acquire an inode lock
    42  func (vS *volumeStruct) GetReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
    43  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	err = lock.ReadLock()
    49  	return lock, err
    50  }
    51  
    52  // GetWriteLock is a convenience function to create and acquire an inode lock
    53  func (vS *volumeStruct) GetWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
    54  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	err = lock.WriteLock()
    60  	return lock, err
    61  }
    62  
    63  // AttemptReadLock is a convenience function to create and try to acquire an inode lock
    64  func (vS *volumeStruct) AttemptReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
    65  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	err = lock.TryReadLock()
    71  	return lock, err
    72  }
    73  
    74  // AttemptWriteLock is a convenience function to create and try to acquire an inode lock
    75  func (vS *volumeStruct) AttemptWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
    76  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	err = lock.TryWriteLock()
    82  	return lock, err
    83  }
    84  
    85  // EnsureReadLock ensures that a lock of the right type is held by the given callerID. If the lock is not held, it
    86  // acquires it. If the lock is held, it returns nil (so you don't unlock twice; even if that's not crashworthy, you'd
    87  // still release a lock that other code thinks it still holds).
    88  func (vS *volumeStruct) EnsureReadLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
    89  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	if lock.IsReadHeld() {
    95  		return nil, nil
    96  	}
    97  
    98  	err = lock.ReadLock()
    99  	return lock, err
   100  }
   101  
   102  // EnsureWriteLock ensures that a lock of the right type is held by the given callerID. If the lock is not held, it
   103  // acquires it. If the lock is held, it returns nil (so you don't unlock twice; even if that's not crashworthy, you'd
   104  // still release a lock that other code thinks it still holds).
   105  func (vS *volumeStruct) EnsureWriteLock(inodeNumber InodeNumber, callerID dlm.CallerID) (*dlm.RWLockStruct, error) {
   106  	lock, err := vS.InitInodeLock(inodeNumber, callerID)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	if lock.IsWriteHeld() {
   112  		return nil, nil
   113  	}
   114  
   115  	err = lock.WriteLock()
   116  	return lock, err
   117  }