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: ceph#1011

Signed-off-by: John Mulligan <jmulligan@redhat.com>
  • Loading branch information
phlogistonjohn committed Jul 29, 2024
1 parent e20ffbd commit 9331e1e
Show file tree
Hide file tree
Showing 4 changed files with 321 additions and 0 deletions.
33 changes: 33 additions & 0 deletions rados/striper/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//go:build ceph_preview
// +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)
}
84 changes: 84 additions & 0 deletions rados/striper/read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//go:build ceph_preview
// +build 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"
)

// 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)
}

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

type StriperStat struct {
Size uint64
ModTime 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) (StriperStat, 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 StriperStat{}, getError(ret)
}
return StriperStat{
Size: uint64(size),
ModTime: Timespec(ts.CStructToTimespec(ts.CTimespecPtr(&mtime))),
}, nil
}
97 changes: 97 additions & 0 deletions rados/striper/striper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//go:build ceph_preview
// +build ceph_preview

package striper

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

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

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 CG it prematurely.
ioctx *rados.IOContext
}

type StriperParams 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
}

// NewWithParams returns a rados Striper object created from a rados
// IOContext and striper parameters. These parameters will be used when
// new objects are created.
func NewWithParams(ioctx *rados.IOContext, params StriperParams) (*Striper, error) {
striper, err := New(ioctx)
if err != nil {
return nil, err
}
if err := striper.SetObjectLayoutStripeUnit(params.StripeUnit); err != nil {
return nil, err
}
if err := striper.SetObjectLayoutStripeCount(params.StripeCount); err != nil {
return nil, err
}
if err := striper.SetObjectLayoutObjectSize(params.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)
}

func (s *Striper) SetObjectLayoutStripeUnit(count uint) error {
ret := C.rados_striper_set_object_layout_stripe_unit(
s.striper,
C.uint(count),
)
return getError(ret)
}

func (s *Striper) SetObjectLayoutStripeCount(count uint) error {
ret := C.rados_striper_set_object_layout_stripe_count(
s.striper,
C.uint(count),
)
return getError(ret)
}

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)
}
107 changes: 107 additions & 0 deletions rados/striper/write.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//go:build ceph_preview
// +build ceph_preview

package striper

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

import "unsafe"

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

bufptr := (*C.char)(unsafe.Pointer(&data[0]))
ret := C.rados_striper_write(
s.striper,
csoid,
bufptr,
C.size_t(len(data)),
C.uint64_t(offset))
return getError(ret)
}

// WriteFull writes all of the bytes in data to the striped object, truncating
// the object to the length of data.
//
// Implements:
//
// int rados_striper_write_full(rados_striper_t striper,
// const char *soid,
// const char *buf,
// size_t len);
func (s *Striper) WriteFull(soid string, data []byte) error {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

bufptr := (*C.char)(unsafe.Pointer(&data[0]))
ret := C.rados_striper_write_full(
s.striper,
csoid,
bufptr,
C.size_t(len(data)))
return getError(ret)
}

// Append the bytes in data to the end of the striped object.
//
// Implements:
//
// int rados_striper_append(rados_striper_t striper,
// const char *soid,
// const char *buf,
// size_t len);
func (s *Striper) Append(soid string, data []byte) error {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

bufptr := (*C.char)(unsafe.Pointer(&data[0]))
ret := C.rados_striper_append(
s.striper,
csoid,
bufptr,
C.size_t(len(data)))
return getError(ret)
}

// Remove a striped RADOS object.
//
// Implements:
//
// int rados_striper_remove(rados_striper_t striper,
// const char *soid);
func (s *Striper) Remove(soid string) error {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

ret := C.rados_striper_remove(s.striper, csoid)
return getError(ret)
}

// Truncate a striped object, setting it to the specified size.
//
// Implements:
//
// int rados_striper_trunc(rados_striper_t striper, const char *soid, uint64_t size);
func (s *Striper) Truncate(soid string, size uint64) error {
csoid := C.CString(soid)
defer C.free(unsafe.Pointer(csoid))

ret := C.rados_striper_trunc(
s.striper,
csoid,
C.uint64_t(size))
return getError(ret)
}

0 comments on commit 9331e1e

Please sign in to comment.