summaryrefslogtreecommitdiff
path: root/internal/db/bundb/mention.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-01-19 12:57:29 +0000
committerLibravatar GitHub <noreply@github.com>2024-01-19 12:57:29 +0000
commit7ec1e1332e7d04e74451acef18b41f389722b698 (patch)
tree9c69eca7fc664ab5564279a2e065dfd5c2ddd17b /internal/db/bundb/mention.go
parent[chore] chore rationalise http return codes for activitypub handlers (#2540) (diff)
downloadgotosocial-7ec1e1332e7d04e74451acef18b41f389722b698.tar.xz
[performance] overhaul struct (+ result) caching library for simplicity, performance and multiple-result lookups (#2535)
* rewrite cache library as codeberg.org/gruf/go-structr, implement in gotosocial * use actual go-structr release version (not just commit hash) * revert go toolchain changes (damn you go for auto changing this) * fix go mod woes * ensure %w is used in calls to errs.Appendf() * fix error checking * fix possible panic * remove unnecessary start/stop functions, move to main Cache{} struct, add note regarding which caches require start/stop * fix copy-paste artifact... :innocent: * fix all comment copy-paste artifacts * remove dropID() function, now we can just use slices.DeleteFunc() * use util.Deduplicate() instead of collate(), move collate to util * move orderByIDs() to util package and "generify" * add a util.DeleteIf() function, use this to delete entries on failed population * use slices.DeleteFunc() instead of util.DeleteIf() (i had the logic mixed up in my head somehow lol) * add note about how collate differs from deduplicate
Diffstat (limited to 'internal/db/bundb/mention.go')
-rw-r--r--internal/db/bundb/mention.go71
1 files changed, 58 insertions, 13 deletions
diff --git a/internal/db/bundb/mention.go b/internal/db/bundb/mention.go
index 30a20b0c1..b069423bb 100644
--- a/internal/db/bundb/mention.go
+++ b/internal/db/bundb/mention.go
@@ -20,6 +20,7 @@ package bundb
import (
"context"
"errors"
+ "slices"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
@@ -27,6 +28,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/state"
+ "github.com/superseriousbusiness/gotosocial/internal/util"
"github.com/uptrace/bun"
)
@@ -36,7 +38,7 @@ type mentionDB struct {
}
func (m *mentionDB) GetMention(ctx context.Context, id string) (*gtsmodel.Mention, error) {
- mention, err := m.state.Caches.GTS.Mention().Load("ID", func() (*gtsmodel.Mention, error) {
+ mention, err := m.state.Caches.GTS.Mention.LoadOne("ID", func() (*gtsmodel.Mention, error) {
var mention gtsmodel.Mention
q := m.db.
@@ -63,21 +65,64 @@ func (m *mentionDB) GetMention(ctx context.Context, id string) (*gtsmodel.Mentio
}
func (m *mentionDB) GetMentions(ctx context.Context, ids []string) ([]*gtsmodel.Mention, error) {
- mentions := make([]*gtsmodel.Mention, 0, len(ids))
+ // Preallocate at-worst possible length.
+ uncached := make([]string, 0, len(ids))
+
+ // Load all mention IDs via cache loader callbacks.
+ mentions, err := m.state.Caches.GTS.Mention.Load("ID",
+
+ // Load cached + check for uncached.
+ func(load func(keyParts ...any) bool) {
+ for _, id := range ids {
+ if !load(id) {
+ uncached = append(uncached, id)
+ }
+ }
+ },
+
+ // Uncached mention loader function.
+ func() ([]*gtsmodel.Mention, error) {
+ // Preallocate expected length of uncached mentions.
+ mentions := make([]*gtsmodel.Mention, 0, len(uncached))
+
+ // Perform database query scanning
+ // the remaining (uncached) IDs.
+ if err := m.db.NewSelect().
+ Model(&mentions).
+ Where("? IN (?)", bun.Ident("id"), bun.In(uncached)).
+ Scan(ctx); err != nil {
+ return nil, err
+ }
+
+ return mentions, nil
+ },
+ )
+ if err != nil {
+ return nil, err
+ }
- for _, id := range ids {
- // Attempt fetch from DB
- mention, err := m.GetMention(ctx, id)
- if err != nil {
- log.Errorf(ctx, "error getting mention %q: %v", id, err)
- continue
- }
+ // Reorder the mentions by their
+ // IDs to ensure in correct order.
+ getID := func(m *gtsmodel.Mention) string { return m.ID }
+ util.OrderBy(mentions, ids, getID)
- // Append mention
- mentions = append(mentions, mention)
+ if gtscontext.Barebones(ctx) {
+ // no need to fully populate.
+ return mentions, nil
}
+ // Populate all loaded mentions, removing those we fail to
+ // populate (removes needing so many nil checks everywhere).
+ mentions = slices.DeleteFunc(mentions, func(mention *gtsmodel.Mention) bool {
+ if err := m.PopulateMention(ctx, mention); err != nil {
+ log.Errorf(ctx, "error populating mention %s: %v", mention.ID, err)
+ return true
+ }
+ return false
+ })
+
return mentions, nil
+
}
func (m *mentionDB) PopulateMention(ctx context.Context, mention *gtsmodel.Mention) (err error) {
@@ -120,14 +165,14 @@ func (m *mentionDB) PopulateMention(ctx context.Context, mention *gtsmodel.Menti
}
func (m *mentionDB) PutMention(ctx context.Context, mention *gtsmodel.Mention) error {
- return m.state.Caches.GTS.Mention().Store(mention, func() error {
+ return m.state.Caches.GTS.Mention.Store(mention, func() error {
_, err := m.db.NewInsert().Model(mention).Exec(ctx)
return err
})
}
func (m *mentionDB) DeleteMentionByID(ctx context.Context, id string) error {
- defer m.state.Caches.GTS.Mention().Invalidate("ID", id)
+ defer m.state.Caches.GTS.Mention.Invalidate("ID", id)
// Load mention into cache before attempting a delete,
// as we need it cached in order to trigger the invalidate