Skip to content
Permalink
Browse files
Check_db
Add a check_db on char-serv startup to ensure all sql-tables was loaded
correctly and avoid error on runtime.
Fix OnInterIfInitOnce being executed on reloadscript, (now only done at
server startup)
  • Loading branch information
lighta committed Jan 9, 2014
1 parent 65d1ee3 commit 4af314500ee1716fab12a25983720e2a2bd52b35
Showing with 268 additions and 17 deletions.
  1. +3 −0 conf/char_athena.conf
  2. +3 −0 npc/re/scripts_main.conf
  3. +1 −0 npc/scripts_test.conf
  4. +8 −0 npc/test/OnInterInit.txt
  5. +240 −1 src/char/char.c
  6. +1 −0 src/char/char.h
  7. +0 −10 src/common/showmsg.c
  8. +2 −1 src/login/login.c
  9. +1 −0 src/login/login.h
  10. +7 −2 src/map/chrif.c
  11. +0 −2 src/map/elemental.c
  12. +1 −0 src/map/map.c
  13. +1 −0 src/map/map.h
  14. +0 −1 src/map/npc.c
@@ -201,4 +201,7 @@ char_movetoused: yes
// Allow users to move characters as often as they like?
char_moves_unlimited: no

// Should we check if sql-tables are correct on server startup ?
char_checkdb: yes

import: conf/import/char_conf.txt
@@ -41,6 +41,9 @@ import: npc/re/scripts_mapflags.conf
import: npc/re/scripts_monsters.conf
import: npc/re/scripts_warps.conf

// Test for regressions and such
//import: npc/scripts_test.conf

// ------------------- Custom Script Files ----------------------
// - Your NPCs go in this file!
import: npc/scripts_custom.conf
@@ -0,0 +1 @@
npc: npc/test/OnInterInit.txt
@@ -0,0 +1,8 @@
- script OnInterChk -1,{
OnInterIfInit:
debugmes "Loaded OnInterIfInit <-------";
end;
OnInterIfInitOnce:
debugmes "Loaded OnInterIfInitOnce <-------";
end;
}
@@ -112,6 +112,7 @@ int char_del_option = 2; // Character deletion type, email = 1, birthdate = 2 (d

int log_char = 1; // loggin char or not [devil]
int log_inter = 1; // loggin inter or not [devil]
int char_check_db = 1; ///cheking sql-table at begining ?

// Advanced subnet check [LuzZza]
struct s_subnet {
@@ -4842,7 +4843,7 @@ int parse_console(const char* buf)

if( n == 2 && strcmpi("server", type) == 0 ){
if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 ){
runflag = 0;
runflag = CHARSERVER_ST_SHUTDOWN;
}
else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 )
ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
@@ -5384,6 +5385,235 @@ int char_lan_config_read(const char *lancfgName)
return 0;
}

