mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
accounting: add context to Account and propagate changes #3257
This is preparation for getting the Accounting to check the context, buf first we need to get it in place. Since this is one of those changes that makes lots of noise, this is in a seperate commit.
This commit is contained in:
parent
0bab9903ee
commit
421585dd72
@ -79,7 +79,7 @@ func Object(w http.ResponseWriter, r *http.Request, o fs.Object) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
tr.Done(err)
|
tr.Done(err)
|
||||||
}()
|
}()
|
||||||
in := tr.Account(file) // account the transfer (no buffering)
|
in := tr.Account(r.Context(), file) // account the transfer (no buffering)
|
||||||
|
|
||||||
w.WriteHeader(code)
|
w.WriteHeader(code)
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ type Account struct {
|
|||||||
// shouldn't.
|
// shouldn't.
|
||||||
mu sync.Mutex // mutex protects these values
|
mu sync.Mutex // mutex protects these values
|
||||||
in io.Reader
|
in io.Reader
|
||||||
|
ctx context.Context // current context for transfer - may change
|
||||||
origIn io.ReadCloser
|
origIn io.ReadCloser
|
||||||
close io.Closer
|
close io.Closer
|
||||||
size int64
|
size int64
|
||||||
@ -64,10 +65,11 @@ const averagePeriod = 16 // period to do exponentially weighted averages over
|
|||||||
|
|
||||||
// newAccountSizeName makes an Account reader for an io.ReadCloser of
|
// newAccountSizeName makes an Account reader for an io.ReadCloser of
|
||||||
// the given size and name
|
// the given size and name
|
||||||
func newAccountSizeName(stats *StatsInfo, in io.ReadCloser, size int64, name string) *Account {
|
func newAccountSizeName(ctx context.Context, stats *StatsInfo, in io.ReadCloser, size int64, name string) *Account {
|
||||||
acc := &Account{
|
acc := &Account{
|
||||||
stats: stats,
|
stats: stats,
|
||||||
in: in,
|
in: in,
|
||||||
|
ctx: ctx,
|
||||||
close: in,
|
close: in,
|
||||||
origIn: in,
|
origIn: in,
|
||||||
size: size,
|
size: size,
|
||||||
@ -160,7 +162,7 @@ func (acc *Account) Abandon() {
|
|||||||
|
|
||||||
// UpdateReader updates the underlying io.ReadCloser stopping the
|
// UpdateReader updates the underlying io.ReadCloser stopping the
|
||||||
// async buffer (if any) and re-adding it
|
// async buffer (if any) and re-adding it
|
||||||
func (acc *Account) UpdateReader(in io.ReadCloser) {
|
func (acc *Account) UpdateReader(ctx context.Context, in io.ReadCloser) {
|
||||||
acc.mu.Lock()
|
acc.mu.Lock()
|
||||||
withBuf := acc.withBuf
|
withBuf := acc.withBuf
|
||||||
if withBuf {
|
if withBuf {
|
||||||
@ -168,6 +170,7 @@ func (acc *Account) UpdateReader(in io.ReadCloser) {
|
|||||||
acc.withBuf = false
|
acc.withBuf = false
|
||||||
}
|
}
|
||||||
acc.in = in
|
acc.in = in
|
||||||
|
acc.ctx = ctx
|
||||||
acc.close = in
|
acc.close = in
|
||||||
acc.origIn = in
|
acc.origIn = in
|
||||||
acc.closed = false
|
acc.closed = false
|
||||||
|
@ -2,6 +2,7 @@ package accounting
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -29,7 +30,7 @@ var (
|
|||||||
func TestNewAccountSizeName(t *testing.T) {
|
func TestNewAccountSizeName(t *testing.T) {
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
assert.Equal(t, in, acc.in)
|
assert.Equal(t, in, acc.in)
|
||||||
assert.Equal(t, acc, stats.inProgress.get("test"))
|
assert.Equal(t, acc, stats.inProgress.get("test"))
|
||||||
err := acc.Close()
|
err := acc.Close()
|
||||||
@ -44,7 +45,7 @@ func TestAccountWithBuffer(t *testing.T) {
|
|||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
||||||
|
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, -1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, -1, "test")
|
||||||
assert.False(t, acc.HasBuffer())
|
assert.False(t, acc.HasBuffer())
|
||||||
acc.WithBuffer()
|
acc.WithBuffer()
|
||||||
assert.True(t, acc.HasBuffer())
|
assert.True(t, acc.HasBuffer())
|
||||||
@ -53,7 +54,7 @@ func TestAccountWithBuffer(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.NoError(t, acc.Close())
|
assert.NoError(t, acc.Close())
|
||||||
|
|
||||||
acc = newAccountSizeName(stats, in, 1, "test")
|
acc = newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
acc.WithBuffer()
|
acc.WithBuffer()
|
||||||
// should not have a buffer for a small size
|
// should not have a buffer for a small size
|
||||||
_, ok = acc.in.(*asyncreader.AsyncReader)
|
_, ok = acc.in.(*asyncreader.AsyncReader)
|
||||||
@ -66,7 +67,7 @@ func TestAccountGetUpdateReader(t *testing.T) {
|
|||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
|
|
||||||
assert.Equal(t, in, acc.GetReader())
|
assert.Equal(t, in, acc.GetReader())
|
||||||
assert.Equal(t, acc, stats.inProgress.get("test"))
|
assert.Equal(t, acc, stats.inProgress.get("test"))
|
||||||
@ -77,7 +78,7 @@ func TestAccountGetUpdateReader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
in2 := ioutil.NopCloser(bytes.NewBuffer([]byte{1}))
|
||||||
acc.UpdateReader(in2)
|
acc.UpdateReader(context.Background(), in2)
|
||||||
|
|
||||||
assert.Equal(t, in2, acc.GetReader())
|
assert.Equal(t, in2, acc.GetReader())
|
||||||
assert.Equal(t, acc, stats.inProgress.get("test"))
|
assert.Equal(t, acc, stats.inProgress.get("test"))
|
||||||
@ -92,7 +93,7 @@ func TestAccountGetUpdateReader(t *testing.T) {
|
|||||||
func TestAccountRead(t *testing.T) {
|
func TestAccountRead(t *testing.T) {
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
|
|
||||||
assert.True(t, acc.values.start.IsZero())
|
assert.True(t, acc.values.start.IsZero())
|
||||||
acc.values.mu.Lock()
|
acc.values.mu.Lock()
|
||||||
@ -133,7 +134,7 @@ func testAccountWriteTo(t *testing.T, withBuffer bool) {
|
|||||||
}
|
}
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer(buf))
|
in := ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, int64(len(buf)), "test")
|
acc := newAccountSizeName(context.Background(), stats, in, int64(len(buf)), "test")
|
||||||
if withBuffer {
|
if withBuffer {
|
||||||
acc = acc.WithBuffer()
|
acc = acc.WithBuffer()
|
||||||
}
|
}
|
||||||
@ -173,7 +174,7 @@ func TestAccountWriteToWithBuffer(t *testing.T) {
|
|||||||
func TestAccountString(t *testing.T) {
|
func TestAccountString(t *testing.T) {
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 3, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 3, "test")
|
||||||
|
|
||||||
// FIXME not an exhaustive test!
|
// FIXME not an exhaustive test!
|
||||||
|
|
||||||
@ -193,7 +194,7 @@ func TestAccountString(t *testing.T) {
|
|||||||
func TestAccountAccounter(t *testing.T) {
|
func TestAccountAccounter(t *testing.T) {
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
in := ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3}))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 3, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 3, "test")
|
||||||
|
|
||||||
assert.True(t, in == acc.OldStream())
|
assert.True(t, in == acc.OldStream())
|
||||||
|
|
||||||
@ -260,7 +261,7 @@ func TestAccountMaxTransfer(t *testing.T) {
|
|||||||
|
|
||||||
in := ioutil.NopCloser(bytes.NewBuffer(make([]byte, 100)))
|
in := ioutil.NopCloser(bytes.NewBuffer(make([]byte, 100)))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
|
|
||||||
var b = make([]byte, 10)
|
var b = make([]byte, 10)
|
||||||
|
|
||||||
@ -277,7 +278,7 @@ func TestAccountMaxTransfer(t *testing.T) {
|
|||||||
|
|
||||||
fs.Config.CutoffMode = fs.CutoffModeSoft
|
fs.Config.CutoffMode = fs.CutoffModeSoft
|
||||||
stats = NewStats()
|
stats = NewStats()
|
||||||
acc = newAccountSizeName(stats, in, 1, "test")
|
acc = newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
|
|
||||||
n, err = acc.Read(b)
|
n, err = acc.Read(b)
|
||||||
assert.Equal(t, 10, n)
|
assert.Equal(t, 10, n)
|
||||||
@ -302,7 +303,7 @@ func TestAccountMaxTransferWriteTo(t *testing.T) {
|
|||||||
|
|
||||||
in := ioutil.NopCloser(readers.NewPatternReader(1024))
|
in := ioutil.NopCloser(readers.NewPatternReader(1024))
|
||||||
stats := NewStats()
|
stats := NewStats()
|
||||||
acc := newAccountSizeName(stats, in, 1, "test")
|
acc := newAccountSizeName(context.Background(), stats, in, 1, "test")
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package accounting
|
package accounting
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
@ -135,12 +136,12 @@ func (tr *Transfer) Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Account returns reader that knows how to keep track of transfer progress.
|
// Account returns reader that knows how to keep track of transfer progress.
|
||||||
func (tr *Transfer) Account(in io.ReadCloser) *Account {
|
func (tr *Transfer) Account(ctx context.Context, in io.ReadCloser) *Account {
|
||||||
tr.mu.Lock()
|
tr.mu.Lock()
|
||||||
if tr.acc == nil {
|
if tr.acc == nil {
|
||||||
tr.acc = newAccountSizeName(tr.stats, in, tr.size, tr.remote)
|
tr.acc = newAccountSizeName(ctx, tr.stats, in, tr.size, tr.remote)
|
||||||
} else {
|
} else {
|
||||||
tr.acc.UpdateReader(in)
|
tr.acc.UpdateReader(ctx, in)
|
||||||
}
|
}
|
||||||
tr.mu.Unlock()
|
tr.mu.Unlock()
|
||||||
return tr.acc
|
return tr.acc
|
||||||
|
@ -318,7 +318,7 @@ func checkIdenticalDownload(ctx context.Context, dst, src fs.Object) (differ boo
|
|||||||
defer func() {
|
defer func() {
|
||||||
tr1.Done(nil) // error handling is done by the caller
|
tr1.Done(nil) // error handling is done by the caller
|
||||||
}()
|
}()
|
||||||
in1 = tr1.Account(in1).WithBuffer() // account and buffer the transfer
|
in1 = tr1.Account(ctx, in1).WithBuffer() // account and buffer the transfer
|
||||||
|
|
||||||
in2, err := src.Open(ctx)
|
in2, err := src.Open(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -328,7 +328,7 @@ func checkIdenticalDownload(ctx context.Context, dst, src fs.Object) (differ boo
|
|||||||
defer func() {
|
defer func() {
|
||||||
tr2.Done(nil) // error handling is done by the caller
|
tr2.Done(nil) // error handling is done by the caller
|
||||||
}()
|
}()
|
||||||
in2 = tr2.Account(in2).WithBuffer() // account and buffer the transfer
|
in2 = tr2.Account(ctx, in2).WithBuffer() // account and buffer the transfer
|
||||||
|
|
||||||
// To assign err variable before defer.
|
// To assign err variable before defer.
|
||||||
differ, err = CheckEqualReaders(in1, in2)
|
differ, err = CheckEqualReaders(in1, in2)
|
||||||
|
@ -158,7 +158,7 @@ func multiThreadCopy(ctx context.Context, f fs.Fs, remote string, src fs.Object,
|
|||||||
mc.calculateChunks()
|
mc.calculateChunks()
|
||||||
|
|
||||||
// Make accounting
|
// Make accounting
|
||||||
mc.acc = tr.Account(nil)
|
mc.acc = tr.Account(ctx, nil)
|
||||||
|
|
||||||
// create write file handle
|
// create write file handle
|
||||||
mc.wc, err = openWriterAt(gCtx, remote, mc.size)
|
mc.wc, err = openWriterAt(gCtx, remote, mc.size)
|
||||||
|
@ -366,7 +366,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
|
|||||||
return nil, accounting.ErrorMaxTransferLimitReachedFatal
|
return nil, accounting.ErrorMaxTransferLimitReachedFatal
|
||||||
}
|
}
|
||||||
if doCopy := f.Features().Copy; doCopy != nil && (SameConfig(src.Fs(), f) || (SameRemoteType(src.Fs(), f) && f.Features().ServerSideAcrossConfigs)) {
|
if doCopy := f.Features().Copy; doCopy != nil && (SameConfig(src.Fs(), f) || (SameRemoteType(src.Fs(), f) && f.Features().ServerSideAcrossConfigs)) {
|
||||||
in := tr.Account(nil) // account the transfer
|
in := tr.Account(ctx, nil) // account the transfer
|
||||||
in.ServerSideCopyStart()
|
in.ServerSideCopyStart()
|
||||||
newDst, err = doCopy(ctx, src, remote)
|
newDst, err = doCopy(ctx, src, remote)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -421,7 +421,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
|
|||||||
dst, err = Rcat(ctx, f, remote, in0, src.ModTime(ctx))
|
dst, err = Rcat(ctx, f, remote, in0, src.ModTime(ctx))
|
||||||
newDst = dst
|
newDst = dst
|
||||||
} else {
|
} else {
|
||||||
in := tr.Account(in0).WithBuffer() // account and buffer the transfer
|
in := tr.Account(ctx, in0).WithBuffer() // account and buffer the transfer
|
||||||
var wrappedSrc fs.ObjectInfo = src
|
var wrappedSrc fs.ObjectInfo = src
|
||||||
// We try to pass the original object if possible
|
// We try to pass the original object if possible
|
||||||
if src.Remote() != remote {
|
if src.Remote() != remote {
|
||||||
@ -1054,7 +1054,7 @@ func Cat(ctx context.Context, f fs.Fs, w io.Writer, offset, count int64) error {
|
|||||||
if count >= 0 {
|
if count >= 0 {
|
||||||
in = &readCloser{Reader: &io.LimitedReader{R: in, N: count}, Closer: in}
|
in = &readCloser{Reader: &io.LimitedReader{R: in, N: count}, Closer: in}
|
||||||
}
|
}
|
||||||
in = tr.Account(in).WithBuffer() // account and buffer the transfer
|
in = tr.Account(ctx, in).WithBuffer() // account and buffer the transfer
|
||||||
// take the lock just before we output stuff, so at the last possible moment
|
// take the lock just before we output stuff, so at the last possible moment
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
@ -1072,7 +1072,7 @@ func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser,
|
|||||||
defer func() {
|
defer func() {
|
||||||
tr.Done(err)
|
tr.Done(err)
|
||||||
}()
|
}()
|
||||||
in = tr.Account(in).WithBuffer()
|
in = tr.Account(ctx, in).WithBuffer()
|
||||||
|
|
||||||
readCounter := readers.NewCountingReader(in)
|
readCounter := readers.NewCountingReader(in)
|
||||||
var trackingIn io.Reader
|
var trackingIn io.Reader
|
||||||
@ -1420,7 +1420,7 @@ func RcatSize(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadClo
|
|||||||
tr.Done(err)
|
tr.Done(err)
|
||||||
}()
|
}()
|
||||||
body := ioutil.NopCloser(in) // we let the server close the body
|
body := ioutil.NopCloser(in) // we let the server close the body
|
||||||
in := tr.Account(body) // account the transfer (no buffering)
|
in := tr.Account(ctx, body) // account the transfer (no buffering)
|
||||||
|
|
||||||
if SkipDestructive(ctx, dstFileName, "upload from pipe") {
|
if SkipDestructive(ctx, dstFileName, "upload from pipe") {
|
||||||
// prevents "broken pipe" errors
|
// prevents "broken pipe" errors
|
||||||
|
@ -79,7 +79,7 @@ func (fh *ReadFileHandle) openPending() (err error) {
|
|||||||
}
|
}
|
||||||
tr := accounting.GlobalStats().NewTransfer(o)
|
tr := accounting.GlobalStats().NewTransfer(o)
|
||||||
fh.done = tr.Done
|
fh.done = tr.Done
|
||||||
fh.r = tr.Account(r).WithBuffer() // account the transfer
|
fh.r = tr.Account(context.TODO(), r).WithBuffer() // account the transfer
|
||||||
fh.opened = true
|
fh.opened = true
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -158,7 +158,7 @@ func (fh *ReadFileHandle) seek(offset int64, reopen bool) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fh.r.UpdateReader(r)
|
fh.r.UpdateReader(context.TODO(), r)
|
||||||
fh.offset = offset
|
fh.offset = offset
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -495,7 +495,7 @@ func (dl *downloader) open(offset int64) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "vfs reader: failed to open source file")
|
return errors.Wrap(err, "vfs reader: failed to open source file")
|
||||||
}
|
}
|
||||||
dl.in = dl.tr.Account(in0).WithBuffer() // account and buffer the transfer
|
dl.in = dl.tr.Account(dl.dls.ctx, in0).WithBuffer() // account and buffer the transfer
|
||||||
|
|
||||||
dl.offset = offset
|
dl.offset = offset
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user