diff --git a/MANUAL.md b/MANUAL.md index 1080107f2..641c14aea 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -854,6 +854,12 @@ For example to limit bandwidth usage to 10 MBytes/s use `--bwlimit 10M` This only limits the bandwidth of the data transfer, it doesn't limit the bandwith of the directory listings etc. +For Linux/Unix operating systems: rclone will toggle the bandwidth limiter on +and off upon receipt of the SIGUSR2 signal. This feature allows the user to +remove the bandwidth limitations of a long running rclone transfer during +off-peak hours, and to restore it back to the value specified with --bwlimit +again when needed. + ### --checkers=N ### The number of checkers to run in parallel. Checkers do the equality diff --git a/fs/accounting.go b/fs/accounting.go index 3f1e9b296..37cb9f71e 100644 --- a/fs/accounting.go +++ b/fs/accounting.go @@ -17,8 +17,10 @@ import ( // Globals var ( - Stats = NewStats() - tokenBucket *tb.Bucket + Stats = NewStats() + tokenBucket *tb.Bucket + origTokenBucket = tokenBucket + prevTokenBucket = tokenBucket ) // Start the token bucket if necessary @@ -27,6 +29,12 @@ func startTokenBucket() { tokenBucket = tb.NewBucket(int64(bwLimit), 100*time.Millisecond) Log(nil, "Starting bandwidth limiter at %vBytes/s", &bwLimit) } + origTokenBucket = tokenBucket + prevTokenBucket = tokenBucket + + // Start the SIGUSR2 signal handler to toggle bandwidth. + // This function does nothing in windows systems. + startSignalHandler() } // stringSet holds a set of strings @@ -333,6 +341,16 @@ func (acc *Account) read(in io.Reader, p []byte) (n int, err error) { Stats.Bytes(int64(n)) + // Log bandwidth limiter status change. + if tokenBucket != prevTokenBucket { + s := "disabled" + if tokenBucket != nil { + s = "enabled" + } + Log(nil, "Bandwidth limit %s by user", s) + prevTokenBucket = tokenBucket + } + // Limit the transfer speed if required if tokenBucket != nil { tokenBucket.Wait(int64(n)) diff --git a/fs/accounting_unix.go b/fs/accounting_unix.go new file mode 100644 index 000000000..a14310505 --- /dev/null +++ b/fs/accounting_unix.go @@ -0,0 +1,35 @@ +// Accounting and limiting reader +// Unix specific functions. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package fs + +import ( + "os" + "os/signal" + "syscall" +) + +// startSignalHandler() sets a signal handler to catch SIGUSR2 and toggle throttling. +func startSignalHandler() { + // Don't do anything if no bandwidth limits requested. + if bwLimit <= 0 { + return + } + + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGUSR2) + + go func() { + // This runs forever, but blocks until the signal is received. + for { + <-signals + if tokenBucket == nil { + tokenBucket = origTokenBucket + } else { + tokenBucket = nil + } + } + }() +} diff --git a/fs/accounting_windows.go b/fs/accounting_windows.go new file mode 100644 index 000000000..3aa030901 --- /dev/null +++ b/fs/accounting_windows.go @@ -0,0 +1,10 @@ +// Accounting and limiting reader +// Windows specific functions. + +// +build windows + +package fs + +// startSignalHandler() is Unix specific and does nothing under windows +// platforms. +func startSignalHandler() {}