Skip to content

Commit b877087

Browse files
committed
2 parents 67d1741 + 3297dbc commit b877087

4 files changed

Lines changed: 169 additions & 62 deletions

File tree

Shared/PlasmaShared/PlasmaShared.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
<Compile Include="EventArgs.cs" />
8181
<Compile Include="EventExtensions.cs" />
8282
<Compile Include="GlobalConst.cs" />
83+
<Compile Include="PriorityScheduler.cs" />
8384
<Compile Include="Hash.cs" />
8485
<Compile Include="IContentService\AccountInfo.cs" />
8586
<Compile Include="IContentService\ClientMissionInfo.cs" />
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
7+
namespace ZkData
8+
{
9+
//Priority Scheduler implementation from https://stackoverflow.com/a/9056702/ by Roman Starkov
10+
public class PriorityScheduler : TaskScheduler
11+
{
12+
public static PriorityScheduler AboveNormal = new PriorityScheduler(ThreadPriority.AboveNormal);
13+
public static PriorityScheduler BelowNormal = new PriorityScheduler(ThreadPriority.BelowNormal);
14+
public static PriorityScheduler Lowest = new PriorityScheduler(ThreadPriority.Lowest);
15+
16+
private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
17+
private Thread[] _threads;
18+
private ThreadPriority _priority;
19+
private readonly int _maximumConcurrencyLevel = Math.Max(1, Environment.ProcessorCount);
20+
21+
public PriorityScheduler(ThreadPriority priority)
22+
{
23+
_priority = priority;
24+
}
25+
26+
public override int MaximumConcurrencyLevel
27+
{
28+
get { return _maximumConcurrencyLevel; }
29+
}
30+
31+
protected override IEnumerable<Task> GetScheduledTasks()
32+
{
33+
return _tasks;
34+
}
35+
36+
protected override void QueueTask(Task task)
37+
{
38+
_tasks.Add(task);
39+
40+
if (_threads == null)
41+
{
42+
_threads = new Thread[_maximumConcurrencyLevel];
43+
for (int i = 0; i < _threads.Length; i++)
44+
{
45+
int local = i;
46+
_threads[i] = new Thread(() =>
47+
{
48+
foreach (Task t in _tasks.GetConsumingEnumerable())
49+
base.TryExecuteTask(t);
50+
});
51+
_threads[i].Name = string.Format("PriorityScheduler: ", i);
52+
_threads[i].Priority = _priority;
53+
_threads[i].IsBackground = true;
54+
_threads[i].Start();
55+
}
56+
}
57+
}
58+
59+
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
60+
{
61+
return false; // we might not want to execute task that should schedule as high or low priority inline
62+
}
63+
}
64+
}

ZkData/Ef/WHR/RatingSystems.cs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,26 @@ public static void Init()
3030
{
3131
try
3232
{
33-
ZkDataContext data = new ZkDataContext();
34-
for (int year = 10; year > 0; year--)
33+
using (ZkDataContext data = new ZkDataContext())
3534
{
36-
DateTime minStartTime = DateTime.Now.AddYears(-year);
37-
DateTime maxStartTime = DateTime.Now.AddYears(-year + 1);
38-
foreach (SpringBattle b in data.SpringBattles
39-
.Where(x => x.StartTime > minStartTime && x.StartTime < maxStartTime)
40-
.Include(x => x.ResourceByMapResourceID)
41-
.Include(x => x.SpringBattlePlayers)
42-
.Include(x => x.SpringBattleBots)
43-
.AsNoTracking()
44-
.OrderBy(x => x.StartTime))
35+
for (int year = 10; year > 0; year--)
4536
{
46-
ProcessBattle(b);
37+
DateTime minStartTime = DateTime.Now.AddYears(-year);
38+
DateTime maxStartTime = DateTime.Now.AddYears(-year + 1);
39+
foreach (SpringBattle b in data.SpringBattles
40+
.Where(x => x.StartTime > minStartTime && x.StartTime < maxStartTime)
41+
.Include(x => x.ResourceByMapResourceID)
42+
.Include(x => x.SpringBattlePlayers)
43+
.Include(x => x.SpringBattleBots)
44+
.AsNoTracking()
45+
.OrderBy(x => x.StartTime))
46+
{
47+
ProcessBattle(b);
48+
}
4749
}
50+
Initialized = true;
51+
whr.Values.ForEach(w => w.UpdateRatings());
4852
}
49-
Initialized = true;
50-
whr.Values.ForEach(w => w.UpdateRatings());
5153
}
5254
catch (Exception ex)
5355
{

ZkData/Ef/WHR/WholeHistoryRating.cs

Lines changed: 88 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections;
66
using System.Collections.Concurrent;
77
using System.Collections.Generic;
8+
using System.Data.Entity;
89
using System.Diagnostics;
910
using System.IO;
1011
using System.Linq;
@@ -106,27 +107,60 @@ public void ProcessBattle(SpringBattle battle)
106107
}
107108
}
108109

