summaryrefslogtreecommitdiff
path: root/internal/db/bundb/media.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/media.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/media.go')
-rw-r--r--internal/db/bundb/media.go70
1 files changed, 51 insertions, 19 deletions
diff --git a/internal/db/bundb/media.go b/internal/db/bundb/media.go
index a2603eacc..ce3c90083 100644
--- a/internal/db/bundb/media.go
+++ b/internal/db/bundb/media.go
@@ -20,14 +20,15 @@ package bundb
import (
"context"
"errors"
+ "slices"
"time"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"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"
)
@@ -51,25 +52,52 @@ func (m *mediaDB) GetAttachmentByID(ctx context.Context, id string) (*gtsmodel.M
}
func (m *mediaDB) GetAttachmentsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.MediaAttachment, error) {
- attachments := make([]*gtsmodel.MediaAttachment, 0, len(ids))
-
- for _, id := range ids {
- // Attempt fetch from DB
- attachment, err := m.GetAttachmentByID(ctx, id)
- if err != nil {
- log.Errorf(ctx, "error getting attachment %q: %v", id, err)
- continue
- }
+ // Preallocate at-worst possible length.
+ uncached := make([]string, 0, len(ids))
+
+ // Load all media IDs via cache loader callbacks.
+ media, err := m.state.Caches.GTS.Media.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 media loader function.
+ func() ([]*gtsmodel.MediaAttachment, error) {
+ // Preallocate expected length of uncached media attachments.
+ media := make([]*gtsmodel.MediaAttachment, 0, len(uncached))
+
+ // Perform database query scanning
+ // the remaining (uncached) IDs.
+ if err := m.db.NewSelect().
+ Model(&media).
+ Where("? IN (?)", bun.Ident("id"), bun.In(uncached)).
+ Scan(ctx); err != nil {
+ return nil, err
+ }
- // Append attachment
- attachments = append(attachments, attachment)
+ return media, nil
+ },
+ )
+ if err != nil {
+ return nil, err
}
- return attachments, nil
+ // Reorder the media by their
+ // IDs to ensure in correct order.
+ getID := func(m *gtsmodel.MediaAttachment) string { return m.ID }
+ util.OrderBy(media, ids, getID)
+
+ return media, nil
}
func (m *mediaDB) getAttachment(ctx context.Context, lookup string, dbQuery func(*gtsmodel.MediaAttachment) error, keyParts ...any) (*gtsmodel.MediaAttachment, error) {
- return m.state.Caches.GTS.Media().Load(lookup, func() (*gtsmodel.MediaAttachment, error) {
+ return m.state.Caches.GTS.Media.LoadOne(lookup, func() (*gtsmodel.MediaAttachment, error) {
var attachment gtsmodel.MediaAttachment
// Not cached! Perform database query
@@ -82,7 +110,7 @@ func (m *mediaDB) getAttachment(ctx context.Context, lookup string, dbQuery func
}
func (m *mediaDB) PutAttachment(ctx context.Context, media *gtsmodel.MediaAttachment) error {
- return m.state.Caches.GTS.Media().Store(media, func() error {
+ return m.state.Caches.GTS.Media.Store(media, func() error {
_, err := m.db.NewInsert().Model(media).Exec(ctx)
return err
})
@@ -95,7 +123,7 @@ func (m *mediaDB) UpdateAttachment(ctx context.Context, media *gtsmodel.MediaAtt
columns = append(columns, "updated_at")
}
- return m.state.Caches.GTS.Media().Store(media, func() error {
+ return m.state.Caches.GTS.Media.Store(media, func() error {
_, err := m.db.NewUpdate().
Model(media).
Where("? = ?", bun.Ident("media_attachment.id"), media.ID).
@@ -119,7 +147,7 @@ func (m *mediaDB) DeleteAttachment(ctx context.Context, id string) error {
}
// On return, ensure that media with ID is invalidated.
- defer m.state.Caches.GTS.Media().Invalidate("ID", id)
+ defer m.state.Caches.GTS.Media.Invalidate("ID", id)
// Delete media attachment in new transaction.
err = m.db.RunInTx(ctx, func(tx Tx) error {
@@ -171,8 +199,12 @@ func (m *mediaDB) DeleteAttachment(ctx context.Context, id string) error {
return gtserror.Newf("error selecting status: %w", err)
}
- if updatedIDs := dropID(status.AttachmentIDs, id); // nocollapse
- len(updatedIDs) != len(status.AttachmentIDs) {
+ // Delete all instances of this deleted media ID from status attachments.
+ updatedIDs := slices.DeleteFunc(status.AttachmentIDs, func(s string) bool {
+ return s == id
+ })
+
+ if len(updatedIDs) != len(status.AttachmentIDs) {
// Note: this handles not found.
//
// Attachments changed, update the status.