Skip to content

Commit

Permalink
rbd: Add rbd_sparsify_with_progress rbd API
Browse files Browse the repository at this point in the history
Added a new rbd API `rbd_sparsify_with_progress`, and supporting
tests.

Fixes: #281

Signed-off-by: Nikhil-Ladha <nikhilladha1999@gmail.com>
  • Loading branch information
Nikhil-Ladha authored and anoopcs9 committed Apr 4, 2023
1 parent 66ffbfa commit 275b36f
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/api-status.json
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,12 @@
"comment": "SetMirrorPeerSiteDirection sets the direction of a mirror peer site.\n",
"added_in_version": "v0.21.0",
"expected_stable_version": "v0.23.0"
},
{
"name": "Image.SparsifyWithProgress",
"comment": "SparsifyWithProgress makes an image sparse by deallocating runs of zeros.\nThe sparseSize value will be used to find runs of zeros and must be\na power of two no less than 4096 and no larger than the image size.\nThe given progress callback will be called to report on the progress\nof sparse. The operation will be aborted if the progress callback returns\na non-zero value.\n\nImplements:\n\n\tint rbd_sparsify_with_progress(rbd_image_t image, size_t sparse_size,\n\t\t\t\t\t\t\t\t librbd_progress_fn_t cb, void *cbdata);\n",
"added_in_version": "$NEXT_RELEASE",
"expected_stable_version": "$NEXT_RELEASE_STABLE"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions docs/api-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ ListMirrorPeerSite | v0.21.0 | v0.23.0 |
SetMirrorPeerSiteClientName | v0.21.0 | v0.23.0 |
SetMirrorPeerSiteName | v0.21.0 | v0.23.0 |
SetMirrorPeerSiteDirection | v0.21.0 | v0.23.0 |
Image.SparsifyWithProgress | $NEXT_RELEASE | $NEXT_RELEASE_STABLE |

### Deprecated APIs

Expand Down
82 changes: 82 additions & 0 deletions rbd/rbd_sparsify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//go:build !nautilus && ceph_preview
// +build !nautilus,ceph_preview

package rbd

/*
#cgo LDFLAGS: -lrbd
#include <errno.h>
#include <stdlib.h>
#include <rbd/librbd.h>
extern int sparsifyCallback(uint64_t, uint64_t, uintptr_t);
// inline wrapper to cast uintptr_t to void*
static inline int wrap_rbd_sparsify_with_progress(
rbd_image_t image, size_t sparse_size, uintptr_t arg) {
return rbd_sparsify_with_progress(
image, sparse_size, (librbd_progress_fn_t)sparsifyCallback, (void*)arg);
};
*/
import "C"

import (
"github.com/ceph/go-ceph/internal/callbacks"
)

// SparsifyCallback defines the function signature needed for the
// SparsifyWithProgress callback.
//
// This callback will be called by SparsifyWithProgress when it
// wishes to report progress on sparse.
type SparsifyCallback func(uint64, uint64, interface{}) int

var sparsifyCallbacks = callbacks.New()

type sparsifyCallbackCtx struct {
callback SparsifyCallback
data interface{}
}

// SparsifyWithProgress makes an image sparse by deallocating runs of zeros.
// The sparseSize value will be used to find runs of zeros and must be
// a power of two no less than 4096 and no larger than the image size.
// The given progress callback will be called to report on the progress
// of sparse. The operation will be aborted if the progress callback returns
// a non-zero value.
//
// Implements:
//
// int rbd_sparsify_with_progress(rbd_image_t image, size_t sparse_size,
// librbd_progress_fn_t cb, void *cbdata);
func (image *Image) SparsifyWithProgress(
sparseSize uint, cb SparsifyCallback, data interface{}) error {
// the provided callback must be a real function
if cb == nil {
return rbdError(C.EINVAL)
}

if err := image.validate(imageIsOpen); err != nil {
return err
}

ctx := sparsifyCallbackCtx{
callback: cb,
data: data,
}
cbIndex := sparsifyCallbacks.Add(ctx)
defer diffIterateCallbacks.Remove(cbIndex)

ret := C.wrap_rbd_sparsify_with_progress(image.image, C.size_t(sparseSize), C.uintptr_t(cbIndex))

return getError(ret)
}

//export sparsifyCallback
func sparsifyCallback(
offset, total C.uint64_t, index uintptr) C.int {

v := sparsifyCallbacks.Lookup(index)
ctx := v.(sparsifyCallbackCtx)
return C.int(ctx.callback(uint64(offset), uint64(total), ctx.data))
}
94 changes: 94 additions & 0 deletions rbd/rbd_sparsify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//go:build !nautilus && ceph_preview
// +build !nautilus,ceph_preview

package rbd

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestSparsifyWithProgress(t *testing.T) {
conn := radosConnect(t)
defer conn.Shutdown()

poolname := GetUUID()
err := conn.MakePool(poolname)
require.NoError(t, err)
defer conn.DeletePool(poolname)

ioctx, err := conn.OpenIOContext(poolname)
require.NoError(t, err)
defer ioctx.Destroy()

name := GetUUID()
err = quickCreate(ioctx, name, testImageSize, testImageOrder)
require.NoError(t, err)
defer func() { assert.NoError(t, RemoveImage(ioctx, name)) }()

t.Run("valid", func(t *testing.T) {
img, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
defer func() { assert.NoError(t, img.Close()) }()

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 = img.SparsifyWithProgress(4096, cb, 0)
assert.NoError(t, err)
assert.GreaterOrEqual(t, cc, 1)
})

t.Run("negativeReturnValue", func(t *testing.T) {
img, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
defer func() { assert.NoError(t, img.Close()) }()

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 -1
}

err = img.SparsifyWithProgress(4096, cb, 0)
assert.Error(t, err)
})

t.Run("closedImage", func(t *testing.T) {
img, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
assert.NoError(t, img.Close())

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 = img.SparsifyWithProgress(4096, cb, 0)
assert.Error(t, err)
})

t.Run("invalidValue", func(t *testing.T) {
img, err := OpenImage(ioctx, name, NoSnapshot)
assert.NoError(t, err)
defer func() { assert.NoError(t, img.Close()) }()

err = img.SparsifyWithProgress(4096, nil, nil)
assert.Error(t, err)
})
}

0 comments on commit 275b36f

Please sign in to comment.