Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb858a0d6f | ||
|
|
b478845e1c |
@@ -207,8 +207,11 @@ type C struct {
|
||||
ArchiveCacheTTLHrs int `env:"ORLY_ARCHIVE_CACHE_TTL_HRS" default:"24" usage:"hours to cache query fingerprints to avoid repeated archive requests"`
|
||||
|
||||
// Storage management configuration (access-based garbage collection)
|
||||
// TODO: GC implementation needs batch transaction handling to avoid Badger race conditions
|
||||
// TODO: GC should use smaller batches with delays between transactions on large datasets
|
||||
// TODO: GC deletion should be serialized or use transaction pools to prevent concurrent txn issues
|
||||
MaxStorageBytes int64 `env:"ORLY_MAX_STORAGE_BYTES" default:"0" usage:"maximum storage in bytes (0=auto-detect 80%% of filesystem)"`
|
||||
GCEnabled bool `env:"ORLY_GC_ENABLED" default:"true" usage:"enable continuous garbage collection based on access patterns"`
|
||||
GCEnabled bool `env:"ORLY_GC_ENABLED" default:"false" usage:"enable continuous garbage collection based on access patterns (EXPERIMENTAL - may cause crashes under load)"`
|
||||
GCIntervalSec int `env:"ORLY_GC_INTERVAL_SEC" default:"60" usage:"seconds between GC runs when storage exceeds limit"`
|
||||
GCBatchSize int `env:"ORLY_GC_BATCH_SIZE" default:"1000" usage:"number of events to consider per GC run"`
|
||||
|
||||
|
||||
@@ -590,14 +590,14 @@ func (d *D) QueryEventsWithOptions(c context.Context, f *filter.F, includeDelete
|
||||
if f.Limit != nil && len(evs) > int(*f.Limit) {
|
||||
evs = evs[:*f.Limit]
|
||||
}
|
||||
// delete the expired events in a background thread
|
||||
go func() {
|
||||
for i, ser := range expDeletes {
|
||||
if err = d.DeleteEventBySerial(c, ser, expEvs[i]); chk.E(err) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}()
|
||||
// TODO: DISABLED - inline deletion of expired events causes Badger race conditions
|
||||
// under high concurrent load ("assignment to entry in nil map" panic).
|
||||
// Expired events should be cleaned up by a separate, rate-limited background
|
||||
// worker instead of being deleted inline during query processing.
|
||||
// See: pkg/storage/gc.go TODOs for proper batch deletion implementation.
|
||||
if len(expDeletes) > 0 {
|
||||
log.D.F("QueryEvents: found %d expired events (deletion disabled)", len(expDeletes))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
package storage
|
||||
|
||||
// TODO: IMPORTANT - This GC implementation is EXPERIMENTAL and may cause crashes under high load.
|
||||
// The current implementation has the following issues that need to be addressed:
|
||||
//
|
||||
// 1. Badger race condition: DeleteEventBySerial runs transactions that can trigger
|
||||
// "assignment to entry in nil map" panics in Badger v4.8.0 under concurrent load.
|
||||
// This happens when GC deletes events while many REQ queries are being processed.
|
||||
//
|
||||
// 2. Batch transaction handling: On large datasets (14+ GB), deletions should be:
|
||||
// - Serialized or use a transaction pool to prevent concurrent txn issues
|
||||
// - Batched with proper delays between batches to avoid overwhelming Badger
|
||||
// - Rate-limited based on current system load
|
||||
//
|
||||
// 3. The current 10ms delay every 100 events (line ~237) is insufficient for busy relays.
|
||||
// Consider adaptive rate limiting based on pending transaction count.
|
||||
//
|
||||
// 4. Consider using Badger's WriteBatch API instead of individual Update transactions
|
||||
// for bulk deletions, which may be more efficient and avoid some race conditions.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
@@ -1 +1 @@
|
||||
v0.52.7
|
||||
v0.52.9
|
||||
|
||||
Reference in New Issue
Block a user