summaryrefslogtreecommitdiff
path: root/internal/cache/status.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2021-09-01 10:08:21 +0100
committerLibravatar GitHub <noreply@github.com>2021-09-01 11:08:21 +0200
commit7d193de25fbccc00923d6d791d6d4e0d2d5d498e (patch)
treeda993d91aeaccc07c2fff461067325fbe89bba73 /internal/cache/status.go
parentAdd SQLite support, fix un-thread-safe DB caches, small performance f… (#172) (diff)
downloadgotosocial-7d193de25fbccc00923d6d791d6d4e0d2d5d498e.tar.xz
Improve GetRemoteStatus and db.GetStatus() logic (#174)
* only fetch status parents / children if explicity requested when dereferencing Signed-off-by: kim (grufwub) <grufwub@gmail.com> * Remove recursive DB GetStatus logic, don't fetch parent unless requested Signed-off-by: kim (grufwub) <grufwub@gmail.com> * StatusCache copies status so there are no thread-safety issues with modified status objects Signed-off-by: kim (grufwub) <grufwub@gmail.com> * remove sqlite test files Signed-off-by: kim (grufwub) <grufwub@gmail.com> * fix bugs introduced by previous commit Signed-off-by: kim (grufwub) <grufwub@gmail.com> * fix not continue on error in loop Signed-off-by: kim (grufwub) <grufwub@gmail.com> * use our own RunInTx implementation (possible fix for nested tx error) Signed-off-by: kim (grufwub) <grufwub@gmail.com> * fix cast statement to work with SQLite Signed-off-by: kim (grufwub) <grufwub@gmail.com> * be less strict about valid status in cache Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add cache=shared ALWAYS for SQLite db instances Signed-off-by: kim (grufwub) <grufwub@gmail.com> * Fix EnrichRemoteAccount when updating account fails Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add nolint tag Signed-off-by: kim (grufwub) <grufwub@gmail.com> * ensure file: prefixes the filename in sqlite addr Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add an account cache, add status author account from db Signed-off-by: kim (grufwub) <grufwub@gmail.com> * Fix incompatible SQLite query Signed-off-by: kim (grufwub) <grufwub@gmail.com> * *actually* use the new getAccount() function in accountsDB Signed-off-by: kim (grufwub) <grufwub@gmail.com> * update cache tests to use test suite Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add RelationshipTestSuite, add tests for methods with changed SQL Signed-off-by: kim (grufwub) <grufwub@gmail.com>
Diffstat (limited to 'internal/cache/status.go')
-rw-r--r--internal/cache/status.go70
1 files changed, 58 insertions, 12 deletions
diff --git a/internal/cache/status.go b/internal/cache/status.go
index 895a5692c..028abc8f7 100644
--- a/internal/cache/status.go
+++ b/internal/cache/status.go
@@ -37,7 +37,7 @@ func NewStatusCache() *StatusCache {
return &c
}
-// GetByID attempts to fetch a status from the cache by its ID
+// GetByID attempts to fetch a status from the cache by its ID, you will receive a copy for thread-safety
func (c *StatusCache) GetByID(id string) (*gtsmodel.Status, bool) {
c.mutex.Lock()
status, ok := c.getByID(id)
@@ -45,7 +45,7 @@ func (c *StatusCache) GetByID(id string) (*gtsmodel.Status, bool) {
return status, ok
}
-// GetByURL attempts to fetch a status from the cache by its URL
+// GetByURL attempts to fetch a status from the cache by its URL, you will receive a copy for thread-safety
func (c *StatusCache) GetByURL(url string) (*gtsmodel.Status, bool) {
// Perform safe ID lookup
c.mutex.Lock()
@@ -63,7 +63,7 @@ func (c *StatusCache) GetByURL(url string) (*gtsmodel.Status, bool) {
return status, ok
}
-// GetByURI attempts to fetch a status from the cache by its URI
+// GetByURI attempts to fetch a status from the cache by its URI, you will receive a copy for thread-safety
func (c *StatusCache) GetByURI(uri string) (*gtsmodel.Status, bool) {
// Perform safe ID lookup
c.mutex.Lock()
@@ -81,26 +81,72 @@ func (c *StatusCache) GetByURI(uri string) (*gtsmodel.Status, bool) {
return status, ok
}
-// getByID performs an unsafe (no mutex locks) lookup of status by ID
+// getByID performs an unsafe (no mutex locks) lookup of status by ID, returning a copy of status in cache
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
+ return copyStatus(v.(*gtsmodel.Status)), true
}
-// Put places a status in the cache
+// Put places a status in the cache, ensuring that the object place is a copy for thread-safety
func (c *StatusCache) Put(status *gtsmodel.Status) {
- if status == nil || status.ID == "" ||
- status.URL == "" ||
- status.URI == "" {
+ if status == nil || status.ID == "" {
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.cache.Set(status.ID, copyStatus(status))
+ if status.URL != "" {
+ c.urls[status.URL] = status.ID
+ }
+ if status.URI != "" {
+ c.uris[status.URI] = status.ID
+ }
c.mutex.Unlock()
}
+
+// 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 copyStatus(status *gtsmodel.Status) *gtsmodel.Status {
+ return &gtsmodel.Status{
+ ID: status.ID,
+ URI: status.URI,
+ URL: status.URL,
+ Content: status.Content,
+ AttachmentIDs: status.AttachmentIDs,
+ Attachments: nil,
+ TagIDs: status.TagIDs,
+ Tags: nil,
+ MentionIDs: status.MentionIDs,
+ Mentions: nil,
+ EmojiIDs: status.EmojiIDs,
+ Emojis: nil,
+ CreatedAt: status.CreatedAt,
+ UpdatedAt: status.UpdatedAt,
+ Local: status.Local,
+ AccountID: status.AccountID,
+ Account: nil,
+ AccountURI: status.AccountURI,
+ InReplyToID: status.InReplyToID,
+ InReplyTo: nil,
+ InReplyToURI: status.InReplyToURI,
+ InReplyToAccountID: status.InReplyToAccountID,
+ InReplyToAccount: nil,
+ BoostOfID: status.BoostOfID,
+ BoostOf: nil,
+ BoostOfAccountID: status.BoostOfAccountID,
+ BoostOfAccount: nil,
+ ContentWarning: status.ContentWarning,
+ Visibility: status.Visibility,
+ Sensitive: status.Sensitive,
+ Language: status.Language,
+ CreatedWithApplicationID: status.CreatedWithApplicationID,
+ VisibilityAdvanced: status.VisibilityAdvanced,
+ ActivityStreamsType: status.ActivityStreamsType,
+ Text: status.Text,
+ Pinned: status.Pinned,
+ }
+}