rados: implement binding for rados_read_op_read

This commit implements binding for rados_read_op_read RADOS Read operation.
Includes a unit test.

Signed-off-by: Robert Vasek <robert.vasek@cern.ch>
This commit is contained in:
Robert Vasek 2021-12-03 10:14:58 +01:00 committed by John Mulligan
parent 0e3ed2982f
commit 937f8d8164
5 changed files with 151 additions and 0 deletions

View File

@ -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"
}
]
},

View File

@ -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

75
rados/read_op_read.go Normal file
View File

@ -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
}

View File

@ -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
rados/read_step.go Normal file
View File

@ -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
cReadLen: C.size_t(len(b)),
cOffset: C.uint64_t(offset),
}
}