Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rados: implement binding for rados_read_op_read #615

Merged
merged 1 commit into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/api-status.json
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,12 @@
"comment": "CmpExt ensures that given object range (extent) satisfies comparison.\n PREVIEW\n\nImplements:\n void rados_write_op_cmpext(rados_write_op_t write_op,\n const char * cmp_buf,\n size_t cmp_len,\n uint64_t off,\n int * prval);\n",
"added_in_version": "v0.12.0",
"expected_stable_version": "v0.14.0"
},
{
"name": "ReadOp.Read",
"comment": "Read bytes from offset into buffer.\nlen(buffer) is the maximum number of bytes read from the object.\nbuffer[:ReadOpReadStep.BytesRead] then contains object data.\n PREVIEW\n\nImplements:\n void rados_read_op_read(rados_read_op_t read_op,\n uint64_t offset,\n size_t len,\n char * buffer,\n size_t * bytes_read,\n int * prval)\n",
"added_in_version": "v0.14.0",
"expected_stable_version": "v0.16.0"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions docs/api-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Name | Added in Version | Expected Stable Version |
---- | ---------------- | ----------------------- |
WriteOp.CmpExt | v0.12.0 | v0.14.0 |
ReadOp.Read | v0.14.0 | v0.16.0 |

## Package: rbd

Expand Down
75 changes: 75 additions & 0 deletions rados/read_op_read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:build ceph_preview
// +build ceph_preview

package rados

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

import (
"unsafe"
)

// 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(C.sizeof_size_t)),
prval: (*C.int)(C.malloc(C.sizeof_int)),
}
}

// 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, 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_read_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, offset uint64) *readStep {
return &readStep{
b: b,
cBuffer: (*C.char)(unsafe.Pointer(&b[0])), // TODO: must be pinned
ansiwen marked this conversation as resolved.
Show resolved Hide resolved
cReadLen: C.size_t(len(b)),
cOffset: C.uint64_t(offset),
}
}