Skip to content

Commit

Permalink
rados/striper: start new striper package
Browse files Browse the repository at this point in the history
Start a new `rados/striper` package that wraps Ceph's libradosstriper.
The libradosstriper library builds on top of the librados library to
support striping large "objects" over multiple RADOS objects.

Fixes: #1011

Signed-off-by: John Mulligan <jmulligan@redhat.com>
  • Loading branch information
phlogistonjohn authored and mergify[bot] committed Aug 8, 2024
1 parent 60ea53d commit 33ed5ce
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 0 deletions.
32 changes: 32 additions & 0 deletions rados/striper/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//go:build ceph_preview

package striper

/*
#include <errno.h>
*/
import "C"

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

// radosStriperError represents an error condition returned from the Ceph
// rados striper APIs.
type radosStriperError int

// Error returns the error string for the radosStriperError type.
func (e radosStriperError) Error() string {
return errutil.FormatErrorCode("rados", int(e))
}

func (e radosStriperError) ErrorCode() int {
return int(e)
}

func getError(e C.int) error {
if e == 0 {
return nil
}
return radosStriperError(e)
}
42 changes: 42 additions & 0 deletions rados/striper/read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//go:build ceph_preview

package striper

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <stdlib.h>
// #include <radosstriper/libradosstriper.h>
import "C"

import (
"unsafe"
)

// Read bytes into data from the striped object at the specified offset.
//
// Implements:
//
// int rados_striper_read(rados_striper_t striper,
// const char *soid,
// const char *buf,
// size_t len,
// uint64_t off);
func (s *Striper) Read(soid string, data []byte, offset uint64) (int, error) {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

var bufptr *C.char
if len(data) > 0 {
bufptr = (*C.char)(unsafe.Pointer(&data[0]))
}

ret := C.rados_striper_read(
s.striper,
csoid,
bufptr,
C.size_t(len(data)),
C.uint64_t(offset))
if ret >= 0 {
return int(ret), nil
}
return 0, getError(ret)
}
47 changes: 47 additions & 0 deletions rados/striper/stat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build (octopus || pacific || quincy) && ceph_preview

package striper

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <stdlib.h>
// #include <radosstriper/libradosstriper.h>
import "C"

import (
"unsafe"
)

// Stat returns metadata describing the striped object.
// This version of Stat uses an older API that does not provide time
// granularity below a second: the Nsec value of the StatInfo.ModTime field
// will always be zero.
//
// Implements:
//
// int rados_striper_stat(rados_striper_t striper,
// const char* soid,
// uint64_t *psize,
// time_t *pmtime);
func (s *Striper) Stat(soid string) (StatInfo, error) {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

var (
size C.uint64_t
mtime C.time_t
)
ret := C.rados_striper_stat(
s.striper,
csoid,
&size,
&mtime)

if ret < 0 {
return StatInfo{}, getError(ret)
}
modts := Timespec{Sec: int64(mtime)}
return StatInfo{
Size: uint64(size),
ModTime: modts,
}, nil
}
45 changes: 45 additions & 0 deletions rados/striper/stat2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//go:build !(octopus || pacific || quincy) && ceph_preview

package striper

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <stdlib.h>
// #include <radosstriper/libradosstriper.h>
import "C"

import (
"unsafe"

ts "github.com/ceph/go-ceph/internal/timespec"
)

// Stat returns metadata describing the striped object.
//
// Implements:
//
// int rados_striper_stat2(rados_striper_t striper,
// const char* soid,
// uint64_t *psize,
// struct timespec *pmtime);
func (s *Striper) Stat(soid string) (StatInfo, error) {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

var (
size C.uint64_t
mtime C.struct_timespec
)
ret := C.rados_striper_stat2(
s.striper,
csoid,
&size,
&mtime)

if ret < 0 {
return StatInfo{}, getError(ret)
}
return StatInfo{
Size: uint64(size),
ModTime: Timespec(ts.CStructToTimespec(ts.CTimespecPtr(&mtime))),
}, nil
}
16 changes: 16 additions & 0 deletions rados/striper/stat_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build ceph_preview

