diff --git a/dbbackup b/dbbackup index 84e0432..c29686a 100755 Binary files a/dbbackup and b/dbbackup differ diff --git a/internal/backup/engine.go b/internal/backup/engine.go index ded9539..a7c0e56 100644 --- a/internal/backup/engine.go +++ b/internal/backup/engine.go @@ -374,7 +374,7 @@ func (e *Engine) BackupCluster(ctx context.Context) error { // Create archive e.printf(" Creating compressed archive...\n") - if err := e.createArchive(tempDir, outputFile); err != nil { + if err := e.createArchive(ctx, tempDir, outputFile); err != nil { quietProgress.Fail(fmt.Sprintf("Failed to create archive: %v", err)) operation.Fail("Archive creation failed") return fmt.Errorf("failed to create archive: %w", err) @@ -672,7 +672,7 @@ func (e *Engine) backupGlobals(ctx context.Context, tempDir string) error { } // createArchive creates a compressed tar archive -func (e *Engine) createArchive(sourceDir, outputFile string) error { +func (e *Engine) createArchive(ctx context.Context, sourceDir, outputFile string) error { // Use pigz for faster parallel compression if available, otherwise use standard gzip compressCmd := "tar" compressArgs := []string{"-czf", outputFile, "-C", sourceDir, "."} @@ -681,28 +681,46 @@ func (e *Engine) createArchive(sourceDir, outputFile string) error { if _, err := exec.LookPath("pigz"); err == nil { // Use pigz with number of cores for parallel compression compressArgs = []string{"-cf", "-", "-C", sourceDir, "."} - cmd := exec.Command("tar", compressArgs...) + cmd := exec.CommandContext(ctx, "tar", compressArgs...) - // Pipe to pigz for parallel compression - pigzCmd := exec.Command("pigz", "-p", strconv.Itoa(e.cfg.Jobs), ">", outputFile) - - tarOut, err := cmd.StdoutPipe() + // Create output file + outFile, err := os.Create(outputFile) if err != nil { // Fallback to regular tar goto regularTar } - pigzCmd.Stdin = tarOut + defer outFile.Close() + // Pipe to pigz for parallel compression + pigzCmd := exec.CommandContext(ctx, "pigz", "-p", strconv.Itoa(e.cfg.Jobs)) + + tarOut, err := cmd.StdoutPipe() + if err != nil { + outFile.Close() + // Fallback to regular tar + goto regularTar + } + pigzCmd.Stdin = tarOut + pigzCmd.Stdout = outFile + + // Start both commands if err := pigzCmd.Start(); err != nil { + outFile.Close() goto regularTar } if err := cmd.Start(); err != nil { + pigzCmd.Process.Kill() + outFile.Close() goto regularTar } + // Wait for tar to finish if err := cmd.Wait(); err != nil { + pigzCmd.Process.Kill() return fmt.Errorf("tar failed: %w", err) } + + // Wait for pigz to finish if err := pigzCmd.Wait(); err != nil { return fmt.Errorf("pigz compression failed: %w", err) } @@ -711,7 +729,7 @@ func (e *Engine) createArchive(sourceDir, outputFile string) error { regularTar: // Standard tar with gzip (fallback) - cmd := exec.Command(compressCmd, compressArgs...) + cmd := exec.CommandContext(ctx, compressCmd, compressArgs...) // Stream stderr to avoid memory issues stderr, err := cmd.StderrPipe() diff --git a/internal/tui/backup_exec.go b/internal/tui/backup_exec.go index 8b73710..677c7d2 100644 --- a/internal/tui/backup_exec.go +++ b/internal/tui/backup_exec.go @@ -61,7 +61,18 @@ func (m BackupExecutionModel) Init() tea.Cmd { }) }) - return executeBackupWithTUIProgress(m.config, m.logger, m.backupType, m.databaseName, m.ratio, reporter) + return tea.Batch( + executeBackupWithTUIProgress(m.config, m.logger, m.backupType, m.databaseName, m.ratio, reporter), + backupTickCmd(), + ) +} + +type backupTickMsg time.Time + +func backupTickCmd() tea.Cmd { + return tea.Tick(time.Millisecond*100, func(t time.Time) tea.Msg { + return backupTickMsg(t) + }) } type backupProgressMsg struct { @@ -142,6 +153,12 @@ func executeBackupWithTUIProgress(cfg *config.Config, log logger.Logger, backupT func (m BackupExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case backupTickMsg: + if !m.done { + return m, backupTickCmd() + } + return m, nil + case backupProgressMsg: m.status = msg.status m.progress = msg.progress diff --git a/internal/tui/status.go b/internal/tui/status.go index 69f5186..95eaf62 100644 --- a/internal/tui/status.go +++ b/internal/tui/status.go @@ -37,7 +37,18 @@ func NewStatusView(cfg *config.Config, log logger.Logger, parent tea.Model) Stat } func (m StatusViewModel) Init() tea.Cmd { - return fetchStatus(m.config, m.logger) + return tea.Batch( + fetchStatus(m.config, m.logger), + tickCmd(), + ) +} + +type tickMsg time.Time + +func tickCmd() tea.Cmd { + return tea.Tick(time.Millisecond*100, func(t time.Time) tea.Msg { + return tickMsg(t) + }) } type statusMsg struct { @@ -98,6 +109,12 @@ func fetchStatus(cfg *config.Config, log logger.Logger) tea.Cmd { func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case tickMsg: + if m.loading { + return m, tickCmd() + } + return m, nil + case statusMsg: m.loading = false if msg.status != "" {