Index: go/src/infra/gae/libs/memlock/memlock.go |
diff --git a/go/src/infra/gae/libs/memlock/memlock.go b/go/src/infra/gae/libs/memlock/memlock.go |
index fee7dcd2374ddd9690f0325b29c06f8321001e77..c3004c625ecb10d80181e364f337e037842a5700 100644 |
--- a/go/src/infra/gae/libs/memlock/memlock.go |
+++ b/go/src/infra/gae/libs/memlock/memlock.go |
@@ -12,7 +12,6 @@ import ( |
"bytes" |
"errors" |
"golang.org/x/net/context" |
- "sync/atomic" |
"time" |
"infra/gae/libs/gae" |
@@ -58,7 +57,7 @@ var memcacheLockTime = 16 * time.Second |
// the same data must use the same key. clientID is the unique identifier for |
// this client (lock-holder). If it's empty then TryWithLock() will return |
// ErrEmptyClientID. |
dnj
2015/07/17 18:01:35
Document that the context that "f" is called with
iannucci
2015/07/17 18:08:25
I think you're misunderstanding how the cancelatio
dnj
2015/07/17 18:10:29
Ah bad comment on my part, I was mostly suggesting
|
-func TryWithLock(ctx context.Context, key, clientID string, f func(check func() bool) error) error { |
+func TryWithLock(ctx context.Context, key, clientID string, f func(context.Context) error) error { |
if len(clientID) == 0 { |
return ErrEmptyClientID |
} |
@@ -128,39 +127,36 @@ func TryWithLock(ctx context.Context, key, clientID string, f func(check func() |
} |
// At this point we nominally have the lock (at least for memcacheLockTime). |
- |
- stopChan := make(chan struct{}) |
- stoppedChan := make(chan struct{}) |
- held := uint32(1) |
- |
+ finished := make(chan struct{}) |
+ subCtx, cancelFunc := context.WithCancel(ctx) |
dnj
2015/07/17 18:01:35
Main concern using contexts here is that if the pa
iannucci
2015/07/17 18:08:25
Yes
|
defer func() { |
- close(stopChan) |
- <-stoppedChan // this blocks TryWithLock until the goroutine below quits. |
+ cancelFunc() |
+ <-finished |
}() |
// This goroutine checks to see if we still posess the lock, and refreshes it |
- // if we do. It will stop doing this when either stopChan is activated (e.g. |
- // the user's function returns) or we lose the lock (memcache flake, etc.). |
+ // if we do. |
go func() { |
- defer close(stoppedChan) |
+ defer func() { |
+ cancelFunc() |
+ close(finished) |
+ }() |
checkLoop: |
for { |
select { |
- case <-stopChan: |
+ case <-subCtx.Done(): |
break checkLoop |
case <-clock.Get(ctx).After(delay): |
} |
if !checkAnd(refresh) { |
- atomic.StoreUint32(&held, 0) |
log.Warningf("lost lock: %s", err) |
return |
} |
} |
checkAnd(release) |
- atomic.StoreUint32(&held, 0) |
}() |
- return f(func() bool { return atomic.LoadUint32(&held) == 1 }) |
+ return f(subCtx) |
} |