mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-28 19:34:58 +01:00
292b85b5ef
- drop HintMostRecentCommonAncestor rpc call - it is wrong to put faith into the active side of the replication to always make that call (we might not trust it, ref pull setup) - clean up step holds + step bookmarks + replication cursor bookmarks on send RPC instead - this makes it symmetric with Receive RPC - use a cache (endpoint.sendAbstractionsCache) to avoid the cost of listing the on-disk endpoint abstractions state on every step The "create" methods for endpoint abstractions (CreateReplicationCursor, HoldStep) are now fully idempotent and return an Abstraction. Notes about endpoint.sendAbstractionsCache: - fills lazily from disk state on first `Get` operation - fill from disk is generally only attempted once - unless the `ListAbstractions` fails, in which case the fill from disk is retried on next `Get` (the current `Get` will observe a subset of the actual on-disk abstractions) - the `Invalidate` method is called - it is a global (zrepl process-wide) cache fixes #316
76 lines
1.6 KiB
Go
76 lines
1.6 KiB
Go
package tests
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/zrepl/zrepl/platformtest"
|
|
"github.com/zrepl/zrepl/zfs"
|
|
)
|
|
|
|
func IdempotentDestroy(ctx *platformtest.Context) {
|
|
|
|
platformtest.Run(ctx, platformtest.PanicErr, ctx.RootDataset, `
|
|
DESTROYROOT
|
|
CREATEROOT
|
|
+ "foo bar"
|
|
+ "foo bar@a snap"
|
|
`)
|
|
|
|
fs := fmt.Sprintf("%s/foo bar", ctx.RootDataset)
|
|
asnap := fsversion(ctx, fs, "@a snap")
|
|
_, err := zfs.ZFSBookmark(ctx, fs, asnap, "a bookmark")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
type testCase struct {
|
|
description, path string
|
|
}
|
|
|
|
cases := []testCase{
|
|
{"snapshot", fmt.Sprintf("%s@a snap", fs)},
|
|
{"bookmark", fmt.Sprintf("%s#a bookmark", fs)},
|
|
{"filesystem", fs},
|
|
}
|
|
|
|
for i := range cases {
|
|
func() {
|
|
c := cases[i]
|
|
|
|
log.Printf("SUBBEGIN testing idempotent destroy %q for path %q", c.description, c.path)
|
|
|
|
log.Println("destroy existing")
|
|
err = zfs.ZFSDestroy(ctx, c.path)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
log.Println("destroy again, non-idempotently, must error")
|
|
err = zfs.ZFSDestroy(ctx, c.path)
|
|
if _, ok := err.(*zfs.DatasetDoesNotExist); !ok {
|
|
panic(fmt.Sprintf("%T: %s", err, err))
|
|
}
|
|
log.Println("destroy again, idempotently, must not error")
|
|
err = zfs.ZFSDestroyIdempotent(ctx, c.path)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
log.Println("SUBEND")
|
|
|
|
}()
|
|
}
|
|
|
|
// also test idempotent destroy for cases where the parent dataset does not exist
|
|
err = zfs.ZFSDestroyIdempotent(ctx, fmt.Sprintf("%s/not foo bar@nonexistent snapshot", ctx.RootDataset))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = zfs.ZFSDestroyIdempotent(ctx, fmt.Sprintf("%s/not foo bar#nonexistent bookmark", ctx.RootDataset))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|