Skip to content

Commit

Permalink
rados: implement binding for rados_read_op_read
Browse files Browse the repository at this point in the history
This commit implements binding for rados_read_op_read RADOS Read operation.
Includes a unit test.

Signed-off-by: Robert Vasek <[email protected]>
  • Loading branch information
gman0 committed Dec 3, 2021
1 parent 20da1c6 commit b3de1a4
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 0 deletions.
77 changes: 77 additions & 0 deletions rados/read_op_preview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//go:build ceph_preview
// +build ceph_preview

package rados

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

import (
"unsafe"

"github.com/ceph/go-ceph/internal/cutil"
)

// ReadOpReadStep holds the result of the Read read operation.
// Result is valid only after Operate() was called.
type ReadOpReadStep struct {
// C returned data:
bytesRead *C.size_t
prval *C.int

BytesRead int64 // Bytes read by this action.
Result int // Result of this action.
}

func (s *ReadOpReadStep) update() error {
s.BytesRead = (int64)(*s.bytesRead)
s.Result = (int)(*s.prval)

return nil
}

func (s *ReadOpReadStep) free() {
C.free(unsafe.Pointer(s.bytesRead))
C.free(unsafe.Pointer(s.prval))

s.bytesRead = nil
s.prval = nil
}

func newReadOpReadStep() *ReadOpReadStep {
return &ReadOpReadStep{
bytesRead: (*C.size_t)(C.malloc(cutil.SizeTSize)),
prval: (*C.int)(C.malloc(cutil.IntSize)),
}
}

// Read bytes from offset into buffer.
// `len(buffer)` is the maximum number of bytes read from the object.
// `buffer[:ReadOpReadStep.BytesRead]` then contains object data.
// PREVIEW
//
// Implements:
// void rados_read_op_read(rados_read_op_t read_op,
// uint64_t offset,
// size_t len,
// char * buffer,
// size_t * bytes_read,
// int * prval)
func (r *ReadOp) Read(offset uint64, buffer []byte) *ReadOpReadStep {
oe := newReadStep(buffer, uint64(len(buffer)), offset)
readStep := newReadOpReadStep()
r.steps = append(r.steps, oe, readStep)
C.rados_read_op_read(
r.op,
oe.cOffset,
oe.cReadLen,
oe.cBuffer,
readStep.bytesRead,
readStep.prval,
)

return readStep
}
38 changes: 38 additions & 0 deletions rados/read_op_preview_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build ceph_preview
// +build ceph_preview

package rados

import (
"github.com/stretchr/testify/assert"
)

func (suite *RadosTestSuite) TestReadOpRead() {
suite.SetupConnection()
ta := assert.New(suite.T())

var (
oid = "TestReadOpRead"
data = []byte("data to read")
err error
)

// Create an object and populate it with data.
op1 := CreateWriteOp()
defer op1.Release()
op1.Create(CreateIdempotent)
op1.WriteFull(data)
err = op1.Operate(suite.ioctx, oid, OperationNoFlag)
ta.NoError(err)

// Read the object's contents and compare them with expected data.
readBuf := make([]byte, 64)
op2 := CreateReadOp()
defer op2.Release()
readOpRes := op2.Read(0, readBuf)
err = op2.Operate(suite.ioctx, oid, OperationNoFlag)
ta.NoError(err)
ta.Equal(int(0), readOpRes.Result)
ta.Equal(int64(len(data)), readOpRes.BytesRead)
ta.Equal(data, readBuf[:readOpRes.BytesRead])
}
31 changes: 31 additions & 0 deletions rados/read_step.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package rados

// #include <stdint.h>
import "C"

import (
"unsafe"
)

type readStep struct {
withoutUpdate
withoutFree
// the c pointer utilizes the Go byteslice data and no free is needed

// inputs:
b []byte

// arguments:
cBuffer *C.char
cReadLen C.size_t
cOffset C.uint64_t
}

func newReadStep(b []byte, readLen, offset uint64) *readStep {
return &readStep{
b: b,
cBuffer: (*C.char)(unsafe.Pointer(&b[0])), // TODO: must be pinned
cReadLen: C.size_t(readLen),
cOffset: C.uint64_t(offset),
}
}

0 comments on commit b3de1a4

Please sign in to comment.