From 5c48102ede644f4de4a9bdc9797937a2c5bb9fda Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Mon, 25 Sep 2023 11:13:40 +0100 Subject: [PATCH] b2: fix locking window when getting mutipart upload URL Before this change, the lock was held while the upload URL was being fetched from the server. This meant that any other threads were blocked from getting upload URLs unecessarily. It also increased the potential for deadlock. --- backend/b2/upload.go | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/backend/b2/upload.go b/backend/b2/upload.go index 206c7abe4..9fe58295c 100644 --- a/backend/b2/upload.go +++ b/backend/b2/upload.go @@ -169,24 +169,26 @@ func (f *Fs) newLargeUpload(ctx context.Context, o *Object, in io.Reader, src fs // This should be returned with returnUploadURL when finished func (up *largeUpload) getUploadURL(ctx context.Context) (upload *api.GetUploadPartURLResponse, err error) { up.uploadMu.Lock() - defer up.uploadMu.Unlock() - if len(up.uploads) == 0 { - opts := rest.Opts{ - Method: "POST", - Path: "/b2_get_upload_part_url", - } - var request = api.GetUploadPartURLRequest{ - ID: up.id, - } - err := up.f.pacer.Call(func() (bool, error) { - resp, err := up.f.srv.CallJSON(ctx, &opts, &request, &upload) - return up.f.shouldRetry(ctx, resp, err) - }) - if err != nil { - return nil, fmt.Errorf("failed to get upload URL: %w", err) - } - } else { + if len(up.uploads) > 0 { upload, up.uploads = up.uploads[0], up.uploads[1:] + up.uploadMu.Unlock() + return upload, nil + } + up.uploadMu.Unlock() + + opts := rest.Opts{ + Method: "POST", + Path: "/b2_get_upload_part_url", + } + var request = api.GetUploadPartURLRequest{ + ID: up.id, + } + err = up.f.pacer.Call(func() (bool, error) { + resp, err := up.f.srv.CallJSON(ctx, &opts, &request, &upload) + return up.f.shouldRetry(ctx, resp, err) + }) + if err != nil { + return nil, fmt.Errorf("failed to get upload URL: %w", err) } return upload, nil }