Skip to content

Commit 9dcb775

Browse files
committed
Add in support for a TryLock to attempt to get a lock within a timeout
1 parent 03869bc commit 9dcb775

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ var (
131131
ErrSessionMoved = errors.New("zk: session moved to another server, so operation is ignored")
132132
ErrReconfigDisabled = errors.New("attempts to perform a reconfiguration operation when reconfiguration feature is disabled")
133133
ErrBadArguments = errors.New("invalid arguments")
134+
ErrTimeout = errors.New("timeout exceeded")
134135
// ErrInvalidCallback = errors.New("zk: invalid callback specified")
135136

136137
errCodeToError = map[ErrCode]error{
@@ -151,6 +152,7 @@ var (
151152
errSessionMoved: ErrSessionMoved,
152153
errZReconfigDisabled: ErrReconfigDisabled,
153154
errBadArguments: ErrBadArguments,
155+
errTimeout: ErrTimeout,
154156
}
155157
)
156158

@@ -173,6 +175,7 @@ const (
173175
errOperationTimeout = -7
174176
errBadArguments = -8
175177
errInvalidState = -9
178+
errTimeout = -10
176179
// API errors
177180
errAPIError ErrCode = -100
178181
errNoNode ErrCode = -101 // *

lock.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strconv"
77
"strings"
8+
"time"
89
)
910

1011
var (
@@ -49,10 +50,24 @@ func (l *Lock) Lock() error {
4950
return l.LockWithData([]byte{})
5051
}
5152

53+
// TryLock attempts to acquire the lock before a timeout. It works like LockWithData, but it doesn't
54+
// write any data to the lock node.
55+
func (l *Lock) TryLock(timeout time.Duration) error {
56+
return l.TryLockWithData([]byte{}, timeout)
57+
}
58+
5259
// LockWithData attempts to acquire the lock, writing data into the lock node.
5360
// It will wait to return until the lock is acquired or an error occurs. If
5461
// this instance already has the lock then ErrDeadlock is returned.
5562
func (l *Lock) LockWithData(data []byte) error {
63+
return l.TryLockWithData(data, time.Duration(-1))
64+
}
65+
66+
// TryLockWithData attempts to acquire the lock, writing data into the lock node.
67+
// It will wait to return until the lock is acquired, an error occurs, or the timeout. If
68+
// this instance already has the lock then ErrDeadlock is returned. A negative
69+
// timeout is waiting forever
70+
func (l *Lock) TryLockWithData(data []byte, timeout time.Duration) error {
5671
if l.lockPath != "" {
5772
return ErrDeadlock
5873
}
@@ -97,6 +112,8 @@ func (l *Lock) LockWithData(data []byte) error {
97112
return err
98113
}
99114

115+
start := time.Now()
116+
100117
for {
101118
children, _, err := l.c.Children(l.path)
102119
if err != nil {
@@ -134,9 +151,25 @@ func (l *Lock) LockWithData(data []byte) error {
134151
continue
135152
}
136153

137-
ev := <-ch
138-
if ev.Err != nil {
139-
return ev.Err
154+
if timeout >= 0 {
155+
wait := start.Add(timeout).Sub(time.Now())
156+
if wait < 0 {
157+
wait = time.Duration(1)
158+
}
159+
delay := time.NewTimer(wait)
160+
select {
161+
case ev := <-ch:
162+
if ev.Err != nil {
163+
return ev.Err
164+
}
165+
case <-delay.C:
166+
return ErrTimeout
167+
}
168+
} else {
169+
ev := <-ch
170+
if ev.Err != nil {
171+
return ev.Err
172+
}
140173
}
141174
}
142175

0 commit comments

Comments
 (0)