replication & pruning: ditch replicated-property, use bookmark as cursor instead

A bookmark with a well-known name is used to track which version was
last successfully received by the receiver.
The createtxg that can be retrieved from the bookmark using `zfs get` is
used to set the Replicated attribute of each snap on the sender:
If the snap's CreateTXG > the cursor's, it is not yet replicated,
otherwise it has been.

There is an optional config option to change the behvior to
`CreateTXG >= the cursor's`, and the implementation defaults to that.

The reason: While things work just fine with `CreateTXG > the cursor's`,
ZFS does not provide size estimates in a `zfs send` dry run
(see acd2418).
However, to enable the use case of keeping the snapshot only around for
the replication, the config flag exists.
This commit is contained in:
Christian Schwarz
2018-09-05 18:24:15 -07:00
parent acd2418803
commit 975fdee217
9 changed files with 559 additions and 294 deletions
+12 -9
View File
@@ -42,7 +42,7 @@ type Sender interface {
// any next call to the parent github.com/zrepl/zrepl/replication.Endpoint.
// If the send request is for dry run the io.ReadCloser will be nil
Send(ctx context.Context, r *pdu.SendReq) (*pdu.SendRes, io.ReadCloser, error)
SnapshotReplicationStatus(ctx context.Context, r *pdu.SnapshotReplicationStatusReq) (*pdu.SnapshotReplicationStatusRes, error)
ReplicationCursor(ctx context.Context, req *pdu.ReplicationCursorReq) (*pdu.ReplicationCursorRes, error)
}
// A Sender is usually part of a github.com/zrepl/zrepl/replication.Endpoint.
@@ -423,19 +423,22 @@ func (s *ReplicationStep) doMarkReplicated(ctx context.Context, sender Sender) S
return s.state
}
log.Debug("mark snapshot as replicated")
req := pdu.SnapshotReplicationStatusReq{
log.Debug("advance replication cursor")
req := &pdu.ReplicationCursorReq{
Filesystem: s.parent.fs,
Snapshot: s.to.GetName(),
Op: pdu.SnapshotReplicationStatusReq_SetReplicated,
Op: &pdu.ReplicationCursorReq_Set{
Set: &pdu.ReplicationCursorReq_SetOp{
Snapshot: s.to.GetName(),
},
},
}
res, err := sender.SnapshotReplicationStatus(ctx, &req)
res, err := sender.ReplicationCursor(ctx, req)
if err != nil {
log.WithError(err).Error("error marking snapshot as replicated")
log.WithError(err).Error("error advancing replication cursor")
return updateStateError(err)
}
if res.Status != pdu.SnapshotReplicationStatusRes_Replicated {
err := fmt.Errorf("sender did not report snapshot as replicated: %s", res.Status)
if res.GetError() != "" {
err := fmt.Errorf("cannot advance replication cursor: %s", res.GetError())
log.Error(err.Error())
return updateStateError(err)
}