/**
* Check if our table are all ok in sqlserver
* Char tables to check
* @return 0:fail, 1:success
*/
bool char_checkdb(void){
int i;
const char* sqltable[] = {
char_db, hotkey_db, scdata_db, cart_db, inventory_db, charlog_db, storage_db, reg_db, skill_db, interlog_db, memo_db,
guild_db, guild_alliance_db, guild_castle_db, guild_expulsion_db, guild_member_db, guild_skill_db, guild_position_db, guild_storage_db,
party_db, pet_db, friend_db, mail_db, auction_db, quest_db, homunculus_db, skill_homunculus_db, mercenary_db, mercenary_owner_db,
elemental_db, ragsrvinfo_db, skillcooldown_db, bonus_script_db
};
ShowInfo("Start checking DB integrity\n");
for (i=0; i<ARRAYLENGTH(sqltable); i++){ //check if they all exist and we can acces them in sql-server
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT * from `%s`;", sqltable[i]) )
return false;
}
//checking char_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,"
"`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,"
"`max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,"
"`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,`hair_color`,`clothes_color`,`weapon`,"
"`shield`,`head_top`,`head_mid`,`head_bottom`,`robe`,`last_map`,`last_x`,`last_y`,`save_map`,"
"`save_x`,`save_y`,`partner_id`,`online`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`moves`"
" from `%s`;", char_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking charlog_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `time`,`char_msg`,`account_id`,`char_num`,`name`,"
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`"
" from `%s`;", charlog_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking reg_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`str`,`value`,`type`,`account_id` from `%s`;", reg_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking hotkey_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`hotkey`,`type`,`itemskill_id`,`skill_lvl`"
" from `%s`;", hotkey_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking scdata_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`type`,`tick`,`val1`,`val2`,`val3`,`val4`"
" from `%s`;", scdata_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking skill_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`id`,`lv`,`flag` from `%s`;", skill_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking interlog_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `time`,`log` from `%s`;", interlog_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking memo_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `memo_id`,`char_id`,`map`,`x`,`y` from `%s`;", memo_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`name`,`char_id`,`master`,`guild_lv`,"
"`connect_member`,`max_member`,`average_lv`,`exp`,`next_exp`,`skill_point`,`mes1`,`mes2`,"
"`emblem_len`,`emblem_id`,`emblem_data`"
" from `%s`;", guild_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_alliance_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`opposition`,`alliance_id`,`name` from `%s`;", guild_alliance_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_castle_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `castle_id`,`guild_id`,`economy`,`defense`,`triggerE`,"
"`triggerD`,`nextTime`,`payTime`,`createTime`,`visibleC`,`visibleG0`,`visibleG1`,`visibleG2`,"
"`visibleG3`,`visibleG4`,`visibleG5`,`visibleG6`,`visibleG7` "
" from `%s`;", guild_castle_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_expulsion_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`account_id`,`name`,`mes` from `%s`;", guild_expulsion_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_member_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`account_id`,`char_id`,`hair`,"
"`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`"
" from `%s`;", guild_member_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_skill_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`id`,`lv` from `%s`;", guild_skill_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_position_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id`,`position`,`name`,`mode`,`exp_mode` from `%s`;", guild_position_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking party_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`,`name`,`exp`,`item`,`leader_id`,`leader_char` from `%s`;", party_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking pet_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`,`class`,`name`,`account_id`,`char_id`,`level`,"
"`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`"
" from `%s`;", pet_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking friend_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`friend_account`,`friend_id` from `%s`;", friend_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking mail_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,"
"`title`,`message`,`time`,`status`,`zeny`,`nameid`,`amount`,`refine`,`attribute`,`identify`,"
"`card0`,`card1`,`card2`,`card3`,`unique_id`"
" from `%s`;", mail_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking auction_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,"
"`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`card0`,`card1`,"
"`card2`,`card3`,`unique_id` "
"from `%s`;", auction_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking quest_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`quest_id`,`state`,`time`,`count1`,`count2`,`count3` from `%s`;", quest_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking homunculus_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`prev_class`,`name`,`level`,`exp`,`intimacy`,`hunger`,"
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`alive`,`rename_flag`,`vaporize` "
" from `%s`;", homunculus_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking skill_homunculus_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`id`,`lv` from `%s`;", skill_homunculus_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking mercenary_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `mer_id`,`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time` from `%s`;", mercenary_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking mercenary_owner_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`merc_id`,`arch_calls`,`arch_faith`,"
"`spear_calls`,`spear_faith`,`sword_calls`,`sword_faith`"
" from `%s`;", mercenary_owner_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking elemental_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `ele_id`,`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,"
"`atk1`,`atk2`,`matk`,`aspd`,`def`,`mdef`,`flee`,`hit`,`life_time` "
" from `%s`;", elemental_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking ragsrvinfo_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `index`,`name`,`exp`,`jexp`,`drop` from `%s`;", ragsrvinfo_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking skillcooldown_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`skill`,`tick` from `%s`;", skillcooldown_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking bonus_script_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`script`,`tick`,`flag`,`type`,`icon` from `%s`;", bonus_script_db) ){
Sql_ShowDebug(sql_handle);
return false;
}

//checking cart_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`char_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
" from `%s`;", cart_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking inventory_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`char_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`favorite`,`bound`,`unique_id`"
" from `%s`;", inventory_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking storage_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`account_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
" from `%s`;", storage_db) ){
Sql_ShowDebug(sql_handle);
return false;
}
//checking guild_storage_db
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
"`attribute`,`card0`,`card1`,`card2`,`card3`,`expire_time`,`bound`,`unique_id`"
" from `%s`;", guild_storage_db) ){
Sql_ShowDebug(sql_handle);
return false;
}

ShowInfo("DB integrity check finished with success\n");
return true;
}

