zfs: use createtxg and guid properties for FilesystemVersion

This commit is contained in:
Christian Schwarz 2017-05-06 10:57:43 +02:00
parent 22454738af
commit aa696dd0ce
2 changed files with 45 additions and 6 deletions

View File

@ -3,6 +3,8 @@ package zfs
import ( import (
"errors" "errors"
"fmt" "fmt"
"sort"
"strconv"
"strings" "strings"
) )
@ -15,8 +17,24 @@ const (
type FilesystemVersion struct { type FilesystemVersion struct {
Type VersionType Type VersionType
// Display name. Should not be used for identification, only for user output
Name string Name string
//ZFS_PROP_CREATETX and ZFS_PROP_GUID would be nice here => ZFS_PROP_CREATETX, libzfs_dataset.c:zfs_prop_get
// 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
}
type fsbyCreateTXG []FilesystemVersion
func (l fsbyCreateTXG) Len() int { return len(l) }
func (l fsbyCreateTXG) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l fsbyCreateTXG) Less(i, j int) bool {
return l[i].CreateTXG < l[j].CreateTXG
} }
/* The sender (left) wants to know if the receiver (right) has more recent versions /* The sender (left) wants to know if the receiver (right) has more recent versions
@ -69,10 +87,10 @@ type FilesystemDiff struct {
func ZFSListFilesystemVersions(fs DatasetPath) (res []FilesystemVersion, err error) { func ZFSListFilesystemVersions(fs DatasetPath) (res []FilesystemVersion, err error) {
var fieldLines [][]string var fieldLines [][]string
fieldLines, err = ZFSList( fieldLines, err = ZFSList(
[]string{"name"}, []string{"name", "guid", "createtxg"},
"-r", "-d", "1", "-r", "-d", "1",
"-t", "bookmark,snapshot", "-t", "bookmark,snapshot",
"-s", "creation", fs.ToString()) "-s", "createtxg", fs.ToString())
if err != nil { if err != nil {
return return
} }
@ -100,6 +118,16 @@ func ZFSListFilesystemVersions(fs DatasetPath) (res []FilesystemVersion, err err
v.Type = Bookmark 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 res[i] = v
} }
@ -110,15 +138,26 @@ func ZFSListFilesystemVersions(fs DatasetPath) (res []FilesystemVersion, err err
// 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) {
// Assert both left and right are sorted by createtxg
var leftSorted, rightSorted fsbyCreateTXG
leftSorted = left
rightSorted = right
if !sort.IsSorted(leftSorted) {
panic("cannot make filesystem diff: unsorted left")
}
if !sort.IsSorted(rightSorted) {
panic("cannot make filesystem diff: unsorted right")
}
// Find most recent common ancestor by name, preferring snapshots over bookmars // Find most recent common ancestor by name, preferring snapshots over bookmars
mrcaLeft := len(left) - 1 mrcaLeft := len(left) - 1
var mrcaRight int var mrcaRight int
outer: outer:
for ; mrcaLeft >= 0; mrcaLeft-- { for ; mrcaLeft >= 0; mrcaLeft-- {
for i := len(right) - 1; i >= 0; i-- { for i := len(right) - 1; i >= 0; i-- {
if left[mrcaLeft].Name == right[i].Name { if left[mrcaLeft].Guid == right[i].Guid {
mrcaRight = i mrcaRight = i
if i-1 >= 0 && right[i-1].Name == right[i].Name && right[i-1].Type == Snapshot { if i-1 >= 0 && right[i-1].Guid == right[i].Guid && right[i-1].Type == Snapshot {
// prefer snapshots over bookmarks // prefer snapshots over bookmarks
mrcaRight = i - 1 mrcaRight = i - 1
} }

View File

@ -66,7 +66,7 @@ func ZFSList(properties []string, zfsArgs ...string) (res [][]string, err error)
args := make([]string, 0, 4+len(zfsArgs)) args := make([]string, 0, 4+len(zfsArgs))
args = append(args, args = append(args,
"list", "-H", "list", "-H", "-p",
"-o", strings.Join(properties, ",")) "-o", strings.Join(properties, ","))
args = append(args, zfsArgs...) args = append(args, zfsArgs...)