-
Notifications
You must be signed in to change notification settings - Fork 282
cephfs: add support for cephfs file block diff api #1191
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,326 @@ | ||
| //go:build ceph_preview | ||
|
|
||
| package cephfs | ||
|
|
||
| /* | ||
| #cgo LDFLAGS: -lcephfs | ||
| #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 | ||
| #include <stdlib.h> | ||
| #include <dirent.h> | ||
| #include <cephfs/libcephfs.h> | ||
|
|
||
| // Types and constants are copied from libcephfs.h with added "_" as prefix. This | ||
| // prevents redefinition of the types on libcephfs versions that have them | ||
| // already. | ||
|
|
||
| // struct ceph_file_blockdiff_result lacks a definition, so create an alias and | ||
| // treat it as opaque. | ||
| typedef struct _ceph_file_blockdiff_result _ceph_file_blockdiff_result; | ||
|
|
||
| typedef struct | ||
| { | ||
| struct ceph_mount_info* cmount; | ||
| struct _ceph_file_blockdiff_result* blockp; | ||
| } _ceph_file_blockdiff_info; | ||
|
|
||
| typedef struct | ||
| { | ||
| uint64_t offset; | ||
| uint64_t len; | ||
| } _cblock; | ||
|
|
||
| typedef struct | ||
| { | ||
| uint64_t num_blocks; | ||
| struct _cblock *b; | ||
| } _ceph_file_blockdiff_changedblocks; | ||
|
|
||
| // ceph_file_blockdiff_init_fn matches the ceph_file_blockdiff_init function signature. | ||
| typedef int(*ceph_file_blockdiff_init_fn)(struct ceph_mount_info* cmount, | ||
| const char* root_path, | ||
| const char* rel_path, | ||
| const char* snap1, | ||
| const char* snap2, | ||
| _ceph_file_blockdiff_info* out_info); | ||
|
|
||
| // ceph_file_blockdiff_init_dlsym take *fn as ceph_file_blockdiff_init and calls the dynamically loaded | ||
| // ceph_file_blockdiff_init function passed as 1st argument. | ||
| static inline int ceph_file_blockdiff_init_dlsym(void *fn, | ||
| struct ceph_mount_info* cmount, | ||
| const char* root_path, | ||
| const char* rel_path, | ||
| const char* snap1, | ||
| const char* snap2, | ||
| _ceph_file_blockdiff_info* out_info) { | ||
| // cast function pointer fn to ceph_file_blockdiff_init and call the function | ||
| return ((ceph_file_blockdiff_init_fn) fn)(cmount, root_path, rel_path, snap1, snap2, out_info); | ||
| } | ||
|
|
||
| // ceph_file_blockdiff_fn matches the ceph_file_blockdiff function signature. | ||
| typedef int(*ceph_file_blockdiff_fn)(_ceph_file_blockdiff_info* info, | ||
| _ceph_file_blockdiff_changedblocks* blocks); | ||
|
|
||
| // ceph_file_blockdiff_dlsym take *fn as ceph_file_blockdiff and calls the dynamically loaded | ||
| // ceph_file_blockdiff function passed as 1st argument. | ||
| static inline int ceph_file_blockdiff_dlsym(void *fn, | ||
| _ceph_file_blockdiff_info* info, | ||
| _ceph_file_blockdiff_changedblocks* blocks) { | ||
| // cast function pointer fn to ceph_file_blockdiff and call the function | ||
| return ((ceph_file_blockdiff_fn) fn)(info, blocks); | ||
| } | ||
|
|
||
| // ceph_free_file_blockdiff_buffer_fn matches the ceph_free_file_blockdiff_buffer function signature. | ||
| typedef void(*ceph_free_file_blockdiff_buffer_fn)(_ceph_file_blockdiff_changedblocks* blocks); | ||
|
|
||
| // ceph_free_file_blockdiff_buffer_dlsym take *fn as ceph_free_file_blockdiff_buffer and calls the dynamically loaded | ||
| // ceph_free_file_blockdiff_buffer function passed as 1st argument. | ||
| static inline void ceph_free_file_blockdiff_buffer_dlsym(void *fn, | ||
| _ceph_file_blockdiff_changedblocks* blocks) { | ||
| // cast function pointer fn to ceph_free_file_blockdiff_buffer and call the function | ||
| ((ceph_free_file_blockdiff_buffer_fn) fn)(blocks); | ||
| } | ||
|
|
||
| // ceph_file_blockdiff_finish_fn matches the ceph_file_blockdiff_finish function signature. | ||
| typedef int(*ceph_file_blockdiff_finish_fn)(_ceph_file_blockdiff_info* info); | ||
|
|
||
| // ceph_file_blockdiff_finish_dlsym take *fn as ceph_file_blockdiff_finish and calls the dynamically loaded | ||
| // ceph_file_blockdiff_finish function passed as 1st argument. | ||
| static inline int ceph_file_blockdiff_finish_dlsym(void *fn, | ||
| _ceph_file_blockdiff_info* info) { | ||
| // cast function pointer fn to ceph_file_blockdiff_finish and call the function | ||
| return ((ceph_file_blockdiff_finish_fn) fn)(info); | ||
| } | ||
| */ | ||
| import "C" | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sync" | ||
| "unsafe" | ||
|
|
||
| "github.com/ceph/go-ceph/internal/dlsym" | ||
| ) | ||
|
|
||
| var ( | ||
| cephFileBlockDiffInitOnce sync.Once | ||
| cephFileBlockDiffOnce sync.Once | ||
| cephFreeFileBlockDiffBufferOnce sync.Once | ||
| cephFileBlockDiffFinishOnce sync.Once | ||
|
|
||
| cephFileBlockDiffInitErr error | ||
| cephFileBlockDiffErr error | ||
| cephFreeFileBlockDiffBufferErr error | ||
| cephFileBlockDiffFinishErr error | ||
|
|
||
| cephFileBlockDiffInit unsafe.Pointer | ||
| cephFileBlockDiff unsafe.Pointer | ||
| cephFreeFileBlockDiffBuffer unsafe.Pointer | ||
| cephFileBlockDiffFinish unsafe.Pointer | ||
anoopcs9 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| // FileBlockDiffInfo is a struct that holds the block diff stream handle. | ||
| type FileBlockDiffInfo struct { | ||
| cMount *MountInfo | ||
| cephFileBlockDiffResult *C._ceph_file_blockdiff_result | ||
| more bool | ||
| } | ||
|
|
||
| // ChangedBlock is a struct that holds the offset and length of a block. | ||
| type ChangedBlock struct { | ||
| Offset uint64 | ||
| Len uint64 | ||
| } | ||
|
|
||
| // FileBlockDiffChangedBlocks is a struct that holds the number of blocks | ||
| // and list of Changed Blocks. | ||
| type FileBlockDiffChangedBlocks struct { | ||
| NumBlocks uint64 | ||
| ChangedBlocks []ChangedBlock | ||
| } | ||
|
|
||
| // FileBlockDiffInit initializes the block diff stream to get file block deltas. | ||
| // It takes the mount handle, root path, relative path, snapshot names and returns | ||
| // a FileBlockDiffInfo struct that contains the block diff stream handle. | ||
| // | ||
| // Implements: | ||
| // | ||
| // int ceph_file_blockdiff_init(struct ceph_mount_info* cmount, | ||
| // const char* root_path, | ||
| // const char* rel_path, | ||
| // const char* snap1, | ||
| // const char* snap2, | ||
| // struct ceph_file_blockdiff_info* out_info); | ||
| func FileBlockDiffInit(mount *MountInfo, rootPath, relPath, snap1, snap2 string) (*FileBlockDiffInfo, error) { | ||
| if mount == nil || rootPath == "" || relPath == "" || | ||
| snap1 == "" || snap2 == "" { | ||
| return nil, errInvalid | ||
| } | ||
| cRootPath := C.CString(rootPath) | ||
| cRelPath := C.CString(relPath) | ||
| cSnap1 := C.CString(snap1) | ||
| cSnap2 := C.CString(snap2) | ||
| defer func() { | ||
| C.free(unsafe.Pointer(cRootPath)) | ||
| C.free(unsafe.Pointer(cRelPath)) | ||
| C.free(unsafe.Pointer(cSnap1)) | ||
| C.free(unsafe.Pointer(cSnap2)) | ||
| }() | ||
|
|
||
anoopcs9 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Load the ceph_file_blockdiff_init function from the shared library. | ||
| cephFileBlockDiffInitOnce.Do(func() { | ||
| cephFileBlockDiffInit, cephFileBlockDiffInitErr = dlsym.LookupSymbol("ceph_file_blockdiff_init") | ||
| }) | ||
| if cephFileBlockDiffInitErr != nil { | ||
| return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffInitErr) | ||
| } | ||
|
|
||
| rawCephBlockDiffInfo := &C._ceph_file_blockdiff_info{} | ||
|
|
||
| // Call the ceph_file_blockdiff_init function with the provided arguments. | ||
| ret := C.ceph_file_blockdiff_init_dlsym(cephFileBlockDiffInit, | ||
| mount.mount, | ||
| cRootPath, | ||
| cRelPath, | ||
| cSnap1, | ||
| cSnap2, | ||
| rawCephBlockDiffInfo, | ||
| ) | ||
| if ret != 0 { | ||
| return nil, getError(ret) | ||
| } | ||
|
|
||
| mountInfo := &MountInfo{ | ||
| mount: rawCephBlockDiffInfo.cmount, | ||
| } | ||
|
|
||
| cephFileBlockDiffInfo := &FileBlockDiffInfo{ | ||
| cMount: mountInfo, | ||
| cephFileBlockDiffResult: rawCephBlockDiffInfo.blockp, | ||
| more: true, | ||
| } | ||
|
|
||
| return cephFileBlockDiffInfo, nil | ||
| } | ||
|
|
||
| // validate checks if the FileBlockDiffInfo struct is valid. | ||
| func (info *FileBlockDiffInfo) validate() error { | ||
| if info.cMount == nil || info.cephFileBlockDiffResult == nil { | ||
| return errInvalid | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Read retrieves the next set of changed blocks for a file. | ||
| // | ||
| // Implements: | ||
| // | ||
| // int ceph_file_blockdiff(struct ceph_file_blockdiff_info* info, | ||
| // struct ceph_file_blockdiff_changedblocks* blocks); | ||
| func (info *FileBlockDiffInfo) Read() (*FileBlockDiffChangedBlocks, error) { | ||
| err := info.validate() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| // Load the ceph_file_blockdiff function from the shared library. | ||
| cephFileBlockDiffOnce.Do(func() { | ||
| cephFileBlockDiff, cephFileBlockDiffErr = dlsym.LookupSymbol("ceph_file_blockdiff") | ||
| }) | ||
| if cephFileBlockDiffErr != nil { | ||
| return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffErr) | ||
| } | ||
| cephFreeFileBlockDiffBufferOnce.Do(func() { | ||
| cephFreeFileBlockDiffBuffer, cephFreeFileBlockDiffBufferErr = dlsym.LookupSymbol("ceph_free_file_blockdiff_buffer") | ||
| }) | ||
| if cephFreeFileBlockDiffBufferErr != nil { | ||
| return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephFreeFileBlockDiffBufferErr) | ||
| } | ||
|
|
||
| rawCephBlockDiffChangedBlocks := &C._ceph_file_blockdiff_changedblocks{} | ||
| rawCephFileBlockDiffInfo := &C._ceph_file_blockdiff_info{ | ||
| cmount: info.cMount.mount, | ||
| blockp: info.cephFileBlockDiffResult, | ||
| } | ||
|
|
||
| // Call the ceph_file_blockdiff function with the provided arguments. | ||
| ret := C.ceph_file_blockdiff_dlsym(cephFileBlockDiff, | ||
| rawCephFileBlockDiffInfo, | ||
| rawCephBlockDiffChangedBlocks, | ||
| ) | ||
| if ret < 0 { | ||
| return nil, getError(ret) | ||
| } | ||
| // ret > 0 indicates that there are more entries after this call. | ||
| info.more = (ret > 0) | ||
|
|
||
| // Free the memory allocated for the blocks by ceph_file_blockdiff. | ||
| defer C.ceph_free_file_blockdiff_buffer_dlsym(cephFreeFileBlockDiffBuffer, | ||
| rawCephBlockDiffChangedBlocks) | ||
|
|
||
| cNumBlocks := uint64(rawCephBlockDiffChangedBlocks.num_blocks) | ||
|
|
||
| // Convert the C struct to Go struct. | ||
| cBlocks := make([]ChangedBlock, int(cNumBlocks)) | ||
| if cNumBlocks == 0 { | ||
| return &FileBlockDiffChangedBlocks{ | ||
| NumBlocks: 0, | ||
| ChangedBlocks: cBlocks, | ||
| }, nil | ||
| } | ||
|
|
||
| currentCBlock := (*C._cblock)(unsafe.Pointer(rawCephBlockDiffChangedBlocks.b)) | ||
| for i := uint64(0); i < cNumBlocks; i++ { | ||
| cBlocks[i] = ChangedBlock{ | ||
| Offset: uint64(currentCBlock.offset), | ||
| Len: uint64(currentCBlock.len), | ||
| } | ||
| currentCBlock = (*C._cblock)(unsafe.Pointer(uintptr(unsafe.Pointer(currentCBlock)) + unsafe.Sizeof(C._cblock{}))) | ||
| } | ||
|
|
||
| return &FileBlockDiffChangedBlocks{ | ||
| NumBlocks: cNumBlocks, | ||
| ChangedBlocks: cBlocks, | ||
| }, nil | ||
| } | ||
|
|
||
| // More returns true if there are more entries to read in the block diff stream. | ||
| func (info *FileBlockDiffInfo) More() bool { | ||
| return info.more | ||
| } | ||
|
|
||
| // Close closes the block diff stream. | ||
| // | ||
| // Implements: | ||
| // | ||
| // int ceph_file_blockdiff_finish(struct ceph_file_blockdiff_info* info); | ||
| func (info *FileBlockDiffInfo) Close() error { | ||
| err := info.validate() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // Load the ceph_file_blockdiff_finish function from the shared library. | ||
| cephFileBlockDiffFinishOnce.Do(func() { | ||
| cephFileBlockDiffFinish, cephFileBlockDiffFinishErr = dlsym.LookupSymbol("ceph_file_blockdiff_finish") | ||
| }) | ||
| if cephFileBlockDiffFinishErr != nil { | ||
| return fmt.Errorf("%w: %w", ErrNotImplemented, cephFileBlockDiffFinishErr) | ||
| } | ||
|
|
||
| rawCephFileBlockDiffInfo := &C._ceph_file_blockdiff_info{ | ||
| cmount: info.cMount.mount, | ||
| blockp: info.cephFileBlockDiffResult, | ||
| } | ||
|
|
||
| // Call the ceph_file_blockdiff_finish function with the provided arguments. | ||
| ret := C.ceph_file_blockdiff_finish_dlsym( | ||
| cephFileBlockDiffFinish, | ||
| rawCephFileBlockDiffInfo, | ||
| ) | ||
| if ret != 0 { | ||
| return getError(ret) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.