Chromium Code Reviews| 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) |
| } |