Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+326
View File
@@ -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
)
// 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))
}()
// 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
}