@@ -44,8 +44,23 @@ import (
44
44
"github.com/cortexproject/cortex/pkg/util/validation"
45
45
)
46
46
47
- // BucketStores is a multi-tenant wrapper of Thanos BucketStore.
48
- type BucketStores struct {
47
+ // BucketStoreType represents the type of bucket store
48
+ type BucketStoreType string
49
+
50
+ const (
51
+ TSDBBucketStore BucketStoreType = "tsdb"
52
+ ParquetBucketStore BucketStoreType = "parquet"
53
+ )
54
+
55
+ // BucketStores defines the methods that any bucket stores implementation must provide
56
+ type BucketStores interface {
57
+ storepb.StoreServer
58
+ SyncBlocks (ctx context.Context ) error
59
+ InitialSync (ctx context.Context ) error
60
+ }
61
+
62
+ // ThanosBucketStores is a multi-tenant wrapper of Thanos BucketStore.
63
+ type ThanosBucketStores struct {
49
64
logger log.Logger
50
65
cfg tsdb.BlocksStorageConfig
51
66
limits * validation.Overrides
@@ -74,7 +89,7 @@ type BucketStores struct {
74
89
storesMu sync.RWMutex
75
90
stores map [string ]* store.BucketStore
76
91
77
- // Keeps the last sync error for the bucket store for each tenant.
92
+ // Keeps the last sync error for the bucket store for each tenant.
78
93
storesErrorsMu sync.RWMutex
79
94
storesErrors map [string ]error
80
95
@@ -86,8 +101,7 @@ type BucketStores struct {
86
101
userScanner users.Scanner
87
102
88
103
// Keeps number of inflight requests
89
- inflightRequestCnt int
90
- inflightRequestMu sync.RWMutex
104
+ inflightRequests * util.InflightRequestTracker
91
105
92
106
// Metrics.
93
107
syncTimes prometheus.Histogram
@@ -99,7 +113,19 @@ type BucketStores struct {
99
113
var ErrTooManyInflightRequests = status .Error (codes .ResourceExhausted , "too many inflight requests in store gateway" )
100
114
101
115
// NewBucketStores makes a new BucketStores.
102
- func NewBucketStores (cfg tsdb.BlocksStorageConfig , shardingStrategy ShardingStrategy , bucketClient objstore.InstrumentedBucket , limits * validation.Overrides , logLevel logging.Level , logger log.Logger , reg prometheus.Registerer ) (* BucketStores , error ) {
116
+ func NewBucketStores (cfg tsdb.BlocksStorageConfig , shardingStrategy ShardingStrategy , bucketClient objstore.InstrumentedBucket , limits * validation.Overrides , logLevel logging.Level , logger log.Logger , reg prometheus.Registerer ) (BucketStores , error ) {
117
+ switch cfg .BucketStore .BucketStoreType {
118
+ case string (ParquetBucketStore ):
119
+ return newParquetBucketStores (cfg , bucketClient , limits , logger , reg )
120
+ case string (TSDBBucketStore ):
121
+ return newThanosBucketStores (cfg , shardingStrategy , bucketClient , limits , logLevel , logger , reg )
122
+ default :
123
+ return nil , fmt .Errorf ("unsupported bucket store type: %s" , cfg .BucketStore .BucketStoreType )
124
+ }
125
+ }
126
+
127
+ // newThanosBucketStores creates a new TSDB-based bucket stores
128
+ func newThanosBucketStores (cfg tsdb.BlocksStorageConfig , shardingStrategy ShardingStrategy , bucketClient objstore.InstrumentedBucket , limits * validation.Overrides , logLevel logging.Level , logger log.Logger , reg prometheus.Registerer ) (* ThanosBucketStores , error ) {
103
129
matchers := tsdb .NewMatchers ()
104
130
cachingBucket , err := tsdb .CreateCachingBucket (cfg .BucketStore .ChunksCache , cfg .BucketStore .MetadataCache , tsdb.ParquetLabelsCacheConfig {}, matchers , bucketClient , logger , reg )
105
131
if err != nil {
@@ -114,7 +140,7 @@ func NewBucketStores(cfg tsdb.BlocksStorageConfig, shardingStrategy ShardingStra
114
140
Help : "Number of maximum concurrent queries allowed." ,
115
141
}).Set (float64 (cfg .BucketStore .MaxConcurrent ))
116
142
117
- u := & BucketStores {
143
+ u := & ThanosBucketStores {
118
144
logger : logger ,
119
145
cfg : cfg ,
120
146
limits : limits ,
@@ -128,6 +154,7 @@ func NewBucketStores(cfg tsdb.BlocksStorageConfig, shardingStrategy ShardingStra
128
154
queryGate : queryGate ,
129
155
partitioner : newGapBasedPartitioner (cfg .BucketStore .PartitionerMaxGapBytes , reg ),
130
156
userTokenBuckets : make (map [string ]* util.TokenBucket ),
157
+ inflightRequests : util .NewInflightRequestTracker (),
131
158
syncTimes : promauto .With (reg ).NewHistogram (prometheus.HistogramOpts {
132
159
Name : "cortex_bucket_stores_blocks_sync_seconds" ,
133
160
Help : "The total time it takes to perform a sync stores" ,
@@ -187,7 +214,7 @@ func NewBucketStores(cfg tsdb.BlocksStorageConfig, shardingStrategy ShardingStra
187
214
}
188
215
189
216
// InitialSync does an initial synchronization of blocks for all users.
190
- func (u * BucketStores ) InitialSync (ctx context.Context ) error {
217
+ func (u * ThanosBucketStores ) InitialSync (ctx context.Context ) error {
191
218
level .Info (u .logger ).Log ("msg" , "synchronizing TSDB blocks for all users" )
192
219
193
220
if err := u .syncUsersBlocksWithRetries (ctx , func (ctx context.Context , s * store.BucketStore ) error {
@@ -202,13 +229,13 @@ func (u *BucketStores) InitialSync(ctx context.Context) error {
202
229
}
203
230
204
231
// SyncBlocks synchronizes the stores state with the Bucket store for every user.
205
- func (u * BucketStores ) SyncBlocks (ctx context.Context ) error {
232
+ func (u * ThanosBucketStores ) SyncBlocks (ctx context.Context ) error {
206
233
return u .syncUsersBlocksWithRetries (ctx , func (ctx context.Context , s * store.BucketStore ) error {
207
234
return s .SyncBlocks (ctx )
208
235
})
209
236
}
210
237
211
- func (u * BucketStores ) syncUsersBlocksWithRetries (ctx context.Context , f func (context.Context , * store.BucketStore ) error ) error {
238
+ func (u * ThanosBucketStores ) syncUsersBlocksWithRetries (ctx context.Context , f func (context.Context , * store.BucketStore ) error ) error {
212
239
retries := backoff .New (ctx , backoff.Config {
213
240
MinBackoff : 1 * time .Second ,
214
241
MaxBackoff : 10 * time .Second ,
@@ -232,7 +259,7 @@ func (u *BucketStores) syncUsersBlocksWithRetries(ctx context.Context, f func(co
232
259
return lastErr
233
260
}
234
261
235
- func (u * BucketStores ) syncUsersBlocks (ctx context.Context , f func (context.Context , * store.BucketStore ) error ) (returnErr error ) {
262
+ func (u * ThanosBucketStores ) syncUsersBlocks (ctx context.Context , f func (context.Context , * store.BucketStore ) error ) (returnErr error ) {
236
263
defer func (start time.Time ) {
237
264
u .syncTimes .Observe (time .Since (start ).Seconds ())
238
265
if returnErr == nil {
@@ -330,7 +357,7 @@ func (u *BucketStores) syncUsersBlocks(ctx context.Context, f func(context.Conte
330
357
}
331
358
332
359
// Series makes a series request to the underlying user bucket store.
333
- func (u * BucketStores ) Series (req * storepb.SeriesRequest , srv storepb.Store_SeriesServer ) error {
360
+ func (u * ThanosBucketStores ) Series (req * storepb.SeriesRequest , srv storepb.Store_SeriesServer ) error {
334
361
spanLog , spanCtx := spanlogger .New (srv .Context (), "BucketStores.Series" )
335
362
defer spanLog .Finish ()
336
363
@@ -356,12 +383,12 @@ func (u *BucketStores) Series(req *storepb.SeriesRequest, srv storepb.Store_Seri
356
383
357
384
maxInflightRequests := u .cfg .BucketStore .MaxInflightRequests
358
385
if maxInflightRequests > 0 {
359
- if u .getInflightRequestCnt () >= maxInflightRequests {
386
+ if u .inflightRequests . Count () >= maxInflightRequests {
360
387
return ErrTooManyInflightRequests
361
388
}
362
389
363
- u .incrementInflightRequestCnt ()
364
- defer u .decrementInflightRequestCnt ()
390
+ u .inflightRequests . Inc ()
391
+ defer u .inflightRequests . Dec ()
365
392
}
366
393
367
394
err = store .Series (req , spanSeriesServer {
@@ -372,26 +399,8 @@ func (u *BucketStores) Series(req *storepb.SeriesRequest, srv storepb.Store_Seri
372
399
return err
373
400
}
374
401
375
- func (u * BucketStores ) getInflightRequestCnt () int {
376
- u .inflightRequestMu .RLock ()
377
- defer u .inflightRequestMu .RUnlock ()
378
- return u .inflightRequestCnt
379
- }
380
-
381
- func (u * BucketStores ) incrementInflightRequestCnt () {
382
- u .inflightRequestMu .Lock ()
383
- u .inflightRequestCnt ++
384
- u .inflightRequestMu .Unlock ()
385
- }
386
-
387
- func (u * BucketStores ) decrementInflightRequestCnt () {
388
- u .inflightRequestMu .Lock ()
389
- u .inflightRequestCnt --
390
- u .inflightRequestMu .Unlock ()
391
- }
392
-
393
402
// LabelNames implements the Storegateway proto service.
394
- func (u * BucketStores ) LabelNames (ctx context.Context , req * storepb.LabelNamesRequest ) (* storepb.LabelNamesResponse , error ) {
403
+ func (u * ThanosBucketStores ) LabelNames (ctx context.Context , req * storepb.LabelNamesRequest ) (* storepb.LabelNamesResponse , error ) {
395
404
spanLog , spanCtx := spanlogger .New (ctx , "BucketStores.LabelNames" )
396
405
defer spanLog .Finish ()
397
406
@@ -421,7 +430,7 @@ func (u *BucketStores) LabelNames(ctx context.Context, req *storepb.LabelNamesRe
421
430
}
422
431
423
432
// LabelValues implements the Storegateway proto service.
424
- func (u * BucketStores ) LabelValues (ctx context.Context , req * storepb.LabelValuesRequest ) (* storepb.LabelValuesResponse , error ) {
433
+ func (u * ThanosBucketStores ) LabelValues (ctx context.Context , req * storepb.LabelValuesRequest ) (* storepb.LabelValuesResponse , error ) {
425
434
spanLog , spanCtx := spanlogger .New (ctx , "BucketStores.LabelValues" )
426
435
defer spanLog .Finish ()
427
436
@@ -450,7 +459,7 @@ func (u *BucketStores) LabelValues(ctx context.Context, req *storepb.LabelValues
450
459
451
460
// scanUsers in the bucket and return the list of found users. It includes active and deleting users
452
461
// but not deleted users.
453
- func (u * BucketStores ) scanUsers (ctx context.Context ) ([]string , error ) {
462
+ func (u * ThanosBucketStores ) scanUsers (ctx context.Context ) ([]string , error ) {
454
463
activeUsers , deletingUsers , _ , err := u .userScanner .ScanUsers (ctx )
455
464
if err != nil {
456
465
return nil , err
@@ -477,13 +486,13 @@ func deduplicateUsers(users []string) []string {
477
486
return uniqueUsers
478
487
}
479
488
480
- func (u * BucketStores ) getStore (userID string ) * store.BucketStore {
489
+ func (u * ThanosBucketStores ) getStore (userID string ) * store.BucketStore {
481
490
u .storesMu .RLock ()
482
491
defer u .storesMu .RUnlock ()
483
492
return u .stores [userID ]
484
493
}
485
494
486
- func (u * BucketStores ) getStoreError (userID string ) error {
495
+ func (u * ThanosBucketStores ) getStoreError (userID string ) error {
487
496
u .storesErrorsMu .RLock ()
488
497
defer u .storesErrorsMu .RUnlock ()
489
498
return u .storesErrors [userID ]
@@ -499,7 +508,7 @@ var (
499
508
// If bucket store doesn't exist, returns errBucketStoreNotFound.
500
509
// If bucket store is not empty, returns errBucketStoreNotEmpty.
501
510
// Otherwise returns error from closing the bucket store.
502
- func (u * BucketStores ) closeEmptyBucketStore (userID string ) error {
511
+ func (u * ThanosBucketStores ) closeEmptyBucketStore (userID string ) error {
503
512
u .storesMu .Lock ()
504
513
unlockInDefer := true
505
514
defer func () {
@@ -537,11 +546,11 @@ func isEmptyBucketStore(bs *store.BucketStore) bool {
537
546
return min == math .MaxInt64 && max == math .MinInt64
538
547
}
539
548
540
- func (u * BucketStores ) syncDirForUser (userID string ) string {
549
+ func (u * ThanosBucketStores ) syncDirForUser (userID string ) string {
541
550
return filepath .Join (u .cfg .BucketStore .SyncDir , userID )
542
551
}
543
552
544
- func (u * BucketStores ) getOrCreateStore (userID string ) (* store.BucketStore , error ) {
553
+ func (u * ThanosBucketStores ) getOrCreateStore (userID string ) (* store.BucketStore , error ) {
545
554
// Check if the store already exists.
546
555
bs := u .getStore (userID )
547
556
if bs != nil {
@@ -721,7 +730,7 @@ func (u *BucketStores) getOrCreateStore(userID string) (*store.BucketStore, erro
721
730
722
731
// deleteLocalFilesForExcludedTenants removes local "sync" directories for tenants that are not included in the current
723
732
// shard.
724
- func (u * BucketStores ) deleteLocalFilesForExcludedTenants (includeUserIDs map [string ]struct {}) {
733
+ func (u * ThanosBucketStores ) deleteLocalFilesForExcludedTenants (includeUserIDs map [string ]struct {}) {
725
734
files , err := os .ReadDir (u .cfg .BucketStore .SyncDir )
726
735
if err != nil {
727
736
return
@@ -760,13 +769,13 @@ func (u *BucketStores) deleteLocalFilesForExcludedTenants(includeUserIDs map[str
760
769
}
761
770
}
762
771
763
- func (u * BucketStores ) getUserTokenBucket (userID string ) * util.TokenBucket {
772
+ func (u * ThanosBucketStores ) getUserTokenBucket (userID string ) * util.TokenBucket {
764
773
u .userTokenBucketsMu .RLock ()
765
774
defer u .userTokenBucketsMu .RUnlock ()
766
775
return u .userTokenBuckets [userID ]
767
776
}
768
777
769
- func (u * BucketStores ) getTokensToRetrieve (tokens uint64 , dataType store.StoreDataType ) int64 {
778
+ func (u * ThanosBucketStores ) getTokensToRetrieve (tokens uint64 , dataType store.StoreDataType ) int64 {
770
779
tokensToRetrieve := float64 (tokens )
771
780
switch dataType {
772
781
case store .PostingsFetched :
0 commit comments