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 }