rbd: add GroupSnapRollbackWithProgress function

* Add GroupSnapRollbackWithProgress implementing rbd_group_snap_rollback_with_progress

This has supporting code basically the same as our other existing
callback functions.
Tests too.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2021-01-25 15:21:15 -05:00 committed by mergify[bot]
parent 8e6dfe4259
commit 1286e0d4d0
2 changed files with 145 additions and 0 deletions

View File

@ -2,14 +2,26 @@ package rbd
/*
#cgo LDFLAGS: -lrbd
#include <errno.h>
#include <stdlib.h>
#include <rbd/librbd.h>
extern int snapRollbackCallback(uint64_t, uint64_t, uintptr_t);
// inline wrapper to cast uintptr_t to void*
static inline int wrap_rbd_group_snap_rollback_with_progress(
rados_ioctx_t group_p, const char *group_name,
const char *snap_name, uintptr_t arg) {
return rbd_group_snap_rollback_with_progress(
group_p, group_name, snap_name, (librbd_progress_fn_t)snapRollbackCallback, (void*)arg);
};
*/
import "C"
import (
"unsafe"
"github.com/ceph/go-ceph/internal/callbacks"
"github.com/ceph/go-ceph/internal/retry"
"github.com/ceph/go-ceph/rados"
)
@ -147,3 +159,65 @@ func GroupSnapRollback(ioctx *rados.IOContext, group, snap string) error {
ret := C.rbd_group_snap_rollback(cephIoctx(ioctx), cGroupName, cSnapName)
return getError(ret)
}
// GroupSnapRollbackCallback defines the function signature needed for the
// GroupSnapRollbackWithProgress callback.
//
// This callback will be called by GroupSnapRollbackWithProgress when it
// wishes to report progress rolling back a group snapshot.
type GroupSnapRollbackCallback func(uint64, uint64, interface{}) int
var groupSnapRollbackCallbacks = callbacks.New()
// GroupSnapRollbackWithProgress will roll back the images in the group
// to that of given snapshot. The given progress callback will be called
// to report on the progress of the snapshot rollback.
//
// Implements:
// int rbd_group_snap_rollback_with_progress(rados_ioctx_t group_p,
// const char *group_name,
// const char *snap_name,
// librbd_progress_fn_t cb,
// void *cbdata);
func GroupSnapRollbackWithProgress(
ioctx *rados.IOContext, group, snap string,
cb GroupSnapRollbackCallback, data interface{}) error {
// the provided callback must be a real function
if cb == nil {
return rbdError(C.EINVAL)
}
cGroupName := C.CString(group)
defer C.free(unsafe.Pointer(cGroupName))
cSnapName := C.CString(snap)
defer C.free(unsafe.Pointer(cSnapName))
ctx := gsnapRollbackCallbackCtx{
callback: cb,
data: data,
}
cbIndex := groupSnapRollbackCallbacks.Add(ctx)
defer diffIterateCallbacks.Remove(cbIndex)
ret := C.wrap_rbd_group_snap_rollback_with_progress(
cephIoctx(ioctx),
cGroupName,
cSnapName,
C.uintptr_t(cbIndex))
return getError(ret)
}
type gsnapRollbackCallbackCtx struct {
callback GroupSnapRollbackCallback
data interface{}
}
//export snapRollbackCallback
func snapRollbackCallback(
offset, total C.uint64_t, index uintptr) C.int {
v := groupSnapRollbackCallbacks.Lookup(index)
ctx := v.(gsnapRollbackCallbackCtx)
return C.int(ctx.callback(uint64(offset), uint64(total), ctx.data))
}

View File

@ -153,6 +153,69 @@ func TestGroupSnapshots(t *testing.T) {
err = GroupSnapRemove(ioctx, gname, snapname)
assert.NoError(t, err)
})
t.Run("groupSnapRollbackWithProgress", func(t *testing.T) {
img, err := OpenImage(ioctx, name1, NoSnapshot)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("SAY CHEESE"), 0)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("AND SMILE_"), 10240)
assert.NoError(t, err)
err = img.Close()
assert.NoError(t, err)
snapname := "snap2r"
err = GroupSnapCreate(ioctx, gname, snapname)
assert.NoError(t, err)
img, err = OpenImage(ioctx, name1, NoSnapshot)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("GOODBYE WORLD"), 0)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("_THIS_IS_ALL_"), 10240)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("I_HAVE_TO_SAY"), 11240)
assert.NoError(t, err)
err = img.Close()
assert.NoError(t, err)
img, err = OpenImage(ioctx, name2, NoSnapshot)
assert.NoError(t, err)
_, err = img.WriteAt([]byte("3333333333333"), 0)
assert.NoError(t, err)
err = img.Close()
assert.NoError(t, err)
cc := 0
cb := func(offset, total uint64, v interface{}) int {
cc++
val := v.(int)
assert.Equal(t, 0, val)
assert.Equal(t, uint64(1), total)
return 0
}
err = GroupSnapRollbackWithProgress(ioctx, gname, snapname, cb, 0)
assert.NoError(t, err)
assert.GreaterOrEqual(t, cc, 2)
b := make([]byte, 8)
img, err = OpenImage(ioctx, name1, NoSnapshot)
assert.NoError(t, err)
_, err = img.ReadAt(b, 0)
assert.NoError(t, err)
err = img.Close()
assert.NoError(t, err)
assert.Equal(t, []byte("SAY CHEE"), b)
img, err = OpenImage(ioctx, name2, NoSnapshot)
assert.NoError(t, err)
_, err = img.ReadAt(b, 0)
assert.NoError(t, err)
err = img.Close()
assert.NoError(t, err)
assert.Equal(t, []byte("\x00\x00\x00\x00\x00\x00\x00\x00"), b)
err = GroupSnapRemove(ioctx, gname, snapname)
assert.NoError(t, err)
})
t.Run("invalidIOContext", func(t *testing.T) {
assert.Panics(t, func() {
@ -170,5 +233,13 @@ func TestGroupSnapshots(t *testing.T) {
assert.Panics(t, func() {
GroupSnapRollback(nil, gname, "foo")
})
assert.Panics(t, func() {
cb := func(o, t uint64, v interface{}) int { return 0 }
GroupSnapRollbackWithProgress(nil, gname, "foo", cb, nil)
})
})
t.Run("invalidCallback", func(t *testing.T) {
err := GroupSnapRollbackWithProgress(ioctx, gname, "foo", nil, nil)
assert.Error(t, err)
})
}