lib/backup/fslocal: add FS.MustStop() method for stopping bandwidth limiter

This commit is contained in:
Aliaksandr Valialkin 2020-10-09 15:11:28 +03:00
parent 272d6976b3
commit cf5f2874cd
4 changed files with 34 additions and 3 deletions

View file

@ -90,6 +90,7 @@ func main() {
if err := a.Run(); err != nil { if err := a.Run(); err != nil {
logger.Fatalf("cannot create backup: %s", err) logger.Fatalf("cannot create backup: %s", err)
} }
srcFS.MustStop()
} }
func usage() { func usage() {

View file

@ -52,6 +52,7 @@ func main() {
if err := a.Run(); err != nil { if err := a.Run(); err != nil {
logger.Fatalf("cannot restore from backup: %s", err) logger.Fatalf("cannot restore from backup: %s", err)
} }
dstFS.MustStop()
} }
func usage() { func usage() {

View file

@ -15,6 +15,9 @@ type bandwidthLimiter struct {
// quota for the current second // quota for the current second
quota int quota int
stopCh chan struct{}
wg sync.WaitGroup
} }
func newBandwidthLimiter(perSecondLimit int) *bandwidthLimiter { func newBandwidthLimiter(perSecondLimit int) *bandwidthLimiter {
@ -25,10 +28,20 @@ func newBandwidthLimiter(perSecondLimit int) *bandwidthLimiter {
bl.perSecondLimit = perSecondLimit bl.perSecondLimit = perSecondLimit
var mu sync.Mutex var mu sync.Mutex
bl.c = sync.NewCond(&mu) bl.c = sync.NewCond(&mu)
go bl.perSecondUpdater() bl.stopCh = make(chan struct{})
bl.wg.Add(1)
go func() {
defer bl.wg.Done()
bl.perSecondUpdater()
}()
return &bl return &bl
} }
func (bl *bandwidthLimiter) MustStop() {
close(bl.stopCh)
bl.wg.Wait()
}
func (bl *bandwidthLimiter) NewReadCloser(rc io.ReadCloser) *bandwidthLimitedReader { func (bl *bandwidthLimiter) NewReadCloser(rc io.ReadCloser) *bandwidthLimitedReader {
return &bandwidthLimitedReader{ return &bandwidthLimitedReader{
rc: rc, rc: rc,
@ -83,7 +96,12 @@ func (blw *bandwidthLimitedWriter) Close() error {
func (bl *bandwidthLimiter) perSecondUpdater() { func (bl *bandwidthLimiter) perSecondUpdater() {
tc := time.NewTicker(time.Second) tc := time.NewTicker(time.Second)
c := bl.c c := bl.c
for range tc.C { for {
select {
case <-tc.C:
case <-bl.stopCh:
return
}
c.L.Lock() c.L.Lock()
bl.quota = bl.perSecondLimit bl.quota = bl.perSecondLimit
c.Signal() c.Signal()

View file

@ -27,7 +27,9 @@ type FS struct {
bl *bandwidthLimiter bl *bandwidthLimiter
} }
// Init initializes fs // Init initializes fs.
//
// The returned fs must be stopped when no long needed with MustStop call.
func (fs *FS) Init() error { func (fs *FS) Init() error {
if fs.MaxBytesPerSecond > 0 { if fs.MaxBytesPerSecond > 0 {
fs.bl = newBandwidthLimiter(fs.MaxBytesPerSecond) fs.bl = newBandwidthLimiter(fs.MaxBytesPerSecond)
@ -35,6 +37,15 @@ func (fs *FS) Init() error {
return nil return nil
} }
// MustStop stops fs.
func (fs *FS) MustStop() {
if fs.bl == nil {
return
}
fs.bl.MustStop()
fs.bl = nil
}
// String returns user-readable representation for the fs. // String returns user-readable representation for the fs.
func (fs *FS) String() string { func (fs *FS) String() string {
return fmt.Sprintf("fslocal %q", fs.Dir) return fmt.Sprintf("fslocal %q", fs.Dir)