reorganize playertimes columns (in create table). speed up point recalculation by inlining things where possible and caching wr last calculated against.

This commit is contained in:
rtldg 2021-10-10 07:50:45 +00:00
parent 60c614df9d
commit 41882d3465
3 changed files with 75 additions and 51 deletions

View File

@ -44,7 +44,7 @@
#define HUD_NOSOUNDS (1 << 11) // disables sounds on personal best, world record etc
#define HUD_NOPRACALERT (1 << 12) // hides practice mode chat alert
#define SHAVIT_LOG_QUERIES 0
#define SHAVIT_LOG_QUERIES 1
// status
enum TimerStatus

View File

@ -166,14 +166,15 @@ public void SQL_CreateTables(Database2 hSQL, const char[] prefix, bool mysql)
if (gB_MySQL)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `time` FLOAT NOT NULL, `jumps` INT, `style` TINYINT NOT NULL DEFAULT 0, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, `exact_time_int` INT DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, `exact_time_int` INT DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;",
gS_SQLPrefix);
}
else
{
// id style track time auth map points points_calced_from exact_time_int
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `time` FLOAT NOT NULL, `jumps` INT, `style` TINYINT NOT NULL DEFAULT 0, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, `exact_time_int` INT DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0);",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, `exact_time_int` INT DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1);",
gS_SQLPrefix);
}
hTrans.AddQuery(sQuery);
@ -391,7 +392,7 @@ void ApplyMigration_LowercaseMaps(const char[] table, int migration)
void ApplyMigration_AddPlayertimesPointsCalcedFrom()
{
char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `points_calced_from` FLOAT NOT NULL DEFAULT 0 AFTER `exact_time_int`;", gS_SQLPrefix);
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `points_calced_from` FLOAT NOT NULL DEFAULT 0 AFTER `points`;", gS_SQLPrefix);
gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlayertimesPointsCalcedFrom, DBPrio_High);
}

View File

@ -73,6 +73,7 @@ bool gB_HasSQLRANK = false; // whether the sql driver supports RANK()
bool gB_Stats = false;
bool gB_Late = false;
bool gB_TierQueried = false;
bool gB_TierRetrieved = false;
int gI_Tier = 1; // No floating numbers for tiers, sorry.
@ -103,6 +104,7 @@ Handle gH_Forwards_OnRankAssigned = null;
chatstrings_t gS_ChatStrings;
int gI_Styles = 0;
bool gB_InitialRecalcStarted = false;
bool gB_WorldRecordsCached = false;
bool gB_WRHolderTablesMade = false;
bool gB_WRHoldersRefreshed = false;
@ -169,8 +171,8 @@ public void OnPluginStart()
gCV_PointsPerTier = new Convar("shavit_rankings_pointspertier", "50.0", "Base points to use for per-tier scaling.\nRead the design idea to see how it works: https://github.com/shavitush/bhoptimer/issues/465", 0, true, 1.0);
gCV_WeightingMultiplier = new Convar("shavit_rankings_weighting", "0.975", "Weighing multiplier. 1.0 to disable weighting.\nFormula: p[1] * this^0 + p[2] * this^1 + p[3] * this^2 + ... + p[n] * this^(n-1)\nRestart server to apply.", 0, true, 0.01, true, 1.0);
gCV_WeightingLimit = new Convar("shavit_rankings_weighting_limit", "0", "Limit the number of times retreived for calculating a player's weighted points to this number.\n0 = no limit\nFor reference, a weighting of 0.975 to the power of 200 is 0.00632299938 and results in pretty much nil points for any further weighted times.\nUnused when shavit_rankings_weighting is 1.0.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, false);
gCV_LastLoginRecalculate = new Convar("shavit_rankings_llrecalc", "10080", "Maximum amount of time (in minutes) since last login to recalculate points for a player.\nsm_recalcall does not respect this setting.\n0 - disabled, don't filter anyone", 0, true, 0.0);
gCV_WeightingLimit = new Convar("shavit_rankings_weighting_limit", "0", "Limit the number of times retreived for calculating a player's weighted points to this number.\n0 = no limit\nFor reference, a weighting of 0.975 to the power of 300 is 0.00050278777 and results in pretty much nil points for any further weighted times.\nUnused when shavit_rankings_weighting is 1.0.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, false);
gCV_LastLoginRecalculate = new Convar("shavit_rankings_llrecalc", "0", "Maximum amount of time (in minutes) since last login to recalculate points for a player.\nsm_recalcall does not respect this setting.\n0 - disabled, don't filter anyone", 0, true, 0.0);
gCV_MVPRankOnes_Slow = new Convar("shavit_rankings_mvprankones_slow", "1", "Uses a slower but more featureful MVP counting system.\nEnables the WR Holder ranks & counts for every style & track.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, true, 1.0);
gCV_MVPRankOnes = new Convar("shavit_rankings_mvprankones", "2", "Set the players' amount of MVPs to the amount of #1 times they have.\n0 - Disabled\n1 - Enabled, for all styles.\n2 - Enabled, for default style only.\n(CS:S/CS:GO only)", 0, true, 0.0, true, 2.0);
gCV_MVPRankOnes_Main = new Convar("shavit_rankings_mvprankones_maintrack", "1", "If set to 0, all tracks will be counted for the MVP stars.\nOtherwise, only the main track will be checked.\n\nRequires \"shavit_stats_mvprankones\" set to 1 or above.\n(CS:S/CS:GO only)", 0, true, 0.0, true, 1.0);
@ -380,7 +382,7 @@ public void OnMapStart()
}
// do NOT keep running this more than once per map, as UpdateAllPoints() is called after this eventually and locks up the database while it is running
if(gB_TierQueried)
if (gB_TierQueried)
{
return;
}
@ -427,10 +429,15 @@ public void SQL_FillTierCache_Callback(Database db, DBResultSet results, const c
SortADTArray(gA_ValidMaps, Sort_Ascending, Sort_String);
gB_TierRetrieved = true;
if (gA_MapTiers.GetValue(gS_Map, gI_Tier))
{
RecalculateCurrentMap();
UpdateAllPoints();
if (gB_WorldRecordsCached && !gB_InitialRecalcStarted)
{
RecalculateCurrentMap();
UpdateAllPoints();
}
}
else
{
@ -442,20 +449,29 @@ public void SQL_FillTierCache_Callback(Database db, DBResultSet results, const c
public void OnMapEnd()
{
gB_TierQueried = false;
gB_WRHoldersRefreshed = false;
gB_WorldRecordsCached = false;
// might be null if Shavit_OnDatabaseLoaded hasn't been called yet
if (gH_SQL != null)
if (gH_SQL != null && gB_TierRetrieved && gB_WorldRecordsCached)
{
RecalculateCurrentMap();
}
gB_InitialRecalcStarted = false;
gB_TierQueried = false;
gB_TierRetrieved = false;
gB_WRHoldersRefreshed = false;
gB_WorldRecordsCached = false;
}
public void Shavit_OnWorldRecordsCached()
{
gB_WorldRecordsCached = true;
if (gB_TierRetrieved && !gB_InitialRecalcStarted)
{
gB_InitialRecalcStarted = true;
RecalculateCurrentMap();
UpdateAllPoints();
}
}
void CS_SetMVPCount_Test(int client, int count)
@ -730,7 +746,7 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
if (Shavit_GetStyleSettingBool(style, "unranked") || fMultiplier == 0.0)
{
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes SET points = 0 WHERE style = %d AND track %c 0 %s%s%s;",
"UPDATE %splayertimes SET points = 0, points_calced_from = 0 WHERE style = %d AND track %c 0 %s%s%s;",
gS_MySQLPrefix,
style,
(track > 0) ? '>' : '=',
@ -752,19 +768,17 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes PT " ...
"SET PT.points = ( "...
" ((%f * %d) * 1.5) + (%f / 15.0)) " ...
"* (%f / PT.time) " ...
"* %f " ...
"WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s';",
"SET PT.points_calced_from = %f, " ...
" PT.points = " ...
" %f * (%f / PT.time) " ...
"WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s' AND PT.points_calced_from != %f;",
gS_MySQLPrefix,
gCV_PointsPerTier.FloatValue,
gI_Tier,
fWR,
(((fWR * gCV_PointsPerTier.FloatValue) * 1.5) + (fWR / 15.0)) * fMultiplier,
fWR,
fMultiplier,
style,
gS_Map
gS_Map,
fWR
);
}
else
@ -772,18 +786,18 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes PT " ...
"INNER JOIN %swrs WR ON " ...
" PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ...
"SET PT.points = ( "...
" ((%f * %d) * 1.5) + (WR.time / 15.0)) " ...
" PT.track = 0 AND PT.track = WR.track AND PT.style = %d AND PT.style = WR.style AND PT.map = '%s' AND PT.map = WR.map AND PT.points_calced_from != WR.time " ...
"SET PT.points_calced_from = WR.time, " ...
" PT.points = "...
" (%f + (WR.time / 15.0)) " ...
" * (WR.time / PT.time) " ...
" * %f " ...
"WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s';",
";",
gS_MySQLPrefix, gS_MySQLPrefix,
gCV_PointsPerTier.FloatValue,
gI_Tier,
fMultiplier,
style,
gS_Map
gS_Map,
((gCV_PointsPerTier.FloatValue * gI_Tier) * 1.5),
fMultiplier
);
}
}
@ -792,18 +806,18 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes PT " ...
"INNER JOIN %swrs WR ON " ...
" PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ...
"SET PT.points = ( "...
" ((%f * 1) * 1.5) + (WR.time / 15.0)) " ...
" PT.track > 0 AND PT.track = WR.track AND PT.style = %d AND PT.style = WR.style AND PT.map = '%s' AND PT.map = WR.map AND PT.points_calced_from != WR.time " ...
"SET PT.points_calced_from = WR.time, " ...
" PT.points = "...
" (%f + (WR.time / 15.0)) " ...
" * (WR.time / PT.time) " ...
" * %f " ...
" * 0.25 " ...
"WHERE PT.style = %d AND PT.track > 0 AND PT.map = '%s';",
";",
gS_MySQLPrefix, gS_MySQLPrefix,
gCV_PointsPerTier.FloatValue,
fMultiplier,
style,
gS_Map
gS_Map,
((gCV_PointsPerTier.FloatValue * 1) * 1.5),
fMultiplier * 0.25
);
}
}
@ -812,11 +826,12 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes PT " ...
"INNER JOIN %swrs WR ON " ...
" PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ...
" PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map AND PT.points_calced_from != WR.time " ...
"INNER JOIN %smaptiers MT ON " ...
" PT.map = MT.map " ...
"SET PT.points = ( "...
" ((%f * MT.tier) * 1.5) + (WR.time / 15.0)) " ...
"SET PT.points_calced_from = WR.time, " ...
" PT.points = "...
" (((%f * MT.tier) * 1.5) + (WR.time / 15.0)) " ...
"* (WR.time / PT.time) " ...
"* %f %s " ...
"WHERE PT.style = %d AND PT.track %c 0;",
@ -837,7 +852,7 @@ public Action Command_RecalcAll(int client, int args)
Transaction2 trans = new Transaction2();
char sQuery[1024];
FormatEx(sQuery, sizeof(sQuery), "UPDATE %splayertimes SET points = 0;", gS_MySQLPrefix);
FormatEx(sQuery, sizeof(sQuery), "UPDATE %splayertimes SET points = 0, points_calced_from = 0;", gS_MySQLPrefix);
trans.AddQuery(sQuery);
FormatEx(sQuery, sizeof(sQuery), "UPDATE %susers SET points = 0;", gS_MySQLPrefix);
trans.AddQuery(sQuery);
@ -898,10 +913,13 @@ void RecalculateCurrentMap()
for(int i = 0; i < gI_Styles; i++)
{
FormatRecalculate(true, Track_Main, i, sQuery, sizeof(sQuery));
gH_SQL_b.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 0, DBPrio_High);
FormatRecalculate(true, Track_Bonus, i, sQuery, sizeof(sQuery));
gH_SQL.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 1, DBPrio_High);
if (!Shavit_GetStyleSettingBool(i, "unranked") && Shavit_GetStyleSettingFloat(i, "rankingmultiplier") != 0.0)
{
FormatRecalculate(true, Track_Main, i, sQuery, sizeof(sQuery));
gH_SQL_b.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 0, DBPrio_High);
FormatRecalculate(true, Track_Bonus, i, sQuery, sizeof(sQuery));
gH_SQL.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 1, DBPrio_High);
}
}
}
@ -912,6 +930,11 @@ public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, i
return;
}
if (Shavit_GetStyleSettingBool(style, "unranked") || Shavit_GetStyleSettingFloat(style, "rankingmultiplier") == 0.0)
{
return;
}
#if defined DEBUG
PrintToServer("Recalculating points. (%s, %d, %d)", map, track, style);
#endif
@ -948,7 +971,7 @@ void UpdateAllPoints(bool recalcall = false)
char sQuery[512];
char sLastLogin[256];
if (recalcall || gCV_LastLoginRecalculate.IntValue == 0)
if (!recalcall && gCV_LastLoginRecalculate.IntValue > 0)
{
FormatEx(sLastLogin, sizeof(sLastLogin), "lastlogin > %d", (GetTime() - gCV_LastLoginRecalculate.IntValue * 60));
}