Skip to content

Commit

Permalink
Reports upload ignores reports over 2 weeks old, add ManyTasks utilit…
Browse files Browse the repository at this point in the history
…y class - optimization for making many queries at once, bugfix for map script crashing if no incoming data is available for a hovered village
  • Loading branch information
tylercamp committed Sep 8, 2018
1 parent c3ea21f commit b8793b8
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 94 deletions.
36 changes: 18 additions & 18 deletions TW.Vault/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,24 +272,24 @@ public async Task<IActionResult> GetTroopsSummary()

// This is a mess because of different classes for Player, CurrentPlayer, etc

// Get all CurrentVillages from the user's tribe - list of (Player, CurrentVillage)
var tribeVillages = await (
from player in context.Player.FromWorld(CurrentWorldId)
join village in context.Village.FromWorld(CurrentWorldId) on player.PlayerId equals village.PlayerId
join currentVillage in context.CurrentVillage.IncludeCurrentVillageData()
on village.VillageId equals currentVillage.VillageId
where player.TribeId == CurrentTribeId
select new { player, currentVillage }
).ToListAsync();

// Get all CurrentPlayer data for the user's tribe (separate from global 'Player' table
// so we can also output stats for players that haven't uploaded anything yet)
var currentPlayers = await (
from currentPlayer in context.CurrentPlayer.FromWorld(CurrentWorldId)
join player in context.Player on currentPlayer.PlayerId equals player.PlayerId
where player.TribeId == CurrentTribeId
select currentPlayer
).ToListAsync();
var (tribeVillages, currentPlayers) = await ManyTasks.RunToList(
// Get all CurrentVillages from the user's tribe - list of (Player, CurrentVillage)
from player in context.Player.FromWorld(CurrentWorldId)
join village in context.Village.FromWorld(CurrentWorldId) on player.PlayerId equals village.PlayerId
join currentVillage in context.CurrentVillage.IncludeCurrentVillageData()
on village.VillageId equals currentVillage.VillageId
where player.TribeId == CurrentTribeId
select new { player, currentVillage }

,

// Get all CurrentPlayer data for the user's tribe (separate from global 'Player' table
// so we can also output stats for players that haven't uploaded anything yet)
from currentPlayer in context.CurrentPlayer.FromWorld(CurrentWorldId)
join player in context.Player on currentPlayer.PlayerId equals player.PlayerId
where player.TribeId == CurrentTribeId
select currentPlayer
);

// Collect villages grouped by owner
var villagesByPlayer = tribeVillages
Expand Down
46 changes: 22 additions & 24 deletions TW.Vault/Controllers/CommandController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,40 +109,38 @@ public async Task<IActionResult> Post([FromBody]JSON.ManyCommands jsonCommands)
var mappedCommands = jsonCommands.Commands.ToDictionary(c => c.CommandId, c => c);
var commandIds = jsonCommands.Commands.Select(c => c.CommandId).ToList();


var scaffoldCommands = await Profile("Get existing scaffold commands", () => (
from command in context.Command.IncludeCommandData().FromWorld(CurrentWorldId)
where commandIds.Contains(command.CommandId)
select command
).ToListAsync()
);

var mappedScaffoldCommands = scaffoldCommands.ToDictionary(c => c.CommandId, c => c);
var allVillageIds = jsonCommands.Commands
.Select(c => c.SourceVillageId)
.Concat(jsonCommands.Commands.Select(c => c.TargetVillageId))
.Select(id => id.Value)
.Distinct();

var villageIdsFromCommandsMissingTroopType = jsonCommands.Commands
.Where(c => c.TroopType == null)
.SelectMany(c => new[] { c.SourceVillageId, c.TargetVillageId })
.Distinct()
.ToList();

