mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 10:12:26 -05:00
[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
This commit is contained in:
parent
7d09863393
commit
de6e3e5f2a
100 changed files with 4423 additions and 2367 deletions
|
|
@ -20,11 +20,13 @@ package bundb
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
|
|
@ -37,18 +39,15 @@ type accountDB struct {
|
|||
state *state.State
|
||||
}
|
||||
|
||||
func (a *accountDB) newAccountQ(account *gtsmodel.Account) *bun.SelectQuery {
|
||||
return a.conn.
|
||||
NewSelect().
|
||||
Model(account)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountByID(ctx context.Context, id string) (*gtsmodel.Account, db.Error) {
|
||||
return a.getAccount(
|
||||
ctx,
|
||||
"ID",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.newAccountQ(account).Where("? = ?", bun.Ident("account.id"), id).Scan(ctx)
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.id"), id).
|
||||
Scan(ctx)
|
||||
},
|
||||
id,
|
||||
)
|
||||
|
|
@ -59,7 +58,10 @@ func (a *accountDB) GetAccountByURI(ctx context.Context, uri string) (*gtsmodel.
|
|||
ctx,
|
||||
"URI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.newAccountQ(account).Where("? = ?", bun.Ident("account.uri"), uri).Scan(ctx)
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.uri"), uri).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
)
|
||||
|
|
@ -70,7 +72,10 @@ func (a *accountDB) GetAccountByURL(ctx context.Context, url string) (*gtsmodel.
|
|||
ctx,
|
||||
"URL",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.newAccountQ(account).Where("? = ?", bun.Ident("account.url"), url).Scan(ctx)
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.url"), url).
|
||||
Scan(ctx)
|
||||
},
|
||||
url,
|
||||
)
|
||||
|
|
@ -81,7 +86,8 @@ func (a *accountDB) GetAccountByUsernameDomain(ctx context.Context, username str
|
|||
ctx,
|
||||
"Username.Domain",
|
||||
func(account *gtsmodel.Account) error {
|
||||
q := a.newAccountQ(account)
|
||||
q := a.conn.NewSelect().
|
||||
Model(account)
|
||||
|
||||
if domain != "" {
|
||||
q = q.
|
||||
|
|
@ -105,12 +111,71 @@ func (a *accountDB) GetAccountByPubkeyID(ctx context.Context, id string) (*gtsmo
|
|||
ctx,
|
||||
"PublicKeyURI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.newAccountQ(account).Where("? = ?", bun.Ident("account.public_key_uri"), id).Scan(ctx)
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.public_key_uri"), id).
|
||||
Scan(ctx)
|
||||
},
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountByInboxURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
|
||||
return a.getAccount(
|
||||
ctx,
|
||||
"InboxURI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.inbox_uri"), uri).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountByOutboxURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
|
||||
return a.getAccount(
|
||||
ctx,
|
||||
"OutboxURI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.outbox_uri"), uri).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountByFollowersURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
|
||||
return a.getAccount(
|
||||
ctx,
|
||||
"FollowersURI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.followers_uri"), uri).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetAccountByFollowingURI(ctx context.Context, uri string) (*gtsmodel.Account, db.Error) {
|
||||
return a.getAccount(
|
||||
ctx,
|
||||
"FollowingURI",
|
||||
func(account *gtsmodel.Account) error {
|
||||
return a.conn.NewSelect().
|
||||
Model(account).
|
||||
Where("? = ?", bun.Ident("account.following_uri"), uri).
|
||||
Scan(ctx)
|
||||
},
|
||||
uri,
|
||||
)
|
||||
}
|
||||
|
||||
func (a *accountDB) GetInstanceAccount(ctx context.Context, domain string) (*gtsmodel.Account, db.Error) {
|
||||
var username string
|
||||
|
||||
|
|
@ -141,33 +206,58 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if account.AvatarMediaAttachmentID != "" {
|
||||
// Set the account's related avatar
|
||||
account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.AvatarMediaAttachmentID)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting account %s avatar: %v", account.ID, err)
|
||||
}
|
||||
if gtscontext.Barebones(ctx) {
|
||||
// no need to fully populate.
|
||||
return account, nil
|
||||
}
|
||||
|
||||
if account.HeaderMediaAttachmentID != "" {
|
||||
// Set the account's related header
|
||||
account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.HeaderMediaAttachmentID)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting account %s header: %v", account.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(account.EmojiIDs) > 0 {
|
||||
// Set the account's related emojis
|
||||
account.Emojis, err = a.state.DB.GetEmojisByIDs(ctx, account.EmojiIDs)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting account %s emojis: %v", account.ID, err)
|
||||
}
|
||||
// Further populate the account fields where applicable.
|
||||
if err := a.PopulateAccount(ctx, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func (a *accountDB) PopulateAccount(ctx context.Context, account *gtsmodel.Account) error {
|
||||
var err error
|
||||
|
||||
if account.AvatarMediaAttachment == nil && account.AvatarMediaAttachmentID != "" {
|
||||
// Account avatar attachment is not set, fetch from database.
|
||||
account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(
|
||||
ctx, // these are already barebones
|
||||
account.AvatarMediaAttachmentID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error populating account avatar: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if account.HeaderMediaAttachment == nil && account.HeaderMediaAttachmentID != "" {
|
||||
// Account header attachment is not set, fetch from database.
|
||||
account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(
|
||||
ctx, // these are already barebones
|
||||
account.HeaderMediaAttachmentID,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error populating account header: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !account.EmojisPopulated() {
|
||||
// Account emojis are out-of-date with IDs, repopulate.
|
||||
account.Emojis, err = a.state.DB.GetEmojisByIDs(
|
||||
ctx, // these are already barebones
|
||||
account.EmojiIDs,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error populating account emojis: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *accountDB) PutAccount(ctx context.Context, account *gtsmodel.Account) db.Error {
|
||||
return a.state.Caches.GTS.Account().Store(account, func() error {
|
||||
// It is safe to run this database transaction within cache.Store
|
||||
|
|
@ -198,7 +288,7 @@ func (a *accountDB) UpdateAccount(ctx context.Context, account *gtsmodel.Account
|
|||
columns = append(columns, "updated_at")
|
||||
}
|
||||
|
||||
return a.state.Caches.GTS.Account().Store(account, func() error {
|
||||
err := a.state.Caches.GTS.Account().Store(account, func() error {
|
||||
// It is safe to run this database transaction within cache.Store
|
||||
// as the cache does not attempt a mutex lock until AFTER hook.
|
||||
//
|
||||
|
|
@ -234,6 +324,11 @@ func (a *accountDB) UpdateAccount(ctx context.Context, account *gtsmodel.Account
|
|||
return err
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *accountDB) DeleteAccount(ctx context.Context, id string) db.Error {
|
||||
|
|
@ -258,7 +353,9 @@ func (a *accountDB) DeleteAccount(ctx context.Context, id string) db.Error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Invalidate account from database lookups.
|
||||
a.state.Caches.GTS.Account().Invalidate("ID", id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue