summaryrefslogtreecommitdiff
path: root/internal/cache/status.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/cache/status.go')
-rw-r--r--internal/cache/status.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/cache/status.go b/internal/cache/status.go
new file mode 100644
index 000000000..895a5692c
--- /dev/null
+++ b/internal/cache/status.go
@@ -0,0 +1,106 @@
+package cache
+
+import (
+ "sync"
+
+ "github.com/ReneKroon/ttlcache"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+)
+
+// statusCache is a wrapper around ttlcache.Cache to provide URL and URI lookups for gtsmodel.Status
+type StatusCache struct {
+ cache *ttlcache.Cache // map of IDs -> cached statuses
+ urls map[string]string // map of status URLs -> IDs
+ uris map[string]string // map of status URIs -> IDs
+ mutex sync.Mutex
+}
+
+// newStatusCache returns a new instantiated statusCache object
+func NewStatusCache() *StatusCache {
+ c := StatusCache{
+ cache: ttlcache.NewCache(),
+ urls: make(map[string]string, 100),
+ uris: make(map[string]string, 100),
+ mutex: sync.Mutex{},
+ }
+
+ // Set callback to purge lookup maps on expiration
+ c.cache.SetExpirationCallback(func(key string, value interface{}) {
+ status := value.(*gtsmodel.Status)
+
+ c.mutex.Lock()
+ delete(c.urls, status.URL)
+ delete(c.uris, status.URI)
+ c.mutex.Unlock()
+ })
+
+ return &c
+}
+
+// GetByID attempts to fetch a status from the cache by its ID
+func (c *StatusCache) GetByID(id string) (*gtsmodel.Status, bool) {
+ c.mutex.Lock()
+ status, ok := c.getByID(id)
+ c.mutex.Unlock()
+ return status, ok
+}
+
+// GetByURL attempts to fetch a status from the cache by its URL
+func (c *StatusCache) GetByURL(url string) (*gtsmodel.Status, bool) {
+ // Perform safe ID lookup
+ c.mutex.Lock()
+ id, ok := c.urls[url]
+
+ // Not found, unlock early
+ if !ok {
+ c.mutex.Unlock()
+ return nil, false
+ }
+
+ // Attempt status lookup
+ status, ok := c.getByID(id)
+ c.mutex.Unlock()
+ return status, ok
+}
+
+// GetByURI attempts to fetch a status from the cache by its URI
+func (c *StatusCache) GetByURI(uri string) (*gtsmodel.Status, bool) {
+ // Perform safe ID lookup
+ c.mutex.Lock()
+ id, ok := c.uris[uri]
+
+ // Not found, unlock early
+ if !ok {
+ c.mutex.Unlock()
+ return nil, false
+ }
+
+ // Attempt status lookup
+ status, ok := c.getByID(id)
+ c.mutex.Unlock()
+ return status, ok
+}
+
+// getByID performs an unsafe (no mutex locks) lookup of status by ID
+func (c *StatusCache) getByID(id string) (*gtsmodel.Status, bool) {
+ v, ok := c.cache.Get(id)
+ if !ok {
+ return nil, false
+ }
+ return v.(*gtsmodel.Status), true
+}
+
+// Put places a status in the cache
+func (c *StatusCache) Put(status *gtsmodel.Status) {
+ if status == nil || status.ID == "" ||
+ status.URL == "" ||
+ status.URI == "" {
+ panic("invalid status")
+ }
+
+ c.mutex.Lock()
+ c.cache.Set(status.ID, status)
+ c.urls[status.URL] = status.ID
+ c.uris[status.URI] = status.ID
+ c.mutex.Unlock()
+}