var villagesForMissingTroopTypes = await (
from village in context.Village.FromWorld(CurrentWorldId)
where villageIdsFromCommandsMissingTroopType.Contains(village.VillageId)
select village
).ToListAsync();
var (scaffoldCommands, villageIdsFromCommandsMissingTroopTypes, allVillages) = await ManyTasks.RunToList(
from command in context.Command.IncludeCommandData().FromWorld(CurrentWorldId)
where commandIds.Contains(command.CommandId)
select command

,

from village in context.Village.FromWorld(CurrentWorldId)
where villageIdsFromCommandsMissingTroopType.Contains(village.VillageId)
select village

var allVillageIds = jsonCommands.Commands
.Select(c => c.SourceVillageId)
.Concat(jsonCommands.Commands.Select(c => c.TargetVillageId))
.Select(id => id.Value)
.Distinct();
,

var allVillages = await (
from village in context.Village.FromWorld(CurrentWorldId)
where allVillageIds.Contains(village.VillageId)
select village
).ToListAsync();
from village in context.Village.FromWorld(CurrentWorldId)
where allVillageIds.Contains(village.VillageId)
select village
);


var mappedScaffoldCommands = scaffoldCommands.ToDictionary(c => c.CommandId, c => c);
var villagesById = allVillages.ToDictionary(v => v.VillageId, v => v);

var tx = BuildTransaction();
Expand Down
46 changes: 25 additions & 21 deletions TW.Vault/Controllers/VillageController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,30 +109,32 @@ select tx
}

