mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-20 06:54:28 +00:00
WIP
This commit is contained in:
+343
-342
@@ -18,454 +18,455 @@ package restore
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const batchSize = 1000
|
const batchSize = 1000
|
||||||
const bufSize = 2 * 1024 * 1024
|
const bufSize = 2 * 1024 * 1024
|
||||||
|
|
||||||
type WorkerWriter struct {
|
type WorkerWriter struct {
|
||||||
writer *C.struct_scoutfs_parallel_restore_writer
|
writer *C.struct_scoutfs_parallel_restore_writer
|
||||||
progressCh chan *ScoutfsParallelWriterProgress
|
progressCh chan *ScoutfsParallelWriterProgress
|
||||||
fileCreated int64
|
fileCreated int64
|
||||||
devFd int
|
devFd int
|
||||||
buf unsafe.Pointer
|
buf unsafe.Pointer
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
type MasterWriter struct {
|
type MasterWriter struct {
|
||||||
writer *C.struct_scoutfs_parallel_restore_writer
|
writer *C.struct_scoutfs_parallel_restore_writer
|
||||||
progressCh chan *ScoutfsParallelWriterProgress
|
progressCh chan *ScoutfsParallelWriterProgress
|
||||||
workers []*WorkerWriter
|
workers []*WorkerWriter
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
slice *C.struct_scoutfs_parallel_restore_slice // Add slice field
|
slice *C.struct_scoutfs_parallel_restore_slice // Add slice field
|
||||||
progressWg sync.WaitGroup
|
progressWg sync.WaitGroup
|
||||||
devFd int
|
devFd int
|
||||||
super *C.struct_scoutfs_super_block
|
super *C.struct_scoutfs_super_block
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScoutfsParallelWriterProgress struct {
|
type ScoutfsParallelWriterProgress struct {
|
||||||
Progress *C.struct_scoutfs_parallel_restore_progress
|
Progress *C.struct_scoutfs_parallel_restore_progress
|
||||||
Slice *C.struct_scoutfs_parallel_restore_slice
|
Slice *C.struct_scoutfs_parallel_restore_slice
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MasterWriter) aggregateProgress() {
|
func (m *MasterWriter) aggregateProgress() {
|
||||||
defer m.progressWg.Done()
|
defer m.progressWg.Done()
|
||||||
for progress := range m.progressCh {
|
for progress := range m.progressCh {
|
||||||
ret := C.scoutfs_parallel_restore_add_progress(m.writer, progress.Progress)
|
ret := C.scoutfs_parallel_restore_add_progress(m.writer, progress.Progress)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
// Handle error appropriately, e.g., log it
|
// Handle error appropriately, e.g., log it
|
||||||
fmt.Printf("Failed to add progress, error code: %d\n", ret)
|
fmt.Printf("Failed to add progress, error code: %d\n", ret)
|
||||||
}
|
}
|
||||||
if progress.Slice != nil {
|
if progress.Slice != nil {
|
||||||
ret = C.scoutfs_parallel_restore_add_slice(m.writer, progress.Slice)
|
ret = C.scoutfs_parallel_restore_add_slice(m.writer, progress.Slice)
|
||||||
C.free(unsafe.Pointer(progress.Slice))
|
C.free(unsafe.Pointer(progress.Slice))
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
// Handle error appropriately, e.g., log it
|
// Handle error appropriately, e.g., log it
|
||||||
fmt.Printf("Failed to add slice, error code: %d\n", ret)
|
fmt.Printf("Failed to add slice, error code: %d\n", ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Free the C-allocated progress structures
|
// Free the C-allocated progress structures
|
||||||
C.free(unsafe.Pointer(progress.Progress))
|
C.free(unsafe.Pointer(progress.Progress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MasterWriter) Destroy() {
|
func (m *MasterWriter) Destroy() {
|
||||||
m.wg.Wait()
|
m.wg.Wait()
|
||||||
close(m.progressCh)
|
close(m.progressCh)
|
||||||
m.progressWg.Wait()
|
m.progressWg.Wait()
|
||||||
|
|
||||||
if m.slice != nil {
|
if m.slice != nil {
|
||||||
C.free(unsafe.Pointer(m.slice)) // Free slice on error
|
C.free(unsafe.Pointer(m.slice)) // Free slice on error
|
||||||
}
|
}
|
||||||
if m.super != nil {
|
if m.super != nil {
|
||||||
C.free(unsafe.Pointer(m.super)) // Free superblock on error
|
C.free(unsafe.Pointer(m.super)) // Free superblock on error
|
||||||
}
|
}
|
||||||
if m.devFd != 0 {
|
if m.devFd != 0 {
|
||||||
syscall.Close(m.devFd)
|
syscall.Close(m.devFd)
|
||||||
}
|
}
|
||||||
// Destroy master writer
|
// Destroy master writer
|
||||||
C.scoutfs_parallel_restore_destroy_writer(&m.writer)
|
C.scoutfs_parallel_restore_destroy_writer(&m.writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWriters(path string, numWriters int) (*MasterWriter, []*WorkerWriter, error) {
|
func NewWriters(path string, numWriters int) (*MasterWriter, []*WorkerWriter, error) {
|
||||||
if numWriters <= 1 {
|
if numWriters <= 1 {
|
||||||
return nil, nil, errors.New("number of writers must be positive")
|
return nil, nil, errors.New("number of writers must be positive")
|
||||||
}
|
}
|
||||||
|
|
||||||
devFd, err := syscall.Open(path, syscall.O_DIRECT|syscall.O_RDWR|syscall.O_EXCL, 0)
|
devFd, err := syscall.Open(path, syscall.O_DIRECT|syscall.O_RDWR|syscall.O_EXCL, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("failed to open metadata device '%s': %v", path, err)
|
return nil, nil, fmt.Errorf("failed to open metadata device '%s': %v", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var masterWriter MasterWriter
|
var masterWriter MasterWriter
|
||||||
masterWriter.progressCh = make(chan *ScoutfsParallelWriterProgress, numWriters*2)
|
masterWriter.progressCh = make(chan *ScoutfsParallelWriterProgress, numWriters*2)
|
||||||
masterWriter.workers = make([]*WorkerWriter, 0, numWriters-1)
|
masterWriter.workers = make([]*WorkerWriter, 0, numWriters-1)
|
||||||
masterWriter.devFd = devFd
|
masterWriter.devFd = devFd
|
||||||
|
|
||||||
var ret C.int
|
var ret C.int
|
||||||
// Allocate aligned memory for superblock
|
// Allocate aligned memory for superblock
|
||||||
var super unsafe.Pointer
|
var super unsafe.Pointer
|
||||||
ret = C.posix_memalign(&super, 4096, C.SCOUTFS_BLOCK_SM_SIZE)
|
ret = C.posix_memalign(&super, 4096, C.SCOUTFS_BLOCK_SM_SIZE)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, fmt.Errorf("failed to allocate aligned memory for superblock: %d", ret)
|
return nil, nil, fmt.Errorf("failed to allocate aligned memory for superblock: %d", ret)
|
||||||
}
|
}
|
||||||
masterWriter.super = (*C.struct_scoutfs_super_block)(super)
|
masterWriter.super = (*C.struct_scoutfs_super_block)(super)
|
||||||
|
|
||||||
// Read the superblock from devFd
|
// Read the superblock from devFd
|
||||||
superOffset := C.SCOUTFS_SUPER_BLKNO << C.SCOUTFS_BLOCK_SM_SHIFT
|
superOffset := C.SCOUTFS_SUPER_BLKNO << C.SCOUTFS_BLOCK_SM_SHIFT
|
||||||
count, err := syscall.Pread(devFd, (*[1 << 30]byte)(super)[:C.SCOUTFS_BLOCK_SM_SIZE], int64(superOffset))
|
count, err := syscall.Pread(devFd, (*[1 << 30]byte)(super)[:C.SCOUTFS_BLOCK_SM_SIZE], int64(superOffset))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, fmt.Errorf("failed to read superblock: %v", err)
|
return nil, nil, fmt.Errorf("failed to read superblock: %v", err)
|
||||||
}
|
}
|
||||||
if count != int(C.SCOUTFS_BLOCK_SM_SIZE) {
|
if count != int(C.SCOUTFS_BLOCK_SM_SIZE) {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, fmt.Errorf("failed to read superblock, bytes read: %d", count)
|
return nil, nil, fmt.Errorf("failed to read superblock, bytes read: %d", count)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the superblock is valid.
|
// Check if the superblock is valid.
|
||||||
if C.le64_to_cpu(masterWriter.super.flags)&C.SCOUTFS_FLAG_IS_META_BDEV == 0 {
|
if C.le64_to_cpu(masterWriter.super.flags)&C.SCOUTFS_FLAG_IS_META_BDEV == 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("superblock is not a metadata device")
|
return nil, nil, errors.New("superblock is not a metadata device")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create master writer
|
// Create master writer
|
||||||
ret = C.scoutfs_parallel_restore_create_writer(&masterWriter.writer)
|
ret = C.scoutfs_parallel_restore_create_writer(&masterWriter.writer)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to create master writer")
|
return nil, nil, errors.New("failed to create master writer")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = C.scoutfs_parallel_restore_import_super(masterWriter.writer, masterWriter.super, C.int(devFd))
|
ret = C.scoutfs_parallel_restore_import_super(masterWriter.writer, masterWriter.super, C.int(devFd))
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, fmt.Errorf("failed to import superblock, error code: %d", ret)
|
return nil, nil, fmt.Errorf("failed to import superblock, error code: %d", ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize slices for each worker
|
// Initialize slices for each worker
|
||||||
masterWriter.slice = (*C.struct_scoutfs_parallel_restore_slice)(C.malloc(C.size_t(numWriters) *
|
masterWriter.slice = (*C.struct_scoutfs_parallel_restore_slice)(C.malloc(C.size_t(numWriters) *
|
||||||
C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{}))))
|
C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{}))))
|
||||||
if masterWriter.slice == nil {
|
if masterWriter.slice == nil {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to allocate slices")
|
return nil, nil, errors.New("failed to allocate slices")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = C.scoutfs_parallel_restore_init_slices(masterWriter.writer,
|
ret = C.scoutfs_parallel_restore_init_slices(masterWriter.writer,
|
||||||
masterWriter.slice,
|
masterWriter.slice,
|
||||||
C.int(numWriters))
|
C.int(numWriters))
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to initialize slices")
|
return nil, nil, errors.New("failed to initialize slices")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = C.scoutfs_parallel_restore_add_slice(masterWriter.writer, masterWriter.slice)
|
ret = C.scoutfs_parallel_restore_add_slice(masterWriter.writer, masterWriter.slice)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to add slice to master writer")
|
return nil, nil, errors.New("failed to add slice to master writer")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create worker writers
|
// Create worker writers
|
||||||
for i := 1; i < numWriters; i++ {
|
for i := 1; i < numWriters; i++ {
|
||||||
var bufPtr unsafe.Pointer
|
var bufPtr unsafe.Pointer
|
||||||
if ret := C.posix_memalign(&bufPtr, 4096, bufSize); ret != 0 {
|
if ret := C.posix_memalign(&bufPtr, 4096, bufSize); ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, fmt.Errorf("failed to allocate aligned worker buffer: %d", ret)
|
return nil, nil, fmt.Errorf("failed to allocate aligned worker buffer: %d", ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
worker := &WorkerWriter{
|
worker := &WorkerWriter{
|
||||||
progressCh: masterWriter.progressCh,
|
progressCh: masterWriter.progressCh,
|
||||||
buf: bufPtr,
|
buf: bufPtr,
|
||||||
wg: &masterWriter.wg,
|
wg: &masterWriter.wg,
|
||||||
}
|
}
|
||||||
ret = C.scoutfs_parallel_restore_create_writer(&worker.writer)
|
ret = C.scoutfs_parallel_restore_create_writer(&worker.writer)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to create worker writer")
|
return nil, nil, errors.New("failed to create worker writer")
|
||||||
}
|
}
|
||||||
|
|
||||||
masterWriter.wg.Add(1)
|
masterWriter.wg.Add(1)
|
||||||
|
|
||||||
// Use each slice for the corresponding worker
|
// Use each slice for the corresponding worker
|
||||||
slice := (*C.struct_scoutfs_parallel_restore_slice)(unsafe.Pointer(uintptr(unsafe.Pointer(masterWriter.slice)) +
|
slice := (*C.struct_scoutfs_parallel_restore_slice)(unsafe.Pointer(uintptr(unsafe.Pointer(masterWriter.slice)) +
|
||||||
uintptr(i)*unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{})))
|
uintptr(i)*unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{})))
|
||||||
ret = C.scoutfs_parallel_restore_add_slice(worker.writer, slice)
|
ret = C.scoutfs_parallel_restore_add_slice(worker.writer, slice)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
C.scoutfs_parallel_restore_destroy_writer(&worker.writer)
|
C.scoutfs_parallel_restore_destroy_writer(&worker.writer)
|
||||||
masterWriter.Destroy()
|
masterWriter.Destroy()
|
||||||
return nil, nil, errors.New("failed to add slice to worker writer")
|
return nil, nil, errors.New("failed to add slice to worker writer")
|
||||||
}
|
}
|
||||||
|
|
||||||
masterWriter.workers = append(masterWriter.workers, worker)
|
masterWriter.workers = append(masterWriter.workers, worker)
|
||||||
}
|
}
|
||||||
go masterWriter.aggregateProgress()
|
masterWriter.progressWg.Add(1)
|
||||||
|
go masterWriter.aggregateProgress()
|
||||||
|
|
||||||
return &masterWriter, masterWriter.workers, nil
|
return &masterWriter, masterWriter.workers, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerWriter) getProgress(withSlice bool) (*ScoutfsParallelWriterProgress, error) {
|
func (w *WorkerWriter) getProgress(withSlice bool) (*ScoutfsParallelWriterProgress, error) {
|
||||||
progress := (*C.struct_scoutfs_parallel_restore_progress)(
|
progress := (*C.struct_scoutfs_parallel_restore_progress)(
|
||||||
C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_progress{}))),
|
C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_progress{}))),
|
||||||
)
|
)
|
||||||
if progress == nil {
|
if progress == nil {
|
||||||
return nil, errors.New("failed to allocate memory for progress")
|
return nil, errors.New("failed to allocate memory for progress")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the current progress from the C library
|
// Fetch the current progress from the C library
|
||||||
ret := C.scoutfs_parallel_restore_get_progress(w.writer, progress)
|
ret := C.scoutfs_parallel_restore_get_progress(w.writer, progress)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
C.free(unsafe.Pointer(progress))
|
C.free(unsafe.Pointer(progress))
|
||||||
return nil, fmt.Errorf("failed to get progress, error code: %d", ret)
|
return nil, fmt.Errorf("failed to get progress, error code: %d", ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
var slice *C.struct_scoutfs_parallel_restore_slice
|
var slice *C.struct_scoutfs_parallel_restore_slice
|
||||||
if withSlice {
|
if withSlice {
|
||||||
slice = (*C.struct_scoutfs_parallel_restore_slice)(
|
slice = (*C.struct_scoutfs_parallel_restore_slice)(
|
||||||
C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{}))),
|
C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{}))),
|
||||||
)
|
)
|
||||||
if slice == nil {
|
if slice == nil {
|
||||||
C.free(unsafe.Pointer(progress))
|
C.free(unsafe.Pointer(progress))
|
||||||
return nil, errors.New("failed to allocate memory for slice")
|
return nil, errors.New("failed to allocate memory for slice")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally fetch the slice information
|
// Optionally fetch the slice information
|
||||||
ret = C.scoutfs_parallel_restore_get_slice(w.writer, slice)
|
ret = C.scoutfs_parallel_restore_get_slice(w.writer, slice)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
C.free(unsafe.Pointer(progress))
|
C.free(unsafe.Pointer(progress))
|
||||||
C.free(unsafe.Pointer(slice))
|
C.free(unsafe.Pointer(slice))
|
||||||
return nil, fmt.Errorf("failed to get slice, error code: %d", ret)
|
return nil, fmt.Errorf("failed to get slice, error code: %d", ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ScoutfsParallelWriterProgress{
|
return &ScoutfsParallelWriterProgress{
|
||||||
Progress: progress,
|
Progress: progress,
|
||||||
Slice: slice,
|
Slice: slice,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeBuffer writes data from the buffer to the device file descriptor.
|
// writeBuffer writes data from the buffer to the device file descriptor.
|
||||||
// It uses scoutfs_parallel_restore_write_buf to get data and pwrite to write it.
|
// It uses scoutfs_parallel_restore_write_buf to get data and pwrite to write it.
|
||||||
func (w *WorkerWriter) writeBuffer() (int64, error) {
|
func (w *WorkerWriter) writeBuffer() (int64, error) {
|
||||||
var totalWritten int64
|
var totalWritten int64
|
||||||
var count int64
|
var count int64
|
||||||
var off int64
|
var off int64
|
||||||
var ret C.int
|
var ret C.int
|
||||||
|
|
||||||
// Allocate memory for off and count
|
// Allocate memory for off and count
|
||||||
offPtr := (*C.off_t)(unsafe.Pointer(&off))
|
offPtr := (*C.off_t)(unsafe.Pointer(&off))
|
||||||
countPtr := (*C.size_t)(unsafe.Pointer(&count))
|
countPtr := (*C.size_t)(unsafe.Pointer(&count))
|
||||||
|
|
||||||
for {
|
for {
|
||||||
ret = C.scoutfs_parallel_restore_write_buf(w.writer, w.buf,
|
ret = C.scoutfs_parallel_restore_write_buf(w.writer, w.buf,
|
||||||
C.size_t(bufSize), offPtr, countPtr)
|
C.size_t(bufSize), offPtr, countPtr)
|
||||||
|
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return totalWritten, fmt.Errorf("failed to write buffer: error code %d", ret)
|
return totalWritten, fmt.Errorf("failed to write buffer: error code %d", ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
n, err := syscall.Pwrite(w.devFd, unsafe.Slice((*byte)(w.buf), count), off)
|
n, err := syscall.Pwrite(w.devFd, unsafe.Slice((*byte)(w.buf), count), off)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return totalWritten, fmt.Errorf("pwrite failed: %v", err)
|
return totalWritten, fmt.Errorf("pwrite failed: %v", err)
|
||||||
}
|
}
|
||||||
if n != int(count) {
|
if n != int(count) {
|
||||||
return totalWritten, fmt.Errorf("pwrite wrote %d bytes; expected %d", n, count)
|
return totalWritten, fmt.Errorf("pwrite wrote %d bytes; expected %d", n, count)
|
||||||
}
|
}
|
||||||
totalWritten += int64(n)
|
totalWritten += int64(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalWritten, nil
|
return totalWritten, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerWriter) InsertEntry(entry *C.struct_scoutfs_parallel_restore_entry) error {
|
func (w *WorkerWriter) InsertEntry(entry *C.struct_scoutfs_parallel_restore_entry) error {
|
||||||
// Add the entry using the C library
|
// Add the entry using the C library
|
||||||
ret := C.scoutfs_parallel_restore_add_entry(w.writer, entry)
|
ret := C.scoutfs_parallel_restore_add_entry(w.writer, entry)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return fmt.Errorf("failed to add entry, error code: %d", ret)
|
return fmt.Errorf("failed to add entry, error code: %d", ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the fileCreated counter
|
// Increment the fileCreated counter
|
||||||
w.fileCreated++
|
w.fileCreated++
|
||||||
if w.fileCreated >= batchSize {
|
if w.fileCreated >= batchSize {
|
||||||
_, err := w.writeBuffer()
|
_, err := w.writeBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error writing buffers: %v", err)
|
return fmt.Errorf("error writing buffers: %v", err)
|
||||||
}
|
}
|
||||||
// Allocate memory for progress and slice structures
|
// Allocate memory for progress and slice structures
|
||||||
progress, err := w.getProgress(false)
|
progress, err := w.getProgress(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Send the progress update to the shared progress channel
|
// Send the progress update to the shared progress channel
|
||||||
w.progressCh <- progress
|
w.progressCh <- progress
|
||||||
// Reset the fileCreated counter
|
// Reset the fileCreated counter
|
||||||
w.fileCreated = 0
|
w.fileCreated = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerWriter) InsertXattr(xattr *C.struct_scoutfs_parallel_restore_xattr) error {
|
func (w *WorkerWriter) InsertXattr(xattr *C.struct_scoutfs_parallel_restore_xattr) error {
|
||||||
ret := C.scoutfs_parallel_restore_add_xattr(w.writer, xattr)
|
ret := C.scoutfs_parallel_restore_add_xattr(w.writer, xattr)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return fmt.Errorf("failed to add xattr, error code: %d", ret)
|
return fmt.Errorf("failed to add xattr, error code: %d", ret)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkerWriter) InsertInode(inode *C.struct_scoutfs_parallel_restore_inode) error {
|
func (w *WorkerWriter) InsertInode(inode *C.struct_scoutfs_parallel_restore_inode) error {
|
||||||
ret := C.scoutfs_parallel_restore_add_inode(w.writer, inode)
|
ret := C.scoutfs_parallel_restore_add_inode(w.writer, inode)
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return fmt.Errorf("failed to add inode, error code: %d", ret)
|
return fmt.Errorf("failed to add inode, error code: %d", ret)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// should only be called once
|
// should only be called once
|
||||||
func (w *WorkerWriter) Destroy() error {
|
func (w *WorkerWriter) Destroy() error {
|
||||||
defer w.wg.Done()
|
defer w.wg.Done()
|
||||||
// Send final progress if there are remaining entries
|
// Send final progress if there are remaining entries
|
||||||
if w.fileCreated > 0 {
|
if w.fileCreated > 0 {
|
||||||
_, err := w.writeBuffer()
|
_, err := w.writeBuffer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
progress := &ScoutfsParallelWriterProgress{
|
progress := &ScoutfsParallelWriterProgress{
|
||||||
Progress: (*C.struct_scoutfs_parallel_restore_progress)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_progress{})))),
|
Progress: (*C.struct_scoutfs_parallel_restore_progress)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_progress{})))),
|
||||||
Slice: (*C.struct_scoutfs_parallel_restore_slice)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{})))),
|
Slice: (*C.struct_scoutfs_parallel_restore_slice)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_slice{})))),
|
||||||
}
|
}
|
||||||
w.progressCh <- progress
|
w.progressCh <- progress
|
||||||
w.fileCreated = 0
|
w.fileCreated = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.buf != nil {
|
if w.buf != nil {
|
||||||
C.free(w.buf)
|
C.free(w.buf)
|
||||||
w.buf = nil
|
w.buf = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
C.scoutfs_parallel_restore_destroy_writer(&w.writer)
|
C.scoutfs_parallel_restore_destroy_writer(&w.writer)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add these new types and functions to the existing restore.go file
|
// Add these new types and functions to the existing restore.go file
|
||||||
|
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
Ino uint64
|
Ino uint64
|
||||||
Mode uint32
|
Mode uint32
|
||||||
Uid uint32
|
Uid uint32
|
||||||
Gid uint32
|
Gid uint32
|
||||||
Size uint64
|
Size uint64
|
||||||
Rdev uint64
|
Rdev uint64
|
||||||
AtimeSec int64
|
AtimeSec int64
|
||||||
AtimeNsec int64
|
AtimeNsec int64
|
||||||
MtimeSec int64
|
MtimeSec int64
|
||||||
MtimeNsec int64
|
MtimeNsec int64
|
||||||
CtimeSec int64
|
CtimeSec int64
|
||||||
CtimeNsec int64
|
CtimeNsec int64
|
||||||
NrSubdirs uint64
|
NrSubdirs uint64
|
||||||
NameBytes uint64
|
NameBytes uint64
|
||||||
IsDir bool
|
IsDir bool
|
||||||
IsRegular bool
|
IsRegular bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type XAttr struct {
|
type XAttr struct {
|
||||||
Name string
|
Name string
|
||||||
Value []byte
|
Value []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateInode creates a C inode structure from FileInfo
|
// CreateInode creates a C inode structure from FileInfo
|
||||||
func (w *WorkerWriter) CreateInode(info FileInfo) error {
|
func (w *WorkerWriter) CreateInode(info FileInfo) error {
|
||||||
inode := (*C.struct_scoutfs_parallel_restore_inode)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_inode{}))))
|
inode := (*C.struct_scoutfs_parallel_restore_inode)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_inode{}))))
|
||||||
if inode == nil {
|
if inode == nil {
|
||||||
return fmt.Errorf("failed to allocate inode")
|
return fmt.Errorf("failed to allocate inode")
|
||||||
}
|
}
|
||||||
defer C.free(unsafe.Pointer(inode))
|
defer C.free(unsafe.Pointer(inode))
|
||||||
|
|
||||||
inode.ino = C.__u64(info.Ino)
|
inode.ino = C.__u64(info.Ino)
|
||||||
inode.mode = C.__u32(info.Mode)
|
inode.mode = C.__u32(info.Mode)
|
||||||
inode.uid = C.__u32(info.Uid)
|
inode.uid = C.__u32(info.Uid)
|
||||||
inode.gid = C.__u32(info.Gid)
|
inode.gid = C.__u32(info.Gid)
|
||||||
inode.size = C.__u64(info.Size)
|
inode.size = C.__u64(info.Size)
|
||||||
inode.rdev = C.uint(info.Rdev)
|
inode.rdev = C.uint(info.Rdev)
|
||||||
|
|
||||||
inode.atime.tv_sec = C.__time_t(info.AtimeSec)
|
inode.atime.tv_sec = C.__time_t(info.AtimeSec)
|
||||||
inode.atime.tv_nsec = C.long(info.AtimeNsec)
|
inode.atime.tv_nsec = C.long(info.AtimeNsec)
|
||||||
inode.mtime.tv_sec = C.__time_t(info.MtimeSec)
|
inode.mtime.tv_sec = C.__time_t(info.MtimeSec)
|
||||||
inode.mtime.tv_nsec = C.long(info.MtimeNsec)
|
inode.mtime.tv_nsec = C.long(info.MtimeNsec)
|
||||||
inode.ctime.tv_sec = C.__time_t(info.CtimeSec)
|
inode.ctime.tv_sec = C.__time_t(info.CtimeSec)
|
||||||
inode.ctime.tv_nsec = C.long(info.CtimeNsec)
|
inode.ctime.tv_nsec = C.long(info.CtimeNsec)
|
||||||
inode.crtime = inode.ctime
|
inode.crtime = inode.ctime
|
||||||
|
|
||||||
if info.IsRegular && info.Size > 0 {
|
if info.IsRegular && info.Size > 0 {
|
||||||
inode.offline = C.bool(true)
|
inode.offline = C.bool(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.IsDir {
|
if info.IsDir {
|
||||||
inode.nr_subdirs = C.__u64(info.NrSubdirs)
|
inode.nr_subdirs = C.__u64(info.NrSubdirs)
|
||||||
inode.total_entry_name_bytes = C.__u64(info.NameBytes)
|
inode.total_entry_name_bytes = C.__u64(info.NameBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.InsertInode(inode)
|
return w.InsertInode(inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateEntry creates a directory entry
|
// CreateEntry creates a directory entry
|
||||||
func (w *WorkerWriter) CreateEntry(dirIno uint64, pos uint64, ino uint64, mode uint32, name string) error {
|
func (w *WorkerWriter) CreateEntry(dirIno uint64, pos uint64, ino uint64, mode uint32, name string) error {
|
||||||
entryC := (*C.struct_scoutfs_parallel_restore_entry)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_entry{})) + C.size_t(len(name))))
|
entryC := (*C.struct_scoutfs_parallel_restore_entry)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_entry{})) + C.size_t(len(name))))
|
||||||
|
|
||||||
if entryC == nil {
|
if entryC == nil {
|
||||||
return fmt.Errorf("failed to allocate entry")
|
return fmt.Errorf("failed to allocate entry")
|
||||||
}
|
}
|
||||||
defer C.free(unsafe.Pointer(entryC))
|
defer C.free(unsafe.Pointer(entryC))
|
||||||
|
|
||||||
entryC.dir_ino = C.__u64(dirIno)
|
entryC.dir_ino = C.__u64(dirIno)
|
||||||
entryC.pos = C.__u64(pos)
|
entryC.pos = C.__u64(pos)
|
||||||
entryC.ino = C.__u64(ino)
|
entryC.ino = C.__u64(ino)
|
||||||
entryC.mode = C.__u32(mode)
|
entryC.mode = C.__u32(mode)
|
||||||
entryC.name_len = C.uint(len(name))
|
entryC.name_len = C.uint(len(name))
|
||||||
|
|
||||||
entryC.name = (*C.char)(C.malloc(C.size_t(len(name))))
|
entryC.name = (*C.char)(C.malloc(C.size_t(len(name))))
|
||||||
if entryC.name == nil {
|
if entryC.name == nil {
|
||||||
return fmt.Errorf("failed to allocate entry name")
|
return fmt.Errorf("failed to allocate entry name")
|
||||||
}
|
}
|
||||||
defer C.free(unsafe.Pointer(entryC.name))
|
defer C.free(unsafe.Pointer(entryC.name))
|
||||||
copy((*[1 << 30]byte)(unsafe.Pointer(entryC.name))[:len(name)], []byte(name))
|
copy((*[1 << 30]byte)(unsafe.Pointer(entryC.name))[:len(name)], []byte(name))
|
||||||
|
|
||||||
return w.InsertEntry(entryC)
|
return w.InsertEntry(entryC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateXAttr creates an extended attribute
|
// CreateXAttr creates an extended attribute
|
||||||
func (w *WorkerWriter) CreateXAttr(ino uint64, pos uint64, xattr XAttr) error {
|
func (w *WorkerWriter) CreateXAttr(ino uint64, pos uint64, xattr XAttr) error {
|
||||||
xattrC := (*C.struct_scoutfs_parallel_restore_xattr)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_xattr{})) + C.size_t(len(xattr.Name)) + C.size_t(len(xattr.Value))))
|
xattrC := (*C.struct_scoutfs_parallel_restore_xattr)(C.malloc(C.size_t(unsafe.Sizeof(C.struct_scoutfs_parallel_restore_xattr{})) + C.size_t(len(xattr.Name)) + C.size_t(len(xattr.Value))))
|
||||||
if xattrC == nil {
|
if xattrC == nil {
|
||||||
return fmt.Errorf("failed to allocate xattr")
|
return fmt.Errorf("failed to allocate xattr")
|
||||||
}
|
}
|
||||||
defer C.free(unsafe.Pointer(xattrC))
|
defer C.free(unsafe.Pointer(xattrC))
|
||||||
|
|
||||||
xattrC.ino = C.__u64(ino)
|
xattrC.ino = C.__u64(ino)
|
||||||
xattrC.pos = C.__u64(pos)
|
xattrC.pos = C.__u64(pos)
|
||||||
xattrC.name_len = C.uint(len(xattr.Name))
|
xattrC.name_len = C.uint(len(xattr.Name))
|
||||||
xattrC.value_len = C.__u32(len(xattr.Value))
|
xattrC.value_len = C.__u32(len(xattr.Value))
|
||||||
|
|
||||||
xattrC.name = (*C.char)(C.malloc(C.size_t(len(xattr.Name))))
|
xattrC.name = (*C.char)(C.malloc(C.size_t(len(xattr.Name))))
|
||||||
if xattrC.name == nil {
|
if xattrC.name == nil {
|
||||||
return fmt.Errorf("failed to allocate xattr name")
|
return fmt.Errorf("failed to allocate xattr name")
|
||||||
}
|
}
|
||||||
defer C.free(unsafe.Pointer(xattrC.name))
|
defer C.free(unsafe.Pointer(xattrC.name))
|
||||||
|
|
||||||
copy((*[1 << 30]byte)(unsafe.Pointer(xattrC.name))[:len(xattr.Name)], []byte(xattr.Name))
|
copy((*[1 << 30]byte)(unsafe.Pointer(xattrC.name))[:len(xattr.Name)], []byte(xattr.Name))
|
||||||
|
|
||||||
xattrC.value = unsafe.Pointer(&xattr.Value[0])
|
xattrC.value = unsafe.Pointer(&xattr.Value[0])
|
||||||
|
|
||||||
return w.InsertXattr(xattrC)
|
return w.InsertXattr(xattrC)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user