package striper

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

// Timespec behaves similarly to C's struct timespec.
type Timespec ts.Timespec

// StatInfo contains values returned by a Striper's Stat call.
type StatInfo struct {
Size uint64
ModTime Timespec
}
121 changes: 121 additions & 0 deletions rados/striper/striper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//go:build ceph_preview

package striper

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <errno.h>
// #include <stdlib.h>
// #include <radosstriper/libradosstriper.h>
import "C"

import (
"github.com/ceph/go-ceph/rados"
)

// Striper helps manage the reading, writing, and management of RADOS
// striped objects.
type Striper struct {
striper C.rados_striper_t

// Hold a reference back to the ioctx that the striper depends on so
// that Go doesn't garbage collect it prematurely.
ioctx *rados.IOContext
}

// Layout contains a group of values used to define the size parameters of
// striped objects. Note that these parameters only effect new striped objects.
// Existing striped objects retain the parameters they were created with.
type Layout struct {
StripeUnit uint
StripeCount uint
ObjectSize uint
}

// New returns a rados Striper object created from a rados IOContext.
func New(ioctx *rados.IOContext) (*Striper, error) {
var s C.rados_striper_t
ret := C.rados_striper_create(cephIoctx(ioctx), &s)
if err := getError(ret); err != nil {
return nil, err
}
return &Striper{s, ioctx}, nil
}

// NewWithLayout returns a rados Striper object created from a rados IOContext
// and striper layout parameters. These parameters will be used when new
// objects are created.
func NewWithLayout(ioctx *rados.IOContext, layout Layout) (*Striper, error) {
striper, err := New(ioctx)
if err != nil {
return nil, err
}
if err := striper.SetObjectLayoutStripeUnit(layout.StripeUnit); err != nil {
return nil, err
}
if err := striper.SetObjectLayoutStripeCount(layout.StripeCount); err != nil {
return nil, err
}
if err := striper.SetObjectLayoutObjectSize(layout.ObjectSize); err != nil {
return nil, err
}
return striper, nil
}

// Destroy the radosstriper object at the Ceph API level.
func (s *Striper) Destroy() {
C.rados_striper_destroy(s.striper)
}

// SetObjectLayoutStripeUnit sets the stripe unit value used to layout
// new objects.
//
// Implements:
//
// int rados_striper_set_object_layout_stripe_unit(rados_striper_t striper,
// unsigned int stripe_unit);
func (s *Striper) SetObjectLayoutStripeUnit(count uint) error {
ret := C.rados_striper_set_object_layout_stripe_unit(
s.striper,
C.uint(count),
)
return getError(ret)
}

// SetObjectLayoutStripeCount sets the stripe count value used to layout
// new objects.
//
// Implements:
//
// int rados_striper_set_object_layout_stripe_count(rados_striper_t striper,
// unsigned int stripe_count);
func (s *Striper) SetObjectLayoutStripeCount(count uint) error {
ret := C.rados_striper_set_object_layout_stripe_count(
s.striper,
C.uint(count),
)
return getError(ret)
}

// SetObjectLayoutObjectSize sets the object size value used to layout
// new objects.
//
// Implements:
//
// int rados_striper_set_object_layout_object_size(rados_striper_t striper,
// unsigned int object_size);
func (s *Striper) SetObjectLayoutObjectSize(count uint) error {
ret := C.rados_striper_set_object_layout_object_size(
s.striper,
C.uint(count),
)
return getError(ret)
}

// cephIoctx returns a ceph rados_ioctx_t given a go-ceph rados IOContext.
func cephIoctx(radosIoctx *rados.IOContext) C.rados_ioctx_t {
p := radosIoctx.Pointer()
if p == nil {
panic("invalid IOContext pointer")
}
return C.rados_ioctx_t(p)
}
Loading

0 comments on commit 33ed5ce

Please sign in to comment.