From cd45c30ab2dcc44bfbfac283d15bb09b3d4644bc Mon Sep 17 00:00:00 2001 From: shennetsind Date: Wed, 18 Jul 2012 19:47:51 +0000 Subject: Super performance improvement to groups system, caching permissions levels and atcommand permissions saving thousands of thousands of dbmap lookups. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16443 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/atcommand.c | 77 +++++++++++++++++++++++++++++++++++++++++------------ src/map/atcommand.h | 1 + src/map/pc.c | 16 ++++------- src/map/pc.h | 5 ++-- src/map/pc_groups.c | 53 +++++++++++++++++++++++++++++++++--- src/map/pc_groups.h | 3 +++ 6 files changed, 121 insertions(+), 34 deletions(-) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index a600fec63..9586d5a24 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -60,6 +60,8 @@ typedef struct AliasInfo AliasInfo; struct AtCommandInfo { char command[ATCOMMAND_LENGTH]; AtCommandFunc func; + char* at_groups;/* quick @commands "can-use" lookup */ + char* char_groups;/* quick @charcommands "can-use" lookup */ }; struct AliasInfo { @@ -8393,8 +8395,19 @@ static void atcommand_commands_sub(struct map_session_data* sd, const int fd, At for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { unsigned int slen = 0; - if (!pc_can_use_command(sd, cmd->command, type)) - continue; + switch( type ) { + case COMMAND_CHARCOMMAND: + if( cmd->char_groups[sd->group_pos] == 0 ) + continue; + break; + case COMMAND_ATCOMMAND: + if( cmd->at_groups[sd->group_pos] == 0 ) + continue; + break; + default: + continue; + } + slen = strlen(cmd->command); @@ -8583,8 +8596,8 @@ ACMD_FUNC(set) { /** * Fills the reference of available commands in atcommand DBMap **/ -#define ACMD_DEF(x) { #x, atcommand_ ## x } -#define ACMD_DEF2(x2, x) { x2, atcommand_ ## x } +#define ACMD_DEF(x) { #x, atcommand_ ## x, NULL, NULL } +#define ACMD_DEF2(x2, x) { x2, atcommand_ ## x, NULL, NULL } void atcommand_basecommands(void) { /** * Command reference list, place the base of your commands here @@ -9039,8 +9052,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message //Grab the command information and check for the proper GM level required to use it or if the command exists info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); - if (info == NULL) - { + if (info == NULL) { if( pc_get_group_level(sd) ) { // TODO: remove or replace with proper permission sprintf(output, msg_txt(153), command); // "%s is Unknown Command." clif_displaymessage(fd, output); @@ -9052,8 +9064,8 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message // type == 1 : player invoked if (type == 1) { - if ((*command == atcommand_symbol && !pc_can_use_command(sd, atcommand_checkalias(command + 1), COMMAND_ATCOMMAND)) || - (*command == charcommand_symbol && !pc_can_use_command(sd, atcommand_checkalias(command + 1), COMMAND_CHARCOMMAND))) { + if ((*command == atcommand_symbol && info->at_groups[sd->group_pos] == 0) || + (*command == charcommand_symbol && info->char_groups[sd->group_pos] == 0) ) { return false; } } @@ -9175,17 +9187,50 @@ static void atcommand_config_read(const char* config_filename) ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' command aliases in '"CL_WHITE"%s"CL_RESET"'.\n", num_aliases, config_filename); return; } +void atcommand_db_load_groups(int* group_ids) { + DBIterator *iter = db_iterator(atcommand_db); + AtCommandInfo* cmd; + int i; + + for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { + cmd->at_groups = aMalloc( pc_group_max * sizeof(char) ); + cmd->char_groups = aMalloc( pc_group_max * sizeof(char) ); + for(i = 0; i < pc_group_max; i++) { + if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_ATCOMMAND ) ) + cmd->at_groups[i] = 1; + else + cmd->at_groups[i] = 0; + if( pc_group_can_use_command(group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) ) + cmd->char_groups[i] = 1; + else + cmd->char_groups[i] = 0; + } + } + + dbi_destroy(iter); + + return; +} +void atcommand_db_clear(void) { + + if (atcommand_db != NULL) { + DBIterator *iter = db_iterator(atcommand_db); + AtCommandInfo* cmd; + + for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { + aFree(cmd->at_groups); + aFree(cmd->char_groups); + } + + dbi_destroy(iter); -void atcommand_db_clear(void) -{ - if (atcommand_db != NULL) db_destroy(atcommand_db); + } if (atcommand_alias_db != NULL) db_destroy(atcommand_alias_db); } -void atcommand_doload(void) -{ +void atcommand_doload(void) { atcommand_db_clear(); atcommand_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); atcommand_alias_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); @@ -9193,12 +9238,10 @@ void atcommand_doload(void) atcommand_config_read(ATCOMMAND_CONF_FILENAME); } -void do_init_atcommand(void) -{ +void do_init_atcommand(void) { atcommand_doload(); } -void do_final_atcommand(void) -{ +void do_final_atcommand(void) { atcommand_db_clear(); } diff --git a/src/map/atcommand.h b/src/map/atcommand.h index a0a7c2286..aaf477a97 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -26,6 +26,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message void do_init_atcommand(void); void do_final_atcommand(void); +void atcommand_db_load_groups(int* group_ids); bool atcommand_exists(const char* name); diff --git a/src/map/pc.c b/src/map/pc.c index 1e18e4941..138bc0828 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -101,7 +101,7 @@ inline int pc_get_group_id(struct map_session_data *sd) { } inline int pc_get_group_level(struct map_session_data *sd) { - return pc_group_id2level(pc_get_group_id(sd)); + return sd->group_level; } static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data) @@ -922,6 +922,10 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->login_id2 = login_id2; sd->group_id = group_id; + + /* load user permissions */ + pc_group_pc_load(sd); + memcpy(&sd->status, st, sizeof(*st)); if (st->sex != sd->status.sex) { @@ -8625,16 +8629,6 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command, AtComm return pc_group_can_use_command(pc_get_group_id(sd), command, type); } -/** - * Checks if player has a permission - * @param sd Player map session data - * @param permission permission to check - */ -bool pc_has_permission(struct map_session_data *sd, int permission) -{ - return pc_group_has_permission(pc_get_group_id(sd), permission); -} - /** * Checks if commands used by a player should be logged * according to their group setting. diff --git a/src/map/pc.h b/src/map/pc.h index 6352d362c..2cb859e5b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -158,7 +158,8 @@ struct map_session_data { } special_state; int login_id1, login_id2; unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] - int group_id; + int group_id, group_pos, group_level; + unsigned int permissions;/* group permissions */ int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18 struct mmo_charstatus status; @@ -669,7 +670,7 @@ int pc_getrefinebonus(int lv,int type); bool pc_can_give_items(struct map_session_data *sd); bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type); -bool pc_has_permission(struct map_session_data *sd, int permission); +#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 ) bool pc_should_log_commands(struct map_session_data *sd); int pc_setrestartvalue(struct map_session_data *sd,int type); diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index c6fb6a7b1..59eecb254 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -7,6 +7,7 @@ #include "../common/nullpo.h" #include "../common/showmsg.h" #include "../common/strlib.h" // strcmp +#include "../common/socket.h" #include "atcommand.h" // AtCommandType #include "pc_groups.h" @@ -28,8 +29,10 @@ struct GroupSettings { config_setting_t *inherit; // groups.[].inherit bool inheritance_done; // have all inheritance rules been evaluated? config_setting_t *root; // groups.[] + int group_pos;/* pos on load */ }; +int pc_group_max; /* known number of groups */ static config_t pc_group_config; static DBMap* pc_group_db; // id -> GroupSettings @@ -85,7 +88,7 @@ static void read_config(void) config_setting_t *groups = NULL; const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name int group_count = 0; - + if (conf_read_file(&pc_group_config, config_filename)) return; @@ -153,6 +156,7 @@ static void read_config(void) group_settings->permissions = config_setting_get_member(group, "permissions"); group_settings->inheritance_done = false; group_settings->root = group; + group_settings->group_pos = i; strdb_put(pc_groupname_db, groupname, group_settings); idb_put(pc_group_db, id, group_settings); @@ -292,6 +296,23 @@ static void read_config(void) } ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename); + + + if( ( pc_group_max = group_count ) ) { + DBIterator *iter = db_iterator(pc_group_db); + GroupSettings *group_settings = NULL; + int* group_ids = aMalloc( pc_group_max * sizeof(int) ); + int i = 0; + for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { + group_ids[i++] = group_settings->id; + } + + atcommand_db_load_groups(group_ids); + + aFree(group_ids); + + dbi_destroy(iter); + } } /** @@ -346,7 +367,20 @@ bool pc_group_can_use_command(int group_id, const char *command, AtCommandType t } return false; } - +void pc_group_pc_load(struct map_session_data * sd) { + GroupSettings *group = NULL; + if ((group = id2group(sd->group_id)) == NULL) { + ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", + sd->status.name, + sd->status.account_id, + sd->group_id); + set_eof(sd->fd); + return; + } + sd->permissions = group->e_permissions; + sd->group_pos = group->group_pos; + sd->group_level = group->level; +} /** * Checks if player group has a permission * @param group_id ID of the group @@ -439,8 +473,19 @@ void do_final_pc_groups(void) * Used in @reloadatcommand * @public */ -void pc_groups_reload(void) -{ +void pc_groups_reload(void) { + struct map_session_data* sd = NULL; + struct s_mapiterator* iter = NULL; + do_final_pc_groups(); do_init_pc_groups(); + + /* refresh online users permissions */ + iter = mapit_getallusers(); + for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) { + pc_group_pc_load(sd); + } + mapit_free(iter); + + } diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index 353bbebfa..259b74585 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -6,12 +6,15 @@ #include "atcommand.h" // AtCommandType +extern int pc_group_max; + bool pc_group_exists(int group_id); bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type); bool pc_group_has_permission(int group_id, int permission); bool pc_group_should_log_commands(int group_id); const char* pc_group_id2name(int group_id); int pc_group_id2level(int group_id); +void pc_group_pc_load(struct map_session_data *); void do_init_pc_groups(void); void do_final_pc_groups(void); -- cgit v1.2.3-60-g2f50