110+
private List<Account> laddersCache = new List<Account>();
111+
109112
public List<Account> GetTopPlayers(int count)
110113
{
111-
ZkDataContext db = new ZkDataContext();
112-
List<int> retIDs = topPlayers.Take(count).ToList();
113-
return db.Accounts.Where(a => retIDs.Contains(a.AccountID)).OrderByDescending(x => x.AccountRatings.Where(r => r.RatingCategory == category).Select(r => r.Elo).DefaultIfEmpty(-1).FirstOrDefault()).ToList();
114+
if (count > 200)
115+
{
116+
using (ZkDataContext db = new ZkDataContext())
117+
{
118+
laddersCache = db.Accounts
119+
.Include(a => a.Clan)
120+
.Include(a => a.Faction)
121+
.OrderByDescending(x => x.AccountRatings.Where(r => r.RatingCategory == category).Select(r => r.Elo).DefaultIfEmpty(-1).FirstOrDefault())
122+
.Take(count)
123+
.ToList();
124+
}
125+
}
126+
if (laddersCache.Count < count)
127+
{
128+
129+
using (ZkDataContext db = new ZkDataContext())
130+
{
131+
List<int> retIDs = topPlayers.Take(count).ToList();
132+
laddersCache = db.Accounts
133+
.Where(a => retIDs.Contains(a.AccountID))
134+
.Include(a => a.Clan)
135+
.Include(a => a.Faction)
136+
.OrderByDescending(x => x.AccountRatings.Where(r => r.RatingCategory == category).Select(r => r.Elo).DefaultIfEmpty(-1).FirstOrDefault())
137+
.ToList();
138+
}
139+
}
140+
return laddersCache.Take(count).ToList();
114141
}
115142

116143
public List<Account> GetTopPlayers(int count, Func<Account, bool> selector)
117144
{
118145
lock (updateLockInternal)
119146
{
120147
int counter = 0;
121-
ZkDataContext db = new ZkDataContext();
122148
List<Account> retval = new List<Account>();
123-
foreach (var pair in sortedPlayers)
149+
150+
using (ZkDataContext db = new ZkDataContext())
124151
{
125-
Account acc = db.Accounts.Where(a => a.AccountID == pair.Value).FirstOrDefault();
126-
if (playerRatings[acc.AccountID].Rank < int.MaxValue && selector.Invoke(acc))
152+
foreach (var pair in sortedPlayers)
127153
{
128-
if (counter++ >= count) break;
129-
retval.Add(acc);
154+
Account acc = db.Accounts
155+
.Where(a => a.AccountID == pair.Value)
156+
.Include(a => a.Clan)
157+
.Include(a => a.Faction)
158+
.FirstOrDefault();
159+
if (playerRatings[acc.AccountID].Rank < int.MaxValue && selector.Invoke(acc))
160+
{
161+
if (counter++ >= count) break;
162+
retval.Add(acc);
163+
}
130164
}
131165
}
132166
return retval;
@@ -168,7 +202,7 @@ public void UpdateRatings()
168202
{
169203
updateAction = (() => {
170204
Trace.TraceInformation("Initializing WHR " + category +" ratings for " + battlesRegistered + " battles, this will take some time.. From B" + firstBattle?.SpringBattleID + " to B" + latestBattle?.SpringBattleID);
171-
runIterations(50);
205+
runIterations(75);
172206
UpdateRankings(players.Values);
173207
playerOldRatings = new Dictionary<int, PlayerRating>(playerRatings);
174208
});
@@ -224,7 +258,7 @@ public void UpdateRatings()
224258
{
225259
Trace.TraceError("Thread error while updating WHR " + category +" " + ex);
226260
}
227-
});
261+
}, CancellationToken.None, TaskCreationOptions.None, PriorityScheduler.BelowNormal);
228262
lastUpdate = latestBattle;
229263
}
230264

