Browse Source

Memory improvements

tags/1.0-rc
RogueException 9 years ago
parent
commit
ff1494f15f
5 changed files with 62 additions and 98 deletions
  1. +1
    -14
      src/Discord.Net/DiscordSocketClient.cs
  2. +1
    -1
      src/Discord.Net/Entities/Users/GuildUser.cs
  3. +47
    -66
      src/Discord.Net/Entities/WebSocket/CachedGuild.cs
  4. +13
    -3
      src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs
  5. +0
    -14
      src/Discord.Net/Entities/WebSocket/Presence.cs

+ 1
- 14
src/Discord.Net/DiscordSocketClient.cs View File

@@ -949,20 +949,7 @@ namespace Discord
await _gatewayLogger.WarningAsync("PRESENCE_UPDATE referenced an unknown guild.").ConfigureAwait(false); await _gatewayLogger.WarningAsync("PRESENCE_UPDATE referenced an unknown guild.").ConfigureAwait(false);
break; 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 else
{ {


+ 1
- 1
src/Discord.Net/Entities/Users/GuildUser.cs View File

@@ -69,7 +69,7 @@ namespace Discord
//if (model.Roles.IsSpecified) //if (model.Roles.IsSpecified)
UpdateRoles(model.Roles); UpdateRoles(model.Roles);
} }
public void Update(PresenceModel model, UpdateSource source)
public virtual void Update(PresenceModel model, UpdateSource source)
{ {
if (source == UpdateSource.Rest && IsAttached) return; if (source == UpdateSource.Rest && IsAttached) return;


+ 47
- 66
src/Discord.Net/Entities/WebSocket/CachedGuild.cs View File

@@ -21,7 +21,6 @@ namespace Discord
private TaskCompletionSource<bool> _downloaderPromise; private TaskCompletionSource<bool> _downloaderPromise;
private ConcurrentHashSet<ulong> _channels; private ConcurrentHashSet<ulong> _channels;
private ConcurrentDictionary<ulong, CachedGuildUser> _members; private ConcurrentDictionary<ulong, CachedGuildUser> _members;
private ConcurrentDictionary<ulong, Presence> _presences;
private ConcurrentDictionary<ulong, VoiceState> _voiceStates; private ConcurrentDictionary<ulong, VoiceState> _voiceStates;


public bool Available { get; private set; } public bool Available { get; private set; }
@@ -53,12 +52,8 @@ namespace Discord
_channels = new ConcurrentHashSet<ulong>(); _channels = new ConcurrentHashSet<ulong>();
if (_members == null) if (_members == null)
_members = new ConcurrentDictionary<ulong, CachedGuildUser>(); _members = new ConcurrentDictionary<ulong, CachedGuildUser>();
if (_presences == null)
_presences = new ConcurrentDictionary<ulong, Presence>();
if (_roles == null) if (_roles == null)
_roles = new ConcurrentDictionary<ulong, Role>(); _roles = new ConcurrentDictionary<ulong, Role>();
if (_voiceStates == null)
_voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
if (Emojis == null) if (Emojis == null)
Emojis = ImmutableArray.Create<Emoji>(); Emojis = ImmutableArray.Create<Emoji>();
if (Features == null) if (Features == null)
@@ -69,17 +64,15 @@ namespace Discord
base.Update(model as Model, source); base.Update(model as Model, source);


MemberCount = model.MemberCount; MemberCount = model.MemberCount;

var channels = new ConcurrentHashSet<ulong>();
if (model.Channels != null)
var channels = new ConcurrentHashSet<ulong>(1, (int)(model.Channels.Length * 1.05));
{ {
for (int i = 0; i < model.Channels.Length; i++) for (int i = 0; i < model.Channels.Length; i++)
AddChannel(model.Channels[i], dataStore, channels); AddChannel(model.Channels[i], dataStore, channels);
} }
_channels = channels; _channels = channels;
var members = new ConcurrentDictionary<ulong, CachedGuildUser>();
if (model.Members != null)
var members = new ConcurrentDictionary<ulong, CachedGuildUser>(1, (int)(model.Presences.Length * 1.05));
{ {
DownloadedMemberCount = 0; DownloadedMemberCount = 0;
for (int i = 0; i < model.Members.Length; i++) for (int i = 0; i < model.Members.Length; i++)
@@ -87,23 +80,17 @@ namespace Discord
_downloaderPromise = new TaskCompletionSource<bool>(); _downloaderPromise = new TaskCompletionSource<bool>();
if (!model.Large) if (!model.Large)
_downloaderPromise.SetResult(true); _downloaderPromise.SetResult(true);
}
_members = members;


var presences = new ConcurrentDictionary<ulong, Presence>();
if (model.Presences != null)
{
for (int i = 0; i < model.Presences.Length; i++) for (int i = 0; i < model.Presences.Length; i++)
{ {
var presence = model.Presences[i]; var presence = model.Presences[i];
AddOrUpdatePresence(presence, presences);
UpdatePresence(presence, dataStore, members);
//AddUser(presence, dataStore, members); //AddUser(presence, dataStore, members);
} }
} }
_presences = presences;

var voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
if (model.VoiceStates != null)
_members = members;
var voiceStates = new ConcurrentDictionary<ulong, VoiceState>(1, (int)(model.VoiceStates.Length * 1.05));
{ {
for (int i = 0; i < model.VoiceStates.Length; i++) for (int i = 0; i < model.VoiceStates.Length; i++)
AddOrUpdateVoiceState(model.VoiceStates[i], dataStore, voiceStates); AddOrUpdateVoiceState(model.VoiceStates[i], dataStore, voiceStates);
@@ -128,29 +115,7 @@ namespace Discord
_channels.TryRemove(id); _channels.TryRemove(id);
return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel; return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel;
} }

public Presence AddOrUpdatePresence(PresenceModel model, ConcurrentDictionary<ulong, Presence> 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<ulong, Role> roles = null) public Role AddRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null)
{ {
var role = new Role(this, model); var role = new Role(this, model);
@@ -165,28 +130,6 @@ namespace Discord
return null; return null;
} }


public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> 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<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id)); public override Task<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id));
public override Task<IGuildUser> GetCurrentUserAsync() public override Task<IGuildUser> GetCurrentUserAsync()
=> Task.FromResult<IGuildUser>(CurrentUser); => Task.FromResult<IGuildUser>(CurrentUser);
@@ -197,7 +140,6 @@ namespace Discord
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray()); => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray());
public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null) public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null)
{ {
var user = Discord.GetOrAddUser(model.User, dataStore);
members = members ?? _members; members = members ?? _members;


CachedGuildUser member; CachedGuildUser member;
@@ -205,6 +147,7 @@ namespace Discord
member.Update(model, UpdateSource.WebSocket); member.Update(model, UpdateSource.WebSocket);
else else
{ {
var user = Discord.GetOrAddUser(model.User, dataStore);
member = new CachedGuildUser(this, user, model); member = new CachedGuildUser(this, user, model);
members[user.Id] = member; members[user.Id] = member;
user.AddRef(); user.AddRef();
@@ -243,6 +186,22 @@ namespace Discord
return member; return member;
return null; return null;
} }
public void UpdatePresence(PresenceModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> 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() public async Task DownloadMembersAsync()
{ {
if (!HasAllMembers) if (!HasAllMembers)
@@ -254,6 +213,28 @@ namespace Discord
_downloaderPromise.TrySetResult(true); _downloaderPromise.TrySetResult(true);
} }


public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> 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; public CachedGuild Clone() => MemberwiseClone() as CachedGuild;


new internal ICachedGuildChannel ToChannel(ChannelModel model) new internal ICachedGuildChannel ToChannel(ChannelModel model)


+ 13
- 3
src/Discord.Net/Entities/WebSocket/CachedGuildUser.cs View File

@@ -5,13 +5,15 @@ namespace Discord
{ {
internal class CachedGuildUser : GuildUser, ICachedUser internal class CachedGuildUser : GuildUser, ICachedUser
{ {
private Game? _game;
private UserStatus _status;

public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
public new CachedGuild Guild => base.Guild as CachedGuild; public new CachedGuild Guild => base.Guild as CachedGuild;
public new CachedPublicUser User => base.User as CachedPublicUser; 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 VoiceState? VoiceState => Guild.GetVoiceState(Id);
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; 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; public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser;
ICachedUser ICachedUser.Clone() => Clone(); ICachedUser ICachedUser.Clone() => Clone();
} }


+ 0
- 14
src/Discord.Net/Entities/WebSocket/Presence.cs View File

@@ -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;
}
}
}

Loading…
Cancel
Save