Files
futriix/internal/storage/fsync.go

154 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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
// Поддерживает все платформы: Linux, macOS, BSD, Windows, Solaris/Illumos (OpenIndiana)
package storage
import (
"fmt"
"os"
"runtime"
"time"
)
// RealFsync выполняет реальный fsync на файле.
// Использует стандартный метод Sync() для максимальной совместимости
// со всеми платформами включая OpenIndiana (Solaris/Illumos).
func RealFsync(file *os.File) error {
if file == nil {
return nil
}
// Вызываем системный fsync через стандартный метод Sync
// Это работает на всех платформах: Linux, macOS, BSD, Windows, Solaris/Illumos
return file.Sync()
}
// RealFsyncWithRetry выполняет fsync с повторными попытками.
// Параметры:
// - file: файл для синхронизации
// - maxRetries: максимальное количество попыток
// - retryDelay: задержка между попытками
//
// Возвращает ошибку, если все попытки не удались.
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 синхронизирует директорию (для гарантии, что создание файла записано на диск).
// На некоторых платформах (Windows, Solaris/Illumos) fsync для директорий не поддерживается.
func FsyncDir(dirPath string) error {
dir, err := os.Open(dirPath)
if err != nil {
return err
}
defer dir.Close()
// На Windows и Solaris/Illumos нет прямой поддержки fsync для директорий
// Используем стандартный Sync если доступен
switch runtime.GOOS {
case "windows", "solaris", "illumos", "openindiana":
// На этих платформах fsync для директорий не поддерживается или не нужен
// Возвращаем nil, так как данные уже записаны через fsync файлов
return nil
default:
// Для Linux, BSD, macOS используем Sync
return dir.Sync()
}
}
// FsyncDataOnly выполняет fsync только для данных (не метаданных).
// Использует стандартный Sync для всех платформ.
// Это обеспечивает запись данных на диск без синхронизации метаданных.
func FsyncDataOnly(file *os.File) error {
if file == nil {
return nil
}
// Используем стандартный Sync для всех платформ
// Это обеспечит запись данных на диск
return file.Sync()
}
// FsyncWithTimeout выполняет fsync с таймаутом.
// Если операция не завершается за указанное время, возвращается ошибка.
func FsyncWithTimeout(file *os.File, timeout time.Duration) error {
if file == nil {
return nil
}
// Создаём канал для результата
result := make(chan error, 1)
// Запускаем fsync в отдельной горутине
go func() {
result <- file.Sync()
}()
// Ожидаем результат или таймаут
select {
case err := <-result:
return err
case <-time.After(timeout):
return fmt.Errorf("fsync timeout after %v", timeout)
}
}
// MustFsync выполняет fsync и паникует при ошибке.
// Используется только в критических секциях, где ошибка синхронизации фатальна.
func MustFsync(file *os.File) {
if file == nil {
return
}
if err := file.Sync(); err != nil {
panic(fmt.Sprintf("Fatal: fsync failed: %v", err))
}
}
// IsFsyncSupported возвращает true если платформа поддерживает fsync.
// Все платформы поддерживают fsync через file.Sync().
func IsFsyncSupported() bool {
return true
}
// GetFsyncPlatformInfo возвращает информацию о платформе для диагностики.
func GetFsyncPlatformInfo() map[string]interface{} {
return map[string]interface{}{
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"fsync_supported": IsFsyncSupported(),
"dir_fsync_supported": !(runtime.GOOS == "windows" ||
runtime.GOOS == "solaris" ||
runtime.GOOS == "illumos" ||
runtime.GOOS == "openindiana"),
"method": "file.Sync()",
}
}