// Start getting village data
var currentVillage = await Profile("Get current village", () => (

var (currentVillage, commandsToVillage) = await ManyTasks.Run(
Profile("Get current village", () => (
from cv in context.CurrentVillage
.FromWorld(CurrentWorldId)
.Include(v => v.ArmyOwned)
.Include(v => v.ArmyStationed)
.Include(v => v.ArmyTraveling)
.Include(v => v.ArmyRecentLosses)
.Include(v => v.CurrentBuilding)
.FromWorld(CurrentWorldId)
.Include(v => v.ArmyOwned)
.Include(v => v.ArmyStationed)
.Include(v => v.ArmyTraveling)
.Include(v => v.ArmyRecentLosses)
.Include(v => v.CurrentBuilding)
where cv.VillageId == villageId
select cv
).FirstOrDefaultAsync()
);
).FirstOrDefaultAsync()),

var commandsToVillage = await Profile("Get commands to village", () => (
Profile("Get commands to village", () => (
from command in context.Command
.FromWorld(CurrentWorldId)
.Include(c => c.Army)
where command.TargetVillageId == villageId
where !command.IsReturning
where command.LandsAt > CurrentServerTime
select command
).ToListAsync()
).ToListAsync())
);


var jsonData = new JSON.VillageData();

// Return empty data if no data is available for the village
Expand Down Expand Up @@ -274,13 +276,22 @@ public async Task<IActionResult> PostCurrentArmy([FromBody]JSON.PlayerArmy curre

var villageIds = currentArmySetJson.TroopData.Select(a => a.VillageId.Value).ToList();

var scaffoldCurrentVillages = await Profile("Get existing scaffold current villages", () => (
var (scaffoldCurrentVillages, villagesWithPlayerIds) = await ManyTasks.Run(
Profile("Get existing scaffold current villages", () => (
from cv in context.CurrentVillage.FromWorld(CurrentWorldId).IncludeCurrentVillageData()
where villageIds.Contains(cv.VillageId)
select cv
).ToListAsync()
).ToListAsync())
,
Profile("Get village player IDs", () => (
from v in context.Village.FromWorld(CurrentWorldId)
where villageIds.Contains(v.VillageId)
select new { v.PlayerId, v.VillageId }
).ToListAsync())
);

var villageIdsByPlayerId = villagesWithPlayerIds.ToDictionary(v => v.VillageId, v => v.PlayerId);

var mappedScaffoldVillages = villageIds.ToDictionary(id => id, id => scaffoldCurrentVillages.SingleOrDefault(cv => cv.VillageId == id));
var missingScaffoldVillageIds = mappedScaffoldVillages.Where(kvp => kvp.Value == null).Select(kvp => kvp.Key).ToList();

Expand All @@ -293,13 +304,6 @@ select v
).ToListAsync()
);

var villagePlayerIds = (await Profile("Get village player IDs", () => (
from v in context.Village.FromWorld(CurrentWorldId)
where villageIds.Contains(v.VillageId)
select new { v.PlayerId, v.VillageId }
).ToListAsync()
)).ToDictionary(v => v.VillageId, v => v.PlayerId);

var mappedMissingVillageData = missingVillageData.ToDictionary(vd => vd.VillageId, vd => vd);

// Get or make CurrentVillage
Expand All @@ -324,7 +328,7 @@ where villageIds.Contains(v.VillageId)
foreach (var armySetJson in currentArmySetJson.TroopData)
{
var currentVillage = mappedScaffoldVillages[armySetJson.VillageId.Value];
var villagePlayerId = villagePlayerIds[currentVillage.VillageId];
var villagePlayerId = villageIdsByPlayerId[currentVillage.VillageId];

if (!Configuration.Security.AllowUploadArmyForNonOwner
&& villagePlayerId != CurrentUser.PlayerId)
Expand Down
64 changes: 64 additions & 0 deletions TW.Vault/ManyTasks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace TW.Vault
{
public static class ManyTasks
{
public static async Task<Tuple<T1>> Run<T1>(Task<T1> task1)
{
return new Tuple<T1>(await task1);
}

public static async Task<Tuple<T1, T2>> Run<T1,T2>(Task<T1> task1, Task<T2> task2)
{
var tasks = new Task[] { task1, task2 };
await Task.WhenAll(tasks);
return new Tuple<T1, T2>(task1.Result, task2.Result);
}

public static async Task<Tuple<T1, T2, T3>> Run<T1, T2, T3>(Task<T1> task1, Task<T2> task2, Task<T3> task3)
{
var tasks = new Task[] { task1, task2, task3 };
await Task.WhenAll(tasks);
return new Tuple<T1, T2, T3>(task1.Result, task2.Result, task3.Result);
}

public static async Task<Tuple<T1, T2, T3, T4>> Run<T1, T2, T3, T4>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4)
{
var tasks = new Task[] { task1, task2, task3, task4 };
await Task.WhenAll(tasks);
return new Tuple<T1, T2, T3, T4>(task1.Result, task2.Result, task3.Result, task4.Result);
}

public static async Task<Tuple<T1, T2, T3, T4, T5>> Run<T1, T2, T3, T4, T5>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5)
{
var tasks = new Task[] { task1, task2, task3, task4, task5 };
await Task.WhenAll(tasks);
return new Tuple<T1, T2, T3, T4, T5>(task1.Result, task2.Result, task3.Result, task4.Result, task5.Result);
}

public static async Task<Tuple<T1, T2, T3, T4, T5, T6>> Run<T1, T2, T3, T4, T5, T6>(Task<T1> task1, Task<T2> task2, Task<T3> task3, Task<T4> task4, Task<T5> task5, Task<T6> task6)
{
var tasks = new Task[] { task1, task2, task3, task4, task5, task6 };
await Task.WhenAll(tasks);
return new Tuple<T1, T2, T3, T4, T5, T6>(task1.Result, task2.Result, task3.Result, task4.Result, task5.Result, task6.Result);
}



public static Task<Tuple<List<T1>>> RunToList<T1>(IQueryable<T1> q1) =>
Run(q1.ToListAsync());

public static Task<Tuple<List<T1>, List<T2>>> RunToList<T1, T2>(IQueryable<T1> q1, IQueryable<T2> q2) =>
Run(q1.ToListAsync(), q2.ToListAsync());

public static Task<Tuple<List<T1>, List<T2>, List<T3>>> RunToList<T1, T2, T3>(IQueryable<T1> q1, IQueryable<T2> q2, IQueryable<T3> q3) =>
Run(q1.ToListAsync(), q2.ToListAsync(), q3.ToListAsync());
}
}
Loading

0 comments on commit b8793b8

Please sign in to comment.