mirror of
https://github.com/octoleo/restic.git
synced 2024-11-24 21:57:41 +00:00
Speed up restic init over slow SFTP links
pkg/sftp.Client.MkdirAll(d) does a Stat to determine if d exists and is a directory, then a recursive call to create the parent, so the calls for data/?? each take three round trips. Doing a Mkdir first should eliminate two round trips for 255/256 data directories as well as all but one of the top-level directories. Also, we can do all of the calls concurrently. This may reintroduce some of the Stat calls when multiple goroutines try to create the same parent, but at the default number of connections, that should not be much of a problem.
This commit is contained in:
parent
23ebec717c
commit
2bdc40e612
2
go.mod
2
go.mod
@ -38,7 +38,7 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/sys v0.0.0-20220325203850-36772127a21f
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/text v0.3.7
|
||||
|
3
go.sum
3
go.sum
@ -439,8 +439,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/pkg/sftp"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// SFTP is a backend in a directory accessed via SFTP.
|
||||
@ -154,15 +155,29 @@ func Open(ctx context.Context, cfg Config) (*SFTP, error) {
|
||||
return sftp, nil
|
||||
}
|
||||
|
||||
func (r *SFTP) mkdirAllDataSubdirs() error {
|
||||
func (r *SFTP) mkdirAllDataSubdirs(ctx context.Context, nconn uint) error {
|
||||
// Run multiple MkdirAll calls concurrently. These involve multiple
|
||||
// round-trips and we do a lot of them, so this whole operation can be slow
|
||||
// on high-latency links.
|
||||
g, _ := errgroup.WithContext(ctx)
|
||||
// Use errgroup's built-in semaphore, because r.sem is not initialized yet.
|
||||
g.SetLimit(int(nconn))
|
||||
|
||||
for _, d := range r.Paths() {
|
||||
err := r.c.MkdirAll(d)
|
||||
if err != nil {
|
||||
return err
|
||||
d := d
|
||||
g.Go(func() error {
|
||||
// First try Mkdir. For most directories in Paths, this takes one
|
||||
// round trip, not counting duplicate parent creations causes by
|
||||
// concurrency. MkdirAll first does Stat, then recursive MkdirAll
|
||||
// on the parent, so calls typically take three round trips.
|
||||
if err := r.c.Mkdir(d); err == nil {
|
||||
return nil
|
||||
}
|
||||
return r.c.MkdirAll(d)
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// Join combines path components with slashes (according to the sftp spec).
|
||||
@ -240,7 +255,7 @@ func Create(ctx context.Context, cfg Config) (*SFTP, error) {
|
||||
}
|
||||
|
||||
// create paths for data and refs
|
||||
if err = sftp.mkdirAllDataSubdirs(); err != nil {
|
||||
if err = sftp.mkdirAllDataSubdirs(ctx, cfg.Connections); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user