more profile loading optimizations

This commit is contained in:
RaidMax 2022-02-01 18:20:29 -06:00
parent 6ca94f8da8
commit 2ed5e00bcb
5 changed files with 39 additions and 82 deletions

View File

@ -207,42 +207,30 @@ namespace IW4MAdmin.Application.Misc
public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request) public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request)
{ {
var meta = new List<IClientMeta>(); var metas = await Task.WhenAll(_metaActions.Where(kvp => kvp.Key != MetaType.Information)
.Select(async kvp => await kvp.Value[0](request)));
foreach (var (type, actions) in _metaActions) return metas.SelectMany(m => (IEnumerable<IClientMeta>)m)
{ .OrderByDescending(m => m.When)
// information is not listed chronologically
if (type != MetaType.Information)
{
var metaItems = await actions[0](request);
meta.AddRange(metaItems);
}
}
return meta.OrderByDescending(_meta => _meta.When)
.Take(request.Count) .Take(request.Count)
.ToList(); .ToList();
} }
public async Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest request, MetaType metaType) where T : IClientMeta public async Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest request, MetaType metaType) where T : IClientMeta
{ {
IEnumerable<T> meta;
if (metaType == MetaType.Information) if (metaType == MetaType.Information)
{ {
var allMeta = new List<T>(); var allMeta = new List<T>();
foreach (var individualMetaRegistration in _metaActions[metaType]) var completedMeta = await Task.WhenAll(_metaActions[metaType].Select(async individualMetaRegistration =>
{ (IEnumerable<T>)await individualMetaRegistration(request)));
allMeta.AddRange(await individualMetaRegistration(request));
} allMeta.AddRange(completedMeta.SelectMany(meta => meta));
return ProcessInformationMeta(allMeta); return ProcessInformationMeta(allMeta);
} }
else var meta = await _metaActions[metaType][0](request) as IEnumerable<T>;
{
meta = await _metaActions[metaType][0](request) as IEnumerable<T>;
}
return meta; return meta;
} }

View File

@ -191,7 +191,6 @@ namespace IW4MAdmin.Plugins.Stats
async Task<IEnumerable<InformationResponse>> getStats(ClientPaginationRequest request) async Task<IEnumerable<InformationResponse>> getStats(ClientPaginationRequest request)
{ {
IList<EFClientStatistics> clientStats; IList<EFClientStatistics> clientStats;
int messageCount = 0;
await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false); await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false);
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync(); clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync();

View File

@ -168,10 +168,9 @@ namespace SharedLibraryCore.Services
public async Task<EFClient> Get(int entityId) public async Task<EFClient> Get(int entityId)
{ {
// todo: this needs to be optimized for large linked accounts
await using var context = _contextFactory.CreateContext(false); await using var context = _contextFactory.CreateContext(false);
var client = context.Clients var client = await context.Clients
.Select(_client => new EFClient .Select(_client => new EFClient
{ {
ClientId = _client.ClientId, ClientId = _client.ClientId,
@ -187,26 +186,28 @@ namespace SharedLibraryCore.Services
Name = _client.CurrentAlias.Name, Name = _client.CurrentAlias.Name,
IPAddress = _client.CurrentAlias.IPAddress IPAddress = _client.CurrentAlias.IPAddress
}, },
TotalConnectionTime = _client.TotalConnectionTime TotalConnectionTime = _client.TotalConnectionTime,
AliasLink = new EFAliasLink
{
AliasLinkId = _client.AliasLinkId,
Children = _client.AliasLink.Children
},
LinkedAccounts = new Dictionary<int, long>()
{
{_client.ClientId, _client.NetworkId}
}
}) })
.FirstOrDefault(_client => _client.ClientId == entityId); .FirstOrDefaultAsync(_client => _client.ClientId == entityId);
if (client == null) if (client == null)
{ {
return null; return null;
} }
client.AliasLink = new EFAliasLink if (!_appConfig.EnableImplicitAccountLinking)
{ {
AliasLinkId = client.AliasLinkId, return client;
Children = await context.Aliases }
.Where(_alias => _alias.LinkId == client.AliasLinkId)
.Select(_alias => new EFAlias
{
Name = _alias.Name,
IPAddress = _alias.IPAddress
}).ToListAsync()
};
var foundClient = new var foundClient = new
{ {
@ -220,11 +221,6 @@ namespace SharedLibraryCore.Services
.ToListAsync() .ToListAsync()
}; };
if (foundClient == null)
{
return null;
}
foundClient.Client.LinkedAccounts = new Dictionary<int, long>(); foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
// todo: find out the best way to do this // todo: find out the best way to do this
// I'm doing this here because I don't know the best way to have multiple awaits in the query // I'm doing this here because I don't know the best way to have multiple awaits in the query

View File

@ -163,9 +163,6 @@ namespace SharedLibraryCore.Services
(p.Expires == null || p.Expires > now); (p.Expires == null || p.Expires > now);
await using var context = _contextFactory.CreateContext(false); await using var context = _contextFactory.CreateContext(false);
var iqLinkPenalties = context.Penalties
.Where(p => p.LinkId == linkId)
.Where(filter);
IQueryable<EFPenalty> iqIpPenalties; IQueryable<EFPenalty> iqIpPenalties;
@ -178,35 +175,6 @@ namespace SharedLibraryCore.Services
} }
else else
{ {
/* var aliasIps = await context.Aliases.Where(alias => (alias.LinkId == linkId || alias.AliasId == currentAliasId) && alias.IPAddress != null)
.Select(alias => alias.IPAddress)
.ToListAsync();
if (ip != null)
{
aliasIps.Add(ip);
}
var clientIds = new List<int>();
if (aliasIps.Any())
{
clientIds = await context.Clients.Where(client => aliasIps.Contains(client.CurrentAlias.IPAddress))
.Select(client => client.ClientId).ToListAsync();
}
if (clientIds.Any())
{
iqIpPenalties = context.Penalties.Where(penalty => clientIds.Contains(penalty.OffenderId))
.Where(filter);
}
else
{
iqIpPenalties = Enumerable.Empty<EFPenalty>().AsQueryable();
}*/
var usedIps = await context.Aliases.AsNoTracking() var usedIps = await context.Aliases.AsNoTracking()
.Where(alias => (alias.LinkId == linkId || alias.AliasId == currentAliasId) && alias.IPAddress != null) .Where(alias => (alias.LinkId == linkId || alias.AliasId == currentAliasId) && alias.IPAddress != null)
.Select(alias => alias.IPAddress).ToListAsync(); .Select(alias => alias.IPAddress).ToListAsync();
@ -216,13 +184,12 @@ namespace SharedLibraryCore.Services
.ToListAsync(); .ToListAsync();
iqIpPenalties = context.Penalties.AsNoTracking() iqIpPenalties = context.Penalties.AsNoTracking()
.Where(penalty => aliasedIds.Contains(penalty.LinkId)) .Where(penalty => aliasedIds.Contains(penalty.LinkId) || penalty.LinkId == linkId)
.Where(filter); .Where(filter);
} }
var activeLinkPenalties = await iqLinkPenalties.ToListAsync();
var activeIpPenalties = await iqIpPenalties.ToListAsync(); var activeIpPenalties = await iqIpPenalties.ToListAsync();
var activePenalties = activeLinkPenalties.Concat(activeIpPenalties).Distinct(); var activePenalties = activeIpPenalties.Distinct();
// this is a bit more performant in memory (ordering) // this is a bit more performant in memory (ordering)
return activePenalties.OrderByDescending(p => p.When).ToList(); return activePenalties.OrderByDescending(p => p.When).ToList();

View File

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Data.Models; using Data.Models;
using IW4MAdmin.Plugins.Stats.Config;
using Stats.Config; using Stats.Config;
using WebfrontCore.ViewComponents; using WebfrontCore.ViewComponents;
@ -38,7 +37,16 @@ namespace WebfrontCore.Controllers
var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(client.AliasLinkId, client.CurrentAliasId, client.IPAddress); var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(client.AliasLinkId, client.CurrentAliasId, client.IPAddress);
var tag = await _metaService.GetPersistentMeta(EFMeta.ClientTag, client); var persistentMetaTask = new[]
{
_metaService.GetPersistentMeta(EFMeta.ClientTag, client),
_metaService.GetPersistentMeta("GravatarEmail", client)
};
var persistentMeta = await Task.WhenAll(persistentMetaTask);
var tag = persistentMeta[0];
var gravatar = persistentMeta[1];
if (tag?.LinkedMeta != null) if (tag?.LinkedMeta != null)
{ {
client.SetAdditionalProperty(EFMeta.ClientTag, tag.LinkedMeta.Value); client.SetAdditionalProperty(EFMeta.ClientTag, tag.LinkedMeta.Value);
@ -55,7 +63,7 @@ namespace WebfrontCore.Controllers
displayLevel = string.IsNullOrEmpty(client.Tag) ? displayLevel : $"{displayLevel} ({client.Tag})"; displayLevel = string.IsNullOrEmpty(client.Tag) ? displayLevel : $"{displayLevel} ({client.Tag})";
var clientDto = new PlayerInfo() var clientDto = new PlayerInfo
{ {
Name = client.Name, Name = client.Name,
Level = displayLevel, Level = displayLevel,
@ -92,7 +100,6 @@ namespace WebfrontCore.Controllers
Before = DateTime.UtcNow Before = DateTime.UtcNow
}, MetaType.Information); }, MetaType.Information);
var gravatar = await _metaService.GetPersistentMeta("GravatarEmail", client);
if (gravatar != null) if (gravatar != null)
{ {
clientDto.Meta.Add(new InformationResponse() clientDto.Meta.Add(new InformationResponse()
@ -106,7 +113,7 @@ namespace WebfrontCore.Controllers
clientDto.ActivePenalty = activePenalties.OrderByDescending(_penalty => _penalty.Type).FirstOrDefault(); clientDto.ActivePenalty = activePenalties.OrderByDescending(_penalty => _penalty.Type).FirstOrDefault();
clientDto.Meta.AddRange(Authorized ? meta : meta.Where(m => !m.IsSensitive)); clientDto.Meta.AddRange(Authorized ? meta : meta.Where(m => !m.IsSensitive));
string strippedName = clientDto.Name.StripColors(); var strippedName = clientDto.Name.StripColors();
ViewBag.Title = strippedName.Substring(strippedName.Length - 1).ToLower()[0] == 's' ? ViewBag.Title = strippedName.Substring(strippedName.Length - 1).ToLower()[0] == 's' ?
strippedName + "'" : strippedName + "'" :
strippedName + "'s"; strippedName + "'s";