From 3cceed11b28b5f42a653d85ed779d652fd8c26ad Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:10:13 +0200 Subject: [feature/performance] Store account stats in separate table (#2831) * [feature/performance] Store account stats in separate table, get stats from remote * test account stats * add some missing increment / decrement calls * change stats function signatures * rejig logging a bit * use lock when updating stats --- internal/processing/workers/util.go | 255 ++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) (limited to 'internal/processing/workers/util.go') diff --git a/internal/processing/workers/util.go b/internal/processing/workers/util.go index a38ecd336..cd936f428 100644 --- a/internal/processing/workers/util.go +++ b/internal/processing/workers/util.go @@ -238,3 +238,258 @@ func (u *utilF) redirectFollowers( return true } + +func (u *utilF) incrementStatusesCount( + ctx context.Context, + account *gtsmodel.Account, + status *gtsmodel.Status, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by incrementing status + // count by one and setting last posted. + *account.Stats.StatusesCount++ + account.Stats.LastStatusAt = status.CreatedAt + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "statuses_count", + "last_status_at", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) decrementStatusesCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by decrementing + // status count by one. + // + // Clamp to 0 to avoid funny business. + *account.Stats.StatusesCount-- + if *account.Stats.StatusesCount < 0 { + *account.Stats.StatusesCount = 0 + } + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "statuses_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) incrementFollowersCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by incrementing followers + // count by one and setting last posted. + *account.Stats.FollowersCount++ + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "followers_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) decrementFollowersCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by decrementing + // followers count by one. + // + // Clamp to 0 to avoid funny business. + *account.Stats.FollowersCount-- + if *account.Stats.FollowersCount < 0 { + *account.Stats.FollowersCount = 0 + } + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "followers_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) incrementFollowingCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by incrementing + // followers count by one. + *account.Stats.FollowingCount++ + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "following_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) decrementFollowingCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by decrementing + // following count by one. + // + // Clamp to 0 to avoid funny business. + *account.Stats.FollowingCount-- + if *account.Stats.FollowingCount < 0 { + *account.Stats.FollowingCount = 0 + } + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "following_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) incrementFollowRequestsCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by incrementing + // follow requests count by one. + *account.Stats.FollowRequestsCount++ + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "follow_requests_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} + +func (u *utilF) decrementFollowRequestsCount( + ctx context.Context, + account *gtsmodel.Account, +) error { + // Lock on this account since we're changing stats. + unlock := u.state.AccountLocks.Lock(account.URI) + defer unlock() + + // Populate stats. + if account.Stats == nil { + if err := u.state.DB.PopulateAccountStats(ctx, account); err != nil { + return gtserror.Newf("db error getting account stats: %w", err) + } + } + + // Update stats by decrementing + // follow requests count by one. + // + // Clamp to 0 to avoid funny business. + *account.Stats.FollowRequestsCount-- + if *account.Stats.FollowRequestsCount < 0 { + *account.Stats.FollowRequestsCount = 0 + } + if err := u.state.DB.UpdateAccountStats( + ctx, + account.Stats, + "follow_requests_count", + ); err != nil { + return gtserror.Newf("db error updating account stats: %w", err) + } + + return nil +} -- cgit v1.2.3