Procházet zdrojové kódy

Super performance improvement to groups system, caching permissions levels and atcommand permissions saving thousands of thousands of dbmap lookups.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@16443 54d463be-8e91-2dee-dedb-b68131a5f0ec
shennetsind před 13 roky
rodič
revize
ae40bf0ec7
6 změnil soubory, kde provedl 121 přidání a 34 odebrání
  1. 60 17
      src/map/atcommand.c
  2. 1 0
      src/map/atcommand.h
  3. 5 11
      src/map/pc.c
  4. 3 2
      src/map/pc.h
  5. 49 4
      src/map/pc_groups.c
  6. 3 0
      src/map/pc_groups.h

+ 60 - 17
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();
 }

+ 1 - 0
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);
 

+ 5 - 11
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.

+ 3 - 2
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);

+ 49 - 4
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);
+
+	
 }

+ 3 - 0
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);