diff options
author | 2024-04-02 11:03:40 +0100 | |
---|---|---|
committer | 2024-04-02 12:03:40 +0200 | |
commit | adf345f1ec0cb76a0df94a4505143d891659cba9 (patch) | |
tree | e0cca289c0a50f30191d4b65a2c336704570e470 /internal/cache | |
parent | [feature] Option to hide followers/following (#2788) (diff) | |
download | gotosocial-adf345f1ec0cb76a0df94a4505143d891659cba9.tar.xz |
[chore] bump go structr cache version -> v0.6.0 (#2773)
* update go-structr library -> v0.6.0, add necessary wrapping types + code changes to support these changes
* update readme with go-structr package changes
* improved wrapping of the SliceCache type
* add code comments for the cache wrapper types
* remove test.out :innocent:
---------
Co-authored-by: tobi <31960611+tsmethurst@users.noreply.github.com>
Diffstat (limited to 'internal/cache')
-rw-r--r-- | internal/cache/db.go | 223 | ||||
-rw-r--r-- | internal/cache/invalidate.go | 24 | ||||
-rw-r--r-- | internal/cache/slice.go | 52 | ||||
-rw-r--r-- | internal/cache/visibility.go | 6 | ||||
-rw-r--r-- | internal/cache/wrappers.go | 214 |
5 files changed, 329 insertions, 190 deletions
diff --git a/internal/cache/db.go b/internal/cache/db.go index ff38c1d93..c383ed6c7 100644 --- a/internal/cache/db.go +++ b/internal/cache/db.go @@ -31,10 +31,10 @@ import ( type GTSCaches struct { // Account provides access to the gtsmodel Account database cache. - Account structr.Cache[*gtsmodel.Account] + Account StructCache[*gtsmodel.Account] // AccountNote provides access to the gtsmodel Note database cache. - AccountNote structr.Cache[*gtsmodel.AccountNote] + AccountNote StructCache[*gtsmodel.AccountNote] // TEMPORARY CACHE TO ALLEVIATE SLOW COUNT QUERIES, // (in time will be removed when these IDs are cached). @@ -44,19 +44,19 @@ type GTSCaches struct { }] // AccountSettings provides access to the gtsmodel AccountSettings database cache. - AccountSettings structr.Cache[*gtsmodel.AccountSettings] + AccountSettings StructCache[*gtsmodel.AccountSettings] // Application provides access to the gtsmodel Application database cache. - Application structr.Cache[*gtsmodel.Application] + Application StructCache[*gtsmodel.Application] // Block provides access to the gtsmodel Block (account) database cache. - Block structr.Cache[*gtsmodel.Block] + Block StructCache[*gtsmodel.Block] // FollowIDs provides access to the block IDs database cache. - BlockIDs *SliceCache[string] + BlockIDs SliceCache[string] // BoostOfIDs provides access to the boost of IDs list database cache. - BoostOfIDs *SliceCache[string] + BoostOfIDs SliceCache[string] // DomainAllow provides access to the domain allow database cache. DomainAllow *domain.Cache @@ -65,22 +65,22 @@ type GTSCaches struct { DomainBlock *domain.Cache // Emoji provides access to the gtsmodel Emoji database cache. - Emoji structr.Cache[*gtsmodel.Emoji] + Emoji StructCache[*gtsmodel.Emoji] // EmojiCategory provides access to the gtsmodel EmojiCategory database cache. - EmojiCategory structr.Cache[*gtsmodel.EmojiCategory] + EmojiCategory StructCache[*gtsmodel.EmojiCategory] // Filter provides access to the gtsmodel Filter database cache. - Filter structr.Cache[*gtsmodel.Filter] + Filter StructCache[*gtsmodel.Filter] // FilterKeyword provides access to the gtsmodel FilterKeyword database cache. - FilterKeyword structr.Cache[*gtsmodel.FilterKeyword] + FilterKeyword StructCache[*gtsmodel.FilterKeyword] // FilterStatus provides access to the gtsmodel FilterStatus database cache. - FilterStatus structr.Cache[*gtsmodel.FilterStatus] + FilterStatus StructCache[*gtsmodel.FilterStatus] // Follow provides access to the gtsmodel Follow database cache. - Follow structr.Cache[*gtsmodel.Follow] + Follow StructCache[*gtsmodel.Follow] // FollowIDs provides access to the follower / following IDs database cache. // THIS CACHE IS KEYED AS THE FOLLOWING {prefix}{accountID} WHERE PREFIX IS: @@ -88,76 +88,76 @@ type GTSCaches struct { // - 'l>' for local following IDs // - '<' for follower IDs // - 'l<' for local follower IDs - FollowIDs *SliceCache[string] + FollowIDs SliceCache[string] // FollowRequest provides access to the gtsmodel FollowRequest database cache. - FollowRequest structr.Cache[*gtsmodel.FollowRequest] + FollowRequest StructCache[*gtsmodel.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 - FollowRequestIDs *SliceCache[string] + FollowRequestIDs SliceCache[string] // Instance provides access to the gtsmodel Instance database cache. - Instance structr.Cache[*gtsmodel.Instance] + Instance StructCache[*gtsmodel.Instance] // InReplyToIDs provides access to the status in reply to IDs list database cache. - InReplyToIDs *SliceCache[string] + InReplyToIDs SliceCache[string] // List provides access to the gtsmodel List database cache. - List structr.Cache[*gtsmodel.List] + List StructCache[*gtsmodel.List] // ListEntry provides access to the gtsmodel ListEntry database cache. - ListEntry structr.Cache[*gtsmodel.ListEntry] + ListEntry StructCache[*gtsmodel.ListEntry] // Marker provides access to the gtsmodel Marker database cache. - Marker structr.Cache[*gtsmodel.Marker] + Marker StructCache[*gtsmodel.Marker] // Media provides access to the gtsmodel Media database cache. - Media structr.Cache[*gtsmodel.MediaAttachment] + Media StructCache[*gtsmodel.MediaAttachment] // Mention provides access to the gtsmodel Mention database cache. - Mention structr.Cache[*gtsmodel.Mention] + Mention StructCache[*gtsmodel.Mention] // Move provides access to the gtsmodel Move database cache. - Move structr.Cache[*gtsmodel.Move] + Move StructCache[*gtsmodel.Move] // Notification provides access to the gtsmodel Notification database cache. - Notification structr.Cache[*gtsmodel.Notification] + Notification StructCache[*gtsmodel.Notification] // Poll provides access to the gtsmodel Poll database cache. - Poll structr.Cache[*gtsmodel.Poll] + Poll StructCache[*gtsmodel.Poll] // PollVote provides access to the gtsmodel PollVote database cache. - PollVote structr.Cache[*gtsmodel.PollVote] + PollVote StructCache[*gtsmodel.PollVote] // PollVoteIDs provides access to the poll vote IDs list database cache. - PollVoteIDs *SliceCache[string] + PollVoteIDs SliceCache[string] // Report provides access to the gtsmodel Report database cache. - Report structr.Cache[*gtsmodel.Report] + Report StructCache[*gtsmodel.Report] // Status provides access to the gtsmodel Status database cache. - Status structr.Cache[*gtsmodel.Status] + Status StructCache[*gtsmodel.Status] // StatusFave provides access to the gtsmodel StatusFave database cache. - StatusFave structr.Cache[*gtsmodel.StatusFave] + StatusFave StructCache[*gtsmodel.StatusFave] // StatusFaveIDs provides access to the status fave IDs list database cache. - StatusFaveIDs *SliceCache[string] + StatusFaveIDs SliceCache[string] // Tag provides access to the gtsmodel Tag database cache. - Tag structr.Cache[*gtsmodel.Tag] + Tag StructCache[*gtsmodel.Tag] // Tombstone provides access to the gtsmodel Tombstone database cache. - Tombstone structr.Cache[*gtsmodel.Tombstone] + Tombstone StructCache[*gtsmodel.Tombstone] // ThreadMute provides access to the gtsmodel ThreadMute database cache. - ThreadMute structr.Cache[*gtsmodel.ThreadMute] + ThreadMute StructCache[*gtsmodel.ThreadMute] // User provides access to the gtsmodel User database cache. - User structr.Cache[*gtsmodel.User] + User StructCache[*gtsmodel.User] // Webfinger provides access to the webfinger URL cache. // TODO: move out of GTS caches since unrelated to DB. @@ -198,7 +198,7 @@ func (c *Caches) initAccount() { return a2 } - c.GTS.Account.Init(structr.Config[*gtsmodel.Account]{ + c.GTS.Account.Init(structr.CacheConfig[*gtsmodel.Account]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -212,7 +212,7 @@ func (c *Caches) initAccount() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateAccount, }) } @@ -255,14 +255,14 @@ func (c *Caches) initAccountNote() { return n2 } - c.GTS.AccountNote.Init(structr.Config[*gtsmodel.AccountNote]{ + c.GTS.AccountNote.Init(structr.CacheConfig[*gtsmodel.AccountNote]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID,TargetAccountID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -275,13 +275,13 @@ func (c *Caches) initAccountSettings() { log.Infof(nil, "cache size = %d", cap) - c.GTS.AccountSettings.Init(structr.Config[*gtsmodel.AccountSettings]{ + c.GTS.AccountSettings.Init(structr.CacheConfig[*gtsmodel.AccountSettings]{ Indices: []structr.IndexConfig{ {Fields: "AccountID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: func(s1 *gtsmodel.AccountSettings) *gtsmodel.AccountSettings { + Copy: func(s1 *gtsmodel.AccountSettings) *gtsmodel.AccountSettings { s2 := new(gtsmodel.AccountSettings) *s2 = *s1 return s2 @@ -304,14 +304,14 @@ func (c *Caches) initApplication() { return a2 } - c.GTS.Application.Init(structr.Config[*gtsmodel.Application]{ + c.GTS.Application.Init(structr.CacheConfig[*gtsmodel.Application]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "ClientID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -337,7 +337,7 @@ func (c *Caches) initBlock() { return b2 } - c.GTS.Block.Init(structr.Config[*gtsmodel.Block]{ + c.GTS.Block.Init(structr.CacheConfig[*gtsmodel.Block]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -347,7 +347,7 @@ func (c *Caches) initBlock() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateBlock, }) } @@ -360,10 +360,7 @@ func (c *Caches) initBlockIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.BlockIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.BlockIDs.Init(0, cap) } func (c *Caches) initBoostOfIDs() { @@ -374,10 +371,7 @@ func (c *Caches) initBoostOfIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.BoostOfIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.BoostOfIDs.Init(0, cap) } func (c *Caches) initDomainAllow() { @@ -409,7 +403,7 @@ func (c *Caches) initEmoji() { return e2 } - c.GTS.Emoji.Init(structr.Config[*gtsmodel.Emoji]{ + c.GTS.Emoji.Init(structr.CacheConfig[*gtsmodel.Emoji]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -419,7 +413,7 @@ func (c *Caches) initEmoji() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -438,14 +432,14 @@ func (c *Caches) initEmojiCategory() { return c2 } - c.GTS.EmojiCategory.Init(structr.Config[*gtsmodel.EmojiCategory]{ + c.GTS.EmojiCategory.Init(structr.CacheConfig[*gtsmodel.EmojiCategory]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "Name"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateEmojiCategory, }) } @@ -472,14 +466,14 @@ func (c *Caches) initFilter() { return filter2 } - c.GTS.Filter.Init(structr.Config[*gtsmodel.Filter]{ + c.GTS.Filter.Init(structr.CacheConfig[*gtsmodel.Filter]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID", Multiple: true}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -504,7 +498,7 @@ func (c *Caches) initFilterKeyword() { return filterKeyword2 } - c.GTS.FilterKeyword.Init(structr.Config[*gtsmodel.FilterKeyword]{ + c.GTS.FilterKeyword.Init(structr.CacheConfig[*gtsmodel.FilterKeyword]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID", Multiple: true}, @@ -512,7 +506,7 @@ func (c *Caches) initFilterKeyword() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -537,7 +531,7 @@ func (c *Caches) initFilterStatus() { return filterStatus2 } - c.GTS.FilterStatus.Init(structr.Config[*gtsmodel.FilterStatus]{ + c.GTS.FilterStatus.Init(structr.CacheConfig[*gtsmodel.FilterStatus]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID", Multiple: true}, @@ -545,7 +539,7 @@ func (c *Caches) initFilterStatus() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -571,7 +565,7 @@ func (c *Caches) initFollow() { return f2 } - c.GTS.Follow.Init(structr.Config[*gtsmodel.Follow]{ + c.GTS.Follow.Init(structr.CacheConfig[*gtsmodel.Follow]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -581,7 +575,7 @@ func (c *Caches) initFollow() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateFollow, }) } @@ -594,10 +588,7 @@ func (c *Caches) initFollowIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.FollowIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.FollowIDs.Init(0, cap) } func (c *Caches) initFollowRequest() { @@ -622,7 +613,7 @@ func (c *Caches) initFollowRequest() { return f2 } - c.GTS.FollowRequest.Init(structr.Config[*gtsmodel.FollowRequest]{ + c.GTS.FollowRequest.Init(structr.CacheConfig[*gtsmodel.FollowRequest]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -632,7 +623,7 @@ func (c *Caches) initFollowRequest() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateFollowRequest, }) } @@ -645,10 +636,7 @@ func (c *Caches) initFollowRequestIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.FollowRequestIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.FollowRequestIDs.Init(0, cap) } func (c *Caches) initInReplyToIDs() { @@ -659,10 +647,7 @@ func (c *Caches) initInReplyToIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.InReplyToIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.InReplyToIDs.Init(0, cap) } func (c *Caches) initInstance() { @@ -687,14 +672,14 @@ func (c *Caches) initInstance() { return i1 } - c.GTS.Instance.Init(structr.Config[*gtsmodel.Instance]{ + c.GTS.Instance.Init(structr.CacheConfig[*gtsmodel.Instance]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "Domain"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -720,13 +705,13 @@ func (c *Caches) initList() { return l2 } - c.GTS.List.Init(structr.Config[*gtsmodel.List]{ + c.GTS.List.Init(structr.CacheConfig[*gtsmodel.List]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateList, }) } @@ -752,7 +737,7 @@ func (c *Caches) initListEntry() { return l2 } - c.GTS.ListEntry.Init(structr.Config[*gtsmodel.ListEntry]{ + c.GTS.ListEntry.Init(structr.CacheConfig[*gtsmodel.ListEntry]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "ListID", Multiple: true}, @@ -760,7 +745,7 @@ func (c *Caches) initListEntry() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -779,13 +764,13 @@ func (c *Caches) initMarker() { return m2 } - c.GTS.Marker.Init(structr.Config[*gtsmodel.Marker]{ + c.GTS.Marker.Init(structr.CacheConfig[*gtsmodel.Marker]{ Indices: []structr.IndexConfig{ {Fields: "AccountID,Name"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -804,13 +789,13 @@ func (c *Caches) initMedia() { return m2 } - c.GTS.Media.Init(structr.Config[*gtsmodel.MediaAttachment]{ + c.GTS.Media.Init(structr.CacheConfig[*gtsmodel.MediaAttachment]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateMedia, }) } @@ -838,13 +823,13 @@ func (c *Caches) initMention() { return m2 } - c.GTS.Mention.Init(structr.Config[*gtsmodel.Mention]{ + c.GTS.Mention.Init(structr.CacheConfig[*gtsmodel.Mention]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -857,7 +842,7 @@ func (c *Caches) initMove() { log.Infof(nil, "cache size = %d", cap) - c.GTS.Move.Init(structr.Config[*gtsmodel.Move]{ + c.GTS.Move.Init(structr.CacheConfig[*gtsmodel.Move]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -867,7 +852,7 @@ func (c *Caches) initMove() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: func(m1 *gtsmodel.Move) *gtsmodel.Move { + Copy: func(m1 *gtsmodel.Move) *gtsmodel.Move { m2 := new(gtsmodel.Move) *m2 = *m1 return m2 @@ -898,14 +883,14 @@ func (c *Caches) initNotification() { return n2 } - c.GTS.Notification.Init(structr.Config[*gtsmodel.Notification]{ + c.GTS.Notification.Init(structr.CacheConfig[*gtsmodel.Notification]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "NotificationType,TargetAccountID,OriginAccountID,StatusID", AllowZero: true}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -935,14 +920,14 @@ func (c *Caches) initPoll() { return p2 } - c.GTS.Poll.Init(structr.Config[*gtsmodel.Poll]{ + c.GTS.Poll.Init(structr.CacheConfig[*gtsmodel.Poll]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "StatusID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidatePoll, }) } @@ -969,7 +954,7 @@ func (c *Caches) initPollVote() { return v2 } - c.GTS.PollVote.Init(structr.Config[*gtsmodel.PollVote]{ + c.GTS.PollVote.Init(structr.CacheConfig[*gtsmodel.PollVote]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "PollID", Multiple: true}, @@ -977,7 +962,7 @@ func (c *Caches) initPollVote() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidatePollVote, }) } @@ -990,10 +975,7 @@ func (c *Caches) initPollVoteIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.PollVoteIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.PollVoteIDs.Init(0, cap) } func (c *Caches) initReport() { @@ -1021,13 +1003,13 @@ func (c *Caches) initReport() { return r2 } - c.GTS.Report.Init(structr.Config[*gtsmodel.Report]{ + c.GTS.Report.Init(structr.CacheConfig[*gtsmodel.Report]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -1062,7 +1044,7 @@ func (c *Caches) initStatus() { return s2 } - c.GTS.Status.Init(structr.Config[*gtsmodel.Status]{ + c.GTS.Status.Init(structr.CacheConfig[*gtsmodel.Status]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, @@ -1073,7 +1055,7 @@ func (c *Caches) initStatus() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateStatus, }) } @@ -1101,7 +1083,7 @@ func (c *Caches) initStatusFave() { return f2 } - c.GTS.StatusFave.Init(structr.Config[*gtsmodel.StatusFave]{ + c.GTS.StatusFave.Init(structr.CacheConfig[*gtsmodel.StatusFave]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID,StatusID"}, @@ -1109,7 +1091,7 @@ func (c *Caches) initStatusFave() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateStatusFave, }) } @@ -1122,10 +1104,7 @@ func (c *Caches) initStatusFaveIDs() { log.Infof(nil, "cache size = %d", cap) - c.GTS.StatusFaveIDs = &SliceCache[string]{Cache: simple.New[string, []string]( - 0, - cap, - )} + c.GTS.StatusFaveIDs.Init(0, cap) } func (c *Caches) initTag() { @@ -1143,14 +1122,14 @@ func (c *Caches) initTag() { return m2 } - c.GTS.Tag.Init(structr.Config[*gtsmodel.Tag]{ + c.GTS.Tag.Init(structr.CacheConfig[*gtsmodel.Tag]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "Name"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -1168,7 +1147,7 @@ func (c *Caches) initThreadMute() { return t2 } - c.GTS.ThreadMute.Init(structr.Config[*gtsmodel.ThreadMute]{ + c.GTS.ThreadMute.Init(structr.CacheConfig[*gtsmodel.ThreadMute]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "ThreadID", Multiple: true}, @@ -1177,7 +1156,7 @@ func (c *Caches) initThreadMute() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -1196,14 +1175,14 @@ func (c *Caches) initTombstone() { return t2 } - c.GTS.Tombstone.Init(structr.Config[*gtsmodel.Tombstone]{ + c.GTS.Tombstone.Init(structr.CacheConfig[*gtsmodel.Tombstone]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "URI"}, }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } @@ -1228,7 +1207,7 @@ func (c *Caches) initUser() { return u2 } - c.GTS.User.Init(structr.Config[*gtsmodel.User]{ + c.GTS.User.Init(structr.CacheConfig[*gtsmodel.User]{ Indices: []structr.IndexConfig{ {Fields: "ID"}, {Fields: "AccountID"}, @@ -1238,7 +1217,7 @@ func (c *Caches) initUser() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, Invalidate: c.OnInvalidateUser, }) } diff --git a/internal/cache/invalidate.go b/internal/cache/invalidate.go index a7c4a1552..746d8c7e7 100644 --- a/internal/cache/invalidate.go +++ b/internal/cache/invalidate.go @@ -37,7 +37,7 @@ func (c *Caches) OnInvalidateAccount(account *gtsmodel.Account) { // Invalidate this account's // following / follower lists. // (see FollowIDs() comment for details). - c.GTS.FollowIDs.InvalidateAll( + c.GTS.FollowIDs.Invalidate( ">"+account.ID, "l>"+account.ID, "<"+account.ID, @@ -47,7 +47,7 @@ func (c *Caches) OnInvalidateAccount(account *gtsmodel.Account) { // Invalidate this account's // follow requesting / request lists. // (see FollowRequestIDs() comment for details). - c.GTS.FollowRequestIDs.InvalidateAll( + c.GTS.FollowRequestIDs.Invalidate( ">"+account.ID, "<"+account.ID, ) @@ -96,7 +96,7 @@ func (c *Caches) OnInvalidateFollow(follow *gtsmodel.Follow) { // Invalidate source account's following // lists, and destination's follwer lists. // (see FollowIDs() comment for details). - c.GTS.FollowIDs.InvalidateAll( + c.GTS.FollowIDs.Invalidate( ">"+follow.AccountID, "l>"+follow.AccountID, "<"+follow.AccountID, @@ -115,7 +115,7 @@ func (c *Caches) OnInvalidateFollowRequest(followReq *gtsmodel.FollowRequest) { // Invalidate source account's followreq // lists, and destinations follow req lists. // (see FollowRequestIDs() comment for details). - c.GTS.FollowRequestIDs.InvalidateAll( + c.GTS.FollowRequestIDs.Invalidate( ">"+followReq.AccountID, "<"+followReq.AccountID, ">"+followReq.TargetAccountID, @@ -164,15 +164,13 @@ func (c *Caches) OnInvalidateStatus(status *gtsmodel.Status) { // Invalidate status ID cached visibility. c.Visibility.Invalidate("ItemID", status.ID) - for _, id := range status.AttachmentIDs { - // 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) - } + // 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.InvalidateIDs("ID", status.AttachmentIDs) if status.BoostOfID != "" { // Invalidate boost ID list of the original status. diff --git a/internal/cache/slice.go b/internal/cache/slice.go deleted file mode 100644 index 0a7a6ccdc..000000000 --- a/internal/cache/slice.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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 ( - "slices" - - "codeberg.org/gruf/go-cache/v3/simple" -) - -// SliceCache wraps a simple.Cache to provide simple loader-callback -// functions for fetching + caching slices of objects (e.g. IDs). -type SliceCache[T any] struct { - *simple.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 -} diff --git a/internal/cache/visibility.go b/internal/cache/visibility.go index 878efcdb8..e280054ec 100644 --- a/internal/cache/visibility.go +++ b/internal/cache/visibility.go @@ -24,7 +24,7 @@ import ( ) type VisibilityCache struct { - structr.Cache[*CachedVisibility] + StructCache[*CachedVisibility] } func (c *Caches) initVisibility() { @@ -42,7 +42,7 @@ func (c *Caches) initVisibility() { return v2 } - c.Visibility.Init(structr.Config[*CachedVisibility]{ + c.Visibility.Init(structr.CacheConfig[*CachedVisibility]{ Indices: []structr.IndexConfig{ {Fields: "ItemID", Multiple: true}, {Fields: "RequesterID", Multiple: true}, @@ -50,7 +50,7 @@ func (c *Caches) initVisibility() { }, MaxSize: cap, IgnoreErr: ignoreErrors, - CopyValue: copyF, + Copy: copyF, }) } diff --git a/internal/cache/wrappers.go b/internal/cache/wrappers.go new file mode 100644 index 000000000..edeea9bcd --- /dev/null +++ b/internal/cache/wrappers.go @@ -0,0 +1,214 @@ +// 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 ( + "slices" + + "codeberg.org/gruf/go-cache/v3/simple" + "codeberg.org/gruf/go-structr" +) + +// SliceCache wraps a simple.Cache to provide simple loader-callback +// functions for fetching + caching slices of objects (e.g. IDs). +type SliceCache[T any] struct { + cache simple.Cache[string, []T] +} + +// Init initializes the cache with given length + capacity. +func (c *SliceCache[T]) Init(len, cap int) { + c.cache = simple.Cache[string, []T]{} + c.cache.Init(len, cap) +} + +// Load will attempt to load an existing slice from cache for key, else calling load function and caching the result. +func (c *SliceCache[T]) Load(key string, load func() ([]T, error)) ([]T, error) { + // Look for cached values. + data, ok := c.cache.Get(key) + + if !ok { + var err error + + // Not cached, load! + data, err = load() + if err != nil { + return nil, err + } + + // Store the data. + c.cache.Set(key, data) + } + + // Return data clone for safety. + return slices.Clone(data), nil +} + +// Invalidate: see simple.Cache{}.InvalidateAll(). +func (c *SliceCache[T]) Invalidate(keys ...string) { + _ = c.cache.InvalidateAll(keys...) +} + +// Trim: see simple.Cache{}.Trim(). +func (c *SliceCache[T]) Trim(perc float64) { + c.cache.Trim(perc) +} + +// Clear: see simple.Cache{}.Clear(). +func (c *SliceCache[T]) Clear() { + c.cache.Clear() +} + +// Len: see simple.Cache{}.Len(). +func (c *SliceCache[T]) Len() int { + return c.cache.Len() +} + +// Cap: see simple.Cache{}.Cap(). +func (c *SliceCache[T]) Cap() int { + return c.cache.Cap() +} + +// StructCache wraps a structr.Cache{} to simple index caching +// by name (also to ease update to library version that introduced +// this). (in the future it may be worth embedding these indexes by +// name under the main database caches struct which would reduce +// time required to access cached values). +type StructCache[StructType any] struct { + cache structr.Cache[StructType] + index map[string]*structr.Index +} + +// Init initializes the cache with given structr.CacheConfig{}. +func (c *StructCache[T]) Init(config structr.CacheConfig[T]) { + c.index = make(map[string]*structr.Index, len(config.Indices)) + c.cache = structr.Cache[T]{} + c.cache.Init(config) + for _, cfg := range config.Indices { + c.index[cfg.Fields] = c.cache.Index(cfg.Fields) + } +} + +// GetOne calls structr.Cache{}.GetOne(), using a cached structr.Index{} by 'index' name. +// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}. +func (c *StructCache[T]) GetOne(index string, key ...any) (T, bool) { + i := c.index[index] + return c.cache.GetOne(i, i.Key(key...)) +} + +// Get calls structr.Cache{}.Get(), using a cached structr.Index{} by 'index' name. +// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}. +func (c *StructCache[T]) Get(index string, keys ...[]any) []T { + i := c.index[index] + return c.cache.Get(i, i.Keys(keys...)...) +} + +// Put: see structr.Cache{}.Put(). +func (c *StructCache[T]) Put(values ...T) { + c.cache.Put(values...) +} + +// LoadOne calls structr.Cache{}.LoadOne(), using a cached structr.Index{} by 'index' name. +// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}. +func (c *StructCache[T]) LoadOne(index string, load func() (T, error), key ...any) (T, error) { + i := c.index[index] + return c.cache.LoadOne(i, i.Key(key...), load) +} + +// LoadIDs calls structr.Cache{}.Load(), using a cached structr.Index{} by 'index' name. Note: this also handles +// conversion of the ID strings to structr.Key{} via structr.Index{}. Strong typing is used for caller convenience. +// +// If you need to load multiple cache keys other than by ID strings, please create another convenience wrapper. +func (c *StructCache[T]) LoadIDs(index string, ids []string, load func([]string) ([]T, error)) ([]T, error) { + i := c.index[index] + if i == nil { + // we only perform this check here as + // we're going to use the index before + // passing it to cache in main .Load(). + panic("missing index for cache type") + } + + // Generate cache keys for ID types. + keys := make([]structr.Key, len(ids)) + for x, id := range ids { + keys[x] = i.Key(id) + } + + // Pass loader callback with wrapper onto main cache load function. + return c.cache.Load(i, keys, func(uncached []structr.Key) ([]T, error) { + uncachedIDs := make([]string, len(uncached)) + for i := range uncached { + uncachedIDs[i] = uncached[i].Values()[0].(string) + } + return load(uncachedIDs) + }) +} + +// Store: see structr.Cache{}.Store(). +func (c *StructCache[T]) Store(value T, store func() error) error { + return c.cache.Store(value, store) +} + +// Invalidate calls structr.Cache{}.Invalidate(), using a cached structr.Index{} by 'index' name. +// Note: this also handles conversion of the untyped (any) keys to structr.Key{} via structr.Index{}. +func (c *StructCache[T]) Invalidate(index string, key ...any) { + i := c.index[index] + c.cache.Invalidate(i, i.Key(key...)) +} + +// InvalidateIDs calls structr.Cache{}.Invalidate(), using a cached structr.Index{} by 'index' name. Note: this also +// handles conversion of the ID strings to structr.Key{} via structr.Index{}. Strong typing is used for caller convenience. +// +// If you need to invalidate multiple cache keys other than by ID strings, please create another convenience wrapper. +func (c *StructCache[T]) InvalidateIDs(index string, ids []string) { + i := c.index[index] + if i == nil { + // we only perform this check here as + // we're going to use the index before + // passing it to cache in main .Load(). + panic("missing index for cache type") + } + + // Generate cache keys for ID types. + keys := make([]structr.Key, len(ids)) + for x, id := range ids { + keys[x] = i.Key(id) + } + + // Pass to main invalidate func. + c.cache.Invalidate(i, keys...) +} + +// Trim: see structr.Cache{}.Trim(). +func (c *StructCache[T]) Trim(perc float64) { + c.cache.Trim(perc) +} + +// Clear: see structr.Cache{}.Clear(). +func (c *StructCache[T]) Clear() { + c.cache.Clear() +} + +// Len: see structr.Cache{}.Len(). +func (c *StructCache[T]) Len() int { + return c.cache.Len() +} + +// Cap: see structr.Cache{}.Cap(). +func (c *StructCache[T]) Cap() int { + return c.cache.Cap() +} |