From acd2418803ec42576786122c80428d80e4a5d520 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Wed, 5 Sep 2018 17:41:25 -0700 Subject: [PATCH] handle DryRun send size estimate errors with bookmarks --- client/status.go | 27 ++++++++++++++++----------- endpoint/endpoint.go | 3 +++ replication/fsrep/fsfsm.go | 5 +++-- replication/pdu/pdu.pb.go | 3 ++- replication/pdu/pdu.proto | 3 ++- zfs/zfs.go | 13 +++++++++++++ 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/client/status.go b/client/status.go index 7847c84..e19d474 100644 --- a/client/status.go +++ b/client/status.go @@ -235,23 +235,28 @@ func (t *tui) drawBar(name string, maxNameLength int, status string, bytes int64 t.write(rightPad(status, 14, " ")) t.write(" ") + length := 50 + var completedLength int if totalBytes > 0 { - length := 50 - completedLength := int(int64(length) * bytes / totalBytes) + completedLength = int(int64(length) * bytes / totalBytes) if completedLength > length { completedLength = length } - - t.write("[") - t.write(times("=", completedLength)) - t.write(">") - t.write(times("-", length-completedLength)) - t.write("]") - - t.write(" ") - t.write(rightPad(ByteCountBinary(bytes) + "/" + ByteCountBinary(totalBytes), 20, " ")) } + t.write("[") + t.write(times("=", completedLength)) + t.write(">") + t.write(times("-", length-completedLength)) + t.write("]") + + t.write(" ") + totalBytesStr := ByteCountBinary(totalBytes) + if totalBytes == 0 { + totalBytesStr = "??? B" + } + t.write(rightPad(ByteCountBinary(bytes)+"/"+totalBytesStr, 20, " ")) + t.newline() } diff --git a/endpoint/endpoint.go b/endpoint/endpoint.go index d1ee34f..c6c5b37 100644 --- a/endpoint/endpoint.go +++ b/endpoint/endpoint.go @@ -77,6 +77,9 @@ func (p *Sender) Send(ctx context.Context, r *pdu.SendReq) (*pdu.SendRes, io.Rea if r.DryRun { size, err := zfs.ZFSSendDry(r.Filesystem, r.From, r.To) + if err == zfs.BookmarkSizeEstimationNotSupported { + return &pdu.SendRes{ExpectedSize: 0}, nil, nil + } if err != nil { return nil, nil, err } diff --git a/replication/fsrep/fsfsm.go b/replication/fsrep/fsfsm.go index e1a3ffe..2b992c7 100644 --- a/replication/fsrep/fsfsm.go +++ b/replication/fsrep/fsfsm.go @@ -59,7 +59,7 @@ type StepReport struct { Status StepState Problem string Bytes int64 - ExpectedBytes int64 + ExpectedBytes int64 // 0 means no size estimate possible } type Report struct { @@ -185,7 +185,7 @@ type ReplicationStep struct { err error byteCounter *util.ByteCounterReader - expectedSize int64 + expectedSize int64 // 0 means no size estimate present / possible } func (f *Replication) TakeStep(ctx context.Context, sender Sender, receiver Receiver) (post State, nextStepDate time.Time) { @@ -457,6 +457,7 @@ func (s *ReplicationStep) updateSizeEstimate(ctx context.Context, sender Sender) sres, _, err := sender.Send(ctx, sr) if err != nil { log.WithError(err).Error("dry run send request failed") + return err } s.expectedSize = sres.ExpectedSize return nil diff --git a/replication/pdu/pdu.pb.go b/replication/pdu/pdu.pb.go index be22dea..52f596e 100644 --- a/replication/pdu/pdu.pb.go +++ b/replication/pdu/pdu.pb.go @@ -493,7 +493,8 @@ func (m *Property) GetValue() string { type SendRes struct { // Whether the resume token provided in the request has been used or not. UsedResumeToken bool `protobuf:"varint,1,opt,name=UsedResumeToken,proto3" json:"UsedResumeToken,omitempty"` - // Expected stream size determined by dry run, not exact + // Expected stream size determined by dry run, not exact. + // 0 indicates that for the given SendReq, no size estimate could be made. ExpectedSize int64 `protobuf:"varint,2,opt,name=ExpectedSize,proto3" json:"ExpectedSize,omitempty"` Properties []*Property `protobuf:"bytes,3,rep,name=Properties,proto3" json:"Properties,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` diff --git a/replication/pdu/pdu.proto b/replication/pdu/pdu.proto index f390fd8..1238243 100644 --- a/replication/pdu/pdu.proto +++ b/replication/pdu/pdu.proto @@ -65,7 +65,8 @@ message SendRes { // Whether the resume token provided in the request has been used or not. bool UsedResumeToken = 1; - // Expected stream size determined by dry run, not exact + // Expected stream size determined by dry run, not exact. + // 0 indicates that for the given SendReq, no size estimate could be made. int64 ExpectedSize = 2; repeated Property Properties = 3; diff --git a/zfs/zfs.go b/zfs/zfs.go index a218c72..9c4d6b7 100644 --- a/zfs/zfs.go +++ b/zfs/zfs.go @@ -309,6 +309,9 @@ func ZFSSend(fs string, from, to string) (stream io.ReadCloser, err error) { return } +var BookmarkSizeEstimationNotSupported error = fmt.Errorf("size estimation is not supported for bookmarks") + +// May return BookmarkSizeEstimationNotSupported as err if from is a bookmark. func ZFSSendDry(fs string, from, to string) (size int64, err error) { fromV, err := absVersion(fs, from) @@ -324,6 +327,16 @@ func ZFSSendDry(fs string, from, to string) (size int64, err error) { } } + if strings.Contains(fromV, "#") { + /* TODO: + * ZFS at the time of writing does not support dry-run send because size-estimation + * uses fromSnap's deadlist. However, for a bookmark, that deadlist no longer exists. + * Redacted send & recv will bring this functionality, see + * https://github.com/openzfs/openzfs/pull/484 + */ + return 0, BookmarkSizeEstimationNotSupported + } + args := make([]string, 0) args = append(args, "send", "-n", "-v", "-P")