-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add retention #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Pull Request Review: feat: Add retentionSummaryThis PR adds a retention policy feature to the Squid event database, allowing automatic cleanup of old events. The implementation includes a configurable retention policy, background cleanup goroutine, and proper index cleanup. Overall, the implementation is solid with excellent test coverage. Code Quality: ✅ GoodStrengths
Issues & Recommendations🔴 Critical Issues1. Race Condition in Close() - squid.go:48 if db.retention != nil && db.retention.running {
db.retention.cancel()
<-db.retention.done
}Problem: The Fix: Either:
// Recommended fix:
if db.retention != nil {
db.retention.cancel()
<-db.retention.done
}2. Error Handling Silently Ignores Deletion Failures - retention.go:120-123 for _, entry := range toDelete {
if err := db.deleteEventAndIndices(txn, entry); err != nil {
continue // ⚠️ Silently ignores errors!
}
deleted++
}Problem: Individual deletion errors are silently ignored, making debugging difficult and potentially leaving orphaned indices. Fix: Log errors or collect them: var errs []error
for _, entry := range toDelete {
if err := db.deleteEventAndIndices(txn, entry); err != nil {
errs = append(errs, fmt.Errorf("failed to delete event %s: %w", entry.id, err))
continue
}
deleted++
}
// Consider logging errs if len(errs) > 0🟡 Important Issues3. Potential Memory Issue with Large Deletions - retention.go:139-175 func (db *DB) findExpiredEvents(txn *badger.Txn, before time.Time) ([]deleteEntry, error) {
var toDelete []deleteEntry
// ... accumulates ALL expired events in memoryProblem: For databases with millions of expired events, this loads everything into memory at once. Impact: Could cause OOM on large databases with long retention periods. Fix: Consider batch processing with a configurable limit: const maxBatchSize = 10000 // configurable
func (db *DB) findExpiredEvents(txn *badger.Txn, before time.Time) ([]deleteEntry, error) {
var toDelete []deleteEntry
// ...
for it.Seek(prefix); it.ValidForPrefix(prefix) && len(toDelete) < maxBatchSize; it.Next() {
// ...
}
return toDelete, nil
}4. Missing Immediate Cleanup Synchronization - retention.go:82-84 // Run cleanup immediately on start
cutoff := time.Now().Add(-state.policy.MaxAge)
db.deleteBefore(cutoff)Problem: The immediate cleanup runs asynchronously, so Consideration: Document this behavior clearly, or provide a synchronous option for initial cleanup. 🟢 Minor Issues5. Inconsistent Error Handling in DeleteBefore() - retention.go:99-107 func (db *DB) DeleteBefore(before time.Time) (int64, error) {
db.mu.RLock()
if db.closed {
db.mu.RUnlock()
return 0, ErrClosed
}
db.mu.RUnlock()
return db.deleteBefore(before)
}Suggestion: The internal 6. JSON Unmarshal Error Handling - retention.go:159-163 err := item.Value(func(val []byte) error {
return json.Unmarshal(val, &event)
})
if err != nil {
continue // Silently skips corrupted events
}Suggestion: Consider logging corrupted events for debugging purposes. Performance Considerations✅ Good Choices
|
retention.gowith RetentionPolicySetRetention()configurationgoroutine