Skip to content

Commit 47aa6ad

Browse files
cephfs: add support for cephfs file block diff api
This commit adds support for cephfs file block diff APIs which gives a list of changed blocks with in a file between two snapshots. Signed-off-by: Rakshith R <[email protected]> (cherry picked from commit 03e146b) Co-authored-by: Praveen M <[email protected]>
1 parent cdc15f4 commit 47aa6ad

File tree

4 files changed

+497
-0
lines changed

4 files changed

+497
-0
lines changed

cephfs/block_diff.go

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
//go:build ceph_preview
2+
3+
package cephfs
4+
5+
/*
6+
#cgo LDFLAGS: -lcephfs
7+
#cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64
8+
#include <stdlib.h>
9+
#include <dirent.h>
10+
#include <cephfs/libcephfs.h>
11+
12+
// Types and constants are copied from libcephfs.h with added "_" as prefix. This
13+
// prevents redefinition of the types on libcephfs versions that have them
14+
// already.
15+
16+
struct _ceph_file_blockdiff_result;
17+
18+
// blockdiff stream handle
19+
typedef struct
20+
{
21+
struct ceph_mount_info* cmount;
22+
struct _ceph_file_blockdiff_result* blockp;
23+
} _ceph_file_blockdiff_info;
24+
25+
// set of file block diff's
26+
typedef struct
27+
{
28+
uint64_t offset;
29+
uint64_t len;
30+
} _cblock;
31+
32+
typedef struct
33+
{
34+
uint64_t num_blocks;
35+
struct _cblock *b;
36+
} _ceph_file_blockdiff_changedblocks;
37+
38+
// ceph_file_blockdiff_init_fn matches the ceph_file_blockdiff_init function signature.
39+
typedef int(*ceph_file_blockdiff_init_fn)(struct ceph_mount_info* cmount,
40+
const char* root_path,
41+
const char* rel_path,
42+
const char* snap1,
43+
const char* snap2,
44+
_ceph_file_blockdiff_info* out_info);
45+
46+
// ceph_file_blockdiff_init_dlsym take *fn as ceph_file_blockdiff_init and calls the dynamically loaded
47+
// ceph_file_blockdiff_init function passed as 1st argument.
48+
static inline int ceph_file_blockdiff_init_dlsym(void *fn,
49+
struct ceph_mount_info* cmount,
50+
const char* root_path,
51+
const char* rel_path,
52+
const char* snap1,
53+
const char* snap2,
54+
_ceph_file_blockdiff_info* out_info) {
55+
// cast function pointer fn to ceph_file_blockdiff_init and call the function
56+
return ((ceph_file_blockdiff_init_fn) fn)(cmount, root_path, rel_path, snap1, snap2, out_info);
57+
}
58+
59+
// ceph_file_blockdiff_fn matches the ceph_file_blockdiff function signature.
60+
typedef int(*ceph_file_blockdiff_fn)(_ceph_file_blockdiff_info* info,
61+
_ceph_file_blockdiff_changedblocks* blocks);
62+
63+
// ceph_file_blockdiff_dlsym take *fn as ceph_file_blockdiff and calls the dynamically loaded
64+
// ceph_file_blockdiff function passed as 1st argument.
65+
static inline int ceph_file_blockdiff_dlsym(void *fn,
66+
_ceph_file_blockdiff_info* info,
67+
_ceph_file_blockdiff_changedblocks* blocks) {
68+
// cast function pointer fn to ceph_file_blockdiff and call the function
69+
return ((ceph_file_blockdiff_fn) fn)(info, blocks);
70+
}
71+
72+
// ceph_free_file_blockdiff_buffer_fn matches the ceph_free_file_blockdiff_buffer function signature.
73+
typedef void(*ceph_free_file_blockdiff_buffer_fn)(_ceph_file_blockdiff_changedblocks* blocks);
74+
75+
// ceph_free_file_blockdiff_buffer_dlsym take *fn as ceph_free_file_blockdiff_buffer and calls the dynamically loaded
76+
// ceph_free_file_blockdiff_buffer function passed as 1st argument.
77+
static inline void ceph_free_file_blockdiff_buffer_dlsym(void *fn,
78+
_ceph_file_blockdiff_changedblocks* blocks) {
79+
// cast function pointer fn to ceph_free_file_blockdiff_buffer and call the function
80+
((ceph_free_file_blockdiff_buffer_fn) fn)(blocks);
81+
}
82+
83+
// ceph_file_blockdiff_finish_fn matches the ceph_file_blockdiff_finish function signature.
84+
typedef int(*ceph_file_blockdiff_finish_fn)(_ceph_file_blockdiff_info* info);
85+
86+
// ceph_file_blockdiff_finish_dlsym take *fn as ceph_file_blockdiff_finish and calls the dynamically loaded
87+
// ceph_file_blockdiff_finish function passed as 1st argument.
88+
static inline int ceph_file_blockdiff_finish_dlsym(void *fn,
89+
_ceph_file_blockdiff_info* info) {
90+
// cast function pointer fn to ceph_file_blockdiff_finish and call the function
91+
return ((ceph_file_blockdiff_finish_fn) fn)(info);
92+
}
93+
*/
94+
import "C"
95+
96+
import (
97+
"errors"
98+
"fmt"
99+
"sync"
100+
"unsafe"
101+
102+
"github.com/ceph/go-ceph/internal/dlsym"
103+
)
104+
105+
var (
106+
cephFileBlockDiffInitOnce sync.Once
107+
cephFileBlockDiffOnce sync.Once
108+
cephFreeFileBlockDiffBufferOnce sync.Once
109+
cephFileBlockDiffFinishOnce sync.Once
110+
111+
cephFileBlockDiffInitErr error
112+
cephFileBlockDiffErr error
113+
cephFreeFileBlockDiffBufferErr error
114+
cephFileBlockDiffFinishErr error
115+
116+
cephFileBlockDiffInit unsafe.Pointer
117+
cephFileBlockDiff unsafe.Pointer
118+
cephFreeFileBlockDiffBuffer unsafe.Pointer
119+
cephFileBlockDiffFinish unsafe.Pointer
120+
)
121+
122+
// FileBlockDiffInfo is a struct that holds the block diff stream handle.
123+
type FileBlockDiffInfo struct {
124+
cephFileBlockDiffInfo *C._ceph_file_blockdiff_info
125+
}
126+
127+
// CBlock is a struct that holds the offset and length of a block.
128+
type CBlock struct {
129+
Offset uint64
130+
Len uint64
131+
}
132+
133+
// FileBlockDiffChangedBlocks is a struct that holds the number of blocks
134+
// and list of Changed Blocks.
135+
type FileBlockDiffChangedBlocks struct {
136+
NumBlocks uint64
137+
CBlocks []CBlock
138+
}
139+
140+
// FileBlockDiffInit initializes the block diff stream to get file block deltas.
141+
// It takes the mount handle, root path, relative path, snapshot names and returns
142+
// a FileBlockDiffInfo struct that contains the block diff stream handle.
143+
//
144+
// Implements:
145+
//
146+
// int ceph_file_blockdiff_init(
147+
// struct ceph_mount_info* cmount,
148+
// const char* root_path,
149+
// const char* rel_path,
150+
// const char* snap1,
151+
// const char* snap2,
152+
// struct ceph_file_blockdiff_info* out_info);
153+
func FileBlockDiffInit(mount *MountInfo, rootPath, relPath, snap1, snap2 string) (*FileBlockDiffInfo, error) {
154+
if mount == nil || rootPath == "" || relPath == "" ||
155+
snap1 == "" || snap2 == "" {
156+
return nil, errors.New("invalid argument: mount, rootPath, relPath, snap1 and snap2 must be non-empty")
157+
}
158+
cRootPath := C.CString(rootPath)
159+
cRelPath := C.CString(relPath)
160+
cSnap1 := C.CString(snap1)
161+
cSnap2 := C.CString(snap2)
162+
163+
// Load the ceph_file_blockdiff_init function from the shared library.
164+
cephFileBlockDiffInitOnce.Do(func() {
165+
cephFileBlockDiffInit, cephFileBlockDiffInitErr = dlsym.LookupSymbol("ceph_file_blockdiff_init")
166+
})
167+
if cephFileBlockDiffInitErr != nil {
168+
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffInitErr)
169+
}
170+
171+
rawCephBlockDiffInfo := &C._ceph_file_blockdiff_info{}
172+
173+
// Call the ceph_file_blockdiff_init function with the provided arguments.
174+
ret := C.ceph_file_blockdiff_init_dlsym(cephFileBlockDiffInit,
175+
mount.mount,
176+
cRootPath,
177+
cRelPath,
178+
cSnap1,
179+
cSnap2,
180+
rawCephBlockDiffInfo,
181+
)
182+
if ret != 0 {
183+
return nil, getError(ret)
184+
}
185+
186+
cephFileBlockDiffInfo := &FileBlockDiffInfo{
187+
cephFileBlockDiffInfo: rawCephBlockDiffInfo,
188+
}
189+
190+
return cephFileBlockDiffInfo, nil
191+
}
192+
193+
// validate checks if the FileBlockDiffInfo struct is valid.
194+
func (info *FileBlockDiffInfo) validate() error {
195+
if info.cephFileBlockDiffInfo == nil {
196+
return errInvalid
197+
}
198+
199+
return nil
200+
}
201+
202+
// ReadFileBlockDiff retrieves the next set of file block diffs.
203+
// It returns
204+
// - a boolean which is set to true if there are no more
205+
// entries after this call
206+
// - a FileBlockDiffChangedBlocks struct that contains
207+
// the number of blocks and list of CBlocks.
208+
// - and a error if any.
209+
//
210+
// Implements:
211+
//
212+
// int ceph_file_blockdiff(struct ceph_file_blockdiff_info* info,
213+
// struct ceph_file_blockdiff_changedblocks* blocks);
214+
func (info *FileBlockDiffInfo) ReadFileBlockDiff() (bool, *FileBlockDiffChangedBlocks, error) {
215+
err := info.validate()
216+
if err != nil {
217+
return false, nil, err
218+
}
219+
220+
noMoreEntries := false
221+
// Load the ceph_file_blockdiff function from the shared library.
222+
cephFileBlockDiffOnce.Do(func() {
223+
cephFileBlockDiff, cephFileBlockDiffErr = dlsym.LookupSymbol("ceph_file_blockdiff")
224+
})
225+
if cephFileBlockDiffErr != nil {
226+
return false, nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffErr)
227+
}
228+
cephFreeFileBlockDiffBufferOnce.Do(func() {
229+
cephFreeFileBlockDiffBuffer, cephFreeFileBlockDiffBufferErr = dlsym.LookupSymbol("ceph_free_file_blockdiff_buffer")
230+
})
231+
if cephFreeFileBlockDiffBufferErr != nil {
232+
return false, nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFreeFileBlockDiffBufferErr)
233+
}
234+
235+
// rawCBlocks := make([]C.struct_cblock{}, 0)
236+
rawCephBlockDiffChangedBlocks := &C._ceph_file_blockdiff_changedblocks{}
237+
238+
// Call the ceph_file_blockdiff function with the provided arguments.
239+
ret := C.ceph_file_blockdiff_dlsym(cephFileBlockDiff,
240+
info.cephFileBlockDiffInfo,
241+
rawCephBlockDiffChangedBlocks,
242+
)
243+
if ret < 0 {
244+
return false, nil, getError(ret)
245+
}
246+
// if ret == 0 indicates there is no more entries after this call.
247+
noMoreEntries = (ret == 0)
248+
249+
// Free the memory allocated for the blocks by ceph_file_blockdiff.
250+
defer C.ceph_free_file_blockdiff_buffer_dlsym(cephFreeFileBlockDiffBuffer,
251+
rawCephBlockDiffChangedBlocks)
252+
253+
// Convert the C struct to Go struct.
254+
cBlocks := make([]CBlock, rawCephBlockDiffChangedBlocks.num_blocks)
255+
if rawCephBlockDiffChangedBlocks.num_blocks == 0 {
256+
return noMoreEntries,
257+
&FileBlockDiffChangedBlocks{
258+
NumBlocks: 0,
259+
CBlocks: cBlocks,
260+
}, nil
261+
}
262+
263+
currentCBlock := (*C._cblock)(unsafe.Pointer(rawCephBlockDiffChangedBlocks.b))
264+
for i := uint64(0); i < uint64(rawCephBlockDiffChangedBlocks.num_blocks); i++ {
265+
cBlocks[i] = CBlock{
266+
Offset: uint64(currentCBlock.offset),
267+
Len: uint64(currentCBlock.len),
268+
}
269+
currentCBlock = (*C._cblock)(unsafe.Pointer(uintptr(unsafe.Pointer(currentCBlock)) + unsafe.Sizeof(C._cblock{})))
270+
}
271+
272+
return noMoreEntries,
273+
&FileBlockDiffChangedBlocks{
274+
NumBlocks: uint64(rawCephBlockDiffChangedBlocks.num_blocks),
275+
CBlocks: cBlocks,
276+
}, nil
277+
}
278+
279+
// Close closes the block diff stream.
280+
//
281+
// Implements:
282+
//
283+
// int ceph_file_blockdiff_finish(struct ceph_file_blockdiff_info* info);
284+
func (info *FileBlockDiffInfo) Close() error {
285+
err := info.validate()
286+
if err != nil {
287+
return err
288+
}
289+
290+
// Load the ceph_file_blockdiff_finish function from the shared library.
291+
cephFileBlockDiffFinishOnce.Do(func() {
292+
cephFileBlockDiffFinish, cephFileBlockDiffFinishErr = dlsym.LookupSymbol("ceph_file_blockdiff_finish")
293+
})
294+
if cephFileBlockDiffFinishErr != nil {
295+
return fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffFinishErr)
296+
}
297+
298+
// Call the ceph_file_blockdiff_finish function with the provided arguments.
299+
ret := C.ceph_file_blockdiff_finish_dlsym(
300+
cephFileBlockDiffFinish,
301+
info.cephFileBlockDiffInfo,
302+
)
303+
if ret != 0 {
304+
return getError(ret)
305+
}
306+
307+
return nil
308+
}

0 commit comments

Comments
 (0)