zfs & replication: explicit conflict types for FilesystemDiff + handling in repl

This commit is contained in:
Christian Schwarz 2017-07-08 13:13:16 +02:00
parent 8e378d76b9
commit 4b373fbd95
2 changed files with 65 additions and 28 deletions

View File

@ -321,7 +321,9 @@ func doPull(pull PullContext) (err error) {
diff := zfs.MakeFilesystemDiff(versions, theirVersions) diff := zfs.MakeFilesystemDiff(versions, theirVersions)
log("diff: %#v\n", diff) log("diff: %#v\n", diff)
if diff.IncrementalPath == nil { switch diff.Conflict {
case zfs.ConflictAllRight:
log("performing initial sync, following policy: %#v", pull.InitialReplPolicy) log("performing initial sync, following policy: %#v", pull.InitialReplPolicy)
if pull.InitialReplPolicy != rpc.InitialReplPolicyMostRecent { if pull.InitialReplPolicy != rpc.InitialReplPolicyMostRecent {
@ -367,10 +369,14 @@ func doPull(pull PullContext) (err error) {
} }
log("finished initial transfer") log("finished initial transfer")
return true
} else if len(diff.IncrementalPath) < 2 { case zfs.ConflictIncremental:
if len(diff.IncrementalPath) < 2 {
log("remote and local are in sync") log("remote and local are in sync")
} else { return true
}
log("incremental transfers using path: %#v", diff.IncrementalPath) log("incremental transfers using path: %#v", diff.IncrementalPath)
@ -407,10 +413,29 @@ func doPull(pull PullContext) (err error) {
} }
log("finished incremental transfer path") log("finished incremental transfer path")
return true
case zfs.ConflictNoCommonAncestor:
log("sender and receiver filesystem have snapshots, but no common one")
log("perform manual replication to establish a common snapshot history")
log("sender snapshot list: %#v", diff.MRCAPathRight)
log("receiver snapshot list: %#v", diff.MRCAPathLeft)
return false
case zfs.ConflictDiverged:
log("sender and receiver filesystem share a history but have diverged")
log("perform manual replication or delete snapshots on the receiving" +
"side to establish an incremental replication parse")
log("sender-only snapshots: %#v", diff.MRCAPathRight)
log("receiver-only snapshots: %#v", diff.MRCAPathLeft)
return false
} }
return true panic("implementation error: this should not be reached")
return false
}) })

View File

@ -12,7 +12,16 @@ func (l fsbyCreateTXG) Less(i, j int) bool {
return l[i].CreateTXG < l[j].CreateTXG return l[i].CreateTXG < l[j].CreateTXG
} }
/* The sender (left) wants to know if the receiver (right) has more recent versions type Conflict int
const (
ConflictIncremental = 0 // no conflict, incremental repl possible
ConflictAllRight = 1 // no conflict, initial repl possible
ConflictNoCommonAncestor = 2
ConflictDiverged = 3
)
/* The receiver (left) wants to know if the sender (right) has more recent versions
Left : | C | Left : | C |
Right: | A | B | C | D | E | Right: | A | B | C | D | E |
@ -35,27 +44,27 @@ IMPORTANT: since ZFS currently does not export dataset UUIDs, the best heuristic
*/ */
type FilesystemDiff struct { type FilesystemDiff struct {
// The increments required to get left up to right's most recent version // Which kind of conflict / "way forward" is possible.
// Check this first to determine the semantics of this struct's remaining members
Conflict Conflict
// Conflict = Incremental | AllRight
// The incremental steps required to get left up to right's most recent version
// 0th element is the common ancestor, ordered by birthtime, oldest first // 0th element is the common ancestor, ordered by birthtime, oldest first
// If len() < 2, left and right are at same most recent version // If len() < 2, left and right are at same most recent version
// If nil, there is no incremental path for left to get to right's most recent version // Conflict = otherwise
// This means either (check Diverged field to determine which case we are in) // nil; there is no incremental path for left to get to right's most recent version
// a) no common ancestor (left deleted all the snapshots it previously transferred to right)
// => consult MRCAPathRight and request initial retransfer after prep on left side
// b) divergence bewteen left and right (left made snapshots that right doesn't have)
// => check MRCAPathLeft and MRCAPathRight and decide what to do based on that
IncrementalPath []FilesystemVersion IncrementalPath []FilesystemVersion
// true if left and right diverged, false otherwise // Conflict = Incremental | AllRight: nil
Diverged bool // Conflict = NoCommonAncestor: left as passed as input
// If Diverged, contains path from left most recent common ancestor (mrca) // Conflict = Diverged: contains path from left most recent common ancestor (mrca) to most
// to most recent version on left // recent version on left
// Otherwise: nil
MRCAPathLeft []FilesystemVersion MRCAPathLeft []FilesystemVersion
// If Diverged, contains path from right most recent common ancestor (mrca) // Conflict = Incremental | AllRight: nil
// Conflict = NoCommonAncestor: right as passed as input
// Conflict = Diverged: contains path from right most recent common ancestor (mrca)
// to most recent version on right // to most recent version on right
// If there is no common ancestor (i.e. not diverged), contains entire list of
// versions on right
MRCAPathRight []FilesystemVersion MRCAPathRight []FilesystemVersion
} }
@ -66,12 +75,14 @@ func MakeFilesystemDiff(left, right []FilesystemVersion) (diff FilesystemDiff) {
if right == nil { if right == nil {
panic("right must not be nil") panic("right must not be nil")
} }
if left == nil { // treat like no common ancestor if left == nil {
diff = FilesystemDiff{ diff = FilesystemDiff{
IncrementalPath: nil, IncrementalPath: nil,
Diverged: false, Conflict: ConflictAllRight,
MRCAPathLeft: left,
MRCAPathRight: right, MRCAPathRight: right,
} }
return
} }
// Assert both left and right are sorted by createtxg // Assert both left and right are sorted by createtxg
@ -108,7 +119,8 @@ outer:
if mrcaLeft == -1 { if mrcaLeft == -1 {
diff = FilesystemDiff{ diff = FilesystemDiff{
IncrementalPath: nil, IncrementalPath: nil,
Diverged: false, Conflict: ConflictNoCommonAncestor,
MRCAPathLeft: left,
MRCAPathRight: right, MRCAPathRight: right,
} }
return return
@ -118,7 +130,7 @@ outer:
if mrcaLeft != len(left)-1 { if mrcaLeft != len(left)-1 {
diff = FilesystemDiff{ diff = FilesystemDiff{
IncrementalPath: nil, IncrementalPath: nil,
Diverged: true, Conflict: ConflictDiverged,
MRCAPathLeft: left[mrcaLeft:], MRCAPathLeft: left[mrcaLeft:],
MRCAPathRight: right[mrcaRight:], MRCAPathRight: right[mrcaRight:],
} }