diff --git a/rbd/rbd_mimic.go b/rbd/rbd_mimic.go index 523e806..d25ac74 100644 --- a/rbd/rbd_mimic.go +++ b/rbd/rbd_mimic.go @@ -15,29 +15,34 @@ import ( "bytes" "unsafe" + "github.com/ceph/go-ceph/internal/retry" "github.com/ceph/go-ceph/rados" ) // GetImageNames returns the list of current RBD images. func GetImageNames(ioctx *rados.IOContext) (names []string, err error) { - buf := make([]byte, 4096) - for { - size := C.size_t(len(buf)) + var ( + buf []byte + csize C.size_t + ) + // from 4KiB to 32KiB + retry.WithSizes(4096, 1<<15, func(size int) retry.Hint { + csize = C.size_t(size) + buf = make([]byte, csize) ret := C.rbd_list(cephIoctx(ioctx), - (*C.char)(unsafe.Pointer(&buf[0])), &size) - if ret == -C.ERANGE { - buf = make([]byte, size) - continue - } else if ret < 0 { - return nil, RBDError(ret) - } - tmp := bytes.Split(buf[:size-1], []byte{0}) - for _, s := range tmp { - if len(s) > 0 { - name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) - names = append(names, name) - } - } - return names, nil + (*C.char)(unsafe.Pointer(&buf[0])), &csize) + err = getErrorIfNegative(ret) + return retry.Size(int(csize)).If(err == errRange) + }) + if err != nil { + return nil, err } + tmp := bytes.Split(buf[:csize-1], []byte{0}) + for _, s := range tmp { + if len(s) > 0 { + name := C.GoString((*C.char)(unsafe.Pointer(&s[0]))) + names = append(names, name) + } + } + return names, nil } diff --git a/rbd/snapshot_nautilus.go b/rbd/snapshot_nautilus.go index e46390d..6018463 100644 --- a/rbd/snapshot_nautilus.go +++ b/rbd/snapshot_nautilus.go @@ -11,8 +11,9 @@ package rbd import "C" import ( - "fmt" "unsafe" + + "github.com/ceph/go-ceph/internal/retry" ) // GetParentInfo looks for the parent of the image and stores the pool, name @@ -76,27 +77,28 @@ func (image *Image) ListChildren() (pools []string, images []string, err error) return nil, nil, err } - size := C.size_t(0) - ret := C.rbd_list_children3(image.image, nil, &size) - if ret < 0 && ret != -C.ERANGE { - return nil, nil, RBDError(ret) - } else if ret > 0 { - return nil, nil, fmt.Errorf("rbd_list_children3() returned %d, expected 0", ret) - } else if ret == 0 && size == 0 { - return nil, nil, nil + var ( + csize C.size_t + children []C.rbd_linked_image_spec_t + ) + retry.WithSizes(16, 4096, func(size int) retry.Hint { + csize = C.size_t(size) + children = make([]C.rbd_linked_image_spec_t, csize) + ret := C.rbd_list_children3( + image.image, + (*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), + &csize) + err = getErrorIfNegative(ret) + return retry.Size(int(csize)).If(err == errRange) + }) + if err != nil { + return nil, nil, err } + defer C.rbd_linked_image_spec_list_cleanup((*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), csize) - // expected: ret == -ERANGE, size contains number of image names - children := make([]C.rbd_linked_image_spec_t, size) - ret = C.rbd_list_children3(image.image, (*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), &size) - if ret < 0 { - return nil, nil, RBDError(ret) - } - defer C.rbd_linked_image_spec_list_cleanup((*C.rbd_linked_image_spec_t)(unsafe.Pointer(&children[0])), size) - - pools = make([]string, size) - images = make([]string, size) - for i, child := range children { + pools = make([]string, csize) + images = make([]string, csize) + for i, child := range children[:csize] { pools[i] = C.GoString(child.pool_name) images[i] = C.GoString(child.image_name) } diff --git a/rbd/watchers_mimic.go b/rbd/watchers_mimic.go index 6f6bfbd..198292a 100644 --- a/rbd/watchers_mimic.go +++ b/rbd/watchers_mimic.go @@ -9,6 +9,10 @@ package rbd // #include import "C" +import ( + "github.com/ceph/go-ceph/internal/retry" +) + // ImageWatcher is a representation of the rbd_image_watcher_t from librbd.h type ImageWatcher struct { Addr string @@ -30,28 +34,28 @@ func (image *Image) ListWatchers() ([]ImageWatcher, error) { return nil, err } - count := C.ulong(0) - ret := C.rbd_watchers_list(image.image, nil, &count) - if ret != 0 && ret != -C.ERANGE { - return nil, getError(ret) - } - if ret == 0 && count == 0 { - return nil, nil - } - - watchers := make([]C.rbd_image_watcher_t, count) - ret = C.rbd_watchers_list(image.image, &watchers[0], &count) - if ret != 0 && ret != -C.ERANGE { - return nil, getError(ret) + var ( + err error + count C.size_t + watchers []C.rbd_image_watcher_t + ) + retry.WithSizes(16, 4096, func(size int) retry.Hint { + count = C.size_t(size) + watchers = make([]C.rbd_image_watcher_t, count) + ret := C.rbd_watchers_list(image.image, &watchers[0], &count) + err = getErrorIfNegative(ret) + return retry.Size(int(count)).If(err == errRange) + }) + if err != nil { + return nil, err } defer C.rbd_watchers_list_cleanup(&watchers[0], count) - imageWatchers := make([]ImageWatcher, len(watchers)) - for i, watcher := range watchers { + imageWatchers := make([]ImageWatcher, count) + for i, watcher := range watchers[:count] { imageWatchers[i].Addr = C.GoString(watcher.addr) imageWatchers[i].Id = int64(watcher.id) imageWatchers[i].Cookie = uint64(watcher.cookie) } - return imageWatchers, nil }