MySQL-Query + Verbindungsabriss: Kein Programmabsturz



  • Hallo.

    Ich habe heute mein erstes C++ Programm durch autonomes Lernen erstellt. Ich verwende G++ in Linux. Es soll ein Daemon werden, der ständig im Hintergrund läuft.

    Ich habe aber ein Problem mit den MySQL-Anfragen:
    Reist die MySQL-Verbindung während einer SQL-Anfrage ab, gibt es einen "Speicherzugriffsfehler in a.out" und das Programm terminiert - was bei einem Daemon natürlich niemals passieren darf.

    Ist die MySQL-Verbindung von anfang an fehlerhaft (z.B. wegen eines Auth-Fehlers), wird der Fehler erkannt und das Script wartet bis zum nächsten Durchlauf.

    Was habe ich falsch gemacht?

    MySQL wird wie folgt verwendet:

    void* neuer_durchlauf(void*) {
    	if (!pwb_mysql_connect()) {
    		std::cout << loghead() << "[ERROR] Could not connect to MySQL database." << ::std::endl;
    		return 0;
    	}
    
    	pwb_save_timestamp();
    
    	MYSQL_RES* result = NULL; // MySQL-Result
    	MYSQL_ROW row; // MySQL-Zeile
    
    	result = _mysql_query("SELECT `...` FROM `...` WHERE `active` = '1'");
    
    	if (result != NULL) {
    		if (mysql_num_rows(result) > 0) {
    			while (row = mysql_fetch_row(result)) {
    				//row[0];
    			}
    		}
    	}
    
    	pwb_mysql_disconnect();
    }
    

    (Hoffentlich alle) verwendeten Funktionen:

    //********************************************************************************************
    //
    // PChar
    //
    // Wandelt einen String in einen Char-Array um
    
    char* PChar(string text) {
    	char* tmp = strdup(text.c_str());
    	return tmp;
    }
    
    //********************************************************************************************
    //
    // _mysql_checkerror
    //
    // Gibt einen evtl. vorhandenen mySQL-Fehler aus
    
    bool _mysql_checkerror() {
       if (mysql_errno(my) != 0) {
          if (verbose >= VERBOSE_LEVEL_ERROR) std::cout << loghead() << "[ERROR] MySQL error occured: '" << mysql_error(my) << "'" << ::std::endl;
    	  return false;
       }
       return true;
    }
    
    //********************************************************************************************
    //
    // _mysql_query
    //
    // Verkürzte Variante von mysql_real_query mit
    // den gleichen Sicherheitsaspekten
    
    MYSQL_RES* _mysql_query(string query) {
    	if (verbose >= VERBOSE_LEVEL_DEBUG) std::cout << loghead() << "[DEBUG] Executing MySQL query: '" << query << "'" << ::std::endl;
    	mysql_real_query(my, PChar(query), strlen(PChar(query)));
    	if (_mysql_checkerror()) // Ist ein Fehler aufgetreten?
    	{
    		// Kein Fehler aufgetreten
    		return mysql_store_result(my);
    	} else return NULL;
    }
    
    //********************************************************************************************
    //
    // pwb_mysql_connect
    //
    // Stellt die Verbindung zur Personal WebBase Portaldatenbank her
    
    bool pwb_mysql_connect(void) {
    
    	my = mysql_init(NULL);
    
    	if(my == NULL) return false;
    
    	if (mysql_real_connect(my, MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, 0, "/var/run/mysqld/mysqld.sock", 0) == NULL) return false;
    
    	return true;
    }
    
    //********************************************************************************************
    //
    // pwb_mysql_disconnect
    //
    // Trennt die Verbindung zur Personal WebBase Portaldatenbank wieder
    
    void pwb_mysql_disconnect(void) {
    	mysql_close (my);
    }
    

    Gruß
    blackdrake



  • Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Linux/Unix in das Forum Datenbanken verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • was dein problem ist, kann ich dir leider nicht sagen. ich hätte aber zwei tipps:

    - deine PChar funktion erzeugt recht große speicherlecks, da du strdup verwendest, ohne das dublikat freizugeben. im endeffekt ist diese funktion aber auch unnötig. alternativ zu deiner version kannst du mysql_real_query so aufrufen:

    mysql_real_query(my, query.c_str(), query.length());
    

    - probier mal valgrind aus, um dein problem zu finden. das programm sollte sowieso standardmäßig bei jeder entwicklung verwendet werden. installier es aber am besten über deine distribution.



  • IMO solltest du als erstes feststellen wo das programm denn genau crasht, welche Zeile, welche Funktion.
    Wenn du weisst wo ist die nächste Frage warum.
    Dann hast du normalerweise den Fehler gefunden.
    Ob du ihn einfach beheben kannst oder nicht, hängt dann davon ab, ob der Fehler in deinem Code begründet ist, oder in einem Code-Stück auf das du keinen Einfluss hast (z.B. der MySQL Library die du verwendest).



  • Hallo.

    Ich werde mal versuchen, das Speicherleck in PChar() zu beheben. Bin dort leider sehr unerfahren.

    Einen MySQL-Verbindungsabriss _während_ einer Query hinzubekommen ist extrem schwierig zu reproduzieren. Ich hatte das Glück, dass es einmal passiert ist. Bei einem Daemon muss man aber jeden Fall abprüfen.

    Ich weiß nicht, WO der Fehler aufgetreten ist. Ich erhielt von der MySQL-Query-Funktion meine erzeugte Fehlermeldung mit dem MySQL-Fehler "Connection lost", danach kam einfach nur "Speicherzugriffsfehler in a.out", mehr nicht. Ich muss scheinbar bei Fetch-Row oder der MySQL-Query diverse Fehlerfälle abfangen, damit ein Verbindungsabriss egal an welcher Stelle keine Access-Violation-Exception erzeugt. Kann mir jemand helfen?

    Gruß
    blackdrake



  • Ich habe das Problem mit PChar gelöst und überall string.c_str() durchgesetzt.

    Die Speicherzugriffsfehler entstehen nicht, wenn die MySQL-Verbindung abbricht sondern kamen durch einen asynchronen Funktionsaufruf zu stande.

    mysql_connect();

    async_function_call(...);

    mysql_close();

    --> Fehler, da mysql_close() den MySQL-Zeiger auf NULL setzt und ein evtl. noch nicht beendeter asynchroner Funktionsaufruf dann auf NULL zugreift - das löste den Fehler aus.

    Jetzt passiert folgendes, wenn die Verbingung abbricht:

    Sun Jan 25 22:11:10 2009 - PWB Promoter: [ERROR] MySQL error occured: 'MySQL server has gone away'
    Sun Jan 25 22:11:10 2009 - PWB Promoter: [DEBUG] Run ended
    

    Den Fehler kann man dann abfangen und erneut versuchen, eine Verbindung aufzubauen.



  • mich wundert, dass dir die verbindungen derart oft abbrechen. das ist sehr ungewöhnlich. vielleicht solltest du sehen, dass die verbindung nicht andauernd abbrechen.



  • Vielleicht gehört er auch zu den Programmierern die sogar hin und wieder mal Corner-Cases testen, und andere sollten sich ein Beispiel nehmen. Vielleicht ist er auch durch Zufall draufgekommen, und hatte dann so ein schlechtes Gewissen, dass er es fixen wollte.

    Vielleicht ist aber auch ganz egal wieso er dahintergekommen ist, und nur wichtig, dass es ein Fehler ist, denn man definitiv nicht ignorieren sollte. Vielleicht bist du aber auch anderer Meinung, und schreibst gern Programme die nur meistens funktionieren. Vielleicht würde ich dich dann aber für ne Doofnuss halten.


Anmelden zum Antworten