Skip to content

Commit 242586b

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 f70e015 commit 242586b

File tree

4 files changed

+495
-0
lines changed

4 files changed

+495
-0
lines changed

cephfs/block_diff.go

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

0 commit comments

Comments
 (0)