diff options
| author | Zeyla Hellyer <[email protected]> | 2017-02-09 13:34:08 -0800 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2017-02-09 13:34:08 -0800 |
| commit | 0c9ec377aa7281fb3d4bc390c896b426660a5387 (patch) | |
| tree | a355bda0c0d02d8b67331e0a99090c7b26206cb1 /src/model/user.rs | |
| parent | Release v0.1.5 (diff) | |
| download | serenity-0c9ec377aa7281fb3d4bc390c896b426660a5387.tar.xz serenity-0c9ec377aa7281fb3d4bc390c896b426660a5387.zip | |
Optimize caching
Improve the cache by keeping track of new maps, making other maps have
`Arc<RwLock>` values, optimizing already-existing methods, and take advantage
of new, more efficient retrievals (e.g. simply keying a value from a map rather
than iterating over vecs or maps and then itering over another vec).
Keep track of two new maps in the cache:
- **channels**: a map of all guild channels that exist, so that they can be
efficiently found, and so a message's guild can be efficiently found
- **users**: a map of all users that exist, so that it can be shared across
all members and presences
Other cache fields now have `Arc<RwLock>` values:
- `groups`
- `guilds`
- `private_channels`
`Cache::unavailable_guilds` is now a `HashSet<GuildId>` instead of a
`Vec<GuildId>`. This should slightly optimize removals/insertions for large
bots.
`ext::cache::ChannelRef` has been removed as it became equivilant in
functionality to `model::Channel`. Also, `model::Channel` now has all variant
data encased in `Arc<RwLock>`s. E.g., `Channel::Group(Group)` is now
`Channel::Group(Arc<RwLock<Group>>)`.
Some model struct fields are now wrapped in an `Arc<RwLock>`. These are:
- `Group::recipients`: `HashMap<UserId, User>` -> `HashMap<UserId, Arc<RwLock<User>>>`
- `Guild::channels`: `HashMap<ChannelId, GuildChannel>` -> `HashMap<ChannelId, Arc<RwLock<GuildChannel>>>`
- `Member::user`: `User` -> `Arc<RwLock<User>>`
- `PrivateChannel::recipient`: `User` -> `Arc<RwLock<User>>`
Some (cache-enabled) event handler signatures have changed to use
`Arc<RwLock>`s:
- `Client::on_call_delete`
- `Client::on_call_update`
- `Client::on_guild_delete`
- `Client::on_guild_update`
Many function signatures have changed:
- `Cache::get_call` now returns a `Option<Arc<RwLock<Call>>>` instead of a
`Option<&Call>`
- `Cache::get_channel` now returns a `Option<Channel>` instead of a
`Option<ChannelRef>`. This now also retrieves directly from the
`Guild::channels` instead of iterating over guilds' for a guild channel
- `Cache::get_guild` now returns a `Option<Arc<RwLock<Guild>>>` instead of a
`Option<&Guild>`
- `Cache::get_guild_channel` now returns a `Option<Arc<RwLock<GuildChannel>>>`
instead of a `Option<&GuildChannel>`
- `Cache::get_group` now returns a `Option<Arc<RwLock<Group>>>` instead of a
`Option<&Group>`
- `Cache::get_member` now returns a `Option<Member>` instead of a
`Option<&Member>`, due to guilds being behind a lock themselves
- `Cache::get_role` now returns a `Option<Role>` instead of a `Option<&Role>`
for the above reason
- `Cache::get_user` now returns a `Option<Arc<RwLock<User>>>` instead of a
`Option<&User>`
- `GuildId::find` now returns a `Option<Arc<RwLock<Guild>>>` instead of a
`Option<Guild>`
- `UserId::find` now returns a `Option<Arc<RwLock<User>>>` instead of a
`Option<User>`
- `Member::display_name` now returns a `Cow<String>` instead of a `&str`
A new cache method has been added, `Cache::get_private_channel`, to retrieve a
`PrivateChannel`.
The `Display` formatter for `Channel` has been optimized to not clone.
Diffstat (limited to 'src/model/user.rs')
| -rw-r--r-- | src/model/user.rs | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/src/model/user.rs b/src/model/user.rs index 8473623..fe2d3bb 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -24,6 +24,8 @@ use ::utils::builder::EditProfile; use ::utils::decode_array; #[cfg(feature="cache")] +use std::sync::{Arc, RwLock}; +#[cfg(feature="cache")] use ::client::CACHE; impl CurrentUser { @@ -87,7 +89,6 @@ impl CurrentUser { } /// Gets a list of guilds that the current user is in. - #[inline] pub fn guilds(&self) -> Result<Vec<GuildInfo>> { rest::get_guilds(GuildPagination::After(GuildId(1)), 100) } @@ -191,15 +192,36 @@ impl User { /// /// [`PrivateChannel`]: struct.PrivateChannel.html /// [`User::dm`]: struct.User.html#method.dm + // A tale with Clippy: + // + // A person named Clippy once asked you to unlock a box and take something + // from it, but you never re-locked it, so you'll die and the universe will + // implode because the box must remain locked unless you're there, and you + // can't just borrow that item from it and take it with you forever. + // + // Instead what you do is unlock the box, take the item out of it, make a + // copy of said item, and then re-lock the box, and take your copy of the + // item with you. + // + // The universe is still fine, and nothing implodes. + // + // (AKA: Clippy is wrong and so we have to mark as allowing this lint.) + #[allow(let_and_return)] pub fn direct_message(&self, content: &str) -> Result<Message> { let private_channel_id = feature_cache! {{ - let finding = CACHE.read() - .unwrap() - .private_channels - .values() - .find(|ch| ch.recipient.id == self.id) - .map(|ch| ch.id); + let finding = { + let cache = CACHE.read().unwrap(); + + let finding = cache.private_channels + .values() + .map(|ch| ch.read().unwrap()) + .find(|ch| ch.recipient.read().unwrap().id == self.id) + .map(|ch| ch.id) + .clone(); + + finding + }; if let Some(finding) = finding { finding @@ -331,7 +353,7 @@ impl User { .unwrap() .guilds .get(&_guild_id) - .map(|g| g.roles.contains_key(&role_id)) + .map(|g| g.read().unwrap().roles.contains_key(&role_id)) .unwrap_or(false) } else { true @@ -393,8 +415,8 @@ impl UserId { /// Search the cache for the user with the Id. #[cfg(feature="cache")] - pub fn find(&self) -> Option<User> { - CACHE.read().unwrap().get_user(*self).cloned() + pub fn find(&self) -> Option<Arc<RwLock<User>>> { + CACHE.read().unwrap().get_user(*self) } /// Gets a user by its Id over the REST API. @@ -416,7 +438,7 @@ impl From<CurrentUser> for UserId { impl From<Member> for UserId { /// Gets the Id of a `Member`. fn from(member: Member) -> UserId { - member.user.id + member.user.read().unwrap().id } } |