zrepl/endpoint/jobid.go
Christian Schwarz 30cdc1430e replication + endpoint: replication guarantees: guarantee_{resumability,incremental,nothing}
This commit

- adds a configuration in which no step holds, replication cursors, etc. are created
- removes the send.step_holds.disable_incremental setting
- creates a new config option `replication` for active-side jobs
- adds the replication.protection.{initial,incremental} settings, each
  of which can have values
    - `guarantee_resumability`
    - `guarantee_incremental`
    - `guarantee_nothing`
  (refer to docs/configuration/replication.rst for semantics)

The `replication` config from an active side is sent to both endpoint.Sender and endpoint.Receiver
for each replication step. Sender and Receiver then act accordingly.

For `guarantee_incremental`, we add the new `tentative-replication-cursor` abstraction.
The necessity for that abstraction is outlined in https://github.com/zrepl/zrepl/issues/340.

fixes https://github.com/zrepl/zrepl/issues/340
2020-07-26 20:32:35 +02:00

79 lines
1.8 KiB
Go

package endpoint
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/zrepl/zrepl/zfs"
)
// JobID instances returned by MakeJobID() guarantee their JobID.String()
// can be used in ZFS dataset names and hold tags.
type JobID struct {
jid string
}
func MakeJobID(s string) (JobID, error) {
if len(s) == 0 {
return JobID{}, fmt.Errorf("must not be empty string")
}
if err := zfs.ComponentNamecheck(s); err != nil {
return JobID{}, errors.Wrap(err, "must be usable as a dataset path component")
}
if _, err := tentativeReplicationCursorBookmarkNameImpl("pool/ds", 0xface601d, s); err != nil {
// note that this might still fail due to total maximum name length, but we can't enforce that
return JobID{}, errors.Wrap(err, "must be usable for a tentative replication cursor bookmark")
}
if _, err := stepHoldTagImpl(s); err != nil {
return JobID{}, errors.Wrap(err, "must be usable for a step hold tag")
}
if _, err := lastReceivedHoldImpl(s); err != nil {
return JobID{}, errors.Wrap(err, "must be usable as a last-received-hold tag")
}
// FIXME replication cursor bookmark name
_, err := zfs.NewDatasetPath(s)
if err != nil {
return JobID{}, fmt.Errorf("must be usable in a ZFS dataset path: %s", err)
}
return JobID{s}, nil
}
func MustMakeJobID(s string) JobID {
jid, err := MakeJobID(s)
if err != nil {
panic(err)
}
return jid
}
func (j JobID) expectInitialized() {
if j.jid == "" {
panic("use of uninitialized JobID")
}
}
func (j JobID) String() string {
j.expectInitialized()
return j.jid
}
var _ json.Marshaler = JobID{}
var _ json.Unmarshaler = (*JobID)(nil)
func (j JobID) MarshalJSON() ([]byte, error) { return json.Marshal(j.jid) }
func (j *JobID) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &j.jid)
}
func (j JobID) MustValidate() { j.expectInitialized() }