Files
opencloud/vendor/github.com/ceph/go-ceph/cephfs/snap_diff.go
Jörn Friedrich Dreyer 8e30e535b0 bump reva and deps
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2026-01-07 17:15:23 +01:00

269 lines
7.7 KiB
Go

//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.
typedef struct {
struct dirent dir_entry;
uint64_t snapid;
} _ceph_snapdiff_entry_t;
typedef struct {
struct ceph_mount_info* cmount;
struct ceph_dir_result* dir1;
struct ceph_dir_result* dir_aux;
} _ceph_snapdiff_info;
// open_snapdiff_fn matches the open_snapdiff function signature.
typedef int(*open_snapdiff_fn)(struct ceph_mount_info* cmount,
const char* root_path,
const char* rel_path,
const char* snap1,
const char* snap2,
_ceph_snapdiff_info* out);
// open_snapdiff_dlsym take *fn as open_snapdiff_fn and calls the dynamically loaded
// open_snapdiff function passed as 1st argument.
static inline int open_snapdiff_dlsym(void *fn,
struct ceph_mount_info* cmount,
const char* root_path,
const char* rel_path,
const char* snap1,
const char* snap2,
_ceph_snapdiff_info* out) {
// cast function pointer fn to open_snapdiff and call the function
return ((open_snapdiff_fn) fn)(cmount, root_path, rel_path, snap1, snap2, out);
}
// readdir_snapdiff_fn matches the readdir_snapdiff function signature.
typedef int(*readdir_snapdiff_fn)(_ceph_snapdiff_info* snapdiff,
_ceph_snapdiff_entry_t* out);
// readdir_snapdiff_dlsym take *fn as readdir_snapdiff_fn and calls the dynamically loaded
// readdir_snapdiff function passed as 1st argument.
static inline int readdir_snapdiff_dlsym(void *fn,
_ceph_snapdiff_info* snapdiff,
_ceph_snapdiff_entry_t* out) {
// cast function pointer fn to readdir_snapdiff and call the function
return ((readdir_snapdiff_fn) fn)(snapdiff, out);
}
// close_snapdiff_fn matches the close_snapdiff function signature.
typedef int(*close_snapdiff_fn)(_ceph_snapdiff_info* snapdiff);
// close_snapdiff_dlsym take *fn as close_snapdiff_fn and calls the dynamically loaded
// close_snapdiff function passed as 1st argument.
static inline int close_snapdiff_dlsym(void *fn,
_ceph_snapdiff_info* snapdiff) {
// cast function pointer fn to close_snapdiff and call the function
return ((close_snapdiff_fn) fn)(snapdiff);
}
*/
import "C"
import (
"fmt"
"sync"
"unsafe"
"github.com/ceph/go-ceph/internal/dlsym"
)
var (
cephOpenSnapDiffOnce sync.Once
cephReaddirSnapDiffOnce sync.Once
cephCloseSnapDiffOnce sync.Once
cephOpenSnapDiff unsafe.Pointer
cephReaddirSnapDiff unsafe.Pointer
cephCloseSnapDiff unsafe.Pointer
cephOpenSnapDiffErr error
cephReaddirSnapDiffErr error
cephCloseSnapDiffErr error
)
// SnapDiffInfo is a handle to a snapshot diff API.
type SnapDiffInfo struct {
cMount *MountInfo
dir1 *Directory
dirAux *Directory
}
// SnapDiffEntry is a single entry in the snapshot diff.
// It contains a DirEntry and the ID of the snapshot to
// which the directory belongs.
type SnapDiffEntry struct {
DirEntry *DirEntry
SnapID uint64
}
// SnapDiffConfig is used to define the parameters of a open_snapdiff call.
// Snapshot Delta is generated between the passed snapshots snap1 and snap2.
// All fields must be specified before passing to OpenSnapDiff().
type SnapDiffConfig struct {
// CMount is the ceph mount handle that will be used for snap.diff retrieval.
CMount *MountInfo
// RootPath represents the root path for snapshots-in-question.
RootPath string
// RelPath is the subpath under the root to build delta for.
RelPath string
// Snap1 is the first snapshot name.
Snap1 string
// Snap2 is the second snapshot name.
Snap2 string
}
// OpenSnapDiff opens a snapshot diff stream to get snapshots delta
// and returns a SnapDiffInfo struct containing the diff information.
//
// Implements:
//
// int ceph_open_snapdiff(struct ceph_mount_info* cmount,
// const char* root_path,
// const char* rel_path,
// const char* snap1,
// const char* snap2,
// struct ceph_snapdiff_info* out);
func OpenSnapDiff(config SnapDiffConfig) (*SnapDiffInfo, error) {
if config.CMount == nil || config.RootPath == "" || config.RelPath == "" ||
config.Snap1 == "" || config.Snap2 == "" {
return nil, errInvalid
}
cephOpenSnapDiffOnce.Do(func() {
cephOpenSnapDiff, cephOpenSnapDiffErr = dlsym.LookupSymbol("ceph_open_snapdiff")
})
if cephOpenSnapDiffErr != nil {
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephOpenSnapDiffErr)
}
rawCephSnapDiffInfo := &C._ceph_snapdiff_info{}
ret := C.open_snapdiff_dlsym(
cephOpenSnapDiff,
config.CMount.mount,
C.CString(config.RootPath),
C.CString(config.RelPath),
C.CString(config.Snap1),
C.CString(config.Snap2),
rawCephSnapDiffInfo)
if ret != 0 {
return nil, getError(ret)
}
mountInfo := &MountInfo{
mount: rawCephSnapDiffInfo.cmount,
}
cephSnapDiffInfo := &SnapDiffInfo{
cMount: mountInfo,
dir1: &Directory{
mount: mountInfo,
dir: rawCephSnapDiffInfo.dir1,
},
dirAux: &Directory{
mount: mountInfo,
dir: rawCephSnapDiffInfo.dir_aux,
},
}
return cephSnapDiffInfo, nil
}
// validate checks that the SnapDiffInfo struct is valid.
func (info *SnapDiffInfo) validate() error {
if info.cMount == nil || info.dir1 == nil || info.dirAux == nil {
return errInvalid
}
return nil
}
// Readdir returns the next entry in the snapshot diff stream.
// If there are no more entries, it returns (nil, nil).
//
// Implements:
//
// int ceph_readdir_snapdiff(struct ceph_snapdiff_info* snapdiff,
// struct ceph_snapdiff_entry_t* out);
func (info *SnapDiffInfo) Readdir() (*SnapDiffEntry, error) {
if err := info.validate(); err != nil {
return nil, err
}
cephReaddirSnapDiffOnce.Do(func() {
cephReaddirSnapDiff, cephReaddirSnapDiffErr = dlsym.LookupSymbol("ceph_readdir_snapdiff")
})
if cephReaddirSnapDiffErr != nil {
return nil, fmt.Errorf("%w: %w", ErrNotImplemented, cephReaddirSnapDiffErr)
}
rawSnapDiffEntry := &C._ceph_snapdiff_entry_t{}
rawSnapDiffInfo := &C._ceph_snapdiff_info{
cmount: info.cMount.mount,
dir1: info.dir1.dir,
dir_aux: info.dirAux.dir,
}
ret := C.readdir_snapdiff_dlsym(
cephReaddirSnapDiff,
rawSnapDiffInfo,
rawSnapDiffEntry)
if ret < 0 {
return nil, getError(ret)
}
if ret == 0 {
// return 0 indicates there is not more entries to return.
return nil, nil
}
snapDiffEntry := &SnapDiffEntry{
DirEntry: toDirEntry(&rawSnapDiffEntry.dir_entry),
SnapID: uint64(rawSnapDiffEntry.snapid),
}
return snapDiffEntry, nil
}
// Close closes the snapshot diff handle.
//
// Implements:
//
// int ceph_close_snapdiff(struct ceph_snapdiff_info* snapdiff);
func (info *SnapDiffInfo) Close() error {
if err := info.validate(); err != nil {
return err
}
cephCloseSnapDiffOnce.Do(func() {
cephCloseSnapDiff, cephCloseSnapDiffErr = dlsym.LookupSymbol("ceph_close_snapdiff")
})
if cephCloseSnapDiffErr != nil {
return fmt.Errorf("%w: %w", ErrNotImplemented, cephCloseSnapDiffErr)
}
rawCephSnapDiffInfo := &C._ceph_snapdiff_info{
cmount: info.cMount.mount,
dir1: info.dir1.dir,
dir_aux: info.dirAux.dir,
}
ret := C.close_snapdiff_dlsym(
cephCloseSnapDiff,
rawCephSnapDiffInfo)
if ret != 0 {
return getError(ret)
}
return nil
}