swift backend: fix premature release of semaphore in Load() & document

concurrency issue in List().

refactor wrapReader from b2 -> semaphore so it can be used elsewhere.

As per discussion in PR #1399.
This commit is contained in:
George Armhold 2017-11-02 12:38:17 -04:00
parent 99ac0da4bc
commit 8515d093e0
3 changed files with 49 additions and 48 deletions

View file

@ -1,6 +1,10 @@
package backend
import "github.com/restic/restic/internal/errors"
import (
"context"
"github.com/restic/restic/internal/errors"
"io"
)
// Semaphore limits access to a restricted resource.
type Semaphore struct {
@ -26,3 +30,39 @@ func (s *Semaphore) GetToken() {
func (s *Semaphore) ReleaseToken() {
<-s.ch
}
// ReleaseTokenOnClose wraps an io.ReadCloser to return a token on Close. Before returning the token,
// cancel, if provided, will be run to free up context resources.
func (s *Semaphore) ReleaseTokenOnClose(rc io.ReadCloser, cancel context.CancelFunc) io.ReadCloser {
return &wrapReader{rc, false, func() {
if cancel != nil {
cancel()
}
s.ReleaseToken()
}}
}
// wrapReader wraps an io.ReadCloser to run an additional function on Close.
type wrapReader struct {
io.ReadCloser
eofSeen bool
f func()
}
func (wr *wrapReader) Read(p []byte) (int, error) {
if wr.eofSeen {
return 0, io.EOF
}
n, err := wr.ReadCloser.Read(p)
if err == io.EOF {
wr.eofSeen = true
}
return n, err
}
func (wr *wrapReader) Close() error {
err := wr.ReadCloser.Close()
wr.f()
return err
}