Bladeren bron

Introducing MySQL Reconnect.
When MySQL disconnects during runtime, the server tries to reconnect either indefinitely (default) or a specified number of times before shutting down.
(Merged from Hercules a4a549d, 64d34dc)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17120 54d463be-8e91-2dee-dedb-b68131a5f0ec

euphyy 12 jaren geleden
bovenliggende
commit
b237ba8ba1
4 gewijzigde bestanden met toevoegingen van 91 en 4 verwijderingen
  1. 11 3
      conf/inter_athena.conf
  2. 2 0
      src/common/core.c
  3. 77 1
      src/common/sql.c
  4. 1 0
      src/common/sql.h

+ 11 - 3
conf/inter_athena.conf

@@ -1,4 +1,5 @@
 // Athena InterServer configuration.
+// Contains settings shared/used by more than 1 server.
 
 // Options for both versions
 
@@ -56,6 +57,14 @@ log_db_db: ragnarok
 log_codepage:
 log_login_db: loginlog
 
+// MySQL Reconnect Settings
+// - mysql_reconnect_type:
+//   1: When MySQL disconnects during runtime, the server tries to reconnect
+//      mysql_reconnect_count times and shuts down if unsuccessful.
+//   2: When mysql disconnects during runtime, it tries to reconnect indefinitely.
+mysql_reconnect_type: 2
+mysql_reconnect_count: 1
+
 // DO NOT CHANGE ANYTHING BEYOND THIS LINE UNLESS YOU KNOW YOUR DATABASE DAMN WELL
 // this is meant for people who KNOW their stuff, and for some reason want to change their
 // database layout. [CLOWNISIUS]
@@ -104,11 +113,10 @@ mob_skill_db_db: mob_skill_db
 mob_skill_db2_db: mob_skill_db2
 mapreg_db: mapreg
 
-//Use SQL item_db, mob_db and mob_skill_db for the map server
+// Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
 use_sql_db: no
 
-// Nick for sending mainchat 
-// messages like whisper
+// Nick for sending main chat messages, similar to a whisper.
 main_chat_nick: Main
 
 import: conf/import/inter_conf.txt

+ 2 - 0
src/common/core.c

@@ -11,6 +11,7 @@
 #include "../common/timer.h"
 #include "../common/thread.h"
 #include "../common/mempool.h"
+#include "../common/sql.h"
 #endif
 
 #include <stdio.h>
@@ -318,6 +319,7 @@ int main (int argc, char **argv)
 	display_title();
 	usercheck();
 
+	Sql_Init();
 	rathread_init();
 	mempool_init();
 	db_init();

+ 77 - 1
src/common/sql.c

@@ -15,7 +15,10 @@
 #include <string.h>// strlen/strnlen/memcpy/memset
 #include <stdlib.h>// strtoul
 
+void ra_mysql_error_handler(unsigned int ecode);
 
+int mysql_reconnect_type;
+unsigned int mysql_reconnect_count;
 
 /// Sql handle
 struct Sql
@@ -74,7 +77,7 @@ Sql* Sql_Malloc(void)
 	self->lengths = NULL;
 	self->result = NULL;
 	self->keepalive = INVALID_TIMER;
-
+	self->handle.reconnect = 1;
 	return self;
 }
 
@@ -266,12 +269,14 @@ int Sql_QueryV(Sql* self, const char* query, va_list args)
 	if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
 	{
 		ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+		ra_mysql_error_handler(mysql_errno(&self->handle));
 		return SQL_ERROR;
 	}
 	self->result = mysql_store_result(&self->handle);
 	if( mysql_errno(&self->handle) != 0 )
 	{
 		ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+		ra_mysql_error_handler(mysql_errno(&self->handle));
 		return SQL_ERROR;
 	}
 	return SQL_SUCCESS;
