- CheckDiskSpace now uses GetEffectiveWorkDir() instead of BackupDir
- Dynamic timeout calculation based on file size:
- diagnoseClusterArchive: 5 + (GB/3) min, max 60 min
- verifyWithPgRestore: 5 + (GB/5) min, max 30 min
- DiagnoseClusterDumps: 10 + (GB/3) min, max 120 min
- TUI safety checks: 10 + (GB/5) min, max 120 min
- Timeout vs corruption differentiation (no false CORRUPTED on timeout)
- Streaming tar listing to avoid OOM on large archives
For 119GB archives: ~45 min timeout instead of 5 min false-positive
CRITICAL FIXES:
- Encryption detection false positive (IsBackupEncrypted returned true for ALL files)
- 12 cmd.Wait() deadlocks fixed with channel-based context handling
- TUI timeout bugs: 60s->10min for safety checks, 15s->60s for DB listing
- diagnose.go timeouts: 60s->5min for tar/pg_restore operations
- Panic recovery added to parallel backup/restore goroutines
- Variable shadowing fix in restore/engine.go
These bugs caused pg_dump backups to fail through TUI for months.
This is a critical bugfix release addressing multiple hardcoded temporary directory paths
that prevented proper use of the WorkDir configuration option.
PROBLEM:
Users configuring WorkDir (e.g., /u01/dba/tmp) for systems with small root filesystems
still experienced failures because critical operations hardcoded /tmp instead of respecting
the configured WorkDir. This made the WorkDir option essentially non-functional.
FIXED LOCATIONS:
1. internal/restore/engine.go:632 - CRITICAL: Used BackupDir instead of WorkDir for extraction
2. cmd/restore.go:354,834 - CLI restore/diagnose commands ignored WorkDir
3. cmd/migrate.go:208,347 - Migration commands hardcoded /tmp
4. internal/migrate/engine.go:120 - Migration engine ignored WorkDir
5. internal/config/config.go:224 - SwapFilePath hardcoded /tmp
6. internal/config/config.go:519 - Backup directory fallback hardcoded /tmp
7. internal/tui/restore_exec.go:161 - Debug logs hardcoded /tmp
8. internal/tui/settings.go:805 - Directory browser default hardcoded /tmp
9. internal/tui/restore_preview.go:474 - Display message hardcoded /tmp
NEW FEATURES:
- Added Config.GetEffectiveWorkDir() helper method
- WorkDir now respects WORK_DIR environment variable
- All temp operations now consistently use configured WorkDir with /tmp fallback
IMPACT:
- Restores on systems with small root disks now work properly with WorkDir configured
- Admins can control disk space usage for all temporary operations
- Debug logs, extraction dirs, swap files all respect WorkDir setting
Version: 3.42.1 (Critical Fix Release)
- Validate SQL dump files BEFORE attempting restore
- Detect unterminated COPY blocks that cause 'syntax error' failures
- Cluster restore now pre-validates ALL dumps upfront (fail-fast)
- Saves hours of wasted restore time on corrupted backups
The truncated resydb.sql.gz was causing 49min restore attempts
that failed with 2.6M errors. Now fails immediately with clear
error message showing which table's COPY block was truncated.
- Better error messages when tar extraction fails
- Detect truncated/corrupted archives without full extraction
- Show archive contents even when extraction fails
- Provide helpful hints for disk space and corruption issues
- Exit status 2 from tar now shows detailed diagnostics
Features:
- restore diagnose command for backup file analysis
- Deep COPY block verification for truncated dump detection
- PGDMP signature and gzip integrity validation
- Detailed error reports with --save-debug-log flag
- Ring buffer stderr capture (prevents OOM on 2M+ errors)
- Error classification with actionable recommendations
TUI Enhancements:
- Automatic dump validity safety check before restore
- Press 'd' in archive browser to diagnose backups
- Press 'd' in restore preview for debug log toggle
- Debug logs saved to /tmp on failure when enabled
Documentation:
- Updated README with diagnose command and examples
- Updated CHANGELOG with full feature list
- Updated restore preview screenshots
- Fix format detection to read database_type from .meta.json metadata file
- Add ensureMySQLDatabaseExists() for MySQL/MariaDB database creation
- Route database creation to correct implementation based on db type
- Add TUI auto-forward in auto-confirm mode (no input required for debugging)
- All TUI components now exit automatically when --auto-confirm is set
- Fix status view to skip loading in auto-confirm mode
- Add .golangci.yml with minimal linters (govet, ineffassign)
- Run gofmt -s and goimports on all files to fix formatting
- Disable fieldalignment and copylocks checks in govet
The format detection now returns PostgreSQL Dump format for .dump files
when the file cannot be opened (e.g., when just checking filename pattern),
instead of falling back to SQL format.
This fixes the test that passes just a filename string without an actual file.
Sanitized all production-specific paths:
- /u01/dba/restore_tmp → /mnt/storage/restore_tmp
- /u01/dba/dumps/ → /mnt/backups/
Changed in:
- cmd/restore.go: Help text and flag description
- internal/restore/safety.go: Error message tip
- README.md: All documentation examples
- bin/*: Rebuilt all platform binaries
This ensures no production environment paths are exposed in public code/docs.
Solves disk space issues on VMs with small system disks but large NFS mounts.
Use case:
- VM has small / partition (e.g., 7.8G with 2.3G used)
- Backup archive on NFS mount (e.g., /u01/dba with 140G free)
- Restore fails: "insufficient disk space: 74.7% used - need at least 4x archive size"
Solution:
- Added --workdir flag to restore cluster command
- Allows specifying alternative extraction directory
- Interactive confirmation required for safety
- Updated error messages with helpful tip
Example:
dbbackup restore cluster backup.tar.gz --workdir /u01/dba/restore_tmp --confirm
This is environmental, not a bug. Code working brilliantly! 👨🍳💋
- Disabled --single-transaction to prevent lock table exhaustion with large objects
- Removed --exit-on-error to allow PostgreSQL to skip ignorable errors
- Fixes 'could not open large object' errors (lock exhaustion with 35K+ BLOBs)
- Fixes 'already exists' errors causing complete restore failure
- Each object now restored in its own transaction (locks released incrementally)
- PostgreSQL default behavior (continue on ignorable errors) is correct
Per PostgreSQL docs: --single-transaction incompatible with large object restores
and causes ALL locks to be held until commit, exhausting lock table with 1000+ objects
- Added detectLargeObjectsInDumps() to scan dump files for BLOB/LARGE OBJECT entries
- Automatically reduces ClusterParallelism to 1 when large objects detected
- Prevents 'could not open large object' and 'max_locks_per_transaction' errors
- Sequential restore eliminates lock table exhaustion when multiple DBs have BLOBs
- Uses pg_restore -l for fast metadata scanning (checks up to 5 dumps)
- Logs warning and shows user notification when parallelism adjusted
- Also includes: CLUSTER_RESTORE_COMPLIANCE.md documentation and enhanced d7030 test DB
IMPROVEMENTS:
- Better formatted error list (newline separated instead of semicolons)
- Detect and log specific error types (max_locks, massive error counts)
- Show succeeded/failed/total count in summary
- Provide actionable hints for known issues
KNOWN ISSUES DETECTED:
- max_locks_per_transaction: suggest increasing in postgresql.conf
- Massive error counts (2M+): indicate data corruption or incompatible dump
This helps users understand partial restore success and take corrective action.
CRITICAL OOM FIX:
- pg_restore --verbose outputs MASSIVE text (gigabytes for large DBs)
- Previous fix accumulated ALL errors in allErrors slice causing OOM
- Now limit error capture to last 10 errors only
- Discard verbose progress output entirely to prevent memory buildup
CHANGES:
- Replace allErrors slice with lastError string + errorCount counter
- Only log first 10 errors to prevent memory exhaustion
- Make --verbose optional via RestoreOptions.Verbose flag
- Disable --verbose for cluster restores (prevent OOM)
- Keep --verbose for single DB restores (better diagnostics)
This resolves 'runtime: out of memory' panic during cluster restore.
Based on PostgreSQL documentation research (postgresql.org/docs/current/app-pgrestore.html):
CRITICAL FIXES:
- Add --exit-on-error: pg_restore continues on errors by default, masking failures
- Add --no-data-for-failed-tables: prevents duplicate data in existing tables
- Use template0 for CREATE DATABASE: avoids duplicate definition errors from template1 additions
- Fix --jobs incompatibility: cannot use with --single-transaction per docs
WHY THIS MATTERS:
- Without --exit-on-error, pg_restore returns success even with failures
- Without --no-data-for-failed-tables, restore fails on existing objects
- template1 may have local additions causing 'duplicate definition' errors
- --jobs with --single-transaction causes pg_restore to fail
This should resolve the 'exit status 1' cluster restore failures.
- Capture all ERROR/FATAL/error: messages from pg_restore/psql stderr
- Include full error details in failure messages for better diagnostics
- Add --verbose flag to pg_restore for comprehensive error reporting
- Improve thread-safe logging in parallel cluster restore
- Help diagnose cluster restore failures with actual PostgreSQL error messages
1. Parallel Cluster Operations (3-5x speedup):
- Added ClusterParallelism config option (default: 2 concurrent operations)
- Implemented worker pool pattern for cluster backup/restore
- Thread-safe progress tracking with sync.Mutex and atomic counters
- Configurable via CLUSTER_PARALLELISM env var
2. Progress Indicator Optimizations:
- Replaced busy-wait select+sleep with time.Ticker in Spinner
- Replaced busy-wait select+sleep with time.Ticker in Dots
- More CPU-efficient, cleaner shutdown pattern
3. Signal Handler Cleanup:
- Added signal.Stop() to properly deregister signal handlers
- Prevents goroutine leaks on long-running operations
- Applied to both single and cluster restore commands
Benefits:
- Cluster backup/restore 3-5x faster with 2-4 workers
- Reduced CPU usage in progress spinners
- Cleaner goroutine lifecycle management
- No breaking changes - sequential by default if parallelism=1
- Replaced CombinedOutput() with streaming StderrPipe() in restore engine
- Fixed executeRestoreCommand() to read stderr in 4KB chunks
- Fixed executeRestoreWithDecompression() to stream output
- Fixed extractArchive() to avoid loading tar output into memory
- Fixed restoreGlobals() to stream large globals.sql files
- Only log ERROR/FATAL messages, not all output
- Prevents out-of-memory crashes on large database restores (GB+ data)
This fixes the 'fatal error: out of memory allocating heap arena metadata'
issue when restoring large cluster backups.
Issue: MySQL/MariaDB functions always used '-h hostname' flag, which can cause
issues with Unix socket authentication when connecting to localhost.
Similar to PostgreSQL peer authentication, MySQL prefers Unix socket connections
for localhost rather than TCP connections. Using '-h localhost' forces TCP which
may fail with socket-based authentication configurations.
Fixed locations:
1. internal/restore/safety.go:
- checkMySQLDatabaseExists() - now conditionally adds -h flag
- listMySQLUserDatabases() - now conditionally adds -h flag
2. cmd/placeholder.go:
- mysqlRestoreCommand() - now conditionally adds -h flag
Pattern applied (consistent with PostgreSQL fixes):
- Skip -h flag when host is localhost, 127.0.0.1, or empty
- Only add -h flag for actual remote hosts
- Allows mysql client to use Unix socket connection for local access
This ensures MySQL/MariaDB operations work correctly with both:
- Socket authentication (localhost via Unix socket)
- Password authentication (remote hosts via TCP)
Issue: Interactive cluster restore preview showed 'Cannot list databases: exit status 2'
when trying to detect existing databases. This happened because the safety check
functions always used '-h hostname' flag with psql, which breaks peer authentication.
Root cause:
- listPostgresUserDatabases() and checkPostgresDatabaseExists() always included -h flag
- For localhost peer auth, psql should connect via Unix socket (no -h flag)
- Adding -h localhost forces TCP connection which fails with peer authentication
Solution: Match the pattern used throughout the codebase:
- Only add -h flag when host is NOT localhost/127.0.0.1/empty
- For localhost, skip -h flag to use Unix socket
- Set PGPASSWORD only if password is provided
Fixed functions in internal/restore/safety.go:
- listPostgresUserDatabases()
- checkPostgresDatabaseExists()
Now interactive mode correctly shows existing databases count and list when
running as postgres user with peer authentication.
- Auto-detects existing user databases before cluster restore
- Shows count and list (first 5) in preview screen
- Toggle option 'c' to enable cluster cleanup
- Drops all user databases before restore when enabled
- Works for PostgreSQL, MySQL, MariaDB
- Safety warning with database count
- Implements practical disaster recovery workflow
BUG #1: restore single --create flag was not implemented
- Added ensureDatabaseExists() call when createIfMissing=true
- Database is now created before restore if --create flag is used
- Added TEST_PLAN.md with comprehensive testing matrix
Tested: restore single --create flag now works correctly
Before: ERROR: database does not exist
After: Database created successfully and restored
- Fixed type mismatch in disk space calculation (int64 casting)
- Created platform-specific disk space implementations:
* diskspace_unix.go (Linux, macOS, FreeBSD)
* diskspace_windows.go (Windows)
* diskspace_bsd.go (OpenBSD)
* diskspace_netbsd.go (NetBSD fallback)
- All 10 platforms now compile successfully:
✅ Linux (amd64, arm64, armv7)
✅ macOS (Intel, Apple Silicon)
✅ Windows (amd64, arm64)
✅ FreeBSD, OpenBSD, NetBSD
- Created internal/progress/estimator.go with ETAEstimator component
- Tracks elapsed time and estimates remaining time based on progress
- Enhanced Spinner and LineByLine indicators to display ETA info
- Integrated into BackupCluster and RestoreCluster functions
- Display format: 'Operation | X/Y (Z%) | Elapsed: Xm | ETA: ~Ym remaining'
- Preserves spinner animation while showing progress/time estimates
- Quick Win approach: no historical data storage, just current operation tracking
HIGH PRIORITY FIXES:
1. Remove unused progressCallback mechanism (dead code cleanup)
2. Add unit tests for restore package (formats, safety checks)
- Test coverage for archive format detection
- Test coverage for safety validation
- Added NullLogger for testing
3. Fix ignored errors in backup pipeline
- Handle StdoutPipe() errors properly
- Log stderr pipe errors
- Document CPU detection errors
IMPROVEMENTS:
- formats_test.go: 8 test functions, all passing
- safety_test.go: 6 test functions for validation
- logger/null.go: Test helper for unit tests
- Proper error handling in streaming compression
- Fixed indentation in stderr handling