diff options
Diffstat (limited to 'internal')
| -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 | ||||
| -rw-r--r-- | internal/db/bundb/emoji.go | 58 | ||||
| -rw-r--r-- | internal/db/bundb/filter.go | 14 | ||||
| -rw-r--r-- | internal/db/bundb/filterkeyword.go | 14 | ||||
| -rw-r--r-- | internal/db/bundb/filterstatus.go | 14 | ||||
| -rw-r--r-- | internal/db/bundb/list.go | 38 | ||||
| -rw-r--r-- | internal/db/bundb/media.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/mention.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/notification.go | 35 | ||||
| -rw-r--r-- | internal/db/bundb/poll.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/relationship.go | 10 | ||||
| -rw-r--r-- | internal/db/bundb/relationship_block.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/relationship_follow.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/relationship_follow_req.go | 19 | ||||
| -rw-r--r-- | internal/db/bundb/status.go | 21 | ||||
| -rw-r--r-- | internal/db/bundb/statusfave.go | 29 | ||||
| -rw-r--r-- | internal/db/bundb/tag.go | 19 | 
21 files changed, 398 insertions, 487 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() +} diff --git a/internal/db/bundb/emoji.go b/internal/db/bundb/emoji.go index 69d33eede..2316e7d71 100644 --- a/internal/db/bundb/emoji.go +++ b/internal/db/bundb/emoji.go @@ -76,23 +76,11 @@ func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error {  	defer func() {  		// Invalidate cached emoji. -		e.state.Caches.GTS. -			Emoji. -			Invalidate("ID", id) +		e.state.Caches.GTS.Emoji.Invalidate("ID", id) -		for _, accountID := range accountIDs { -			// Invalidate cached account. -			e.state.Caches.GTS. -				Account. -				Invalidate("ID", accountID) -		} - -		for _, statusID := range statusIDs { -			// Invalidate cached account. -			e.state.Caches.GTS. -				Status. -				Invalidate("ID", statusID) -		} +		// Invalidate cached account and status IDs. +		e.state.Caches.GTS.Account.InvalidateIDs("ID", accountIDs) +		e.state.Caches.GTS.Status.InvalidateIDs("ID", statusIDs)  	}()  	// Load emoji into cache before attempting a delete, @@ -594,23 +582,10 @@ func (e *emojiDB) GetEmojisByIDs(ctx context.Context, ids []string) ([]*gtsmodel  		return nil, db.ErrNoEntries  	} -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all emoji IDs via cache loader callbacks. -	emojis, err := e.state.Caches.GTS.Emoji.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 emoji loader function. -		func() ([]*gtsmodel.Emoji, error) { +	emojis, err := e.state.Caches.GTS.Emoji.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Emoji, error) {  			// Preallocate expected length of uncached emojis.  			emojis := make([]*gtsmodel.Emoji, 0, len(uncached)) @@ -671,23 +646,10 @@ func (e *emojiDB) GetEmojiCategoriesByIDs(ctx context.Context, ids []string) ([]  		return nil, db.ErrNoEntries  	} -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all category IDs via cache loader callbacks. -	categories, err := e.state.Caches.GTS.EmojiCategory.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 emoji loader function. -		func() ([]*gtsmodel.EmojiCategory, error) { +	categories, err := e.state.Caches.GTS.EmojiCategory.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.EmojiCategory, error) {  			// Preallocate expected length of uncached categories.  			categories := make([]*gtsmodel.EmojiCategory, 0, len(uncached)) diff --git a/internal/db/bundb/filter.go b/internal/db/bundb/filter.go index bcd572f34..d09a5067d 100644 --- a/internal/db/bundb/filter.go +++ b/internal/db/bundb/filter.go @@ -79,17 +79,9 @@ func (f *filterDB) GetFiltersForAccountID(ctx context.Context, accountID string)  	}  	// Get each filter by ID from the cache or DB. -	uncachedFilterIDs := make([]string, 0, len(filterIDs)) -	filters, err := f.state.Caches.GTS.Filter.Load( -		"ID", -		func(load func(keyParts ...any) bool) { -			for _, id := range filterIDs { -				if !load(id) { -					uncachedFilterIDs = append(uncachedFilterIDs, id) -				} -			} -		}, -		func() ([]*gtsmodel.Filter, error) { +	filters, err := f.state.Caches.GTS.Filter.LoadIDs("ID", +		filterIDs, +		func(uncachedFilterIDs []string) ([]*gtsmodel.Filter, error) {  			uncachedFilters := make([]*gtsmodel.Filter, 0, len(uncachedFilterIDs))  			if err := f.db.  				NewSelect(). diff --git a/internal/db/bundb/filterkeyword.go b/internal/db/bundb/filterkeyword.go index 703d58d43..5fd824a0b 100644 --- a/internal/db/bundb/filterkeyword.go +++ b/internal/db/bundb/filterkeyword.go @@ -97,17 +97,9 @@ func (f *filterDB) getFilterKeywords(ctx context.Context, idColumn string, id st  	}  	// Get each filter keyword by ID from the cache or DB. -	uncachedFilterKeywordIDs := make([]string, 0, len(filterKeywordIDs)) -	filterKeywords, err := f.state.Caches.GTS.FilterKeyword.Load( -		"ID", -		func(load func(keyParts ...any) bool) { -			for _, id := range filterKeywordIDs { -				if !load(id) { -					uncachedFilterKeywordIDs = append(uncachedFilterKeywordIDs, id) -				} -			} -		}, -		func() ([]*gtsmodel.FilterKeyword, error) { +	filterKeywords, err := f.state.Caches.GTS.FilterKeyword.LoadIDs("ID", +		filterKeywordIDs, +		func(uncachedFilterKeywordIDs []string) ([]*gtsmodel.FilterKeyword, error) {  			uncachedFilterKeywords := make([]*gtsmodel.FilterKeyword, 0, len(uncachedFilterKeywordIDs))  			if err := f.db.  				NewSelect(). diff --git a/internal/db/bundb/filterstatus.go b/internal/db/bundb/filterstatus.go index 1e98f5958..78985fba1 100644 --- a/internal/db/bundb/filterstatus.go +++ b/internal/db/bundb/filterstatus.go @@ -97,17 +97,9 @@ func (f *filterDB) getFilterStatuses(ctx context.Context, idColumn string, id st  	}  	// Get each filter status by ID from the cache or DB. -	uncachedFilterStatusIDs := make([]string, 0, len(filterStatusIDs)) -	filterStatuses, err := f.state.Caches.GTS.FilterStatus.Load( -		"ID", -		func(load func(keyParts ...any) bool) { -			for _, id := range filterStatusIDs { -				if !load(id) { -					uncachedFilterStatusIDs = append(uncachedFilterStatusIDs, id) -				} -			} -		}, -		func() ([]*gtsmodel.FilterStatus, error) { +	filterStatuses, err := f.state.Caches.GTS.FilterStatus.LoadIDs("ID", +		filterStatusIDs, +		func(uncachedFilterStatusIDs []string) ([]*gtsmodel.FilterStatus, error) {  			uncachedFilterStatuses := make([]*gtsmodel.FilterStatus, 0, len(uncachedFilterStatusIDs))  			if err := f.db.  				NewSelect(). diff --git a/internal/db/bundb/list.go b/internal/db/bundb/list.go index fb97c8fe7..92936a49f 100644 --- a/internal/db/bundb/list.go +++ b/internal/db/bundb/list.go @@ -341,23 +341,10 @@ func (l *listDB) GetListEntries(ctx context.Context,  }  func (l *listDB) GetListsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.List, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all list IDs via cache loader callbacks. -	lists, err := l.state.Caches.GTS.List.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 list loader function. -		func() ([]*gtsmodel.List, error) { +	lists, err := l.state.Caches.GTS.List.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.List, error) {  			// Preallocate expected length of uncached lists.  			lists := make([]*gtsmodel.List, 0, len(uncached)) @@ -401,23 +388,10 @@ func (l *listDB) GetListsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.L  }  func (l *listDB) GetListEntriesByIDs(ctx context.Context, ids []string) ([]*gtsmodel.ListEntry, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all entry IDs via cache loader callbacks. -	entries, err := l.state.Caches.GTS.ListEntry.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 entry loader function. -		func() ([]*gtsmodel.ListEntry, error) { +	entries, err := l.state.Caches.GTS.ListEntry.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.ListEntry, error) {  			// Preallocate expected length of uncached entries.  			entries := make([]*gtsmodel.ListEntry, 0, len(uncached)) diff --git a/internal/db/bundb/media.go b/internal/db/bundb/media.go index 99ef30d22..ed41e7cd9 100644 --- a/internal/db/bundb/media.go +++ b/internal/db/bundb/media.go @@ -53,23 +53,10 @@ func (m *mediaDB) GetAttachmentByID(ctx context.Context, id string) (*gtsmodel.M  }  func (m *mediaDB) GetAttachmentsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.MediaAttachment, error) { -	// 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) { +	media, err := m.state.Caches.GTS.Media.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.MediaAttachment, error) {  			// Preallocate expected length of uncached media attachments.  			media := make([]*gtsmodel.MediaAttachment, 0, len(uncached)) diff --git a/internal/db/bundb/mention.go b/internal/db/bundb/mention.go index 156469544..559e9515c 100644 --- a/internal/db/bundb/mention.go +++ b/internal/db/bundb/mention.go @@ -65,23 +65,10 @@ func (m *mentionDB) GetMention(ctx context.Context, id string) (*gtsmodel.Mentio  }  func (m *mentionDB) GetMentions(ctx context.Context, ids []string) ([]*gtsmodel.Mention, error) { -	// 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) { +	mentions, err := m.state.Caches.GTS.Mention.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Mention, error) {  			// Preallocate expected length of uncached mentions.  			mentions := make([]*gtsmodel.Mention, 0, len(uncached)) diff --git a/internal/db/bundb/notification.go b/internal/db/bundb/notification.go index 3f3d5fbd6..63fb7ed21 100644 --- a/internal/db/bundb/notification.go +++ b/internal/db/bundb/notification.go @@ -104,23 +104,10 @@ func (n *notificationDB) getNotification(ctx context.Context, lookup string, dbQ  }  func (n *notificationDB) GetNotificationsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Notification, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all notif IDs via cache loader callbacks. -	notifs, err := n.state.Caches.GTS.Notification.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 notification loader function. -		func() ([]*gtsmodel.Notification, error) { +	notifs, err := n.state.Caches.GTS.Notification.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Notification, error) {  			// Preallocate expected length of uncached notifications.  			notifs := make([]*gtsmodel.Notification, 0, len(uncached)) @@ -345,12 +332,8 @@ func (n *notificationDB) DeleteNotifications(ctx context.Context, types []string  		return err  	} -	defer func() { -		// Invalidate all IDs on return. -		for _, id := range notifIDs { -			n.state.Caches.GTS.Notification.Invalidate("ID", id) -		} -	}() +	// Invalidate all cached notifications by IDs on return. +	defer n.state.Caches.GTS.Notification.InvalidateIDs("ID", notifIDs)  	// Load all notif into cache, this *really* isn't great  	// but it is the only way we can ensure we invalidate all @@ -383,12 +366,8 @@ func (n *notificationDB) DeleteNotificationsForStatus(ctx context.Context, statu  		return err  	} -	defer func() { -		// Invalidate all IDs on return. -		for _, id := range notifIDs { -			n.state.Caches.GTS.Notification.Invalidate("ID", id) -		} -	}() +	// Invalidate all cached notifications by IDs on return. +	defer n.state.Caches.GTS.Notification.InvalidateIDs("ID", notifIDs)  	// Load all notif into cache, this *really* isn't great  	// but it is the only way we can ensure we invalidate all diff --git a/internal/db/bundb/poll.go b/internal/db/bundb/poll.go index 37a1f26ab..33b621805 100644 --- a/internal/db/bundb/poll.go +++ b/internal/db/bundb/poll.go @@ -270,23 +270,10 @@ func (p *pollDB) GetPollVotes(ctx context.Context, pollID string) ([]*gtsmodel.P  		return nil, err  	} -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(voteIDs)) -  	// Load all votes from IDs via cache loader callbacks. -	votes, err := p.state.Caches.GTS.PollVote.Load("ID", - -		// Load cached + check for uncached. -		func(load func(keyParts ...any) bool) { -			for _, id := range voteIDs { -				if !load(id) { -					uncached = append(uncached, id) -				} -			} -		}, - -		// Uncached poll vote loader function. -		func() ([]*gtsmodel.PollVote, error) { +	votes, err := p.state.Caches.GTS.PollVote.LoadIDs("ID", +		voteIDs, +		func(uncached []string) ([]*gtsmodel.PollVote, error) {  			// Preallocate expected length of uncached votes.  			votes := make([]*gtsmodel.PollVote, 0, len(uncached)) diff --git a/internal/db/bundb/relationship.go b/internal/db/bundb/relationship.go index a97aa71ff..30e3850d2 100644 --- a/internal/db/bundb/relationship.go +++ b/internal/db/bundb/relationship.go @@ -203,7 +203,7 @@ func (r *relationshipDB) CountAccountBlocks(ctx context.Context, accountID strin  }  func (r *relationshipDB) getAccountFollowIDs(ctx context.Context, accountID string, page *paging.Page) ([]string, error) { -	return loadPagedIDs(r.state.Caches.GTS.FollowIDs, ">"+accountID, page, func() ([]string, error) { +	return loadPagedIDs(&r.state.Caches.GTS.FollowIDs, ">"+accountID, page, func() ([]string, error) {  		var followIDs []string  		// Follow IDs not in cache, perform DB query! @@ -233,7 +233,7 @@ func (r *relationshipDB) getAccountLocalFollowIDs(ctx context.Context, accountID  }  func (r *relationshipDB) getAccountFollowerIDs(ctx context.Context, accountID string, page *paging.Page) ([]string, error) { -	return loadPagedIDs(r.state.Caches.GTS.FollowIDs, "<"+accountID, page, func() ([]string, error) { +	return loadPagedIDs(&r.state.Caches.GTS.FollowIDs, "<"+accountID, page, func() ([]string, error) {  		var followIDs []string  		// Follow IDs not in cache, perform DB query! @@ -263,7 +263,7 @@ func (r *relationshipDB) getAccountLocalFollowerIDs(ctx context.Context, account  }  func (r *relationshipDB) getAccountFollowRequestIDs(ctx context.Context, accountID string, page *paging.Page) ([]string, error) { -	return loadPagedIDs(r.state.Caches.GTS.FollowRequestIDs, ">"+accountID, page, func() ([]string, error) { +	return loadPagedIDs(&r.state.Caches.GTS.FollowRequestIDs, ">"+accountID, page, func() ([]string, error) {  		var followReqIDs []string  		// Follow request IDs not in cache, perform DB query! @@ -278,7 +278,7 @@ func (r *relationshipDB) getAccountFollowRequestIDs(ctx context.Context, account  }  func (r *relationshipDB) getAccountFollowRequestingIDs(ctx context.Context, accountID string, page *paging.Page) ([]string, error) { -	return loadPagedIDs(r.state.Caches.GTS.FollowRequestIDs, "<"+accountID, page, func() ([]string, error) { +	return loadPagedIDs(&r.state.Caches.GTS.FollowRequestIDs, "<"+accountID, page, func() ([]string, error) {  		var followReqIDs []string  		// Follow request IDs not in cache, perform DB query! @@ -293,7 +293,7 @@ func (r *relationshipDB) getAccountFollowRequestingIDs(ctx context.Context, acco  }  func (r *relationshipDB) getAccountBlockIDs(ctx context.Context, accountID string, page *paging.Page) ([]string, error) { -	return loadPagedIDs(r.state.Caches.GTS.BlockIDs, accountID, page, func() ([]string, error) { +	return loadPagedIDs(&r.state.Caches.GTS.BlockIDs, accountID, page, func() ([]string, error) {  		var blockIDs []string  		// Block IDs not in cache, perform DB query! diff --git a/internal/db/bundb/relationship_block.go b/internal/db/bundb/relationship_block.go index 178de6aa7..d994559ab 100644 --- a/internal/db/bundb/relationship_block.go +++ b/internal/db/bundb/relationship_block.go @@ -101,23 +101,10 @@ func (r *relationshipDB) GetBlock(ctx context.Context, sourceAccountID string, t  }  func (r *relationshipDB) GetBlocksByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Block, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all blocks IDs via cache loader callbacks. -	blocks, err := r.state.Caches.GTS.Block.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 block loader function. -		func() ([]*gtsmodel.Block, error) { +	blocks, err := r.state.Caches.GTS.Block.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Block, error) {  			// Preallocate expected length of uncached blocks.  			blocks := make([]*gtsmodel.Block, 0, len(uncached)) diff --git a/internal/db/bundb/relationship_follow.go b/internal/db/bundb/relationship_follow.go index 93ee69bd7..02b861ae0 100644 --- a/internal/db/bundb/relationship_follow.go +++ b/internal/db/bundb/relationship_follow.go @@ -78,23 +78,10 @@ func (r *relationshipDB) GetFollow(ctx context.Context, sourceAccountID string,  }  func (r *relationshipDB) GetFollowsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Follow, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all follow IDs via cache loader callbacks. -	follows, err := r.state.Caches.GTS.Follow.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 follow loader function. -		func() ([]*gtsmodel.Follow, error) { +	follows, err := r.state.Caches.GTS.Follow.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Follow, error) {  			// Preallocate expected length of uncached follows.  			follows := make([]*gtsmodel.Follow, 0, len(uncached)) diff --git a/internal/db/bundb/relationship_follow_req.go b/internal/db/bundb/relationship_follow_req.go index 6fd5eefba..0b897f1fa 100644 --- a/internal/db/bundb/relationship_follow_req.go +++ b/internal/db/bundb/relationship_follow_req.go @@ -77,23 +77,10 @@ func (r *relationshipDB) GetFollowRequest(ctx context.Context, sourceAccountID s  }  func (r *relationshipDB) GetFollowRequestsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.FollowRequest, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all follow IDs via cache loader callbacks. -	follows, err := r.state.Caches.GTS.FollowRequest.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 follow req loader function. -		func() ([]*gtsmodel.FollowRequest, error) { +	follows, err := r.state.Caches.GTS.FollowRequest.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.FollowRequest, error) {  			// Preallocate expected length of uncached followReqs.  			follows := make([]*gtsmodel.FollowRequest, 0, len(uncached)) diff --git a/internal/db/bundb/status.go b/internal/db/bundb/status.go index 6d1788b5d..4bb9812dc 100644 --- a/internal/db/bundb/status.go +++ b/internal/db/bundb/status.go @@ -50,23 +50,10 @@ func (s *statusDB) GetStatusByID(ctx context.Context, id string) (*gtsmodel.Stat  }  func (s *statusDB) GetStatusesByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Status, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) - -	// Load all status IDs via cache loader callbacks. -	statuses, err := s.state.Caches.GTS.Status.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 statuses loader function. -		func() ([]*gtsmodel.Status, error) { +	// Load all input status IDs via cache loader callback. +	statuses, err := s.state.Caches.GTS.Status.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Status, error) {  			// Preallocate expected length of uncached statuses.  			statuses := make([]*gtsmodel.Status, 0, len(uncached)) diff --git a/internal/db/bundb/statusfave.go b/internal/db/bundb/statusfave.go index d04578076..8e9ff501c 100644 --- a/internal/db/bundb/statusfave.go +++ b/internal/db/bundb/statusfave.go @@ -113,23 +113,10 @@ func (s *statusFaveDB) GetStatusFaves(ctx context.Context, statusID string) ([]*  		return nil, err  	} -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(faveIDs)) -  	// Load all fave IDs via cache loader callbacks. -	faves, err := s.state.Caches.GTS.StatusFave.Load("ID", - -		// Load cached + check for uncached. -		func(load func(keyParts ...any) bool) { -			for _, id := range faveIDs { -				if !load(id) { -					uncached = append(uncached, id) -				} -			} -		}, - -		// Uncached status faves loader function. -		func() ([]*gtsmodel.StatusFave, error) { +	faves, err := s.state.Caches.GTS.StatusFave.LoadIDs("ID", +		faveIDs, +		func(uncached []string) ([]*gtsmodel.StatusFave, error) {  			// Preallocate expected length of uncached faves.  			faves := make([]*gtsmodel.StatusFave, 0, len(uncached)) @@ -318,13 +305,11 @@ func (s *statusFaveDB) DeleteStatusFaves(ctx context.Context, targetAccountID st  	// Deduplicate determined status IDs.  	statusIDs = util.Deduplicate(statusIDs) -	for _, id := range statusIDs { -		// Invalidate any cached status faves for this status. -		s.state.Caches.GTS.StatusFave.Invalidate("ID", id) +	// Invalidate any cached status faves for this status ID. +	s.state.Caches.GTS.StatusFave.InvalidateIDs("ID", statusIDs) -		// Invalidate any cached status fave IDs for this status. -		s.state.Caches.GTS.StatusFaveIDs.Invalidate(id) -	} +	// Invalidate any cached status fave IDs for this status ID. +	s.state.Caches.GTS.StatusFaveIDs.Invalidate(statusIDs...)  	return nil  } diff --git a/internal/db/bundb/tag.go b/internal/db/bundb/tag.go index e6297d2ab..db1effaf4 100644 --- a/internal/db/bundb/tag.go +++ b/internal/db/bundb/tag.go @@ -71,23 +71,10 @@ func (t *tagDB) GetTagByName(ctx context.Context, name string) (*gtsmodel.Tag, e  }  func (t *tagDB) GetTags(ctx context.Context, ids []string) ([]*gtsmodel.Tag, error) { -	// Preallocate at-worst possible length. -	uncached := make([]string, 0, len(ids)) -  	// Load all tag IDs via cache loader callbacks. -	tags, err := t.state.Caches.GTS.Tag.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 tag loader function. -		func() ([]*gtsmodel.Tag, error) { +	tags, err := t.state.Caches.GTS.Tag.LoadIDs("ID", +		ids, +		func(uncached []string) ([]*gtsmodel.Tag, error) {  			// Preallocate expected length of uncached tags.  			tags := make([]*gtsmodel.Tag, 0, len(uncached)) | 