@@ -235,22 +269,24 @@ public void SaveToDB(IEnumerable<int> players)
235269
lock (dbLock)
236270
{
237271

238-
var db = new ZkDataContext();
239-
foreach (int player in players)
272+
using (var db = new ZkDataContext())
240273
{
241-
var accountRating = db.AccountRatings.Where(x => x.RatingCategory == category && x.AccountID == player).FirstOrDefault();
242-
if (accountRating == null)
243-
{
244-
accountRating = new AccountRating(player, category);
245-
accountRating.UpdateFromRatingSystem(playerRatings[player]);
246-
db.AccountRatings.InsertOnSubmit(accountRating);
247-
}
248-
else
274+
foreach (int player in players)
249275
{
250-
accountRating.UpdateFromRatingSystem(playerRatings[player]);
276+
var accountRating = db.AccountRatings.Where(x => x.RatingCategory == category && x.AccountID == player).FirstOrDefault();
277+
if (accountRating == null)
278+
{
279+
accountRating = new AccountRating(player, category);
280+
accountRating.UpdateFromRatingSystem(playerRatings[player]);
281+
db.AccountRatings.InsertOnSubmit(accountRating);
282+
}
283+
else
284+
{
285+
accountRating.UpdateFromRatingSystem(playerRatings[player]);
286+
}
251287
}
288+
db.SaveChanges();
252289
}
253-
db.SaveChanges();
254290
}
255291
}
256292

@@ -259,37 +295,39 @@ public void SaveToDB()
259295
lock (dbLock)
260296
{
261297
DateTime start = DateTime.Now;
262-
var db = new ZkDataContext();
263-
HashSet<int> processedPlayers = new HashSet<int>();
264-
int deleted = 0;
265-
int added = 0;
266-
foreach (var accountRating in db.AccountRatings.Where(x => x.RatingCategory == category))
298+
using (var db = new ZkDataContext())
267299
{
268-
if (!playerRatings.ContainsKey(accountRating.AccountID))
300+
HashSet<int> processedPlayers = new HashSet<int>();
301+
int deleted = 0;
302+
int added = 0;
303+
foreach (var accountRating in db.AccountRatings.Where(x => x.RatingCategory == category))
269304
{
270-
deleted++;
271-
db.AccountRatings.DeleteOnSubmit(accountRating);
272-
continue;
273-
}
274-
processedPlayers.Add(accountRating.AccountID);
275-
if (Math.Abs(playerRatings[accountRating.AccountID].Elo - accountRating.Elo) > 1)
276-
{
277-
accountRating.UpdateFromRatingSystem(playerRatings[accountRating.AccountID]);
305+
if (!playerRatings.ContainsKey(accountRating.AccountID))
306+
{
307+
deleted++;
308+
db.AccountRatings.DeleteOnSubmit(accountRating);
309+
continue;
310+
}
311+
processedPlayers.Add(accountRating.AccountID);
312+
if (Math.Abs(playerRatings[accountRating.AccountID].Elo - accountRating.Elo) > 1)
313+
{
314+
accountRating.UpdateFromRatingSystem(playerRatings[accountRating.AccountID]);
315+
}
278316
}
279-
}
280-
foreach (int player in playerRatings.Keys)
281-
{
282-
if (!processedPlayers.Contains(player))
317+
foreach (int player in playerRatings.Keys)
283318
{
284-
var accountRating = new AccountRating(player, category);
285-
accountRating.UpdateFromRatingSystem(playerRatings[player]);
286-
db.AccountRatings.InsertOnSubmit(accountRating);
287-
added++;
319+
if (!processedPlayers.Contains(player))
320+
{
321+
var accountRating = new AccountRating(player, category);
322+
accountRating.UpdateFromRatingSystem(playerRatings[player]);
323+
db.AccountRatings.InsertOnSubmit(accountRating);
324+
added++;
325+
}
288326
}
289-
}
290327

291-
db.SaveChanges();
292-
Trace.TraceInformation("WHR " + category +" Ratings saved to DB in " + DateTime.Now.Subtract(start).TotalSeconds + " seconds, " + added + " entries added, " + deleted + " entries removed, " + (GC.GetTotalMemory(false) / (1 << 20)) + "MiB total memory allocated");
328+
db.SaveChanges();
329+
Trace.TraceInformation("WHR " + category + " Ratings saved to DB in " + DateTime.Now.Subtract(start).TotalSeconds + " seconds, " + added + " entries added, " + deleted + " entries removed, " + (GC.GetTotalMemory(false) / (1 << 20)) + "MiB total memory allocated");
330+
}
293331
}
294332
}
295333

@@ -375,6 +413,7 @@ private void UpdateRankings(IEnumerable<Player> players)
375413
}
376414
}
377415
topPlayers = newTopPlayers;
416+
laddersCache = new List<Account>();
378417
Trace.TraceInformation("WHR " + category +" Ladders updated with " + topPlayers.Count + "/" + this.players.Count + " entries, max uncertainty selected: " + DynamicMaxUncertainty);
379418

380419
var playerIds = players.Select(x => x.id).ToList();
@@ -387,6 +426,7 @@ private void UpdateRankings(IEnumerable<Player> players)
387426
}
388427

389428
//check for topX updates
429+
GetTopPlayers(GlobalConst.LadderSize);
390430
foreach (var listener in topPlayersUpdateListeners)
391431
{
392432
if (matched < listener.Value)

0 commit comments

Comments
 (0)