mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 13:32:25 -05:00
[performance] retry db queries on busy errors (#2025)
* catch SQLITE_BUSY errors, wrap bun.DB to use our own busy retrier, remove unnecessary db.Error type Signed-off-by: kim <grufwub@gmail.com> * remove dead code Signed-off-by: kim <grufwub@gmail.com> * remove more dead code, add missing error arguments Signed-off-by: kim <grufwub@gmail.com> * update sqlite to use maxOpenConns() Signed-off-by: kim <grufwub@gmail.com> * add uncommitted changes Signed-off-by: kim <grufwub@gmail.com> * use direct calls-through for the ConnIface to make sure we don't double query hook Signed-off-by: kim <grufwub@gmail.com> * expose underlying bun.DB better Signed-off-by: kim <grufwub@gmail.com> * retry on the correct busy error Signed-off-by: kim <grufwub@gmail.com> * use longer possible maxRetries for db retry-backoff Signed-off-by: kim <grufwub@gmail.com> * remove the note regarding max-open-conns only applying to postgres Signed-off-by: kim <grufwub@gmail.com> * improved code commenting Signed-off-by: kim <grufwub@gmail.com> * remove unnecessary infof call (just use info) Signed-off-by: kim <grufwub@gmail.com> * rename DBConn to WrappedDB to better follow sql package name conventions Signed-off-by: kim <grufwub@gmail.com> * update test error string checks Signed-off-by: kim <grufwub@gmail.com> * shush linter Signed-off-by: kim <grufwub@gmail.com> * update backoff logic to be more transparent Signed-off-by: kim <grufwub@gmail.com> --------- Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
9eff0d46e4
commit
5f3e095717
53 changed files with 1050 additions and 898 deletions
|
|
@ -34,12 +34,12 @@ import (
|
|||
)
|
||||
|
||||
type instanceDB struct {
|
||||
conn *DBConn
|
||||
db *WrappedDB
|
||||
state *state.State
|
||||
}
|
||||
|
||||
func (i *instanceDB) CountInstanceUsers(ctx context.Context, domain string) (int, db.Error) {
|
||||
q := i.conn.
|
||||
func (i *instanceDB) CountInstanceUsers(ctx context.Context, domain string) (int, error) {
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||
Column("account.id").
|
||||
|
|
@ -56,13 +56,13 @@ func (i *instanceDB) CountInstanceUsers(ctx context.Context, domain string) (int
|
|||
|
||||
count, err := q.Count(ctx)
|
||||
if err != nil {
|
||||
return 0, i.conn.ProcessError(err)
|
||||
return 0, i.db.ProcessError(err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (int, db.Error) {
|
||||
q := i.conn.
|
||||
func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (int, error) {
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("statuses"), bun.Ident("status"))
|
||||
|
||||
|
|
@ -78,13 +78,13 @@ func (i *instanceDB) CountInstanceStatuses(ctx context.Context, domain string) (
|
|||
|
||||
count, err := q.Count(ctx)
|
||||
if err != nil {
|
||||
return 0, i.conn.ProcessError(err)
|
||||
return 0, i.db.ProcessError(err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (i *instanceDB) CountInstanceDomains(ctx context.Context, domain string) (int, db.Error) {
|
||||
q := i.conn.
|
||||
func (i *instanceDB) CountInstanceDomains(ctx context.Context, domain string) (int, error) {
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("instances"), bun.Ident("instance"))
|
||||
|
||||
|
|
@ -101,12 +101,12 @@ func (i *instanceDB) CountInstanceDomains(ctx context.Context, domain string) (i
|
|||
|
||||
count, err := q.Count(ctx)
|
||||
if err != nil {
|
||||
return 0, i.conn.ProcessError(err)
|
||||
return 0, i.db.ProcessError(err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (i *instanceDB) GetInstance(ctx context.Context, domain string) (*gtsmodel.Instance, db.Error) {
|
||||
func (i *instanceDB) GetInstance(ctx context.Context, domain string) (*gtsmodel.Instance, error) {
|
||||
// Normalize the domain as punycode
|
||||
var err error
|
||||
domain, err = util.Punify(domain)
|
||||
|
|
@ -118,7 +118,7 @@ func (i *instanceDB) GetInstance(ctx context.Context, domain string) (*gtsmodel.
|
|||
ctx,
|
||||
"Domain",
|
||||
func(instance *gtsmodel.Instance) error {
|
||||
return i.conn.NewSelect().
|
||||
return i.db.NewSelect().
|
||||
Model(instance).
|
||||
Where("? = ?", bun.Ident("instance.domain"), domain).
|
||||
Scan(ctx)
|
||||
|
|
@ -132,7 +132,7 @@ func (i *instanceDB) GetInstanceByID(ctx context.Context, id string) (*gtsmodel.
|
|||
ctx,
|
||||
"ID",
|
||||
func(instance *gtsmodel.Instance) error {
|
||||
return i.conn.NewSelect().
|
||||
return i.db.NewSelect().
|
||||
Model(instance).
|
||||
Where("? = ?", bun.Ident("instance.id"), id).
|
||||
Scan(ctx)
|
||||
|
|
@ -141,14 +141,14 @@ func (i *instanceDB) GetInstanceByID(ctx context.Context, id string) (*gtsmodel.
|
|||
)
|
||||
}
|
||||
|
||||
func (i *instanceDB) getInstance(ctx context.Context, lookup string, dbQuery func(*gtsmodel.Instance) error, keyParts ...any) (*gtsmodel.Instance, db.Error) {
|
||||
func (i *instanceDB) getInstance(ctx context.Context, lookup string, dbQuery func(*gtsmodel.Instance) error, keyParts ...any) (*gtsmodel.Instance, error) {
|
||||
// Fetch instance from database cache with loader callback
|
||||
instance, err := i.state.Caches.GTS.Instance().Load(lookup, func() (*gtsmodel.Instance, error) {
|
||||
var instance gtsmodel.Instance
|
||||
|
||||
// Not cached! Perform database query.
|
||||
if err := dbQuery(&instance); err != nil {
|
||||
return nil, i.conn.ProcessError(err)
|
||||
return nil, i.db.ProcessError(err)
|
||||
}
|
||||
|
||||
return &instance, nil
|
||||
|
|
@ -210,8 +210,8 @@ func (i *instanceDB) PutInstance(ctx context.Context, instance *gtsmodel.Instanc
|
|||
}
|
||||
|
||||
return i.state.Caches.GTS.Instance().Store(instance, func() error {
|
||||
_, err := i.conn.NewInsert().Model(instance).Exec(ctx)
|
||||
return i.conn.ProcessError(err)
|
||||
_, err := i.db.NewInsert().Model(instance).Exec(ctx)
|
||||
return i.db.ProcessError(err)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -230,20 +230,20 @@ func (i *instanceDB) UpdateInstance(ctx context.Context, instance *gtsmodel.Inst
|
|||
}
|
||||
|
||||
return i.state.Caches.GTS.Instance().Store(instance, func() error {
|
||||
_, err := i.conn.
|
||||
_, err := i.db.
|
||||
NewUpdate().
|
||||
Model(instance).
|
||||
Where("? = ?", bun.Ident("instance.id"), instance.ID).
|
||||
Column(columns...).
|
||||
Exec(ctx)
|
||||
return i.conn.ProcessError(err)
|
||||
return i.db.ProcessError(err)
|
||||
})
|
||||
}
|
||||
|
||||
func (i *instanceDB) GetInstancePeers(ctx context.Context, includeSuspended bool) ([]*gtsmodel.Instance, db.Error) {
|
||||
func (i *instanceDB) GetInstancePeers(ctx context.Context, includeSuspended bool) ([]*gtsmodel.Instance, error) {
|
||||
instanceIDs := []string{}
|
||||
|
||||
q := i.conn.
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("instances"), bun.Ident("instance")).
|
||||
// Select just the IDs of each instance.
|
||||
|
|
@ -256,7 +256,7 @@ func (i *instanceDB) GetInstancePeers(ctx context.Context, includeSuspended bool
|
|||
}
|
||||
|
||||
if err := q.Scan(ctx, &instanceIDs); err != nil {
|
||||
return nil, i.conn.ProcessError(err)
|
||||
return nil, i.db.ProcessError(err)
|
||||
}
|
||||
|
||||
if len(instanceIDs) == 0 {
|
||||
|
|
@ -280,7 +280,7 @@ func (i *instanceDB) GetInstancePeers(ctx context.Context, includeSuspended bool
|
|||
return instances, nil
|
||||
}
|
||||
|
||||
func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, maxID string, limit int) ([]*gtsmodel.Account, db.Error) {
|
||||
func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, maxID string, limit int) ([]*gtsmodel.Account, error) {
|
||||
// Ensure reasonable
|
||||
if limit < 0 {
|
||||
limit = 0
|
||||
|
|
@ -296,7 +296,7 @@ func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, max
|
|||
// Make educated guess for slice size
|
||||
accountIDs := make([]string, 0, limit)
|
||||
|
||||
q := i.conn.
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("accounts"), bun.Ident("account")).
|
||||
// Select just the account ID.
|
||||
|
|
@ -315,7 +315,7 @@ func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, max
|
|||
}
|
||||
|
||||
if err := q.Scan(ctx, &accountIDs); err != nil {
|
||||
return nil, i.conn.ProcessError(err)
|
||||
return nil, i.db.ProcessError(err)
|
||||
}
|
||||
|
||||
// Catch case of no accounts early.
|
||||
|
|
@ -340,13 +340,13 @@ func (i *instanceDB) GetInstanceAccounts(ctx context.Context, domain string, max
|
|||
return accounts, nil
|
||||
}
|
||||
|
||||
func (i *instanceDB) GetInstanceModeratorAddresses(ctx context.Context) ([]string, db.Error) {
|
||||
func (i *instanceDB) GetInstanceModeratorAddresses(ctx context.Context) ([]string, error) {
|
||||
addresses := []string{}
|
||||
|
||||
// Select email addresses of approved, confirmed,
|
||||
// and enabled moderators or admins.
|
||||
|
||||
q := i.conn.
|
||||
q := i.db.
|
||||
NewSelect().
|
||||
TableExpr("? AS ?", bun.Ident("users"), bun.Ident("user")).
|
||||
Column("user.email").
|
||||
|
|
@ -361,7 +361,7 @@ func (i *instanceDB) GetInstanceModeratorAddresses(ctx context.Context) ([]strin
|
|||
OrderExpr("? ASC", bun.Ident("user.email"))
|
||||
|
||||
if err := q.Scan(ctx, &addresses); err != nil {
|
||||
return nil, i.conn.ProcessError(err)
|
||||
return nil, i.db.ProcessError(err)
|
||||
}
|
||||
|
||||
if len(addresses) == 0 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue