// Файловые системы: безопасная запись, fsync, атомарная замена
// Запуск: go run fs_demo.go

package main

import (
	"fmt"
	"os"
	"path/filepath"
)

func main() {
	fmt.Println("=== Go: файловые системы ===")
	fmt.Println()

	dir, _ := os.MkdirTemp("", "fs_demo_go")
	defer os.RemoveAll(dir)

	// 1. Простая запись
	fmt.Println("--- 1. Простая запись ---")
	path := filepath.Join(dir, "simple.txt")
	os.WriteFile(path, []byte("Простая запись.\n"), 0644)
	data, _ := os.ReadFile(path)
	fmt.Printf("  Записано: \"%s\"\n", string(data[:len(data)-1]))
	fmt.Println("  os.WriteFile не вызывает fsync — данные могут быть в кеше ОС.")
	fmt.Println()

	// 2. fsync
	fmt.Println("--- 2. file.Sync() = fsync ---")
	path2 := filepath.Join(dir, "synced.txt")
	f, _ := os.Create(path2)
	f.WriteString("Данные, гарантированно записанные на диск.\n")
	f.Sync() // fsync()
	f.Close()
	fmt.Println("  file.Sync() = fsync(): сбрасывает буферы ОС на диск.")
	fmt.Println("  Без Sync() при сбое питания данные могут потеряться.")
	fmt.Println()

	// 3. Безопасная замена файла
	fmt.Println("--- 3. Атомарная замена (write-sync-rename) ---")
	target := filepath.Join(dir, "config.json")
	tmp := filepath.Join(dir, "config.json.tmp")

	// Исходная версия
	os.WriteFile(target, []byte("{\"version\": 1}\n"), 0644)

	// Безопасное обновление
	f, _ = os.Create(tmp)
	f.WriteString("{\"version\": 2}\n")
	f.Sync()  // 1. Данные на диске
	f.Close()
	os.Rename(tmp, target) // 2. Атомарная замена

	result, _ := os.ReadFile(target)
	fmt.Printf("  config.json: %s", result)
	fmt.Println("  Шаги:")
	fmt.Println("    1. Записать во временный файл")
	fmt.Println("    2. file.Sync() — гарантия на диске")
	fmt.Println("    3. os.Rename() — атомарная замена")
	fmt.Println("  При сбое: старая ИЛИ новая версия. Никогда — мусор.")
	fmt.Println()

	// 4. Директория тоже нужна fsync
	fmt.Println("--- 4. fsync директории ---")
	fmt.Println("  rename() обновляет запись в директории.")
	fmt.Println("  Для полной гарантии нужен fsync на директорию:")
	fmt.Println("    d, _ := os.Open(dir)")
	fmt.Println("    d.Sync()")
	fmt.Println("  Без этого при сбое директория может не содержать нового файла.")
	fmt.Println()

	// 5. PostgreSQL fsync (2018)
	fmt.Println("--- 5. Знаменитый баг PostgreSQL ---")
	fmt.Println("  PostgreSQL 2018: «fsync() surprise».")
	fmt.Println("  При ошибке fsync() Linux помечал страницы «чистыми».")
	fmt.Println("  Повторный fsync() возвращал успех — хотя данные не записались.")
	fmt.Println("  PostgreSQL считал, что данные на диске. Потеря данных.")
	fmt.Println("  Исправлено в ядре Linux (5.2): ошибка fsync сохраняется.")
	fmt.Println()

	// 6. Файловые системы
	fmt.Println("--- 6. Файловые системы ---")
	fmt.Println("  ext4 (2008):    журналирование, по умолчанию в Linux")
	fmt.Println("  ZFS (2005):     контрольные суммы каждого блока, снимки, CoW")
	fmt.Println("  Btrfs (2009):   CoW, снимки, сжатие, дедупликация")
	fmt.Println("  bcachefs (2024): в Linux 6.7, CoW, шифрование, сжатие")
	fmt.Println("  APFS (2017):    macOS/iOS, CoW, шифрование, клоны файлов")

	fmt.Println("\n--- 7. SQLite ---")
	fmt.Println("  «SQLite — не замена Oracle. SQLite — замена fopen().»")
	fmt.Println("  WAL-режим: параллельные чтение и запись.")
	fmt.Println("  Самая распространённая БД в мире (каждый телефон).")
	fmt.Println("  Ричард Хипп: «SQLite в общественном достоянии».")

	fmt.Println("\n--- Итог ---")
	fmt.Println("fsync: единственная гарантия данных на диске")
	fmt.Println("write-sync-rename: паттерн безопасного обновления файла")
	fmt.Println("rename() атомарен в пределах ФС, write() — нет")
	fmt.Println("Журнал (WAL): защита от повреждения при сбое")
}
