Files
elowdb-go/pkg/linedb/transaction.go

148 lines
3.8 KiB
Go

package linedb
import (
"fmt"
"os"
"time"
)
// Transaction представляет транзакцию
type Transaction struct {
transactionMode string
transactionID string
timeoutMs int
timeoutID *time.Timer
rollback bool
backupFile string
doNotDeleteBackupFile bool
// mutex sync.RWMutex
active bool
}
// NewTransaction создает новую транзакцию
func NewTransaction(mode string, id string, timeout int, rollback bool) *Transaction {
tx := &Transaction{
transactionMode: mode,
transactionID: id,
timeoutMs: timeout,
rollback: rollback,
active: true,
}
if timeout > 0 {
tx.timeoutID = time.AfterFunc(time.Duration(timeout)*time.Millisecond, func() {
tx.active = false
})
}
return tx
}
// ClearTimeout очищает таймаут транзакции
func (t *Transaction) ClearTimeout() {
if t.timeoutID != nil {
t.timeoutID.Stop()
}
}
// IsActive проверяет, является ли транзакция активной
func (t *Transaction) IsActive() bool {
return t.active
}
// IsReadMode проверяет, является ли транзакция режимом чтения
func (t *Transaction) IsReadMode() bool {
return t.transactionMode == "read"
}
// IsWriteMode проверяет, является ли транзакция режимом записи
func (t *Transaction) IsWriteMode() bool {
return t.transactionMode == "write"
}
// ShouldRollback проверяет, требуется ли откат транзакции при ошибке
func (t *Transaction) ShouldRollback() bool {
return t.rollback
}
// ShouldKeepBackup проверяет, нужно ли сохранять резервную копию
func (t *Transaction) ShouldKeepBackup() bool {
return !t.doNotDeleteBackupFile
}
// GetBackupFile получает путь к файлу резервной копии
func (t *Transaction) GetBackupFile() string {
return t.backupFile
}
// SetBackupFile устанавливает путь к файлу резервной копии
func (t *Transaction) SetBackupFile(path string) {
t.backupFile = path
}
// CreateBackup создает резервную копию файла
func (t *Transaction) CreateBackup(filename string) error {
if filename == "" {
return fmt.Errorf("filename is required")
}
// Создаем резервную копию
backupFile := filename + ".backup"
// Копируем файл
src, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open source file: %w", err)
}
defer src.Close()
dst, err := os.Create(backupFile)
if err != nil {
return fmt.Errorf("failed to create backup file: %w", err)
}
defer dst.Close()
_, err = dst.ReadFrom(src)
if err != nil {
return fmt.Errorf("failed to copy file: %w", err)
}
t.backupFile = backupFile
return nil
}
// RestoreFromBackup восстанавливает из резервной копии
func (t *Transaction) RestoreFromBackup(filename string) error {
if t.backupFile == "" {
return fmt.Errorf("no backup file available")
}
// Копируем резервную копию обратно
src, err := os.Open(t.backupFile)
if err != nil {
return fmt.Errorf("failed to open backup file: %w", err)
}
defer src.Close()
dst, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to create target file: %w", err)
}
defer dst.Close()
_, err = dst.ReadFrom(src)
if err != nil {
return fmt.Errorf("failed to copy backup: %w", err)
}
return nil
}
// CleanupBackup удаляет резервную копию
func (t *Transaction) CleanupBackup() error {
if t.backupFile != "" && !t.doNotDeleteBackupFile {
return os.Remove(t.backupFile)
}
return nil
}