mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 15:02:25 -05:00
[performance] cache follow, follow request and block ID lists (#2027)
This commit is contained in:
parent
de148e9f9f
commit
ed2477ebea
29 changed files with 1283 additions and 335 deletions
80
internal/cache/cache.go
vendored
80
internal/cache/cache.go
vendored
|
|
@ -80,6 +80,27 @@ func (c *Caches) setuphooks() {
|
|||
// Invalidate account ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", account.ID)
|
||||
c.Visibility.Invalidate("RequesterID", account.ID)
|
||||
|
||||
// Invalidate this account's
|
||||
// following / follower lists.
|
||||
// (see FollowIDs() comment for details).
|
||||
c.GTS.FollowIDs().InvalidateAll(
|
||||
">"+account.ID,
|
||||
"l>"+account.ID,
|
||||
"<"+account.ID,
|
||||
"l<"+account.ID,
|
||||
)
|
||||
|
||||
// Invalidate this account's
|
||||
// follow requesting / request lists.
|
||||
// (see FollowRequestIDs() comment for details).
|
||||
c.GTS.FollowRequestIDs().InvalidateAll(
|
||||
">"+account.ID,
|
||||
"<"+account.ID,
|
||||
)
|
||||
|
||||
// Invalidate this account's block lists.
|
||||
c.GTS.BlockIDs().Invalidate(account.ID)
|
||||
})
|
||||
|
||||
c.GTS.Block().SetInvalidateCallback(func(block *gtsmodel.Block) {
|
||||
|
|
@ -90,6 +111,9 @@ func (c *Caches) setuphooks() {
|
|||
// Invalidate block target account ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", block.TargetAccountID)
|
||||
c.Visibility.Invalidate("RequesterID", block.TargetAccountID)
|
||||
|
||||
// Invalidate source account's block lists.
|
||||
c.GTS.BlockIDs().Invalidate(block.AccountID)
|
||||
})
|
||||
|
||||
c.GTS.EmojiCategory().SetInvalidateCallback(func(category *gtsmodel.EmojiCategory) {
|
||||
|
|
@ -98,6 +122,9 @@ func (c *Caches) setuphooks() {
|
|||
})
|
||||
|
||||
c.GTS.Follow().SetInvalidateCallback(func(follow *gtsmodel.Follow) {
|
||||
// Invalidate follow request with this same ID.
|
||||
c.GTS.FollowRequest().Invalidate("ID", follow.ID)
|
||||
|
||||
// Invalidate any related list entries.
|
||||
c.GTS.ListEntry().Invalidate("FollowID", follow.ID)
|
||||
|
||||
|
|
@ -108,19 +135,35 @@ func (c *Caches) setuphooks() {
|
|||
// Invalidate follow target account ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", follow.TargetAccountID)
|
||||
c.Visibility.Invalidate("RequesterID", follow.TargetAccountID)
|
||||
|
||||
// Invalidate source account's following
|
||||
// lists, and destination's follwer lists.
|
||||
// (see FollowIDs() comment for details).
|
||||
c.GTS.FollowIDs().InvalidateAll(
|
||||
">"+follow.AccountID,
|
||||
"l>"+follow.AccountID,
|
||||
"<"+follow.AccountID,
|
||||
"l<"+follow.AccountID,
|
||||
"<"+follow.TargetAccountID,
|
||||
"l<"+follow.TargetAccountID,
|
||||
">"+follow.TargetAccountID,
|
||||
"l>"+follow.TargetAccountID,
|
||||
)
|
||||
})
|
||||
|
||||
c.GTS.FollowRequest().SetInvalidateCallback(func(followReq *gtsmodel.FollowRequest) {
|
||||
// Invalidate follow request origin account ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", followReq.AccountID)
|
||||
c.Visibility.Invalidate("RequesterID", followReq.AccountID)
|
||||
|
||||
// Invalidate follow request target account ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", followReq.TargetAccountID)
|
||||
c.Visibility.Invalidate("RequesterID", followReq.TargetAccountID)
|
||||
|
||||
// Invalidate any cached follow with same ID.
|
||||
// Invalidate follow with this same ID.
|
||||
c.GTS.Follow().Invalidate("ID", followReq.ID)
|
||||
|
||||
// Invalidate source account's followreq
|
||||
// lists, and destinations follow req lists.
|
||||
// (see FollowRequestIDs() comment for details).
|
||||
c.GTS.FollowRequestIDs().InvalidateAll(
|
||||
">"+followReq.AccountID,
|
||||
"<"+followReq.AccountID,
|
||||
">"+followReq.TargetAccountID,
|
||||
"<"+followReq.TargetAccountID,
|
||||
)
|
||||
})
|
||||
|
||||
c.GTS.List().SetInvalidateCallback(func(list *gtsmodel.List) {
|
||||
|
|
@ -128,12 +171,29 @@ func (c *Caches) setuphooks() {
|
|||
c.GTS.ListEntry().Invalidate("ListID", list.ID)
|
||||
})
|
||||
|
||||
c.GTS.Media().SetInvalidateCallback(func(media *gtsmodel.MediaAttachment) {
|
||||
if *media.Avatar || *media.Header {
|
||||
// Invalidate cache of attaching account.
|
||||
c.GTS.Account().Invalidate("ID", media.AccountID)
|
||||
}
|
||||
|
||||
if media.StatusID != "" {
|
||||
// Invalidate cache of attaching status.
|
||||
c.GTS.Status().Invalidate("ID", media.StatusID)
|
||||
}
|
||||
})
|
||||
|
||||
c.GTS.Status().SetInvalidateCallback(func(status *gtsmodel.Status) {
|
||||
// Invalidate status ID cached visibility.
|
||||
c.Visibility.Invalidate("ItemID", status.ID)
|
||||
|
||||
for _, id := range status.AttachmentIDs {
|
||||
// Invalidate cache for attached media IDs,
|
||||
// Invalidate each media by the IDs we're aware of.
|
||||
// This must be done as the status table is aware of
|
||||
// the media IDs in use before the media table is
|
||||
// aware of the status ID they are linked to.
|
||||
//
|
||||
// c.GTS.Media().Invalidate("StatusID") will not work.
|
||||
c.GTS.Media().Invalidate("ID", id)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
150
internal/cache/gts.go
vendored
150
internal/cache/gts.go
vendored
|
|
@ -26,29 +26,31 @@ import (
|
|||
)
|
||||
|
||||
type GTSCaches struct {
|
||||
account *result.Cache[*gtsmodel.Account]
|
||||
accountNote *result.Cache[*gtsmodel.AccountNote]
|
||||
block *result.Cache[*gtsmodel.Block]
|
||||
// TODO: maybe should be moved out of here since it's
|
||||
// not actually doing anything with gtsmodel.DomainBlock.
|
||||
domainBlock *domain.BlockCache
|
||||
emoji *result.Cache[*gtsmodel.Emoji]
|
||||
emojiCategory *result.Cache[*gtsmodel.EmojiCategory]
|
||||
follow *result.Cache[*gtsmodel.Follow]
|
||||
followRequest *result.Cache[*gtsmodel.FollowRequest]
|
||||
instance *result.Cache[*gtsmodel.Instance]
|
||||
list *result.Cache[*gtsmodel.List]
|
||||
listEntry *result.Cache[*gtsmodel.ListEntry]
|
||||
marker *result.Cache[*gtsmodel.Marker]
|
||||
media *result.Cache[*gtsmodel.MediaAttachment]
|
||||
mention *result.Cache[*gtsmodel.Mention]
|
||||
notification *result.Cache[*gtsmodel.Notification]
|
||||
report *result.Cache[*gtsmodel.Report]
|
||||
status *result.Cache[*gtsmodel.Status]
|
||||
statusFave *result.Cache[*gtsmodel.StatusFave]
|
||||
tombstone *result.Cache[*gtsmodel.Tombstone]
|
||||
user *result.Cache[*gtsmodel.User]
|
||||
// TODO: move out of GTS caches since not using database models.
|
||||
account *result.Cache[*gtsmodel.Account]
|
||||
accountNote *result.Cache[*gtsmodel.AccountNote]
|
||||
block *result.Cache[*gtsmodel.Block]
|
||||
blockIDs *SliceCache[string]
|
||||
domainBlock *domain.BlockCache
|
||||
emoji *result.Cache[*gtsmodel.Emoji]
|
||||
emojiCategory *result.Cache[*gtsmodel.EmojiCategory]
|
||||
follow *result.Cache[*gtsmodel.Follow]
|
||||
followIDs *SliceCache[string]
|
||||
followRequest *result.Cache[*gtsmodel.FollowRequest]
|
||||
followRequestIDs *SliceCache[string]
|
||||
instance *result.Cache[*gtsmodel.Instance]
|
||||
list *result.Cache[*gtsmodel.List]
|
||||
listEntry *result.Cache[*gtsmodel.ListEntry]
|
||||
marker *result.Cache[*gtsmodel.Marker]
|
||||
media *result.Cache[*gtsmodel.MediaAttachment]
|
||||
mention *result.Cache[*gtsmodel.Mention]
|
||||
notification *result.Cache[*gtsmodel.Notification]
|
||||
report *result.Cache[*gtsmodel.Report]
|
||||
status *result.Cache[*gtsmodel.Status]
|
||||
statusFave *result.Cache[*gtsmodel.StatusFave]
|
||||
tombstone *result.Cache[*gtsmodel.Tombstone]
|
||||
user *result.Cache[*gtsmodel.User]
|
||||
|
||||
// TODO: move out of GTS caches since unrelated to DB.
|
||||
webfinger *ttl.Cache[string, string]
|
||||
}
|
||||
|
||||
|
|
@ -58,11 +60,14 @@ func (c *GTSCaches) Init() {
|
|||
c.initAccount()
|
||||
c.initAccountNote()
|
||||
c.initBlock()
|
||||
c.initBlockIDs()
|
||||
c.initDomainBlock()
|
||||
c.initEmoji()
|
||||
c.initEmojiCategory()
|
||||
c.initFollow()
|
||||
c.initFollowIDs()
|
||||
c.initFollowRequest()
|
||||
c.initFollowRequestIDs()
|
||||
c.initInstance()
|
||||
c.initList()
|
||||
c.initListEntry()
|
||||
|
|
@ -83,10 +88,28 @@ func (c *GTSCaches) Start() {
|
|||
tryStart(c.account, config.GetCacheGTSAccountSweepFreq())
|
||||
tryStart(c.accountNote, config.GetCacheGTSAccountNoteSweepFreq())
|
||||
tryStart(c.block, config.GetCacheGTSBlockSweepFreq())
|
||||
tryUntil("starting block IDs cache", 5, func() bool {
|
||||
if sweep := config.GetCacheGTSBlockIDsSweepFreq(); sweep > 0 {
|
||||
return c.blockIDs.Start(sweep)
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStart(c.emoji, config.GetCacheGTSEmojiSweepFreq())
|
||||
tryStart(c.emojiCategory, config.GetCacheGTSEmojiCategorySweepFreq())
|
||||
tryStart(c.follow, config.GetCacheGTSFollowSweepFreq())
|
||||
tryUntil("starting follow IDs cache", 5, func() bool {
|
||||
if sweep := config.GetCacheGTSFollowIDsSweepFreq(); sweep > 0 {
|
||||
return c.followIDs.Start(sweep)
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStart(c.followRequest, config.GetCacheGTSFollowRequestSweepFreq())
|
||||
tryUntil("starting follow request IDs cache", 5, func() bool {
|
||||
if sweep := config.GetCacheGTSFollowRequestIDsSweepFreq(); sweep > 0 {
|
||||
return c.followRequestIDs.Start(sweep)
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStart(c.instance, config.GetCacheGTSInstanceSweepFreq())
|
||||
tryStart(c.list, config.GetCacheGTSListSweepFreq())
|
||||
tryStart(c.listEntry, config.GetCacheGTSListEntrySweepFreq())
|
||||
|
|
@ -112,10 +135,28 @@ func (c *GTSCaches) Stop() {
|
|||
tryStop(c.account, config.GetCacheGTSAccountSweepFreq())
|
||||
tryStop(c.accountNote, config.GetCacheGTSAccountNoteSweepFreq())
|
||||
tryStop(c.block, config.GetCacheGTSBlockSweepFreq())
|
||||
tryUntil("stopping block IDs cache", 5, func() bool {
|
||||
if config.GetCacheGTSBlockIDsSweepFreq() > 0 {
|
||||
return c.blockIDs.Stop()
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStop(c.emoji, config.GetCacheGTSEmojiSweepFreq())
|
||||
tryStop(c.emojiCategory, config.GetCacheGTSEmojiCategorySweepFreq())
|
||||
tryStop(c.follow, config.GetCacheGTSFollowSweepFreq())
|
||||
tryUntil("stopping follow IDs cache", 5, func() bool {
|
||||
if config.GetCacheGTSFollowIDsSweepFreq() > 0 {
|
||||
return c.followIDs.Stop()
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStop(c.followRequest, config.GetCacheGTSFollowRequestSweepFreq())
|
||||
tryUntil("stopping follow request IDs cache", 5, func() bool {
|
||||
if config.GetCacheGTSFollowRequestIDsSweepFreq() > 0 {
|
||||
return c.followRequestIDs.Stop()
|
||||
}
|
||||
return true
|
||||
})
|
||||
tryStop(c.instance, config.GetCacheGTSInstanceSweepFreq())
|
||||
tryStop(c.list, config.GetCacheGTSListSweepFreq())
|
||||
tryStop(c.listEntry, config.GetCacheGTSListEntrySweepFreq())
|
||||
|
|
@ -128,7 +169,12 @@ func (c *GTSCaches) Stop() {
|
|||
tryStop(c.statusFave, config.GetCacheGTSStatusFaveSweepFreq())
|
||||
tryStop(c.tombstone, config.GetCacheGTSTombstoneSweepFreq())
|
||||
tryStop(c.user, config.GetCacheGTSUserSweepFreq())
|
||||
tryUntil("stopping *gtsmodel.Webfinger cache", 5, c.webfinger.Stop)
|
||||
tryUntil("stopping *gtsmodel.Webfinger cache", 5, func() bool {
|
||||
if config.GetCacheGTSWebfingerSweepFreq() > 0 {
|
||||
return c.webfinger.Stop()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// Account provides access to the gtsmodel Account database cache.
|
||||
|
|
@ -146,6 +192,11 @@ func (c *GTSCaches) Block() *result.Cache[*gtsmodel.Block] {
|
|||
return c.block
|
||||
}
|
||||
|
||||
// FollowIDs provides access to the block IDs database cache.
|
||||
func (c *GTSCaches) BlockIDs() *SliceCache[string] {
|
||||
return c.blockIDs
|
||||
}
|
||||
|
||||
// DomainBlock provides access to the domain block database cache.
|
||||
func (c *GTSCaches) DomainBlock() *domain.BlockCache {
|
||||
return c.domainBlock
|
||||
|
|
@ -166,11 +217,29 @@ func (c *GTSCaches) Follow() *result.Cache[*gtsmodel.Follow] {
|
|||
return c.follow
|
||||
}
|
||||
|
||||
// FollowIDs provides access to the follower / following IDs database cache.
|
||||
// THIS CACHE IS KEYED AS THE FOLLOWING {prefix}{accountID} WHERE PREFIX IS:
|
||||
// - '>' for following IDs
|
||||
// - 'l>' for local following IDs
|
||||
// - '<' for follower IDs
|
||||
// - 'l<' for local follower IDs
|
||||
func (c *GTSCaches) FollowIDs() *SliceCache[string] {
|
||||
return c.followIDs
|
||||
}
|
||||
|
||||
// FollowRequest provides access to the gtsmodel FollowRequest database cache.
|
||||
func (c *GTSCaches) FollowRequest() *result.Cache[*gtsmodel.FollowRequest] {
|
||||
return c.followRequest
|
||||
}
|
||||
|
||||
// FollowRequestIDs provides access to the follow requester / requesting IDs database
|
||||
// cache. THIS CACHE IS KEYED AS THE FOLLOWING {prefix}{accountID} WHERE PREFIX IS:
|
||||
// - '>' for following IDs
|
||||
// - '<' for follower IDs
|
||||
func (c *GTSCaches) FollowRequestIDs() *SliceCache[string] {
|
||||
return c.followRequestIDs
|
||||
}
|
||||
|
||||
// Instance provides access to the gtsmodel Instance database cache.
|
||||
func (c *GTSCaches) Instance() *result.Cache[*gtsmodel.Instance] {
|
||||
return c.instance
|
||||
|
|
@ -274,6 +343,8 @@ func (c *GTSCaches) initBlock() {
|
|||
{Name: "ID"},
|
||||
{Name: "URI"},
|
||||
{Name: "AccountID.TargetAccountID"},
|
||||
{Name: "AccountID", Multi: true},
|
||||
{Name: "TargetAccountID", Multi: true},
|
||||
}, func(b1 *gtsmodel.Block) *gtsmodel.Block {
|
||||
b2 := new(gtsmodel.Block)
|
||||
*b2 = *b1
|
||||
|
|
@ -283,6 +354,14 @@ func (c *GTSCaches) initBlock() {
|
|||
c.block.IgnoreErrors(ignoreErrors)
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initBlockIDs() {
|
||||
c.blockIDs = &SliceCache[string]{Cache: ttl.New[string, []string](
|
||||
0,
|
||||
config.GetCacheGTSBlockIDsMaxSize(),
|
||||
config.GetCacheGTSBlockIDsTTL(),
|
||||
)}
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initDomainBlock() {
|
||||
c.domainBlock = new(domain.BlockCache)
|
||||
}
|
||||
|
|
@ -321,6 +400,8 @@ func (c *GTSCaches) initFollow() {
|
|||
{Name: "ID"},
|
||||
{Name: "URI"},
|
||||
{Name: "AccountID.TargetAccountID"},
|
||||
{Name: "AccountID", Multi: true},
|
||||
{Name: "TargetAccountID", Multi: true},
|
||||
}, func(f1 *gtsmodel.Follow) *gtsmodel.Follow {
|
||||
f2 := new(gtsmodel.Follow)
|
||||
*f2 = *f1
|
||||
|
|
@ -329,11 +410,21 @@ func (c *GTSCaches) initFollow() {
|
|||
c.follow.SetTTL(config.GetCacheGTSFollowTTL(), true)
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initFollowIDs() {
|
||||
c.followIDs = &SliceCache[string]{Cache: ttl.New[string, []string](
|
||||
0,
|
||||
config.GetCacheGTSFollowIDsMaxSize(),
|
||||
config.GetCacheGTSFollowIDsTTL(),
|
||||
)}
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initFollowRequest() {
|
||||
c.followRequest = result.New([]result.Lookup{
|
||||
{Name: "ID"},
|
||||
{Name: "URI"},
|
||||
{Name: "AccountID.TargetAccountID"},
|
||||
{Name: "AccountID", Multi: true},
|
||||
{Name: "TargetAccountID", Multi: true},
|
||||
}, func(f1 *gtsmodel.FollowRequest) *gtsmodel.FollowRequest {
|
||||
f2 := new(gtsmodel.FollowRequest)
|
||||
*f2 = *f1
|
||||
|
|
@ -342,6 +433,14 @@ func (c *GTSCaches) initFollowRequest() {
|
|||
c.followRequest.SetTTL(config.GetCacheGTSFollowRequestTTL(), true)
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initFollowRequestIDs() {
|
||||
c.followRequestIDs = &SliceCache[string]{Cache: ttl.New[string, []string](
|
||||
0,
|
||||
config.GetCacheGTSFollowRequestIDsMaxSize(),
|
||||
config.GetCacheGTSFollowRequestIDsTTL(),
|
||||
)}
|
||||
}
|
||||
|
||||
func (c *GTSCaches) initInstance() {
|
||||
c.instance = result.New([]result.Lookup{
|
||||
{Name: "ID"},
|
||||
|
|
@ -502,5 +601,6 @@ func (c *GTSCaches) initWebfinger() {
|
|||
c.webfinger = ttl.New[string, string](
|
||||
0,
|
||||
config.GetCacheGTSWebfingerMaxSize(),
|
||||
config.GetCacheGTSWebfingerTTL())
|
||||
config.GetCacheGTSWebfingerTTL(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
76
internal/cache/slice.go
vendored
Normal file
76
internal/cache/slice.go
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cache
|
||||
|
||||
import (
|
||||
"codeberg.org/gruf/go-cache/v3/ttl"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// SliceCache wraps a ttl.Cache to provide simple loader-callback
|
||||
// functions for fetching + caching slices of objects (e.g. IDs).
|
||||
type SliceCache[T any] struct {
|
||||
*ttl.Cache[string, []T]
|
||||
}
|
||||
|
||||
// Load will attempt to load an existing slice from the cache for the given key, else calling the provided load function and caching the result.
|
||||
func (c *SliceCache[T]) Load(key string, load func() ([]T, error)) ([]T, error) {
|
||||
// Look for follow IDs list in cache under this key.
|
||||
data, ok := c.Get(key)
|
||||
|
||||
if !ok {
|
||||
var err error
|
||||
|
||||
// Not cached, load!
|
||||
data, err = load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Store the data.
|
||||
c.Set(key, data)
|
||||
}
|
||||
|
||||
// Return data clone for safety.
|
||||
return slices.Clone(data), nil
|
||||
}
|
||||
|
||||
// LoadRange is functionally the same as .Load(), but will pass the result through provided reslice function before returning a cloned result.
|
||||
func (c *SliceCache[T]) LoadRange(key string, load func() ([]T, error), reslice func([]T) []T) ([]T, error) {
|
||||
// Look for follow IDs list in cache under this key.
|
||||
data, ok := c.Get(key)
|
||||
|
||||
if !ok {
|
||||
var err error
|
||||
|
||||
// Not cached, load!
|
||||
data, err = load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Store the data.
|
||||
c.Set(key, data)
|
||||
}
|
||||
|
||||
// Reslice to range.
|
||||
slice := reslice(data)
|
||||
|
||||
// Return range clone for safety.
|
||||
return slices.Clone(slice), nil
|
||||
}
|
||||
23
internal/cache/util.go
vendored
23
internal/cache/util.go
vendored
|
|
@ -18,28 +18,33 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"codeberg.org/gruf/go-cache/v3/result"
|
||||
errorsv2 "codeberg.org/gruf/go-errors/v2"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
)
|
||||
|
||||
// SentinelError is returned to indicate a non-permanent error return,
|
||||
// i.e. a situation in which we do not want a cache a negative result.
|
||||
// SentinelError is an error that can be returned and checked against to indicate a non-permanent
|
||||
// error return from a cache loader callback, e.g. a temporary situation that will soon be fixed.
|
||||
var SentinelError = errors.New("BUG: error should not be returned") //nolint:revive
|
||||
|
||||
// ignoreErrors is an error ignoring function capable of being passed to
|
||||
// caches, which specifically catches and ignores our sentinel error type.
|
||||
// ignoreErrors is an error matching function used to signal which errors
|
||||
// the result caches should NOT hold onto. these amount to anything non-permanent.
|
||||
func ignoreErrors(err error) bool {
|
||||
return errorsv2.Comparable(
|
||||
return !errorsv2.Comparable(
|
||||
err,
|
||||
SentinelError,
|
||||
context.DeadlineExceeded,
|
||||
context.Canceled,
|
||||
|
||||
// the only cacheable errs,
|
||||
// i.e anything permanent
|
||||
// (until invalidation).
|
||||
db.ErrNoEntries,
|
||||
db.ErrAlreadyExists,
|
||||
sql.ErrNoRows,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue