Skip to content

Commit c72ad2b

Browse files
committed
Optimized hero matches
1 parent 9f077b4 commit c72ad2b

File tree

6 files changed

+100
-74
lines changed

6 files changed

+100
-74
lines changed

src/gameserver/command/ProcessAchievements/process-achievements.handler.ts

+5-8
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ import { MatchmakingMode } from 'gateway/shared-types/matchmaking-mode';
1313

1414
@CommandHandler(ProcessAchievementsCommand)
1515
export class ProcessAchievementsHandler
16-
implements ICommandHandler<ProcessAchievementsCommand> {
16+
implements ICommandHandler<ProcessAchievementsCommand>
17+
{
1718
private readonly logger = new Logger(ProcessAchievementsHandler.name);
1819

1920
constructor(
2021
@InjectRepository(FinishedMatchEntity)
21-
private readonly finishedMatchEntityRepository: Repository<
22-
FinishedMatchEntity
23-
>,
22+
private readonly finishedMatchEntityRepository: Repository<FinishedMatchEntity>,
2423
@InjectRepository(PlayerInMatchEntity)
25-
private readonly playerInMatchEntityRepository: Repository<
26-
PlayerInMatchEntity
27-
>,
24+
private readonly playerInMatchEntityRepository: Repository<PlayerInMatchEntity>,
2825
@InjectRepository(AchievementEntity)
2926
private readonly achievementEntityRepository: Repository<AchievementEntity>,
3027
private readonly ebus: EventBus,
@@ -69,7 +66,7 @@ export class ProcessAchievementsHandler
6966
player.hero,
7067
ach.matchId,
7168
),
72-
); // todo maybe shit
69+
);
7370
}
7471
}
7572
});

src/gameserver/model/player-in-match.entity.ts

