84 lines
2.2 KiB
Go
84 lines
2.2 KiB
Go
|
|
/*
|
|||
|
|
* Copyright 2026 Safronov Grigorii
|
|||
|
|
*
|
|||
|
|
* Licensed under the CDDL, Version 1.0 (the "License");
|
|||
|
|
* you may not use this file except in compliance with the License.
|
|||
|
|
*
|
|||
|
|
* You may obtain a copy of the License at
|
|||
|
|
* https://opensource.org/licenses/CDDL-1.0
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// Файл: internal/storage/fsync.go
|
|||
|
|
// Назначение: Реальная синхронизация с диском (fsync) для WAL
|
|||
|
|
|
|||
|
|
package storage
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"os"
|
|||
|
|
"runtime"
|
|||
|
|
"syscall"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// RealFsync выполняет реальный fsync на файле
|
|||
|
|
func RealFsync(file *os.File) error {
|
|||
|
|
if file == nil {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Вызываем системный fsync
|
|||
|
|
return file.Sync()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RealFsyncWithRetry выполняет fsync с повторными попытками
|
|||
|
|
func RealFsyncWithRetry(file *os.File, maxRetries int, retryDelay time.Duration) error {
|
|||
|
|
if file == nil {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var lastErr error
|
|||
|
|
for i := 0; i < maxRetries; i++ {
|
|||
|
|
if err := RealFsync(file); err != nil {
|
|||
|
|
lastErr = err
|
|||
|
|
if i < maxRetries-1 {
|
|||
|
|
time.Sleep(retryDelay)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
return fmt.Errorf("fsync failed after %d attempts: %v", maxRetries, lastErr)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
return lastErr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FsyncDir синхронизирует директорию (для гарантии, что создание файла записано на диск)
|
|||
|
|
func FsyncDir(dirPath string) error {
|
|||
|
|
dir, err := os.Open(dirPath)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
defer dir.Close()
|
|||
|
|
|
|||
|
|
if runtime.GOOS == "windows" {
|
|||
|
|
// На Windows нет прямой поддержки fsync для директорий
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return dir.Sync()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FsyncDataOnly выполняет fsync только для данных (не метаданных)
|
|||
|
|
func FsyncDataOnly(file *os.File) error {
|
|||
|
|
if file == nil {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fd := int(file.Fd())
|
|||
|
|
_, _, err := syscall.Syscall(syscall.SYS_FSYNC, uintptr(fd), 0, 0)
|
|||
|
|
if err != 0 {
|
|||
|
|
return fmt.Errorf("fsync failed: %v", err)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|