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 }