+1-22
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export default class PlayerInMatchEntity {
7575
gold: number = 0;
7676

7777
@Column('varchar')
78+
@Index('player_in_match_hero_hash_index', { synchronize: false })
7879
hero!: string;
7980

8081
@Column('smallint', { default: 0 })
@@ -100,28 +101,6 @@ export default class PlayerInMatchEntity {
100101

101102
@Column('uuid', { nullable: true, default: null})
102103
party_id?: string;
103-
104-
// constructor(playerId: string, team: number, kills: number, deaths: number, assists: number, level: number, gpm: number, xpm: number, abandoned: boolean, last_hits: number, denies: number, hero: string, items: string, item0: number, item1: number, item2: number, item3: number, item4: number, item5: number) {
105-
// this.playerId = playerId;
106-
// this.team = team;
107-
// this.kills = kills;
108-
// this.deaths = deaths;
109-
// this.assists = assists;
110-
// this.level = level;
111-
// this.gpm = gpm;
112-
// this.xpm = xpm;
113-
// this.abandoned = abandoned;
114-
// this.last_hits = last_hits;
115-
// this.denies = denies;
116-
// this.hero = hero;
117-
// this.items = items;
118-
// this.item0 = item0;
119-
// this.item1 = item1;
120-
// this.item2 = item2;
121-
// this.item3 = item3;
122-
// this.item4 = item4;
123-
// this.item5 = item5;
124-
// }
125104
}
126105

127106
/**

src/rest/match/match.controller.ts

+26-26
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,30 @@ export class MatchController {
3030
) {}
3131

3232
// remove meta service from here
33-
// @ApiQuery({
34-
// name: 'page',
35-
// required: true,
36-
// })
37-
// @ApiQuery({
38-
// name: 'per_page',
39-
// required: false,
40-
// })
41-
// @ApiQuery({
42-
// name: 'hero',
43-
// })
44-
// @Get('/by_hero')
45-
// async heroMatches(
46-
// @Query('page', NullableIntPipe) page: number,
47-
// @Query('per_page', NullableIntPipe) perPage: number = 25,
48-
// @Query('hero') hero: string,
49-
// ): Promise<MatchPageDto> {
50-
// const raw = await this.metaService.heroMatches(page, perPage, hero);
51-
//
52-
// return {
53-
// ...raw,
54-
// data: raw.data.map(this.mapper.mapMatch),
55-
// };
56-
// }
33+
@ApiQuery({
34+
name: 'page',
35+
required: true,
36+
})
37+
@ApiQuery({
38+
name: 'per_page',
39+
required: false,
40+
})
41+
@ApiQuery({
42+
name: 'hero',
43+
})
44+
@Get('/by_hero')
45+
async heroMatches(
46+
@Query('page', NullableIntPipe) page: number,
47+
@Query('per_page', NullableIntPipe) perPage: number = 25,
48+
@Query('hero') hero: string,
49+
): Promise<MatchPageDto> {
50+
const raw = await this.matchService.heroMatches(page, perPage, hero);
51+
52+
return {
53+
...raw,
54+
data: raw.data.map(this.mapper.mapMatch),
55+
};
56+
}
5757

5858
@ApiQuery({
5959
name: 'page',
@@ -73,7 +73,7 @@ export class MatchController {
7373
@Query('per_page', NullableIntPipe) perPage: number = 25,
7474
@Query('mode') mode?: MatchmakingMode,
7575
): Promise<MatchPageDto> {
76-
const [matches, cnt] = await this.matchService.getMatchPageFastest(page, perPage, mode);
76+
const [matches, cnt] = await this.matchService.getMatchPage(page, perPage, mode);
7777
return makePage(matches, cnt, page, perPage, this.mapper.mapMatch);
7878
}
7979

@@ -113,7 +113,7 @@ export class MatchController {
113113
@Query('mode', NullableIntPipe) mode?: MatchmakingMode,
114114
@Query('hero') hero?: string,
115115
): Promise<MatchPageDto> {
116-
const [matches, total] = await this.matchService.playerMatchesNew(steam_id, page, perPage, mode, hero);
116+
const [matches, total] = await this.matchService.getPlayerMatches(steam_id, page, perPage, mode, hero);
117117

118118
return makePage(
119119
matches,

src/rest/service/match.service.ts

+57-17
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import FinishedMatchEntity from 'gameserver/model/finished-match.entity';
55
import { InjectRepository } from '@nestjs/typeorm';
66
import { MatchmakingMode } from 'gateway/shared-types/matchmaking-mode';
77
import PlayerInMatchEntity from 'gameserver/model/player-in-match.entity';
8-
import { ProcessRankedMatchCommand } from 'gameserver/command/ProcessRankedMatch/process-ranked-match.command';
98
import { CommandBus } from '@nestjs/cqrs';
10-
import { PlayerId } from 'gateway/shared-types/player-id';
119
import { MmrChangeLogEntity } from 'gameserver/model/mmr-change-log.entity';
10+
import { Page } from 'rest/dto/page';
11+
import { optimized } from 'util/optimized';
1212

1313
@Injectable()
1414
export class MatchService {
@@ -27,8 +27,9 @@ export class MatchService {
2727
private readonly mmrChangeLogEntityRepository: Repository<MmrChangeLogEntity>,
2828
) {}
2929

30-
@measure("getMatchPage:fastest")
31-
public async getMatchPageFastest(
30+
@optimized(true)
31+
@measure("getMatchPage")
32+
public async getMatchPage(
3233
page: number,
3334
perPage: number,
3435
mode?: MatchmakingMode,
@@ -73,8 +74,9 @@ export class MatchService {
7374

7475
// http_req_waiting...............: avg=218.18ms min=46.31ms med=176.7ms max=1.07s p(90)=348.67ms p(95)=641.38ms
7576
// http_reqs......................: 1695 80.493324/s
76-
@measure("playerMatches:new")
77-
public async playerMatchesNew(
77+
@optimized(true)
78+
@measure("getPlayerMatches")
79+
public async getPlayerMatches(
7880
steam_id: string,
7981
page: number,
8082
perPage: number,
@@ -104,18 +106,56 @@ export class MatchService {
104106
return Promise.combine([pims, total]);
105107
}
106108

107-
async manuallyTriggerMmrForMatch(matchId: number) {
108-
// await this.mmrChangeLogEntityRepository.delete({ matchId : matchId });
109109

110-
const m = await this.finishedMatchEntityRepository.findOne({
111-
where: { id: matchId },
110+
@optimized(true, 'Added index on pim.hero')
111+
@measure("heroMatches")
112+
public async heroMatches(
113+
page: number,
114+
perPage: number,
115+
hero: string,
116+
): Promise<Page<FinishedMatchEntity>> {
117+
const [ids, count] = await this.finishedMatchEntityRepository
118+
.createQueryBuilder('fm')
119+
.select(['fm.id', 'fm.timestamp'])
120+
.addOrderBy('fm.timestamp', 'DESC')
121+
.leftJoin('fm.players', 'pims')
122+
.where('pims.hero = :hero', { hero })
123+
.andWhere('fm.matchmaking_mode in (:...modes)', {
124+
modes: [MatchmakingMode.RANKED, MatchmakingMode.UNRANKED],
125+
})
126+
.take(perPage)
127+
.skip(perPage * page)
128+
.getManyAndCount();
129+
130+
const mapped = await this.finishedMatchEntityRepository.find({
131+
where: {
132+
id: In(ids.map(t => t.id)),
133+
},
112134
});
113-
const winners = m.players
114-
.filter(t => t.team === m.winner)
115-
.map(it => new PlayerId(it.playerId));
116-
const losers = m.players
117-
.filter(t => t.team !== m.winner)
118-
.map(it => new PlayerId(it.playerId));
119-
await this.cbus.execute(new ProcessRankedMatchCommand(matchId, winners, losers, m.matchmaking_mode));
135+
136+
return {
137+
data: mapped,
138+
page,
139+
perPage: perPage,
140+
pages: Math.ceil(count / perPage),
141+
};
120142
}
143+
144+
145+
146+
147+
// async manuallyTriggerMmrForMatch(matchId: number) {
148+
// // await this.mmrChangeLogEntityRepository.delete({ matchId : matchId });
149+
//
150+
// const m = await this.finishedMatchEntityRepository.findOne({
151+
// where: { id: matchId },
152+
// });
153+
// const winners = m.players
154+
// .filter(t => t.team === m.winner)
155+
// .map(it => new PlayerId(it.playerId));
156+
// const losers = m.players
157+
// .filter(t => t.team !== m.winner)
158+
// .map(it => new PlayerId(it.playerId));
159+
// await this.cbus.execute(new ProcessRankedMatchCommand(matchId, winners, losers, m.matchmaking_mode));
160+
// }
121161
}

src/util/optimized.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This only used for marking
2+
export function optimized(value: boolean, info: string = '') {
3+
return function (
4+
target: any,
5+
propertyKey: string,
6+
descriptor: PropertyDescriptor,
7+
) {
8+
9+
};
10+
}

src/util/typeorm-config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const prodDbConfig: TypeOrmModuleOptions = {
7979
dropSchema: false,
8080
poolSize: 50,
8181

82-
// logging: true,
82+
// maxQueryExecutionTime: 10,
8383

8484
ssl: false,
8585
};

0 commit comments

Comments
 (0)