mirror of
https://github.com/Threnklyn/jira.git
synced 2026-06-06 04:58:30 +02:00
rewrite checkpoint
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
script: go test -v ./... -check.vv
|
||||
sudo: false
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2015, Tim Heckman
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of linode-netint nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# go-flock
|
||||
[](https://travis-ci.org/theckman/go-flock)
|
||||
[](https://godoc.org/github.com/theckman/go-flock)
|
||||
[](https://github.com/theckman/go-flock/blob/master/LICENSE)
|
||||
|
||||
`flock` implements a thread-safe sync.Locker interface for file locking. It also
|
||||
includes a non-blocking TryLock() function to allow locking without blocking execution.
|
||||
|
||||
## License
|
||||
`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details.
|
||||
|
||||
## Intsallation
|
||||
```
|
||||
go get -u github.com/theckman/go-flock
|
||||
```
|
||||
|
||||
## Usage
|
||||
```Go
|
||||
import "github.com/theckman/go-flock"
|
||||
|
||||
fileLock := flock.NewFlock("/var/lock/go-lock.lock")
|
||||
|
||||
locked, err := fileLock.TryLock()
|
||||
|
||||
if err != nil {
|
||||
// handle locking error
|
||||
}
|
||||
|
||||
if locked {
|
||||
// do work
|
||||
fileLock.Unlock()
|
||||
}
|
||||
```
|
||||
|
||||
For more detailed usage information take a look at the package API docs on
|
||||
[GoDoc](https://godoc.org/github.com/theckman/go-flock).
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package flock implements a thread-safe sync.Locker interface for file locking.
|
||||
// It also includes a non-blocking TryLock() function to allow locking
|
||||
// without blocking execution.
|
||||
//
|
||||
// Package flock is released under the BSD 3-Clause License. See the LICENSE file
|
||||
// for more details.
|
||||
package flock
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Flock is the struct type to handle file locking. All fields are unexported,
|
||||
// with access to some of the fields provided by getter methods (Path() and Locked()).
|
||||
type Flock struct {
|
||||
path string
|
||||
m sync.RWMutex
|
||||
fh *os.File
|
||||
l bool
|
||||
}
|
||||
|
||||
// NewFlock is a function to return a new instance of *Flock. The only parameter
|
||||
// it takes is the path to the desired lockfile.
|
||||
func NewFlock(path string) *Flock {
|
||||
return &Flock{path: path}
|
||||
}
|
||||
|
||||
// Path is a function to return the path as provided in NewFlock().
|
||||
func (f *Flock) Path() string {
|
||||
return f.path
|
||||
}
|
||||
|
||||
// Locked is a function to return the current lock state (locked: true, unlocked: false).
|
||||
func (f *Flock) Locked() bool {
|
||||
f.m.RLock()
|
||||
defer f.m.RUnlock()
|
||||
return f.l
|
||||
}
|
||||
|
||||
func (f *Flock) String() string {
|
||||
return f.path
|
||||
}
|
||||
|
||||
func (f *Flock) setFh() error {
|
||||
// open a new os.File instance
|
||||
// create it if it doesn't exist, truncate it if it does exist, open the file read-write
|
||||
fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.FileMode(0600))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the filehandle on the struct
|
||||
f.fh = fh
|
||||
return nil
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package flock_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/theckman/go-flock"
|
||||
)
|
||||
|
||||
func ExampleFlock_Locked() {
|
||||
f := flock.NewFlock("/tmp/go-lock.lock")
|
||||
f.TryLock() // unchecked errors here
|
||||
|
||||
fmt.Printf("locked: %v\n", f.Locked())
|
||||
|
||||
f.Unlock()
|
||||
|
||||
fmt.Printf("locked: %v\n", f.Locked())
|
||||
// Output: locked: true
|
||||
// locked: false
|
||||
}
|
||||
|
||||
func ExampleFlock_TryLock() {
|
||||
// should probably put these in /var/lock
|
||||
fileLock := flock.NewFlock("/tmp/go-lock.lock")
|
||||
|
||||
locked, err := fileLock.TryLock()
|
||||
|
||||
if err != nil {
|
||||
// handle locking error
|
||||
}
|
||||
|
||||
if locked {
|
||||
fmt.Printf("path: %s; locked: %v\n", fileLock.Path(), fileLock.Locked())
|
||||
|
||||
if err := fileLock.Unlock(); err != nil {
|
||||
// handle unlock error
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("path: %s; locked: %v\n", fileLock.Path(), fileLock.Locked())
|
||||
// Output: path: /tmp/go-lock.lock; locked: true
|
||||
// path: /tmp/go-lock.lock; locked: false
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package flock_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/theckman/go-flock"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type TestSuite struct {
|
||||
path string
|
||||
flock *flock.Flock
|
||||
}
|
||||
|
||||
var _ = Suite(&TestSuite{})
|
||||
|
||||
func Test(t *testing.T) { TestingT(t) }
|
||||
|
||||
func (t *TestSuite) SetUpTest(c *C) {
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "go-flock-")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(tmpFile, Not(IsNil))
|
||||
|
||||
t.path = tmpFile.Name()
|
||||
|
||||
defer os.Remove(t.path)
|
||||
tmpFile.Close()
|
||||
|
||||
t.flock = flock.NewFlock(t.path)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TearDownTest(c *C) {
|
||||
t.flock.Unlock()
|
||||
os.Remove(t.path)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestNewFlock(c *C) {
|
||||
var f *flock.Flock
|
||||
|
||||
f = flock.NewFlock(t.path)
|
||||
c.Assert(f, Not(IsNil))
|
||||
c.Check(f.Path(), Equals, t.path)
|
||||
c.Check(f.Locked(), Equals, false)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_Path(c *C) {
|
||||
var path string
|
||||
path = t.flock.Path()
|
||||
c.Check(path, Equals, t.path)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_Locked(c *C) {
|
||||
var locked bool
|
||||
locked = t.flock.Locked()
|
||||
c.Check(locked, Equals, false)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_String(c *C) {
|
||||
var str string
|
||||
str = t.flock.String()
|
||||
c.Assert(str, Equals, t.path)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_TryLock(c *C) {
|
||||
c.Assert(t.flock.Locked(), Equals, false)
|
||||
|
||||
var locked bool
|
||||
var err error
|
||||
|
||||
locked, err = t.flock.TryLock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(locked, Equals, true)
|
||||
c.Check(t.flock.Locked(), Equals, true)
|
||||
|
||||
locked, err = t.flock.TryLock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(locked, Equals, true)
|
||||
|
||||
// make sure we just return false with no error in cases
|
||||
// where we would have been blocked
|
||||
locked, err = flock.NewFlock(t.path).TryLock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(locked, Equals, false)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_Unlock(c *C) {
|
||||
var err error
|
||||
|
||||
err = t.flock.Unlock()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
// get a lock for us to unlock
|
||||
locked, err := t.flock.TryLock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(locked, Equals, true)
|
||||
c.Assert(t.flock.Locked(), Equals, true)
|
||||
|
||||
_, err = os.Stat(t.path)
|
||||
c.Assert(os.IsNotExist(err), Equals, false)
|
||||
|
||||
err = t.flock.Unlock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(t.flock.Locked(), Equals, false)
|
||||
}
|
||||
|
||||
func (t *TestSuite) TestFlock_Lock(c *C) {
|
||||
c.Assert(t.flock.Locked(), Equals, false)
|
||||
|
||||
var err error
|
||||
|
||||
err = t.flock.Lock()
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(t.flock.Locked(), Equals, true)
|
||||
|
||||
// test that the short-circuit works
|
||||
err = t.flock.Lock()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
//
|
||||
// Test that Lock() is a blocking call
|
||||
//
|
||||
ch := make(chan error, 2)
|
||||
gf := flock.NewFlock(t.path)
|
||||
defer gf.Unlock()
|
||||
|
||||
go func(ch chan<- error) {
|
||||
ch <- nil
|
||||
ch <- gf.Lock()
|
||||
close(ch)
|
||||
}(ch)
|
||||
|
||||
errCh, ok := <-ch
|
||||
c.Assert(ok, Equals, true)
|
||||
c.Assert(errCh, IsNil)
|
||||
|
||||
err = t.flock.Unlock()
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
errCh, ok = <-ch
|
||||
c.Assert(ok, Equals, true)
|
||||
c.Assert(errCh, IsNil)
|
||||
c.Check(t.flock.Locked(), Equals, false)
|
||||
c.Check(gf.Locked(), Equals, true)
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package flock
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Lock is a blocking call to try and take the file lock. It will wait until it
|
||||
// is able to obtain the exclusive file lock. It's recommended that TryLock() be
|
||||
// used over this function. This function may block the ability to query the
|
||||
// current Locked() status due to a RW-mutex lock.
|
||||
//
|
||||
// If we are already locked, this function short-circuits and returns immediately
|
||||
// assuming it can take the mutex lock.
|
||||
func (f *Flock) Lock() error {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
if f.l {
|
||||
return nil
|
||||
}
|
||||
|
||||
if f.fh == nil {
|
||||
if err := f.setFh(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.l = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
|
||||
// while it is running the Locked() function will be blocked.
|
||||
//
|
||||
// This function short-circuits if we are unlocked already. If not, it calls
|
||||
// syscall.LOCK_UN on the file and closes the file descriptor It does not remove
|
||||
// the file from disk. It's up to your application to do.
|
||||
func (f *Flock) Unlock() error {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
// if we aren't locked or if the lockfile instance is nil
|
||||
// just return a nil error because we are unlocked
|
||||
if !f.l || f.fh == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mark the file as unlocked
|
||||
if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.fh.Close()
|
||||
|
||||
f.l = false
|
||||
f.fh = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TryLock is the preferred function for taking a file lock. This function does
|
||||
// take a RW-mutex lock before it tries to lock the file, so there is the
|
||||
// possibility that this function may block for a short time if another goroutine
|
||||
// is trying to take any action.
|
||||
//
|
||||
// The actual file lock is non-blocking. If we are unable to get the exclusive
|
||||
// file lock, the function will return false instead of waiting for the lock.
|
||||
// If we get the lock, we also set the *Flock instance as being locked.
|
||||
func (f *Flock) TryLock() (bool, error) {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
if f.l {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if f.fh == nil {
|
||||
if err := f.setFh(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
|
||||
|
||||
switch err {
|
||||
case syscall.EWOULDBLOCK:
|
||||
return false, nil
|
||||
case nil:
|
||||
f.l = true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows
|
||||
|
||||
package flock
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32, _ = syscall.LoadLibrary("kernel32.dll")
|
||||
procLockFileEx, _ = syscall.GetProcAddress(kernel32, "LockFileEx")
|
||||
procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx")
|
||||
)
|
||||
|
||||
const (
|
||||
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
|
||||
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
|
||||
)
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (success bool, err error) {
|
||||
r1, _, e1 := syscall.Syscall6(
|
||||
uintptr(procLockFileEx),
|
||||
6,
|
||||
uintptr(handle),
|
||||
uintptr(flags),
|
||||
uintptr(reserved),
|
||||
uintptr(numberOfBytesToLockLow),
|
||||
uintptr(numberOfBytesToLockHigh),
|
||||
uintptr(unsafe.Pointer(offset)))
|
||||
|
||||
success = r1 == 1
|
||||
if !success {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (success bool, err error) {
|
||||
r1, _, e1 := syscall.Syscall6(
|
||||
uintptr(procUnlockFileEx),
|
||||
5,
|
||||
uintptr(handle),
|
||||
uintptr(reserved),
|
||||
uintptr(numberOfBytesToLockLow),
|
||||
uintptr(numberOfBytesToLockHigh),
|
||||
uintptr(unsafe.Pointer(offset)),
|
||||
0)
|
||||
|
||||
success = r1 == 1
|
||||
if !success {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
// Copyright 2015 Tim Heckman. All rights reserved.
|
||||
// Use of this source code is governed by the BSD 3-Clause
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package flock
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Lock is a blocking call to try and take the file lock. It will wait until it
|
||||
// is able to obtain the exclusive file lock. It's recommended that TryLock() be
|
||||
// used over this function. This function may block the ability to query the
|
||||
// current Locked() status due to a RW-mutex lock.
|
||||
//
|
||||
// If we are already locked, this function short-circuits and returns immediately
|
||||
// assuming it can take the mutex lock.
|
||||
func (f *Flock) Lock() error {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
if f.l {
|
||||
return nil
|
||||
}
|
||||
|
||||
if f.fh == nil {
|
||||
if err := f.setFh(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := lockFileEx(syscall.Handle(f.fh.Fd()), LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &syscall.Overlapped{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.l = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so
|
||||
// while it is running the Locked() function will be blocked.
|
||||
//
|
||||
// This function short-circuits if we are unlocked already. If not, it calls
|
||||
// syscall.LOCK_UN on the file and closes the file descriptor It does not remove
|
||||
// the file from disk. It's up to your application to do.
|
||||
func (f *Flock) Unlock() error {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
// if we aren't locked or if the lockfile instance is nil
|
||||
// just return a nil error because we are unlocked
|
||||
if !f.l || f.fh == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mark the file as unlocked
|
||||
if _, err := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.fh.Close()
|
||||
|
||||
f.l = false
|
||||
f.fh = nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TryLock is the preferred function for taking a file lock. This function does
|
||||
// take a RW-mutex lock before it tries to lock the file, so there is the
|
||||
// possibility that this function may block for a short time if another goroutine
|
||||
// is trying to take any action.
|
||||
//
|
||||
// The actual file lock is non-blocking. If we are unable to get the exclusive
|
||||
// file lock, the function will return false instead of waiting for the lock.
|
||||
// If we get the lock, we also set the *Flock instance as being locked.
|
||||
func (f *Flock) TryLock() (bool, error) {
|
||||
f.m.Lock()
|
||||
defer f.m.Unlock()
|
||||
|
||||
if f.l {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if f.fh == nil {
|
||||
if err := f.setFh(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err := lockFileEx(syscall.Handle(f.fh.Fd()), LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &syscall.Overlapped{})
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
f.l = true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
Reference in New Issue
Block a user