@@ -3207,29 +3207,6 @@ type StoreMetrics struct {
3207
3207
DiskWriteMaxBytesPerSecond * metric.Gauge
3208
3208
}
3209
3209
3210
- type tenantMetricsRef struct {
3211
- // All fields are internal. Don't access them.
3212
-
3213
- _tenantID roachpb.TenantID
3214
- _state int32 // atomic; 0=usable 1=poisoned
3215
-
3216
- // _stack helps diagnose use-after-release when it occurs.
3217
- // This field is populated in releaseTenant and printed
3218
- // in assertions on failure.
3219
- _stack struct {
3220
- syncutil.Mutex
3221
- debugutil.SafeStack
3222
- }
3223
- }
3224
-
3225
- func (ref * tenantMetricsRef ) assert (ctx context.Context ) {
3226
- if atomic .LoadInt32 (& ref ._state ) != 0 {
3227
- ref ._stack .Lock ()
3228
- defer ref ._stack .Unlock ()
3229
- log .FatalfDepth (ctx , 1 , "tenantMetricsRef already finalized in:\n %s" , ref ._stack .SafeStack )
3230
- }
3231
- }
3232
-
3233
3210
// TenantsStorageMetrics are metrics which are aggregated over all tenants
3234
3211
// present on the server. The struct maintains child metrics used by each
3235
3212
// tenant to track their individual values. The struct expects that children
@@ -3304,7 +3281,7 @@ func (sm *TenantsStorageMetrics) MetricStruct() {}
3304
3281
// method are reference counted with decrements occurring in the corresponding
3305
3282
// releaseTenant call. This method must be called prior to adding or subtracting
3306
3283
// MVCC stats.
3307
- func (sm * TenantsStorageMetrics ) acquireTenant (tenantID roachpb.TenantID ) * tenantMetricsRef {
3284
+ func (sm * TenantsStorageMetrics ) acquireTenant (tenantID roachpb.TenantID ) * tenantStorageMetrics {
3308
3285
// incRef increments the reference count if it is not already zero indicating
3309
3286
// that the struct has already been destroyed.
3310
3287
incRef := func (m * tenantStorageMetrics ) (alreadyDestroyed bool ) {
@@ -3319,17 +3296,13 @@ func (sm *TenantsStorageMetrics) acquireTenant(tenantID roachpb.TenantID) *tenan
3319
3296
for {
3320
3297
if m , ok := sm .tenants .Load (tenantID ); ok {
3321
3298
if alreadyDestroyed := incRef (m ); ! alreadyDestroyed {
3322
- return & m . ref
3299
+ return m
3323
3300
}
3324
3301
// Somebody else concurrently took the reference count to zero, go back
3325
3302
// around. Because of the locking in releaseTenant, we know that we'll
3326
3303
// find a different value or no value at all on the next iteration.
3327
3304
} else {
3328
- m := & tenantStorageMetrics {
3329
- ref : tenantMetricsRef {
3330
- _tenantID : tenantID ,
3331
- },
3332
- }
3305
+ m := & tenantStorageMetrics {tenantID : tenantID }
3333
3306
m .mu .Lock ()
3334
3307
_ , loaded := sm .tenants .LoadOrStore (tenantID , m )
3335
3308
if loaded {
@@ -3361,33 +3334,28 @@ func (sm *TenantsStorageMetrics) acquireTenant(tenantID roachpb.TenantID) *tenan
3361
3334
m .SysCount = sm .SysCount .AddChild (tenantIDStr )
3362
3335
m .AbortSpanBytes = sm .AbortSpanBytes .AddChild (tenantIDStr )
3363
3336
m .mu .Unlock ()
3364
- return & m . ref
3337
+ return m
3365
3338
}
3366
3339
}
3367
3340
}
3368
3341
3369
3342
// releaseTenant releases the reference to the metrics for this tenant which was
3370
3343
// acquired with acquireTenant. It will fatally log if no entry exists for this
3371
3344
// tenant.
3372
- func (sm * TenantsStorageMetrics ) releaseTenant (ctx context.Context , ref * tenantMetricsRef ) {
3373
- m := sm .getTenant (ctx , ref )
3374
-
3375
- ref ._stack .Lock ()
3376
- ref ._stack .SafeStack = debugutil .Stack ()
3377
- ref ._stack .Unlock ()
3345
+ func (sm * TenantsStorageMetrics ) releaseTenant (ctx context.Context , m * tenantStorageMetrics ) {
3378
3346
m .mu .Lock ()
3379
3347
defer m .mu .Unlock ()
3348
+ if m .mu .released .Load () {
3349
+ log .FatalfDepth (ctx , 1 , "tenant metrics already released in:\n %s" , m .mu .stack )
3350
+ }
3380
3351
m .mu .refCount --
3381
- if m .mu .refCount < 0 {
3382
- log .Fatalf (ctx , "invalid refCount on metrics for tenant %v: %d" , ref . _tenantID , m . mu . refCount )
3383
- } else if m . mu . refCount > 0 {
3352
+ if n := m .mu .refCount ; n < 0 {
3353
+ log .Fatalf (ctx , "invalid refCount on metrics for tenant %v: %d" , m . tenantID , n )
3354
+ } else if n > 0 {
3384
3355
return
3385
3356
}
3386
3357
3387
- if atomic .SwapInt32 (& ref ._state , 1 ) != 0 {
3388
- log .FatalfDepth (ctx , 1 , "tenant metrics already released in:\n %s" , ref ._stack .SafeStack )
3389
- return // unreachable
3390
- }
3358
+ m .mu .released .Store (true )
3391
3359
3392
3360
// The refCount is zero, delete this instance after destroying its metrics.
3393
3361
// Note that concurrent attempts to create an instance will detect the zero
@@ -3419,27 +3387,26 @@ func (sm *TenantsStorageMetrics) releaseTenant(ctx context.Context, ref *tenantM
3419
3387
(* gptr ).Unlink ()
3420
3388
* gptr = nil
3421
3389
}
3422
- sm .tenants .Delete (ref ._tenantID )
3423
- }
3424
-
3425
- // getTenant is a helper method used to retrieve the metrics for a tenant. The
3426
- // call will log fatally if no such tenant has been previously acquired.
3427
- func (sm * TenantsStorageMetrics ) getTenant (
3428
- ctx context.Context , ref * tenantMetricsRef ,
3429
- ) * tenantStorageMetrics {
3430
- ref .assert (ctx )
3431
- m , ok := sm .tenants .Load (ref ._tenantID )
3432
- if ! ok {
3433
- log .Fatalf (ctx , "no metrics exist for tenant %v" , ref ._tenantID )
3434
- }
3435
- return m
3390
+ sm .tenants .Delete (m .tenantID )
3436
3391
}
3437
3392
3393
+ // tenantStorageMetrics is a struct that holds the metrics for all replicas (
3394
+ // within a Store) of a given tenant.
3395
+ //
3396
+ // Whenever it is guaranteed that the replica is not destroyed, the metrics
3397
+ // fields can be accessed directly (for example, when holding raftMu and having
3398
+ // previously checked the replica's destroyStatus).
3399
+ //
3400
+ // Whenever this is *not* guaranteed, use `TenantsStorageMetrics.acquireTenant`
3401
+ // ( followed by releaseTenant after completion of usage) instead to avoid
3402
+ // racing with a potential concurrent attempt to release the metrics.
3438
3403
type tenantStorageMetrics struct {
3439
- ref tenantMetricsRef
3440
- mu struct {
3404
+ tenantID roachpb. TenantID
3405
+ mu struct {
3441
3406
syncutil.Mutex
3442
3407
refCount int
3408
+ released atomic.Bool // allowed to read without holding mu
3409
+ stack debugutil.SafeStack
3443
3410
}
3444
3411
3445
3412
LiveBytes * aggmetric.Gauge
@@ -3464,6 +3431,14 @@ type tenantStorageMetrics struct {
3464
3431
AbortSpanBytes * aggmetric.Gauge
3465
3432
}
3466
3433
3434
+ func (tm * tenantStorageMetrics ) assert (ctx context.Context ) {
3435
+ if tm .mu .released .Load () {
3436
+ tm .mu .Lock ()
3437
+ defer tm .mu .Unlock ()
3438
+ log .Fatalf (ctx , "tenant metrics already released in:\n %s" , tm .mu .stack )
3439
+ }
3440
+ }
3441
+
3467
3442
func newTenantsStorageMetrics () * TenantsStorageMetrics {
3468
3443
b := aggmetric .MakeBuilder (multitenant .TenantIDLabel )
3469
3444
sm := & TenantsStorageMetrics {
@@ -4023,10 +3998,9 @@ func newStoreMetrics(histogramWindow time.Duration) *StoreMetrics {
4023
3998
// single snapshot of these gauges in the registry might mix the values of two
4024
3999
// subsequent updates.
4025
4000
func (sm * TenantsStorageMetrics ) incMVCCGauges (
4026
- ctx context.Context , ref * tenantMetricsRef , delta enginepb.MVCCStats ,
4001
+ ctx context.Context , tm * tenantStorageMetrics , delta enginepb.MVCCStats ,
4027
4002
) {
4028
- ref .assert (ctx )
4029
- tm := sm .getTenant (ctx , ref )
4003
+ tm .assert (ctx )
4030
4004
tm .LiveBytes .Inc (delta .LiveBytes )
4031
4005
tm .KeyBytes .Inc (delta .KeyBytes )
4032
4006
tm .ValBytes .Inc (delta .ValBytes )
@@ -4050,17 +4024,17 @@ func (sm *TenantsStorageMetrics) incMVCCGauges(
4050
4024
}
4051
4025
4052
4026
func (sm * TenantsStorageMetrics ) addMVCCStats (
4053
- ctx context.Context , ref * tenantMetricsRef , delta enginepb.MVCCStats ,
4027
+ ctx context.Context , tm * tenantStorageMetrics , delta enginepb.MVCCStats ,
4054
4028
) {
4055
- sm .incMVCCGauges (ctx , ref , delta )
4029
+ sm .incMVCCGauges (ctx , tm , delta )
4056
4030
}
4057
4031
4058
4032
func (sm * TenantsStorageMetrics ) subtractMVCCStats (
4059
- ctx context.Context , ref * tenantMetricsRef , delta enginepb.MVCCStats ,
4033
+ ctx context.Context , tm * tenantStorageMetrics , delta enginepb.MVCCStats ,
4060
4034
) {
4061
4035
var neg enginepb.MVCCStats
4062
4036
neg .Subtract (delta )
4063
- sm .incMVCCGauges (ctx , ref , neg )
4037
+ sm .incMVCCGauges (ctx , tm , neg )
4064
4038
}
4065
4039
4066
4040
func (sm * StoreMetrics ) updateEngineMetrics (m storage.Metrics ) {
0 commit comments