From 0ba4b5eda68a676d5dd705aeef6132bd069f7ac5 Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Mon, 14 Oct 2019 17:48:47 +0200 Subject: [PATCH] zfs: helper for ZFSGet `guid` and `createtxg` --- zfs/replication_history.go | 23 +++++------------------ zfs/zfs.go | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/zfs/replication_history.go b/zfs/replication_history.go index 36663c3..167ffae 100644 --- a/zfs/replication_history.go +++ b/zfs/replication_history.go @@ -2,7 +2,6 @@ package zfs import ( "fmt" - "strconv" "github.com/pkg/errors" ) @@ -26,30 +25,18 @@ func ZFSGetReplicationCursor(fs *DatasetPath) (*FilesystemVersion, error) { func ZFSSetReplicationCursor(fs *DatasetPath, snapname string) (guid uint64, err error) { snapPath := fmt.Sprintf("%s@%s", fs.ToString(), snapname) debug("replication cursor: snap path %q", snapPath) - propsSnap, err := zfsGet(snapPath, []string{"createtxg", "guid"}, sourceAny) + snapProps, err := ZFSGetCreateTXGAndGuid(snapPath) if err != nil { - return 0, errors.Wrap(err, "zfs: replication cursor: get snapshot createtxg") - } - snapGuid, err := strconv.ParseUint(propsSnap.Get("guid"), 10, 64) - if err != nil { - return 0, errors.Wrap(err, "zfs: replication cursor: parse snapshot guid") + return 0, errors.Wrapf(err, "get properties of %q", snapPath) } bookmarkPath := fmt.Sprintf("%s#%s", fs.ToString(), ReplicationCursorBookmarkName) - propsBookmark, err := zfsGet(bookmarkPath, []string{"createtxg"}, sourceAny) + propsBookmark, err := ZFSGetCreateTXGAndGuid(bookmarkPath) _, bookmarkNotExistErr := err.(*DatasetDoesNotExist) if err != nil && !bookmarkNotExistErr { return 0, errors.Wrap(err, "zfs: replication cursor: get bookmark txg") } if err == nil { - bookmarkTxg, err := strconv.ParseUint(propsBookmark.Get("createtxg"), 10, 64) - if err != nil { - return 0, errors.Wrap(err, "zfs: replication cursor: parse bookmark createtxg") - } - snapTxg, err := strconv.ParseUint(propsSnap.Get("createtxg"), 10, 64) - if err != nil { - return 0, errors.Wrap(err, "zfs: replication cursor: parse snapshot createtxg") - } - if snapTxg < bookmarkTxg { + if snapProps.CreateTXG < propsBookmark.CreateTXG { return 0, errors.New("zfs: replication cursor: can only be advanced, not set back") } if err := ZFSDestroy(bookmarkPath); err != nil { // FIXME make safer by using new temporary bookmark, then rename, possible with channel programs @@ -59,5 +46,5 @@ func ZFSSetReplicationCursor(fs *DatasetPath, snapname string) (guid uint64, err if err := ZFSBookmark(fs, snapname, ReplicationCursorBookmarkName); err != nil { return 0, errors.Wrapf(err, "zfs: replication cursor: create bookmark") } - return snapGuid, nil + return snapProps.Guid, nil } diff --git a/zfs/zfs.go b/zfs/zfs.go index 328036c..d555e4b 100644 --- a/zfs/zfs.go +++ b/zfs/zfs.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "encoding/json" - "errors" "fmt" "io" "os" @@ -20,6 +19,7 @@ import ( "github.com/prometheus/client_golang/prometheus" + "github.com/pkg/errors" "github.com/zrepl/zrepl/util/envconst" ) @@ -1024,6 +1024,41 @@ func zfsGet(path string, props []string, allowedSources zfsPropertySource) (*ZFS return res, nil } +type ZFSPropCreateTxgAndGuidProps struct { + CreateTXG, Guid uint64 +} + +func ZFSGetCreateTXGAndGuid(ds string) (ZFSPropCreateTxgAndGuidProps, error) { + props, err := zfsGetNumberProps(ds, []string{"createtxg", "guid"}, sourceAny) + if err != nil { + return ZFSPropCreateTxgAndGuidProps{}, err + } + return ZFSPropCreateTxgAndGuidProps{ + CreateTXG: props["createtxg"], + Guid: props["guid"], + }, nil +} + +// returns *DatasetDoesNotExist if the dataset does not exist +func zfsGetNumberProps(ds string, props []string, src zfsPropertySource) (map[string]uint64, error) { + sps, err := zfsGet(ds, props, sourceAny) + if err != nil { + if _, ok := err.(*DatasetDoesNotExist); ok { + return nil, err // pass through as is + } + return nil, errors.Wrap(err, "zfs: set replication cursor: get snapshot createtxg") + } + r := make(map[string]uint64, len(props)) + for _, p := range props { + v, err := strconv.ParseUint(sps.Get(p), 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "zfs get: parse number property %q", p) + } + r[p] = v + } + return r, nil +} + type DestroySnapshotsError struct { RawLines []string Filesystem string