Add reliability improvements and config persistence feature
- Implement context cleanup with sync.Once and io.Closer interface - Add regex-based error classification for robust error handling - Create ProcessManager with thread-safe process tracking - Add disk space caching with 30s TTL for performance - Implement metrics collection with structured logging - Add config persistence (.dbbackup.conf) for directory-local settings - Auto-save/auto-load configuration with --no-config and --no-save-config flags - Successfully tested with 42GB d7030 database (35K large objects, 36min backup) - All cross-platform builds working (9/10 platforms)
This commit is contained in:
83
internal/checks/cache.go
Normal file
83
internal/checks/cache.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package checks
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// cacheEntry holds cached disk space information with TTL
|
||||
type cacheEntry struct {
|
||||
check *DiskSpaceCheck
|
||||
timestamp time.Time
|
||||
}
|
||||
|
||||
// DiskSpaceCache provides thread-safe caching of disk space checks with TTL
|
||||
type DiskSpaceCache struct {
|
||||
cache map[string]*cacheEntry
|
||||
cacheTTL time.Duration
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewDiskSpaceCache creates a new disk space cache with specified TTL
|
||||
func NewDiskSpaceCache(ttl time.Duration) *DiskSpaceCache {
|
||||
if ttl <= 0 {
|
||||
ttl = 30 * time.Second // Default 30 second cache
|
||||
}
|
||||
|
||||
return &DiskSpaceCache{
|
||||
cache: make(map[string]*cacheEntry),
|
||||
cacheTTL: ttl,
|
||||
}
|
||||
}
|
||||
|
||||
// Get retrieves cached disk space check or performs new check if cache miss/expired
|
||||
func (c *DiskSpaceCache) Get(path string) *DiskSpaceCheck {
|
||||
c.mu.RLock()
|
||||
if entry, exists := c.cache[path]; exists {
|
||||
if time.Since(entry.timestamp) < c.cacheTTL {
|
||||
c.mu.RUnlock()
|
||||
return entry.check
|
||||
}
|
||||
}
|
||||
c.mu.RUnlock()
|
||||
|
||||
// Cache miss or expired - perform new check
|
||||
check := CheckDiskSpace(path)
|
||||
|
||||
c.mu.Lock()
|
||||
c.cache[path] = &cacheEntry{
|
||||
check: check,
|
||||
timestamp: time.Now(),
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
return check
|
||||
}
|
||||
|
||||
// Clear removes all cached entries
|
||||
func (c *DiskSpaceCache) Clear() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.cache = make(map[string]*cacheEntry)
|
||||
}
|
||||
|
||||
// Cleanup removes expired entries (call periodically)
|
||||
func (c *DiskSpaceCache) Cleanup() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for path, entry := range c.cache {
|
||||
if now.Sub(entry.timestamp) >= c.cacheTTL {
|
||||
delete(c.cache, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Global cache instance with 30-second TTL
|
||||
var globalDiskCache = NewDiskSpaceCache(30 * time.Second)
|
||||
|
||||
// CheckDiskSpaceCached performs cached disk space check
|
||||
func CheckDiskSpaceCached(path string) *DiskSpaceCheck {
|
||||
return globalDiskCache.Get(path)
|
||||
}
|
||||
Reference in New Issue
Block a user