summaryrefslogtreecommitdiff
path: root/internal/cache
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2022-09-02 11:17:46 +0100
committerLibravatar GitHub <noreply@github.com>2022-09-02 12:17:46 +0200
commitd68c04a6c0964d795a8d475c2f73d201bc72e68b (patch)
tree415746fa7279c4776ee822f1513f45c28a22e547 /internal/cache
parent[feature] Federate custom emoji (outbound) (#791) (diff)
downloadgotosocial-d68c04a6c0964d795a8d475c2f73d201bc72e68b.tar.xz
[performance] cache recently allowed/denied domains to cut down on db calls (#794)
* fetch creation and fetching domain blocks from db Signed-off-by: kim <grufwub@gmail.com> * add separate domainblock cache type, handle removing block from cache on delete Signed-off-by: kim <grufwub@gmail.com> * fix sentinel nil values being passed into cache Signed-off-by: kim <grufwub@gmail.com> Signed-off-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/cache')
-rw-r--r--internal/cache/domain.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/cache/domain.go b/internal/cache/domain.go
new file mode 100644
index 000000000..7b5a93d39
--- /dev/null
+++ b/internal/cache/domain.go
@@ -0,0 +1,106 @@
+/*
+ GoToSocial
+ Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
+
+ 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 (
+ "time"
+
+ "codeberg.org/gruf/go-cache/v2"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+)
+
+// DomainCache is a cache wrapper to provide URL and URI lookups for gtsmodel.Status
+type DomainBlockCache struct {
+ cache cache.LookupCache[string, string, *gtsmodel.DomainBlock]
+}
+
+// NewStatusCache returns a new instantiated statusCache object
+func NewDomainBlockCache() *DomainBlockCache {
+ c := &DomainBlockCache{}
+ c.cache = cache.NewLookup(cache.LookupCfg[string, string, *gtsmodel.DomainBlock]{
+ RegisterLookups: func(lm *cache.LookupMap[string, string]) {
+ lm.RegisterLookup("id")
+ },
+
+ AddLookups: func(lm *cache.LookupMap[string, string], block *gtsmodel.DomainBlock) {
+ // Block can be equal to nil when sentinel
+ if block != nil && block.ID != "" {
+ lm.Set("id", block.ID, block.Domain)
+ }
+ },
+
+ DeleteLookups: func(lm *cache.LookupMap[string, string], block *gtsmodel.DomainBlock) {
+ // Block can be equal to nil when sentinel
+ if block != nil && block.ID != "" {
+ lm.Delete("id", block.ID)
+ }
+ },
+ })
+ c.cache.SetTTL(time.Minute*5, false)
+ c.cache.Start(time.Second * 10)
+ return c
+}
+
+// GetByID attempts to fetch a status from the cache by its ID, you will receive a copy for thread-safety
+func (c *DomainBlockCache) GetByID(id string) (*gtsmodel.DomainBlock, bool) {
+ return c.cache.GetBy("id", id)
+}
+
+// GetByURL attempts to fetch a status from the cache by its URL, you will receive a copy for thread-safety
+func (c *DomainBlockCache) GetByDomain(domain string) (*gtsmodel.DomainBlock, bool) {
+ return c.cache.Get(domain)
+}
+
+// Put places a status in the cache, ensuring that the object place is a copy for thread-safety
+func (c *DomainBlockCache) Put(domain string, block *gtsmodel.DomainBlock) {
+ if domain == "" {
+ panic("invalid domain")
+ }
+
+ if block == nil {
+ // This is a sentinel value for (no block)
+ c.cache.Set(domain, nil)
+ } else {
+ // This is a valid domain block
+ c.cache.Set(domain, copyDomainBlock(block))
+ }
+}
+
+// InvalidateByDomain will invalidate a domain block from the cache by domain name.
+func (c *DomainBlockCache) InvalidateByDomain(domain string) {
+ c.cache.Invalidate(domain)
+}
+
+// copyStatus performs a surface-level copy of status, only keeping attached IDs intact, not the objects.
+// due to all the data being copied being 99% primitive types or strings (which are immutable and passed by ptr)
+// this should be a relatively cheap process
+func copyDomainBlock(block *gtsmodel.DomainBlock) *gtsmodel.DomainBlock {
+ return &gtsmodel.DomainBlock{
+ ID: block.ID,
+ CreatedAt: block.CreatedAt,
+ UpdatedAt: block.UpdatedAt,
+ Domain: block.Domain,
+ CreatedByAccountID: block.CreatedByAccountID,
+ CreatedByAccount: nil,
+ PrivateComment: block.PrivateComment,
+ PublicComment: block.PublicComment,
+ Obfuscate: block.Obfuscate,
+ SubscriptionID: block.SubscriptionID,
+ }
+}