From ff1494f15f9fb196803c8236650232096c9c5d10 Mon Sep 17 00:00:00 2001 From: RogueException Date: Fri, 17 Jun 2016 22:11:39 -0300 Subject: [PATCH] Memory improvements --- src/Discord.Net/DiscordSocketClient.cs | 15 +-- src/Discord.Net/Entities/Users/GuildUser.cs | 2 +- .../Entities/WebSocket/CachedGuild.cs | 113 ++++++++---------- .../Entities/WebSocket/CachedGuildUser.cs | 16 ++- .../Entities/WebSocket/Presence.cs | 14 --- 5 files changed, 62 insertions(+), 98 deletions(-) delete mode 100644 src/Discord.Net/Entities/WebSocket/Presence.cs diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs index 145350e15..b7a42e748 100644 --- a/src/Discord.Net/DiscordSocketClient.cs +++ b/src/Discord.Net/DiscordSocketClient.cs @@ -949,20 +949,7 @@ namespace Discord await _gatewayLogger.WarningAsync("PRESENCE_UPDATE referenced an unknown guild.").ConfigureAwait(false); break; } - if (data.Status == UserStatus.Offline) - guild.RemovePresence(data.User.Id); - else - { - guild.AddOrUpdatePresence(data); - if (data.Roles.IsSpecified || data.Nick.IsSpecified) //Happens when a user we haven't seen before logs in - { - CachedGuildUser user = guild.GetUser(data.User.Id); - if (user == null) - guild.AddUser(data, DataStore); - else - user.Update(data, UpdateSource.WebSocket); - } - } + guild.UpdatePresence(data, DataStore); } else { diff --git a/src/Discord.Net/Entities/Users/GuildUser.cs b/src/Discord.Net/Entities/Users/GuildUser.cs index aa9485771..cc99fcb25 100644 --- a/src/Discord.Net/Entities/Users/GuildUser.cs +++ b/src/Discord.Net/Entities/Users/GuildUser.cs @@ -69,7 +69,7 @@ namespace Discord //if (model.Roles.IsSpecified) UpdateRoles(model.Roles); } - public void Update(PresenceModel model, UpdateSource source) + public virtual void Update(PresenceModel model, UpdateSource source) { if (source == UpdateSource.Rest && IsAttached) return; diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs index 66106e1db..ffe03c962 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs +++ b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs @@ -21,7 +21,6 @@ namespace Discord private TaskCompletionSource _downloaderPromise; private ConcurrentHashSet _channels; private ConcurrentDictionary _members; - private ConcurrentDictionary _presences; private ConcurrentDictionary _voiceStates; public bool Available { get; private set; } @@ -53,12 +52,8 @@ namespace Discord _channels = new ConcurrentHashSet(); if (_members == null) _members = new ConcurrentDictionary(); - if (_presences == null) - _presences = new ConcurrentDictionary(); if (_roles == null) _roles = new ConcurrentDictionary(); - if (_voiceStates == null) - _voiceStates = new ConcurrentDictionary(); if (Emojis == null) Emojis = ImmutableArray.Create(); if (Features == null) @@ -69,17 +64,15 @@ namespace Discord base.Update(model as Model, source); MemberCount = model.MemberCount; - - var channels = new ConcurrentHashSet(); - if (model.Channels != null) + + var channels = new ConcurrentHashSet(1, (int)(model.Channels.Length * 1.05)); { for (int i = 0; i < model.Channels.Length; i++) AddChannel(model.Channels[i], dataStore, channels); } _channels = channels; - var members = new ConcurrentDictionary(); - if (model.Members != null) + var members = new ConcurrentDictionary(1, (int)(model.Presences.Length * 1.05)); { DownloadedMemberCount = 0; for (int i = 0; i < model.Members.Length; i++) @@ -87,23 +80,17 @@ namespace Discord _downloaderPromise = new TaskCompletionSource(); if (!model.Large) _downloaderPromise.SetResult(true); - } - _members = members; - var presences = new ConcurrentDictionary(); - if (model.Presences != null) - { for (int i = 0; i < model.Presences.Length; i++) { var presence = model.Presences[i]; - AddOrUpdatePresence(presence, presences); + UpdatePresence(presence, dataStore, members); //AddUser(presence, dataStore, members); } } - _presences = presences; - - var voiceStates = new ConcurrentDictionary(); - if (model.VoiceStates != null) + _members = members; + + var voiceStates = new ConcurrentDictionary(1, (int)(model.VoiceStates.Length * 1.05)); { for (int i = 0; i < model.VoiceStates.Length; i++) AddOrUpdateVoiceState(model.VoiceStates[i], dataStore, voiceStates); @@ -128,29 +115,7 @@ namespace Discord _channels.TryRemove(id); return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel; } - - public Presence AddOrUpdatePresence(PresenceModel model, ConcurrentDictionary presences = null) - { - var game = model.Game != null ? new Game(model.Game) : (Game?)null; - var presence = new Presence(model.Status, game); - (presences ?? _presences)[model.User.Id] = presence; - return presence; - } - public Presence? GetPresence(ulong id) - { - Presence presence; - if (_presences.TryGetValue(id, out presence)) - return presence; - return null; - } - public Presence? RemovePresence(ulong id) - { - Presence presence; - if (_presences.TryRemove(id, out presence)) - return presence; - return null; - } - + public Role AddRole(RoleModel model, ConcurrentDictionary roles = null) { var role = new Role(this, model); @@ -165,28 +130,6 @@ namespace Discord return null; } - public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary voiceStates = null) - { - var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel; - var voiceState = new VoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress); - (voiceStates ?? _voiceStates)[model.UserId] = voiceState; - return voiceState; - } - public VoiceState? GetVoiceState(ulong id) - { - VoiceState voiceState; - if (_voiceStates.TryGetValue(id, out voiceState)) - return voiceState; - return null; - } - public VoiceState? RemoveVoiceState(ulong id) - { - VoiceState voiceState; - if (_voiceStates.TryRemove(id, out voiceState)) - return voiceState; - return null; - } - public override Task GetUserAsync(ulong id) => Task.FromResult(GetUser(id)); public override Task GetCurrentUserAsync() => Task.FromResult(CurrentUser); @@ -197,7 +140,6 @@ namespace Discord => Task.FromResult>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray()); public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary members = null) { - var user = Discord.GetOrAddUser(model.User, dataStore); members = members ?? _members; CachedGuildUser member; @@ -205,6 +147,7 @@ namespace Discord member.Update(model, UpdateSource.WebSocket); else { + var user = Discord.GetOrAddUser(model.User, dataStore); member = new CachedGuildUser(this, user, model); members[user.Id] = member; user.AddRef(); @@ -243,6 +186,22 @@ namespace Discord return member; return null; } + public void UpdatePresence(PresenceModel model, DataStore dataStore, ConcurrentDictionary members = null) + { + members = members ?? _members; + + CachedGuildUser member; + if (members.TryGetValue(model.User.Id, out member)) + member.Update(model, UpdateSource.WebSocket); + else + { + var user = Discord.GetOrAddUser(model.User, dataStore); + member = new CachedGuildUser(this, user, model); + members[user.Id] = member; + user.AddRef(); + DownloadedMemberCount++; + } + } public async Task DownloadMembersAsync() { if (!HasAllMembers) @@ -254,6 +213,28 @@ namespace Discord _downloaderPromise.TrySetResult(true); } + public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary voiceStates = null) + { + var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel; + var voiceState = new VoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress); + (voiceStates ?? _voiceStates)[model.UserId] = voiceState; + return voiceState; + } + public VoiceState? GetVoiceState(ulong id) + { + VoiceState voiceState; + if (_voiceStates.TryGetValue(id, out voiceState)) + return voiceState; + return null; + } + public VoiceState? RemoveVoiceState(ulong id) + { + VoiceState voiceState; + if (_voiceStates.TryRemove(id, out voiceState)) + return voiceState; + return null; + } + public CachedGuild Clone() => MemberwiseClone() as CachedGuild; new internal ICachedGuildChannel ToChannel(ChannelModel model) diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs b/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs index 2a7f3326d..13dadf5c1 100644 --- a/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs +++ b/src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs @@ -5,13 +5,15 @@ namespace Discord { internal class CachedGuildUser : GuildUser, ICachedUser { + private Game? _game; + private UserStatus _status; + public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new CachedGuild Guild => base.Guild as CachedGuild; public new CachedPublicUser User => base.User as CachedPublicUser; - public Presence? Presence => Guild.GetPresence(Id); - public override Game? Game => Presence?.Game; - public override UserStatus Status => Presence?.Status ?? UserStatus.Offline; + public override Game? Game => _game; + public override UserStatus Status => _status; public VoiceState? VoiceState => Guild.GetVoiceState(Id); public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; @@ -28,6 +30,14 @@ namespace Discord { } + public override void Update(PresenceModel model, UpdateSource source) + { + base.Update(model, source); + + _status = model.Status; + _game = model.Game != null ? new Game(model.Game) : (Game?)null; + } + public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser; ICachedUser ICachedUser.Clone() => Clone(); } diff --git a/src/Discord.Net/Entities/WebSocket/Presence.cs b/src/Discord.Net/Entities/WebSocket/Presence.cs deleted file mode 100644 index 349751351..000000000 --- a/src/Discord.Net/Entities/WebSocket/Presence.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Discord -{ - internal struct Presence : IPresence - { - public UserStatus Status { get; } - public Game? Game { get; } - - public Presence(UserStatus status, Game? game) - { - Status = status; - Game = game; - } - } -}