mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-25 09:54:47 +01:00
zfs & replication: explicit conflict types for FilesystemDiff + handling in repl
This commit is contained in:
parent
8e378d76b9
commit
4b373fbd95
@ -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
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
52
zfs/diff.go
52
zfs/diff.go
@ -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:],
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user