-
-
Notifications
You must be signed in to change notification settings - Fork 349
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add an account cache, add status author account from db
Signed-off-by: kim (grufwub) <[email protected]>
- Loading branch information
1 parent
a6d0e6e
commit a211708
Showing
6 changed files
with
251 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package cache | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/ReneKroon/ttlcache" | ||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||
) | ||
|
||
// AccountCache is a wrapper around ttlcache.Cache to provide URL and URI lookups for gtsmodel.Account | ||
type AccountCache struct { | ||
cache *ttlcache.Cache // map of IDs -> cached accounts | ||
urls map[string]string // map of account URLs -> IDs | ||
uris map[string]string // map of account URIs -> IDs | ||
mutex sync.Mutex | ||
} | ||
|
||
// NewAccountCache returns a new instantiated AccountCache object | ||
func NewAccountCache() *AccountCache { | ||
c := AccountCache{ | ||
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{}) { | ||
account := value.(*gtsmodel.Account) | ||
|
||
c.mutex.Lock() | ||
delete(c.urls, account.URL) | ||
delete(c.uris, account.URI) | ||
c.mutex.Unlock() | ||
}) | ||
|
||
return &c | ||
} | ||
|
||
// GetByID attempts to fetch a account from the cache by its ID, you will receive a copy for thread-safety | ||
func (c *AccountCache) GetByID(id string) (*gtsmodel.Account, bool) { | ||
c.mutex.Lock() | ||
account, ok := c.getByID(id) | ||
c.mutex.Unlock() | ||
return account, ok | ||
} | ||
|
||
// GetByURL attempts to fetch a account from the cache by its URL, you will receive a copy for thread-safety | ||
func (c *AccountCache) GetByURL(url string) (*gtsmodel.Account, 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 account lookup | ||
account, ok := c.getByID(id) | ||
c.mutex.Unlock() | ||
return account, ok | ||
} | ||
|
||
// GetByURI attempts to fetch a account from the cache by its URI, you will receive a copy for thread-safety | ||
func (c *AccountCache) GetByURI(uri string) (*gtsmodel.Account, 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 account lookup | ||
account, ok := c.getByID(id) | ||
c.mutex.Unlock() | ||
return account, ok | ||
} | ||
|
||
// getByID performs an unsafe (no mutex locks) lookup of account by ID, returning a copy of account in cache | ||
func (c *AccountCache) getByID(id string) (*gtsmodel.Account, bool) { | ||
v, ok := c.cache.Get(id) | ||
if !ok { | ||
return nil, false | ||
} | ||
return copyAccount(v.(*gtsmodel.Account)), true | ||
} | ||
|
||
// Put places a account in the cache, ensuring that the object place is a copy for thread-safety | ||
func (c *AccountCache) Put(account *gtsmodel.Account) { | ||
if account == nil || account.ID == "" { | ||
panic("invalid account") | ||
} | ||
|
||
c.mutex.Lock() | ||
c.cache.Set(account.ID, copyAccount(account)) | ||
if account.URL != "" { | ||
c.urls[account.URL] = account.ID | ||
} | ||
if account.URI != "" { | ||
c.uris[account.URI] = account.ID | ||
} | ||
c.mutex.Unlock() | ||
} | ||
|
||
// copyAccount performs a surface-level copy of account, 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 copyAccount(account *gtsmodel.Account) *gtsmodel.Account { | ||
return >smodel.Account{ | ||
ID: account.ID, | ||
Username: account.Username, | ||
Domain: account.Domain, | ||
AvatarMediaAttachmentID: account.AvatarMediaAttachmentID, | ||
AvatarMediaAttachment: nil, | ||
AvatarRemoteURL: account.AvatarRemoteURL, | ||
HeaderMediaAttachmentID: account.HeaderMediaAttachmentID, | ||
HeaderMediaAttachment: nil, | ||
HeaderRemoteURL: account.HeaderRemoteURL, | ||
DisplayName: account.DisplayName, | ||
Fields: account.Fields, | ||
Note: account.Note, | ||
Memorial: account.Memorial, | ||
MovedToAccountID: account.MovedToAccountID, | ||
CreatedAt: account.CreatedAt, | ||
UpdatedAt: account.UpdatedAt, | ||
Bot: account.Bot, | ||
Reason: account.Reason, | ||
Locked: account.Locked, | ||
Discoverable: account.Discoverable, | ||
Privacy: account.Privacy, | ||
Sensitive: account.Sensitive, | ||
Language: account.Language, | ||
URI: account.URI, | ||
URL: account.URL, | ||
LastWebfingeredAt: account.LastWebfingeredAt, | ||
InboxURI: account.InboxURI, | ||
OutboxURI: account.OutboxURI, | ||
FollowingURI: account.FollowingURI, | ||
FollowersURI: account.FollowersURI, | ||
FeaturedCollectionURI: account.FeaturedCollectionURI, | ||
ActorType: account.ActorType, | ||
AlsoKnownAs: account.AlsoKnownAs, | ||
PrivateKey: nil, | ||
PublicKey: account.PublicKey, | ||
PublicKeyURI: account.PublicKeyURI, | ||
SensitizedAt: account.SensitizedAt, | ||
SilencedAt: account.SilencedAt, | ||
SuspendedAt: account.SuspendedAt, | ||
HideCollections: account.HideCollections, | ||
SuspensionOrigin: account.SuspensionOrigin, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package cache_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/superseriousbusiness/gotosocial/internal/cache" | ||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||
) | ||
|
||
func TestAccountCache(t *testing.T) { | ||
cache := cache.NewAccountCache() | ||
|
||
// Attempt to place an account | ||
account := gtsmodel.Account{ | ||
ID: "id", | ||
URI: "uri", | ||
URL: "url", | ||
} | ||
cache.Put(&account) | ||
|
||
var ok bool | ||
var check *gtsmodel.Account | ||
|
||
// Check we can retrieve | ||
check, ok = cache.GetByID(account.ID) | ||
if !ok || !accountIs(&account, check) { | ||
t.Fatal("Could not find expected status") | ||
} | ||
check, ok = cache.GetByURI(account.URI) | ||
if !ok || !accountIs(&account, check) { | ||
t.Fatal("Could not find expected status") | ||
} | ||
check, ok = cache.GetByURL(account.URL) | ||
if !ok || !accountIs(&account, check) { | ||
t.Fatal("Could not find expected status") | ||
} | ||
} | ||
|
||
func accountIs(account1, account2 *gtsmodel.Account) bool { | ||
return account1.ID == account2.ID && account1.URI == account2.URI && account1.URL == account2.URL | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters