replication: refactor driving logic (no more explicit state machine)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "pdu";
|
||||
|
||||
service Replication {
|
||||
rpc ListFilesystems (ListFilesystemReq) returns (ListFilesystemRes);
|
||||
rpc ListFilesystemVersions (ListFilesystemVersionsReq) returns (ListFilesystemVersionsRes);
|
||||
rpc DestroySnapshots (DestroySnapshotsReq) returns (DestroySnapshotsRes);
|
||||
rpc ReplicationCursor (ReplicationCursorReq) returns (ReplicationCursorRes);
|
||||
// for Send and Recv, see package rpc
|
||||
}
|
||||
|
||||
message ListFilesystemReq {}
|
||||
|
||||
message ListFilesystemRes {
|
||||
repeated Filesystem Filesystems = 1;
|
||||
bool Empty = 2;
|
||||
}
|
||||
|
||||
message Filesystem {
|
||||
string Path = 1;
|
||||
string ResumeToken = 2;
|
||||
}
|
||||
|
||||
message ListFilesystemVersionsReq {
|
||||
string Filesystem = 1;
|
||||
}
|
||||
|
||||
message ListFilesystemVersionsRes {
|
||||
repeated FilesystemVersion Versions = 1;
|
||||
}
|
||||
|
||||
message FilesystemVersion {
|
||||
enum VersionType {
|
||||
Snapshot = 0;
|
||||
Bookmark = 1;
|
||||
}
|
||||
VersionType Type = 1;
|
||||
string Name = 2;
|
||||
uint64 Guid = 3;
|
||||
uint64 CreateTXG = 4;
|
||||
string Creation = 5; // RFC 3339
|
||||
}
|
||||
|
||||
|
||||
message SendReq {
|
||||
string Filesystem = 1;
|
||||
string From = 2;
|
||||
// May be empty / null to request a full transfer of From
|
||||
string To = 3;
|
||||
|
||||
// If ResumeToken is not empty, the resume token that CAN be tried for 'zfs send' by the sender.
|
||||
// The sender MUST indicate in SendRes.UsedResumeToken
|
||||
// If it does not work, the sender SHOULD clear the resume token on their side
|
||||
// and use From and To instead
|
||||
// If ResumeToken is not empty, the GUIDs of From and To
|
||||
// MUST correspond to those encoded in the ResumeToken.
|
||||
// Otherwise, the Sender MUST return an error.
|
||||
string ResumeToken = 4;
|
||||
bool Compress = 5;
|
||||
bool Dedup = 6;
|
||||
|
||||
bool DryRun = 7;
|
||||
}
|
||||
|
||||
message Property {
|
||||
string Name = 1;
|
||||
string Value = 2;
|
||||
}
|
||||
|
||||
message SendRes {
|
||||
// Whether the resume token provided in the request has been used or not.
|
||||
bool UsedResumeToken = 2;
|
||||
|
||||
// Expected stream size determined by dry run, not exact.
|
||||
// 0 indicates that for the given SendReq, no size estimate could be made.
|
||||
int64 ExpectedSize = 3;
|
||||
|
||||
repeated Property Properties = 4;
|
||||
}
|
||||
|
||||
message ReceiveReq {
|
||||
string Filesystem = 1; // FIXME should be snapshot name, we can enforce that on recv
|
||||
|
||||
// If true, the receiver should clear the resume token before perfoming the zfs recv of the stream in the request
|
||||
bool ClearResumeToken = 2;
|
||||
}
|
||||
|
||||
message ReceiveRes {}
|
||||
|
||||
message DestroySnapshotsReq {
|
||||
string Filesystem = 1;
|
||||
// Path to filesystem, snapshot or bookmark to be destroyed
|
||||
repeated FilesystemVersion Snapshots = 2;
|
||||
}
|
||||
|
||||
message DestroySnapshotRes {
|
||||
FilesystemVersion Snapshot = 1;
|
||||
string Error = 2;
|
||||
}
|
||||
|
||||
message DestroySnapshotsRes {
|
||||
repeated DestroySnapshotRes Results = 1;
|
||||
}
|
||||
|
||||
message ReplicationCursorReq {
|
||||
string Filesystem = 1;
|
||||
message GetOp {}
|
||||
message SetOp {
|
||||
string Snapshot = 2;
|
||||
}
|
||||
oneof op {
|
||||
GetOp get = 2;
|
||||
SetOp set = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ReplicationCursorRes {
|
||||
oneof Result {
|
||||
uint64 Guid = 1;
|
||||
bool Notexist = 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package pdu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/zrepl/zrepl/zfs"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (v *FilesystemVersion) RelName() string {
|
||||
zv, err := v.ZFSFilesystemVersion()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return zv.String()
|
||||
}
|
||||
|
||||
func (v FilesystemVersion_VersionType) ZFSVersionType() zfs.VersionType {
|
||||
switch v {
|
||||
case FilesystemVersion_Snapshot:
|
||||
return zfs.Snapshot
|
||||
case FilesystemVersion_Bookmark:
|
||||
return zfs.Bookmark
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected v.Type %#v", v))
|
||||
}
|
||||
}
|
||||
|
||||
func FilesystemVersionFromZFS(fsv *zfs.FilesystemVersion) *FilesystemVersion {
|
||||
var t FilesystemVersion_VersionType
|
||||
switch fsv.Type {
|
||||
case zfs.Bookmark:
|
||||
t = FilesystemVersion_Bookmark
|
||||
case zfs.Snapshot:
|
||||
t = FilesystemVersion_Snapshot
|
||||
default:
|
||||
panic("unknown fsv.Type: " + fsv.Type)
|
||||
}
|
||||
return &FilesystemVersion{
|
||||
Type: t,
|
||||
Name: fsv.Name,
|
||||
Guid: fsv.Guid,
|
||||
CreateTXG: fsv.CreateTXG,
|
||||
Creation: fsv.Creation.Format(time.RFC3339),
|
||||
}
|
||||
}
|
||||
|
||||
func FilesystemVersionCreation(t time.Time) string {
|
||||
return t.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
func (v *FilesystemVersion) CreationAsTime() (time.Time, error) {
|
||||
return time.Parse(time.RFC3339, v.Creation)
|
||||
}
|
||||
|
||||
// implement fsfsm.FilesystemVersion
|
||||
func (v *FilesystemVersion) SnapshotTime() time.Time {
|
||||
t, err := v.CreationAsTime()
|
||||
if err != nil {
|
||||
panic(err) // FIXME
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (v *FilesystemVersion) ZFSFilesystemVersion() (*zfs.FilesystemVersion, error) {
|
||||
ct, err := v.CreationAsTime()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &zfs.FilesystemVersion{
|
||||
Type: v.Type.ZFSVersionType(),
|
||||
Name: v.Name,
|
||||
Guid: v.Guid,
|
||||
CreateTXG: v.CreateTXG,
|
||||
Creation: ct,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package pdu
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFilesystemVersion_RelName(t *testing.T) {
|
||||
|
||||
type TestCase struct {
|
||||
In FilesystemVersion
|
||||
Out string
|
||||
Panic bool
|
||||
}
|
||||
|
||||
creat := FilesystemVersionCreation(time.Now())
|
||||
tcs := []TestCase{
|
||||
{
|
||||
In: FilesystemVersion{
|
||||
Type: FilesystemVersion_Snapshot,
|
||||
Name: "foobar",
|
||||
Creation: creat,
|
||||
},
|
||||
Out: "@foobar",
|
||||
},
|
||||
{
|
||||
In: FilesystemVersion{
|
||||
Type: FilesystemVersion_Bookmark,
|
||||
Name: "foobar",
|
||||
Creation: creat,
|
||||
},
|
||||
Out: "#foobar",
|
||||
},
|
||||
{
|
||||
In: FilesystemVersion{
|
||||
Type: 2342,
|
||||
Name: "foobar",
|
||||
Creation: creat,
|
||||
},
|
||||
Panic: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
if tc.Panic {
|
||||
assert.Panics(t, func() {
|
||||
tc.In.RelName()
|
||||
})
|
||||
} else {
|
||||
o := tc.In.RelName()
|
||||
assert.Equal(t, tc.Out, o)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestFilesystemVersion_ZFSFilesystemVersion(t *testing.T) {
|
||||
|
||||
empty := &FilesystemVersion{}
|
||||
_, err:= empty.ZFSFilesystemVersion()
|
||||
assert.Error(t, err)
|
||||
|
||||
dateInvalid := &FilesystemVersion{Creation: "foobar"}
|
||||
_, err = dateInvalid.ZFSFilesystemVersion()
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user