@@ -6,6 +6,7 @@ package receive
66import (
77 "context"
88 "fmt"
9+ "maps"
910 "os"
1011 "path"
1112 "path/filepath"
@@ -201,10 +202,10 @@ type localClient struct {
201202 client storepb.StoreClient
202203}
203204
204- func newLocalClient (store * store.TSDBStore ) * localClient {
205+ func newLocalClient (store * store.TSDBStore , readOnly atomic. Bool ) * localClient {
205206 return & localClient {
206207 store : store ,
207- client : storepb .ServerAsClient (store ),
208+ client : storepb .ServerAsClient (store , readOnly ),
208209 }
209210}
210211
@@ -268,13 +269,19 @@ func (l *localClient) SupportsWithoutReplicaLabels() bool {
268269 return true
269270}
270271
272+ func (t * tenant ) setReadOnly (ro bool ) {
273+ t .readOnly .Store (ro )
274+ }
275+
271276type tenant struct {
272277 readyS * ReadyStorage
273278 storeTSDB * store.TSDBStore
274279 exemplarsTSDB * exemplars.TSDB
275280 ship * shipper.Shipper
276281 reg * UnRegisterer
277282
283+ readOnly atomic.Bool
284+
278285 mtx * sync.RWMutex
279286 tsdb * tsdb.DB
280287
@@ -338,7 +345,7 @@ func (t *tenant) client() store.Client {
338345 return nil
339346 }
340347
341- return newLocalClient (tsdbStore )
348+ return newLocalClient (tsdbStore , t . readOnly )
342349}
343350
344351func (t * tenant ) exemplars () * exemplars.TSDB {
@@ -472,14 +479,21 @@ func (t *MultiTSDB) Prune(ctx context.Context) error {
472479
473480 prunedTenants []string
474481 pmtx sync.Mutex
482+
483+ tenants = make (map [string ]* tenant )
475484 )
485+
476486 t .mtx .RLock ()
477- for tenantID , tenantInstance := range t .tenants {
487+ maps .Copy (tenants , t .tenants )
488+ t .mtx .RUnlock ()
489+
490+ begin := time .Now ()
491+ for tenantID , tenantInstance := range tenants {
478492 wg .Add (1 )
479493 go func (tenantID string , tenantInstance * tenant ) {
480494 defer wg .Done ()
481- tlog := log . With ( t . logger , "tenant" , tenantID )
482- pruned , err := t .pruneTSDB (ctx , tlog , tenantInstance )
495+
496+ pruned , err := t .pruneTSDB (ctx , log . With ( t . logger , "tenant" , tenantID ), tenantInstance , tenantID )
483497 if err != nil {
484498 merr .Add (err )
485499 return
@@ -493,50 +507,35 @@ func (t *MultiTSDB) Prune(ctx context.Context) error {
493507 }(tenantID , tenantInstance )
494508 }
495509 wg .Wait ()
496- t .mtx .RUnlock ()
497510
498- t .mtx .Lock ()
499- defer t .mtx .Unlock ()
500- for _ , tenantID := range prunedTenants {
501- // Check that the tenant hasn't been reinitialized in-between locks.
502- if t .tenants [tenantID ].readyStorage ().get () != nil {
503- continue
504- }
505-
506- level .Info (t .logger ).Log ("msg" , "Pruned tenant" , "tenant" , tenantID )
507- t .removeTenantUnlocked (tenantID )
508- }
511+ level .Info (t .logger ).Log ("msg" , "Pruning job completed" , "pruned_tenants_count" , len (prunedTenants ), "pruned_tenants" , prunedTenants , "took_seconds" , time .Since (begin ).Seconds ())
509512
510513 return merr .Err ()
511514}
512515
513516// pruneTSDB removes a TSDB if its past the retention period.
514517// It compacts the TSDB head, sends all remaining blocks to S3 and removes the TSDB from disk.
515- func (t * MultiTSDB ) pruneTSDB (ctx context.Context , logger log.Logger , tenantInstance * tenant ) (pruned bool , rerr error ) {
518+ func (t * MultiTSDB ) pruneTSDB (ctx context.Context , logger log.Logger , tenantInstance * tenant , tenantID string ) (pruned bool , rerr error ) {
516519 tenantTSDB := tenantInstance .readyStorage ()
517520 if tenantTSDB == nil {
518521 return false , nil
519522 }
520- tenantTSDB . mtx . RLock ()
521- if tenantTSDB . a == nil || tenantTSDB .a . db == nil {
522- tenantTSDB . mtx . RUnlock ()
523+
524+ tdb := tenantTSDB .Get ()
525+ if tdb == nil {
523526 return false , nil
524527 }
525528
526- tdb := tenantTSDB .a .db
527529 head := tdb .Head ()
528530 if head .MaxTime () < 0 {
529- tenantTSDB .mtx .RUnlock ()
530531 return false , nil
531532 }
532533
533534 sinceLastAppendMillis := time .Since (time .UnixMilli (head .MaxTime ())).Milliseconds ()
534535 compactThreshold := int64 (1.5 * float64 (t .tsdbOpts .MaxBlockDuration ))
535536 if sinceLastAppendMillis <= compactThreshold {
536- tenantTSDB .mtx .RUnlock ()
537537 return false , nil
538538 }
539- tenantTSDB .mtx .RUnlock ()
540539
541540 // Acquire a write lock and check that no writes have occurred in-between locks.
542541 tenantTSDB .mtx .Lock ()
@@ -585,6 +584,15 @@ func (t *MultiTSDB) pruneTSDB(ctx context.Context, logger log.Logger, tenantInst
585584 }
586585 }
587586
587+ tenantInstance .setReadOnly (true )
588+ defer func () {
589+ if pruned {
590+ return
591+ }
592+
593+ tenantInstance .setReadOnly (false )
594+ }()
595+
588596 if err := tdb .Close (); err != nil {
589597 return false , err
590598 }
@@ -598,6 +606,10 @@ func (t *MultiTSDB) pruneTSDB(ctx context.Context, logger log.Logger, tenantInst
598606 tenantInstance .setComponents (nil , nil , nil , nil , nil )
599607 tenantInstance .mtx .Unlock ()
600608
609+ t .mtx .Lock ()
610+ t .removeTenantUnlocked (tenantID )
611+ t .mtx .Unlock ()
612+
601613 return true , nil
602614}
603615
0 commit comments