void sql_config_read(const char* cfgName)
{
char line[1024], w1[1024], w2[1024];
@@ -5653,6 +5883,8 @@ int char_config_read(const char* cfgName)
char_movetoused = config_switch(w2);
} else if (strcmpi(w1, "char_moves_unlimited") == 0) {
char_moves_unlimited = config_switch(w2);
} else if (strcmpi(w1, "char_checkdb") == 0) {
char_check_db = config_switch(w2);
} else if (strcmpi(w1, "import") == 0) {
char_config_read(w2);
}
@@ -5732,6 +5964,7 @@ void do_shutdown(void)
int do_init(int argc, char **argv)
{
//Read map indexes
runflag = CHARSERVER_ST_STARTING;
mapindex_init();
start_point.map = mapindex_name2id("new_zone01");

@@ -5793,6 +6026,11 @@ int do_init(int argc, char **argv)
add_timer_func_list(online_data_cleanup, "online_data_cleanup");
add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000);

//chek db tables
if(char_check_db && char_checkdb() == 0){
ShowFatalError("char : A tables is missing in sql-server, please fix it, see (sql-files main.sql for structure) \n");
exit(EXIT_FAILURE);
}
//Cleaning the tables for NULL entrys @ startup [Sirius]
//Chardb clean
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) )
@@ -5807,6 +6045,7 @@ int do_init(int argc, char **argv)
Sql_ShowDebug(sql_handle);

set_defaultparse(parse_char);


if( (char_fd = make_listen_bind(bind_ip,char_port)) == -1 ) {
ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",char_port);
@@ -11,6 +11,7 @@
enum E_CHARSERVER_ST
{
CHARSERVER_ST_RUNNING = CORE_ST_LAST,
CHARSERVER_ST_STARTING,
CHARSERVER_ST_SHUTDOWN,
CHARSERVER_ST_LAST
};
@@ -52,7 +52,6 @@
int stdout_with_ansisequence = 0;

int msg_silent = 0; //Specifies how silent the console is.

int console_msg_log = 0;//[Ind] msg error logging

///////////////////////////////////////////////////////////////////////////////
@@ -664,15 +663,6 @@ int FPRINTF(FILE *file, const char *fmt, ...)

#endif// not _WIN32










char timestamp_format[20] = ""; //For displaying Timestamps

int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
@@ -2001,7 +2001,8 @@ void do_shutdown(void)
int do_init(int argc, char** argv)
{
int i;


runflag = LOGINSERVER_ST_STARTING;
// intialize engines (to accept config settings)
for( i = 0; account_engines[i].constructor; ++i )
account_engines[i].db = account_engines[i].constructor();
@@ -11,6 +11,7 @@
enum E_LOGINSERVER_ST
{
LOGINSERVER_ST_RUNNING = CORE_ST_LAST,
LOGINSERVER_ST_STARTING,
LOGINSERVER_ST_SHUTDOWN,
LOGINSERVER_ST_LAST
};
@@ -353,6 +353,11 @@ int chrif_save(struct map_session_data *sd, int flag) {
}

// connects to char-server (plaintext)
/**
* Map-serv request to login into char-serv
* @param fd : char-serv fd to log into
* @return 0:request sent
*/
int chrif_connect(int fd) {
ShowStatus("Logging in to char server...\n", char_fd);
WFIFOHEAD(fd,60);
@@ -482,7 +487,7 @@ int chrif_connectack(int fd) {
static bool char_init_done = false;

if (RFIFOB(fd,2)) {
ShowFatalError("Connection to char-server failed %d.\n", RFIFOB(fd,2));
ShowFatalError("Connection to char-server failed %d, please check conf/import/map_conf userid and passwd.\n", RFIFOB(fd,2));
exit(EXIT_FAILURE);
}

@@ -1481,7 +1486,7 @@ void chrif_on_disconnect(void) {
ShowWarning("Connection to Char Server lost.\n\n");
chrif_connected = 0;

other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect.
other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect.
map_eraseallipport();

//Attempt to reconnect in a second. [Skotlex]

2 comments on commit 4af3145

@Akkarinage
Copy link
Member

@Akkarinage Akkarinage commented on 4af3145 Jun 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[16:46:50] hello, another 2AM complaint from me
[16:46:56] 4af3145
[16:48:01] this committer thinks it's alright to 'check db' by doing a SELECT on all data in every table
[16:52:14] in addition, it's using Sql_Query, which uses mysql_store_result
[16:53:42] so not only is it pulling data from every table, it's also saying "and give it to me all at once"
[16:55:59] this will cause major mysql buffer pool thrashing as it tries read all the blocks from disk, it will also cause a major memory usage spike, since this production db is over 5 gigabytes large...

Can we do something to streamline this?

@cydh
Copy link
Contributor

@cydh cydh commented on 4af3145 Jun 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add LIMIT 1 :P

Please sign in to comment.