@@ -291,12 +296,14 @@ int Sql_QueryStr(Sql* self, const char* query)
 	if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
 	{
 		ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+		ra_mysql_error_handler(mysql_errno(&self->handle));
 		return SQL_ERROR;
 	}
 	self->result = mysql_store_result(&self->handle);
 	if( mysql_errno(&self->handle) != 0 )
 	{
 		ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+		ra_mysql_error_handler(mysql_errno(&self->handle));
 		return SQL_ERROR;
 	}
 	return SQL_SUCCESS;
@@ -639,6 +646,7 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
 	if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
 	{
 		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
 		return SQL_ERROR;
 	}
 	self->bind_params = false;
@@ -660,6 +668,7 @@ int SqlStmt_PrepareStr(SqlStmt* self, const char* query)
 	if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
 	{
 		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
 		return SQL_ERROR;
 	}
 	self->bind_params = false;
@@ -721,12 +730,14 @@ int SqlStmt_Execute(SqlStmt* self)
 		mysql_stmt_execute(self->stmt) )
 	{
 		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
 		return SQL_ERROR;
 	}
 	self->bind_columns = false;
 	if( mysql_stmt_store_result(self->stmt) )// store all the data
 	{
 		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
 		return SQL_ERROR;
 	}
 
@@ -868,6 +879,7 @@ int SqlStmt_NextRow(SqlStmt* self)
 	if( err )
 	{
 		ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+		ra_mysql_error_handler(mysql_stmt_errno(self->stmt));
 		return SQL_ERROR;
 	}
 
@@ -946,3 +958,67 @@ void SqlStmt_Free(SqlStmt* self)
 		aFree(self);
 	}
 }
+
+
+
+/// Receives MySQL error codes during runtime (not on first-time-connects).
+void ra_mysql_error_handler(unsigned int ecode) {
+	static unsigned int retry = 1;
+	switch( ecode ) {
+		case 2003:// Can't connect to MySQL (this error only happens here when failing to reconnect)
+			if( mysql_reconnect_type == 1 ) {
+				if( ++retry > mysql_reconnect_count ) {
+					ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry);
+					exit(EXIT_FAILURE);
+				}
+			}
+			break;
+	}
+}
+
+void Sql_inter_server_read(const char* cfgName, bool first) {
+	int i;
+	char line[1024], w1[1024], w2[1024];
+	FILE* fp;
+	
+	fp = fopen(cfgName, "r");
+	if(fp == NULL) {
+		if( first ) {
+			ShowFatalError("File not found: %s\n", cfgName);
+			exit(EXIT_FAILURE);
+		} else
+			ShowError("File not found: %s\n", cfgName);
+		return;
+	}
+	
+	while(fgets(line, sizeof(line), fp)) {
+		i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2);
+		if(i != 2)
+			continue;
+		
+		if(!strcmpi(w1,"mysql_reconnect_type")) {
+			mysql_reconnect_type = atoi(w2);
+			switch( mysql_reconnect_type ) {
+				case 1:
+				case 2:
+					break;
+				default:
+					ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type);
+					mysql_reconnect_type = 1;
+					break;
+			}
+		} else if(!strcmpi(w1,"mysql_reconnect_count")) {
+			mysql_reconnect_count = atoi(w2);
+			if( mysql_reconnect_count < 1 )
+				mysql_reconnect_count = 1;
+		} else if(!strcmpi(w1,"import"))
+			Sql_inter_server_read(w2,false);
+	}
+	fclose(fp);
+		
+	return;
+}
+
+void Sql_Init(void) {
+	Sql_inter_server_read("conf/inter_athena.conf",true);
+}

+ 1 - 0
src/common/sql.h

@@ -339,6 +339,7 @@ void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned lo
 /// Frees a SqlStmt returned by SqlStmt_Malloc.
 void SqlStmt_Free(SqlStmt* self);
 
+void Sql_Init(void);
 
 
 #endif /* _COMMON_SQL_H_ */