Skip to content

Commit 21934d9

Browse files
Rakshith-RiPraveenParihar
authored andcommitted
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. Co-authored-by: Praveen M <[email protected]> Signed-off-by: Rakshith R <[email protected]>
1 parent 18f6f20 commit 21934d9

File tree

4 files changed

+518
-0
lines changed

4 files changed

+518
-0
lines changed

cephfs/block_diff.go

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
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 lacks a definition, so create an alias and
17+
// treat it as opaque.
18+
typedef struct _ceph_file_blockdiff_result _ceph_file_blockdiff_result;
19+
20+
typedef struct
21+
{
22+
struct ceph_mount_info* cmount;
23+
struct _ceph_file_blockdiff_result* blockp;
24+
} _ceph_file_blockdiff_info;
25+
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+
"fmt"
98+
"sync"
99+
"unsafe"
100+
101+
"github.com/ceph/go-ceph/internal/dlsym"
102+
)
103+
104+
var (
105+
cephFileBlockDiffInitOnce sync.Once
106+
cephFileBlockDiffOnce sync.Once
107+
cephFreeFileBlockDiffBufferOnce sync.Once
108+
cephFileBlockDiffFinishOnce sync.Once
109+
110+
cephFileBlockDiffInitErr error
111+
cephFileBlockDiffErr error
112+
cephFreeFileBlockDiffBufferErr error
113+
cephFileBlockDiffFinishErr error
114+
115+
cephFileBlockDiffInit unsafe.Pointer
116+
cephFileBlockDiff unsafe.Pointer
117+
cephFreeFileBlockDiffBuffer unsafe.Pointer
118+
cephFileBlockDiffFinish unsafe.Pointer
119+
)
120+
121+
// FileBlockDiffInfo is a struct that holds the block diff stream handle.
122+
type FileBlockDiffInfo struct {
123+
cMount *MountInfo
124+
cephFileBlockDiffResult *C._ceph_file_blockdiff_result
125+
more bool
126+
}
127+
128+
// ChangedBlock is a struct that holds the offset and length of a block.
129+
type ChangedBlock struct {
130+
Offset uint64
131+
Len uint64
132+
}
133+
134+
// FileBlockDiffChangedBlocks is a struct that holds the number of blocks
135+
// and list of Changed Blocks.
136+
type FileBlockDiffChangedBlocks struct {
137+
NumBlocks uint64
138+
ChangedBlocks []ChangedBlock
139+
}
140+
141+
// FileBlockDiffInit initializes the block diff stream to get file block deltas.
142+
// It takes the mount handle, root path, relative path, snapshot names and returns
143+
// a FileBlockDiffInfo struct that contains the block diff stream handle.
144+
//
145+
// Implements:
146+
//
147+
// int ceph_file_blockdiff_init(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, errInvalid
157+
}
158+
cRootPath := C.CString(rootPath)
159+
cRelPath := C.CString(relPath)
160+
cSnap1 := C.CString(snap1)
161+
cSnap2 := C.CString(snap2)
162+
defer func() {
163+
C.free(unsafe.Pointer(cRootPath))
164+
C.free(unsafe.Pointer(cRelPath))
165+
C.free(unsafe.Pointer(cSnap1))
166+
C.free(unsafe.Pointer(cSnap2))
167+
}()
168+
169+
// Load the ceph_file_blockdiff_init function from the shared library.
170+
cephFileBlockDiffInitOnce.Do(func() {
171+
cephFileBlockDiffInit, cephFileBlockDiffInitErr = dlsym.LookupSymbol("ceph_file_blockdiff_init")
172+
})
173+
if cephFileBlockDiffInitErr != nil {
174+
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffInitErr)
175+
}
176+
177+
rawCephBlockDiffInfo := &C._ceph_file_blockdiff_info{}
178+
179+
// Call the ceph_file_blockdiff_init function with the provided arguments.
180+
ret := C.ceph_file_blockdiff_init_dlsym(cephFileBlockDiffInit,
181+
mount.mount,
182+
cRootPath,
183+
cRelPath,
184+
cSnap1,
185+
cSnap2,
186+
rawCephBlockDiffInfo,
187+
)
188+
if ret != 0 {
189+
return nil, getError(ret)
190+
}
191+
192+
mountInfo := &MountInfo{
193+
mount: rawCephBlockDiffInfo.cmount,
194+
}
195+
196+
cephFileBlockDiffInfo := &FileBlockDiffInfo{
197+
cMount: mountInfo,
198+
cephFileBlockDiffResult: rawCephBlockDiffInfo.blockp,
199+
more: true,
200+
}
201+
202+
return cephFileBlockDiffInfo, nil
203+
}
204+
205+
// validate checks if the FileBlockDiffInfo struct is valid.
206+
func (info *FileBlockDiffInfo) validate() error {
207+
if info.cMount == nil || info.cephFileBlockDiffResult == nil {
208+
return errInvalid
209+
}
210+
211+
return nil
212+
}
213+
214+
// Read retrieves the next set of changed blocks for a file.
215+
//
216+
// Implements:
217+
//
218+
// int ceph_file_blockdiff(struct ceph_file_blockdiff_info* info,
219+
// struct ceph_file_blockdiff_changedblocks* blocks);
220+
func (info *FileBlockDiffInfo) Read() (*FileBlockDiffChangedBlocks, error) {
221+
err := info.validate()
222+
if err != nil {
223+
return nil, err
224+
}
225+
226+
// Load the ceph_file_blockdiff function from the shared library.
227+
cephFileBlockDiffOnce.Do(func() {
228+
cephFileBlockDiff, cephFileBlockDiffErr = dlsym.LookupSymbol("ceph_file_blockdiff")
229+
})
230+
if cephFileBlockDiffErr != nil {
231+
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffErr)
232+
}
233+
cephFreeFileBlockDiffBufferOnce.Do(func() {
234+
cephFreeFileBlockDiffBuffer, cephFreeFileBlockDiffBufferErr = dlsym.LookupSymbol("ceph_free_file_blockdiff_buffer")
235+
})
236+
if cephFreeFileBlockDiffBufferErr != nil {
237+
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFreeFileBlockDiffBufferErr)
238+
}
239+
240+
rawCephBlockDiffChangedBlocks := &C._ceph_file_blockdiff_changedblocks{}
241+
rawCephFileBlockDiffInfo := &C._ceph_file_blockdiff_info{
242+
cmount: info.cMount.mount,
243+
blockp: info.cephFileBlockDiffResult,
244+
}
245+
246+
// Call the ceph_file_blockdiff function with the provided arguments.
247+
ret := C.ceph_file_blockdiff_dlsym(cephFileBlockDiff,
248+
rawCephFileBlockDiffInfo,
249+
rawCephBlockDiffChangedBlocks,
250+
)
251+
if ret < 0 {
252+
return nil, getError(ret)
253+
}
254+
// ret > 0 indicates that there are more entries after this call.
255+
info.more = (ret > 0)
256+
257+
// Free the memory allocated for the blocks by ceph_file_blockdiff.
258+
defer C.ceph_free_file_blockdiff_buffer_dlsym(cephFreeFileBlockDiffBuffer,
259+
rawCephBlockDiffChangedBlocks)
260+
261+
cNumBlocks := uint64(rawCephBlockDiffChangedBlocks.num_blocks)
262+
263+
// Convert the C struct to Go struct.
264+
cBlocks := make([]ChangedBlock, int(cNumBlocks))
265+
if cNumBlocks == 0 {
266+
return &FileBlockDiffChangedBlocks{
267+
NumBlocks: 0,
268+
ChangedBlocks: cBlocks,
269+
}, nil
270+
}
271+
272+
currentCBlock := (*C._cblock)(unsafe.Pointer(rawCephBlockDiffChangedBlocks.b))
273+
for i := uint64(0); i < cNumBlocks; i++ {
274+
cBlocks[i] = ChangedBlock{
275+
Offset: uint64(currentCBlock.offset),
276+
Len: uint64(currentCBlock.len),
277+
}
278+
currentCBlock = (*C._cblock)(unsafe.Pointer(uintptr(unsafe.Pointer(currentCBlock)) + unsafe.Sizeof(C._cblock{})))
279+
}
280+
281+
return &FileBlockDiffChangedBlocks{
282+
NumBlocks: cNumBlocks,
283+
ChangedBlocks: cBlocks,
284+
}, nil
285+
}
286+
287+
// More returns true if there are more entries to read in the block diff stream.
288+
func (info *FileBlockDiffInfo) More() bool {
289+
return info.more
290+
}
291+
292+
// Close closes the block diff stream.
293+
//
294+
// Implements:
295+
//
296+
// int ceph_file_blockdiff_finish(struct ceph_file_blockdiff_info* info);
297+
func (info *FileBlockDiffInfo) Close() error {
298+
err := info.validate()
299+
if err != nil {
300+
return err
301+
}
302+
303+
// Load the ceph_file_blockdiff_finish function from the shared library.
304+
cephFileBlockDiffFinishOnce.Do(func() {
305+
cephFileBlockDiffFinish, cephFileBlockDiffFinishErr = dlsym.LookupSymbol("ceph_file_blockdiff_finish")
306+
})
307+
if cephFileBlockDiffFinishErr != nil {
308+
return fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffFinishErr)
309+
}
310+
311+
rawCephFileBlockDiffInfo := &C._ceph_file_blockdiff_info{
312+
cmount: info.cMount.mount,
313+
blockp: info.cephFileBlockDiffResult,
314+
}
315+
316+
// Call the ceph_file_blockdiff_finish function with the provided arguments.
317+
ret := C.ceph_file_blockdiff_finish_dlsym(
318+
cephFileBlockDiffFinish,
319+
rawCephFileBlockDiffInfo,
320+
)
321+
if ret != 0 {
322+
return getError(ret)
323+
}
324+
325+
return nil
326+
}

0 commit comments

Comments
 (0)