mirror of
https://github.com/zrepl/zrepl.git
synced 2025-06-19 17:27:46 +02:00
zfs: extract filesystem version code to separate file & add filtering support
This commit is contained in:
parent
2b6f3ece6b
commit
c22190e981
@ -41,7 +41,7 @@ func (h Handler) HandleFilesystemVersionsRequest(r rpc.FilesystemVersionsRequest
|
|||||||
h.Logger.Printf("allowed: %#v\n", r.Filesystem)
|
h.Logger.Printf("allowed: %#v\n", r.Filesystem)
|
||||||
|
|
||||||
// find our versions
|
// find our versions
|
||||||
if versions, err = zfs.ZFSListFilesystemVersions(r.Filesystem); err != nil {
|
if versions, err = zfs.ZFSListFilesystemVersions(r.Filesystem, nil); err != nil {
|
||||||
h.Logger.Printf("our versions error: %#v\n", err)
|
h.Logger.Printf("our versions error: %#v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func doPull(pull PullContext) (err error) {
|
|||||||
|
|
||||||
var versions []zfs.FilesystemVersion
|
var versions []zfs.FilesystemVersion
|
||||||
if m.LocalExists {
|
if m.LocalExists {
|
||||||
if versions, err = zfs.ZFSListFilesystemVersions(m.Local); err != nil {
|
if versions, err = zfs.ZFSListFilesystemVersions(m.Local, nil); err != nil {
|
||||||
log("cannot get filesystem versions, stopping...: %v\n", m.Local.ToString(), m, err)
|
log("cannot get filesystem versions, stopping...: %v\n", m.Local.ToString(), m, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
96
zfs/diff.go
96
zfs/diff.go
@ -1,55 +1,9 @@
|
|||||||
package zfs
|
package zfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type VersionType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Bookmark VersionType = "bookmark"
|
|
||||||
Snapshot = "snapshot"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t VersionType) DelimiterChar() string {
|
|
||||||
switch t {
|
|
||||||
case Bookmark:
|
|
||||||
return "#"
|
|
||||||
case Snapshot:
|
|
||||||
return "@"
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unexpected VersionType %#v", t))
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type FilesystemVersion struct {
|
|
||||||
Type VersionType
|
|
||||||
|
|
||||||
// Display name. Should not be used for identification, only for user output
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// GUID as exported by ZFS. Uniquely identifies a snapshot across pools
|
|
||||||
Guid uint64
|
|
||||||
|
|
||||||
// The TXG in which the snapshot was created. For bookmarks,
|
|
||||||
// this is the GUID of the snapshot it was initially tied to.
|
|
||||||
CreateTXG uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v FilesystemVersion) ToAbsPath(p DatasetPath) string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
b.WriteString(p.ToString())
|
|
||||||
b.WriteString(v.Type.DelimiterChar())
|
|
||||||
b.WriteString(v.Name)
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type fsbyCreateTXG []FilesystemVersion
|
type fsbyCreateTXG []FilesystemVersion
|
||||||
|
|
||||||
func (l fsbyCreateTXG) Len() int { return len(l) }
|
func (l fsbyCreateTXG) Len() int { return len(l) }
|
||||||
@ -105,56 +59,6 @@ type FilesystemDiff struct {
|
|||||||
MRCAPathRight []FilesystemVersion
|
MRCAPathRight []FilesystemVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
func ZFSListFilesystemVersions(fs DatasetPath) (res []FilesystemVersion, err error) {
|
|
||||||
var fieldLines [][]string
|
|
||||||
fieldLines, err = ZFSList(
|
|
||||||
[]string{"name", "guid", "createtxg"},
|
|
||||||
"-r", "-d", "1",
|
|
||||||
"-t", "bookmark,snapshot",
|
|
||||||
"-s", "createtxg", fs.ToString())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res = make([]FilesystemVersion, len(fieldLines))
|
|
||||||
for i, line := range fieldLines {
|
|
||||||
|
|
||||||
if len(line[0]) < 3 {
|
|
||||||
err = errors.New(fmt.Sprintf("snapshot or bookmark name implausibly short: %s", line[0]))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
snapSplit := strings.SplitN(line[0], "@", 2)
|
|
||||||
bookmarkSplit := strings.SplitN(line[0], "#", 2)
|
|
||||||
if len(snapSplit)*len(bookmarkSplit) != 2 {
|
|
||||||
err = errors.New(fmt.Sprintf("dataset cannot be snapshot and bookmark at the same time: %s", line[0]))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var v FilesystemVersion
|
|
||||||
if len(snapSplit) == 2 {
|
|
||||||
v.Name = snapSplit[1]
|
|
||||||
v.Type = Snapshot
|
|
||||||
} else {
|
|
||||||
v.Name = bookmarkSplit[1]
|
|
||||||
v.Type = Bookmark
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Guid, err = strconv.ParseUint(line[1], 10, 64); err != nil {
|
|
||||||
err = errors.New(fmt.Sprintf("cannot parse GUID: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.CreateTXG, err = strconv.ParseUint(line[2], 10, 64); err != nil {
|
|
||||||
err = errors.New(fmt.Sprintf("cannot parse CreateTXG: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res[i] = v
|
|
||||||
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// we must assume left and right are ordered ascendingly by ZFS_PROP_CREATETXG and that
|
// we must assume left and right are ordered ascendingly by ZFS_PROP_CREATETXG and that
|
||||||
// names are unique (bas ZFS_PROP_GUID replacement)
|
// names are unique (bas ZFS_PROP_GUID replacement)
|
||||||
func MakeFilesystemDiff(left, right []FilesystemVersion) (diff FilesystemDiff) {
|
func MakeFilesystemDiff(left, right []FilesystemVersion) (diff FilesystemDiff) {
|
||||||
|
114
zfs/versions.go
Normal file
114
zfs/versions.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package zfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VersionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Bookmark VersionType = "bookmark"
|
||||||
|
Snapshot = "snapshot"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t VersionType) DelimiterChar() string {
|
||||||
|
switch t {
|
||||||
|
case Bookmark:
|
||||||
|
return "#"
|
||||||
|
case Snapshot:
|
||||||
|
return "@"
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected VersionType %#v", t))
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilesystemVersion struct {
|
||||||
|
Type VersionType
|
||||||
|
|
||||||
|
// Display name. Should not be used for identification, only for user output
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// GUID as exported by ZFS. Uniquely identifies a snapshot across pools
|
||||||
|
Guid uint64
|
||||||
|
|
||||||
|
// The TXG in which the snapshot was created. For bookmarks,
|
||||||
|
// this is the GUID of the snapshot it was initially tied to.
|
||||||
|
CreateTXG uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v FilesystemVersion) ToAbsPath(p DatasetPath) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString(p.ToString())
|
||||||
|
b.WriteString(v.Type.DelimiterChar())
|
||||||
|
b.WriteString(v.Name)
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilesystemVersionFilter interface {
|
||||||
|
Filter(fsv FilesystemVersion) (accept bool, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ZFSListFilesystemVersions(fs DatasetPath, filter FilesystemVersionFilter) (res []FilesystemVersion, err error) {
|
||||||
|
var fieldLines [][]string
|
||||||
|
fieldLines, err = ZFSList(
|
||||||
|
[]string{"name", "guid", "createtxg"},
|
||||||
|
"-r", "-d", "1",
|
||||||
|
"-t", "bookmark,snapshot",
|
||||||
|
"-s", "createtxg", fs.ToString())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res = make([]FilesystemVersion, 0, len(fieldLines))
|
||||||
|
for _, line := range fieldLines {
|
||||||
|
|
||||||
|
if len(line[0]) < 3 {
|
||||||
|
err = errors.New(fmt.Sprintf("snapshot or bookmark name implausibly short: %s", line[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
snapSplit := strings.SplitN(line[0], "@", 2)
|
||||||
|
bookmarkSplit := strings.SplitN(line[0], "#", 2)
|
||||||
|
if len(snapSplit)*len(bookmarkSplit) != 2 {
|
||||||
|
err = errors.New(fmt.Sprintf("dataset cannot be snapshot and bookmark at the same time: %s", line[0]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var v FilesystemVersion
|
||||||
|
if len(snapSplit) == 2 {
|
||||||
|
v.Name = snapSplit[1]
|
||||||
|
v.Type = Snapshot
|
||||||
|
} else {
|
||||||
|
v.Name = bookmarkSplit[1]
|
||||||
|
v.Type = Bookmark
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Guid, err = strconv.ParseUint(line[1], 10, 64); err != nil {
|
||||||
|
err = errors.New(fmt.Sprintf("cannot parse GUID: %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.CreateTXG, err = strconv.ParseUint(line[2], 10, 64); err != nil {
|
||||||
|
err = errors.New(fmt.Sprintf("cannot parse CreateTXG: %s", err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accept := true
|
||||||
|
if filter != nil {
|
||||||
|
accept, err = filter.Filter(v)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error executing filter: %s", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if accept {
|
||||||
|
res = append(res, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user