github.com/zhongdalu/gf@v1.0.0/g/os/gflock/gflock.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  
     7  // Package gflock implements a concurrent-safe sync.Locker interface for file locking.
     8  package gflock
     9  
    10  import (
    11  	"github.com/zhongdalu/gf/g/os/gfile"
    12  	"github.com/zhongdalu/gf/third/github.com/theckman/go-flock"
    13  )
    14  
    15  // File locker.
    16  type Locker struct {
    17  	flock *flock.Flock // Underlying file locker.
    18  }
    19  
    20  // New creates and returns a new file locker with given <file>.
    21  // The parameter <file> usually is a absolute file path.
    22  func New(file string) *Locker {
    23  	dir := gfile.TempDir() + gfile.Separator + "gflock"
    24  	if !gfile.Exists(dir) {
    25  		_ = gfile.Mkdir(dir)
    26  	}
    27  	path := dir + gfile.Separator + file
    28  	lock := flock.NewFlock(path)
    29  	return &Locker{
    30  		flock: lock,
    31  	}
    32  }
    33  
    34  // Path returns the file path of the locker.
    35  func (l *Locker) Path() string {
    36  	return l.flock.Path()
    37  }
    38  
    39  // IsLocked returns whether the locker is locked.
    40  func (l *Locker) IsLocked() bool {
    41  	return l.flock.Locked()
    42  }
    43  
    44  // IsRLocked returns whether the locker is rlocked.
    45  func (l *Locker) IsRLocked() bool {
    46  	return l.flock.RLocked()
    47  }
    48  
    49  // TryLock tries get the writing lock of the locker.
    50  // It returns true if success, or else returns false immediately.
    51  func (l *Locker) TryLock() bool {
    52  	ok, _ := l.flock.TryLock()
    53  	return ok
    54  }
    55  
    56  // TryRLock tries get the reading lock of the locker.
    57  // It returns true if success, or else returns false immediately.
    58  func (l *Locker) TryRLock() bool {
    59  	ok, _ := l.flock.TryRLock()
    60  	return ok
    61  }
    62  
    63  // Lock is a blocking call to try and take an exclusive file lock. It will wait
    64  // until it is able to obtain the exclusive file lock. It's recommended that
    65  // TryLock() be used over this function. This function may block the ability to
    66  // query the current Locked() or RLocked() status due to a RW-mutex lock.
    67  //
    68  // If we are already exclusive-locked, this function short-circuits and returns
    69  // immediately assuming it can take the mutex lock.
    70  //
    71  // If the *Flock has a shared lock (RLock), this may transparently replace the
    72  // shared lock with an exclusive lock on some UNIX-like operating systems. Be
    73  // careful when using exclusive locks in conjunction with shared locks
    74  // (RLock()), because calling Unlock() may accidentally release the exclusive
    75  // lock that was once a shared lock.
    76  func (l *Locker) Lock() (err error) {
    77  	return l.flock.Lock()
    78  }
    79  
    80  // Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
    81  // while it is running the Locked() and RLocked() functions will be blocked.
    82  //
    83  // This function short-circuits if we are unlocked already. If not, it calls
    84  // syscall.LOCK_UN on the file and closes the file descriptor. It does not
    85  // remove the file from disk. It's up to your application to do.
    86  //
    87  // Please note, if your shared lock became an exclusive lock this may
    88  // unintentionally drop the exclusive lock if called by the consumer that
    89  // believes they have a shared lock. Please see Lock() for more details.
    90  func (l *Locker) Unlock() (err error) {
    91  	return l.flock.Unlock()
    92  }
    93  
    94  // RLock is a blocking call to try and take a ahred file lock. It will wait
    95  // until it is able to obtain the shared file lock. It's recommended that
    96  // TryRLock() be used over this function. This function may block the ability to
    97  // query the current Locked() or RLocked() status due to a RW-mutex lock.
    98  //
    99  // If we are already shared-locked, this function short-circuits and returns
   100  // immediately assuming it can take the mutex lock.
   101  func (l *Locker) RLock() (err error) {
   102  	return l.flock.RLock()
   103  }
   104  
   105  // Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
   106  // while it is running the Locked() and RLocked() functions will be blocked.
   107  //
   108  // This function short-circuits if we are unlocked already. If not, it calls
   109  // syscall.LOCK_UN on the file and closes the file descriptor. It does not
   110  // remove the file from disk. It's up to your application to do.
   111  //
   112  // Please note, if your shared lock became an exclusive lock this may
   113  // unintentionally drop the exclusive lock if called by the consumer that
   114  // believes they have a shared lock. Please see Lock() for more details.
   115  func (l *Locker) RUnlock() (err error) {
   116  	return l.flock.Unlock()
   117  }