From aa40391eed4a518e751e4a3d79983bba32ea4807 Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Sat, 6 Nov 2021 11:06:04 -0700 Subject: [PATCH] performance: optimized restore performance for webdav/rclone (#1491) This improves the performance of partial data reads, such as the ones during restore by avoiding reading the full blob only to discard most of it. The impact on restore time is dramatic: Restoring 5.6 GB files:132921 dirs:18980 from rclone based on local directory: before: >2h after: 49.45s --- go.mod | 2 +- go.sum | 2 ++ repo/blob/webdav/webdav_storage.go | 29 ++++++++++++++++++----------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index d4d2cba88..ba9a7d637 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/sirupsen/logrus v1.8.1 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.7.0 - github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df + github.com/studio-b12/gowebdav v0.0.0-20211106090535-29e74efa701f github.com/tg123/go-htpasswd v1.2.0 github.com/zalando/go-keyring v0.1.1 github.com/zeebo/blake3 v0.2.1 diff --git a/go.sum b/go.sum index e09d044b4..774981c84 100644 --- a/go.sum +++ b/go.sum @@ -679,6 +679,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df h1:C+J/LwTqP8gRPt1MdSzBNZP0OYuDm5wsmDKgwpLjYzo= github.com/studio-b12/gowebdav v0.0.0-20210917133250-a3a86976a1df/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s= +github.com/studio-b12/gowebdav v0.0.0-20211106090535-29e74efa701f h1:SLJx0nHhb2ZLlYNMAbrYsjwmVwXx4yRT48lNIxOp7ts= +github.com/studio-b12/gowebdav v0.0.0-20211106090535-29e74efa701f/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s= github.com/tg123/go-htpasswd v1.2.0 h1:UKp34m9H467/xklxUxU15wKRru7fwXoTojtxg25ITF0= github.com/tg123/go-htpasswd v1.2.0/go.mod h1:h7IzlfpvIWnVJhNZ0nQ9HaFxHb7pn5uFJYLlEUJa2sM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= diff --git a/repo/blob/webdav/webdav_storage.go b/repo/blob/webdav/webdav_storage.go index 9a598b022..a368e88d8 100644 --- a/repo/blob/webdav/webdav_storage.go +++ b/repo/blob/webdav/webdav_storage.go @@ -54,25 +54,32 @@ func (d *davStorageImpl) GetBlobFromPath(ctx context.Context, dirPath, path stri return blob.ErrInvalidRange } - s, err := d.cli.ReadStream(path) + var ( + s io.ReadCloser + err error + ) + + switch { + case length < 0: + s, err = d.cli.ReadStream(path) + case length == 0: + s, err = d.cli.ReadStreamRange(path, offset, 1) + default: + s, err = d.cli.ReadStreamRange(path, offset, length) + } + if err != nil { return d.translateError(err) } defer s.Close() // nolint:errcheck - if length < 0 { - // nolint:wrapcheck - return iocopy.JustCopy(output, s) + if length == 0 { + return nil } - // this is horrible, but gowebdav does not support seeking (yet). - if err := iocopy.JustCopy(io.Discard, io.LimitReader(s, offset)); err != nil { - return errors.Wrap(err, "error discarding data from stream") - } - - if err := iocopy.JustCopy(output, io.LimitReader(s, length)); err != nil { - return errors.Wrap(err, "error reading stream") + if err := iocopy.JustCopy(output, s); err != nil { + return errors.Wrap(err, "error populating output") } // nolint:wrapcheck