GTAOnline.net
San Andreas Multiplayer (sa:mp) => Scripting SA-MP [Pawn center] => Discussion démarrée par: Jeffreeeey le 06 Avril 2010, 16:20:14
-
Bonjour / Bonsoir. Est-il possible que dans samp une variable d'une de mes tables Mysql prenne une variable pour aucune raison ? Mes joueurs ce retrouve avec des variables qui devraient ce trouvé a "0" alors qu'elle se trouve a "1". Normal ?
-
Oui, c'est tout à fait normal, le plugin MySQL que l'on trouve sur SAMP est bugué, il n'est pas ré entrant et ne permet donc pas de faire plusieurs requêtes à la fois.
En pratique, lorsque l'on fait une requête, le plugin stocke le résultat dans une variable temporaire unique jusqu'à ce qu'on est fini de la lire en entier. Si pendant cette lecture, on fait une autre requête, le premier résultat est écrasé par celui de la seconde requête (il est donc perdu) et si on continue à le lire (le premier résultat) on va lire des données du second résultat. Ce qui peut provoqué des effets inattendus
Les solutions :
1) On protège par un sémaphore les accès à la base de donnée (en utilisant un variable globale du script).
C'est la solution la plus facile à mettre en œuvre mais une seule requête ne peut être exécuté à la fois ce qui à pour effet de ralentir le script.
2) On ré-écrit (ou corrige) le plugin MySQL pour qu'il devienne ré entrant. C'est ce que j'ai fait pour le serveur Lalu's Stunt car j'avais constaté ce genre de problème. C'est la meilleure solution mais elle n'est pas forcément facile à faire.
Pour la correction : chaque résultat de requête est associé à un ID unique, et c'est cet ID qui permet de gérer plusieurs résultats en même temps. Il faut donc faire en sorte que le script puisse récupérer cet ID pour être sur que l'on travaille bien que le bon résultat et non sur celui d'une autre requête.
NB : De plus, ce plugin contient aussi de nombreux bugs de fuite de mémoire qui à long terme vont dégrader les performances du serveur voire le faire planter. Il est important de les corriger aussi.
++
Syg
-
Existe t-il un plugins mysql débugé ?
J'utilise le plugins Mysql V 0.12 http://forum.sa-mp.com/index.php?topic=23931.0 (http://forum.sa-mp.com/index.php?topic=23931.0) Celui-ci.
Je pense que je vais tenter d'esseyer là 0.15. Merci.
Elle déconne un peu, bon je pense rester à la V.0.12
EDIT : Quelqun aurait un bon plugin mysql ?
-
C'est exactement de ce plugin là dont je parle dans mon post précédent (d'ailleurs, à ma connaissance, c'est le seul).
Et quelle que soit la version, il est bugué (même si la version 0.12 est mieux que la 0.15).
Et je ne pense pas qu'il existe une version debuguée de ce plugin (à part chez GtaOnline mais je n'ai pas le droit moral de la donner).
Par contre, je t'ai donné deux solutions et la première est du niveau de n'importe quel scripteur PAWN.
++
Syg
-
ou avez vous la source de ce plugins que j'y jette mes doigt dedans xD
Trouver je doit modder qu'elle fichier ou avec qu'elle logiciel ??
Compilateur: Default compiler
Building Makefile: "C:\Documents and Settings\christophe\Bureau\samp-mysql-lite\samp-mysql-win32\src\Makefile.win"
Exécution de make...
make.exe -f "C:\Documents and Settings\christophe\Bureau\samp-mysql-lite\samp-mysql-win32\src\Makefile.win" all
g++.exe -c sampmysql.cpp -o sampmysql.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -DBUILDING_DLL=1
sampmysql.cpp:28:25: mysql/mysql.h: No such file or directory
sampmysql.cpp:45: error: ISO C++ forbids declaration of `MYSQL_FIELD' with no type
sampmysql.cpp:45: error: expected `;' before '*' token
sampmysql.cpp:46: error: `MYSQL_ROW' does not name a type
sampmysql.cpp:52: error: `MYSQL' does not name a type
sampmysql.cpp:53: error: expected constructor, destructor, or type conversion before '*' token
sampmysql.cpp:53: error: expected `,' or `;' before '*' token
sampmysql.cpp: In function `cell n_samp_mysql_connect(AMX*, cell*)':
sampmysql.cpp:91: error: `connexion' undeclared (first use this function)
sampmysql.cpp:91: error: (Each undeclared identifier is reported only once for each function it appears in.)
sampmysql.cpp:91: error: `mysql_init' undeclared (first use this function)
sampmysql.cpp:104: error: `mysql_real_connect' undeclared (first use this function)
sampmysql.cpp:116: error: `mysql_error' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_select_db(AMX*, cell*)':
sampmysql.cpp:133: error: `connexion' undeclared (first use this function)
sampmysql.cpp:133: error: `mysql_select_db' undeclared (first use this function)
sampmysql.cpp:141: error: `mysql_error' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_query(AMX*, cell*)':
sampmysql.cpp:152: error: `result' undeclared (first use this function)
sampmysql.cpp:154: error: `mysql_free_result' undeclared (first use this function)
sampmysql.cpp:160: error: `connexion' undeclared (first use this function)
sampmysql.cpp:160: error: `mysql_query' undeclared (first use this function)
sampmysql.cpp:168: error: `mysql_error' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_store_result(AMX*, cell*)':
sampmysql.cpp:179: error: `result' undeclared (first use this function)
sampmysql.cpp:179: error: `connexion' undeclared (first use this function)
sampmysql.cpp:179: error: `mysql_store_result' undeclared (first use this function)
sampmysql.cpp:186: error: `mysql_error' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_fetch_row(AMX*, cell*)':
sampmysql.cpp:196: error: `MYSQL_ROW' undeclared (first use this function)
sampmysql.cpp:196: error: expected `;' before "rowtoreturn"
sampmysql.cpp:204: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:208: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:210: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:213: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:214: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:215: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:216: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:217: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:218: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:219: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:220: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:222: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:224: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:225: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:228: error: `result' undeclared (first use this function)
sampmysql.cpp:228: error: `mysql_num_fields' undeclared (first use this function)
sampmysql.cpp:229: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:229: error: `mysql_fetch_row' undeclared (first use this function)
sampmysql.cpp:230: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:230: error: `mysql_fetch_fields' undeclared (first use this function)
sampmysql.cpp:231: error: `mysql_fetch_lengths' undeclared (first use this function)
sampmysql.cpp:232: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:244: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:252: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:276: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:279: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:280: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:281: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:282: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:283: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:284: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:285: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:286: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:288: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp: In function `cell n_samp_mysql_get_field(AMX*, cell*)':
sampmysql.cpp:306: error: 'struct assoc_array' has no member named 'fields'
sampmysql.cpp:308: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:310: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp:311: error: 'struct assoc_array' has no member named 'row'
sampmysql.cpp: In function `cell n_samp_mysql_num_rows(AMX*, cell*)':
sampmysql.cpp:344: error: `result' undeclared (first use this function)
sampmysql.cpp:344: error: `mysql_num_rows' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_num_fields(AMX*, cell*)':
sampmysql.cpp:354: error: `result' undeclared (first use this function)
sampmysql.cpp:354: error: `mysql_num_fields' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_ping(AMX*, cell*)':
sampmysql.cpp:364: error: `connexion' undeclared (first use this function)
sampmysql.cpp:364: error: `mysql_ping' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_real_escape_string(AMX*, cell*)':
sampmysql.cpp:390: error: `connexion' undeclared (first use this function)
sampmysql.cpp:390: error: `mysql_real_escape_string' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_free_result(AMX*, cell*)':
sampmysql.cpp:403: error: `result' undeclared (first use this function)
sampmysql.cpp:403: error: `mysql_free_result' undeclared (first use this function)
sampmysql.cpp: In function `cell n_samp_mysql_close(AMX*, cell*)':
sampmysql.cpp:455: error: `connexion' undeclared (first use this function)
sampmysql.cpp:455: error: `mysql_close' undeclared (first use this function)
make.exe: *** [sampmysql.o] Error 1
Exécution terminée
ptdr il est autant bugger
-
Donc la première solution consiste a faire une seul requette a la fois ? C'est ça ?
-
Oui, c'est ça Jeffreeeey.
Cristab : tu n'as pas installé le package de développement MySQL pour Dev C++ (qui est normalement fourni dans l'archive du plugin) et donc le compilateur ne trouve pas mysql.h.
Sinon, pour la modification, il n'y qu'un seul fichier source : sampmysql.cpp (en fait il y en a deux, un pour Windows et un pour Linux).
++
Syg
-
Ah j'ai eu la même erreur en compilant en gcc sous mon linux. Bon je vais faire ce que tu m'a dit merci.
EDIT : Donc je dispose des fichiers sources, mais j'ai un truc a installer sous linux, un fichier .deb et un fichier .rpm. Je suis sous linux ubuntu, J'installe les deux ou un seul ?
-
Sous Ubuntu, il faut installer le .deb (de toutes façons, tu auras une erreur si tu essaies le .rpm).
++
Syg
-
Je tombe sous une erreur.
root # dpkg -i libmysqlclient15-dev_5.0.21-3ubuntu1_i386.deb
(Reading database ... 25489 files and directories currently installed.)
Preparing to replace libmysqlclient15-dev 5.0.21-3ubuntu1 (using libmysqlclient15-dev_5.0.21-3ubuntu1_i386.deb) ...
Unpacking replacement libmysqlclient15-dev ...
dpkg: dependency problems prevent configuration of libmysqlclient15-dev:
libmysqlclient15-dev depends on zlib1g-dev; however:
Package zlib1g-dev is not installed.
dpkg: error processing libmysqlclient15-dev (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
libmysqlclient15-dev
zlib1g-dev est pas installé apparament. Malheureusement j'ai tenté apt-get install, mais il existe pas. Une solution pour l'installer ?
-
Sur la machine Ubuntu où j'ai installé le package MySql, l'installation de zlib1g-dev s'est faîte automatiquement.
Je ne connais pas assez Linux pour t'aider plus mais tu devrait certainement pouvoir trouver ce package (zlib1g-dev) sur le net.
++
Syg
-
hug ^^
Merci pour l'info c'est le premier plugins que je regarde xD et je ne savait pas je penser que tout les pakage s'installer a l'installation xD
-
Toujours des variables qui se mete a zero. Conseiller moi un plugin Plz :angelnot
-
tente celui ci meme si je doute que le resultat change http://forum.sa-mp.com/index.php?topic=79352.0 (http://forum.sa-mp.com/index.php?topic=79352.0)
-
Je crois ne pas avoir compris. Comment deux requettes peuvent être envoyé en même temp. Par exemple il y a une requette qui est envoyé et qui va duré 2 sec et durant ces deux secondes une autre requette va être envoyé ? C'est ça qu'il faut pas que sa se passe.
-
Tout à fait Jeff.
Il faut donc trouver un mécanisme pour retarder la retarder la deuxième tant que la première n'est pas finie.
Ce qu'il faut avoir en tête c'est que SAMP est événementiel (le script est exécuté en fonction des événements qui se produisent sur le serveur et les différents clients) et que donc il est très courant que deux événements arrivent en même temps. Si ces deux événements font chacun une requête SQL, il y a fort à parier que l'une des deux aura un résultat erroné.
++
Syg
-
Donc j'abandonne le mysql ? et je repasse aux fichiers ? J'ai peur de faire une erreur que je regretterais plus tard.
-
En mettant un timer au login ça peut résoudre ?
-
Non c'est pas là le problème car dés que tu te déconnecte il peut y avoir a tout moment une autre requette SQL et c'est pour ça que la variable Argent ce remet a zero :/
-
Oui Jeff c'est exactement ça le problème.
Et pour éviter que 2 requêtes se fasse en même temps, il faut utiliser un sémaphore (ou mutex=Mutual Exclusive).
Il est très facile de faire un sémaphore acceptable en PAWN, il suffit d'un variable et de deux fonctions :
new MonSemaphore = 0;
PrendreSemaphore ()
{
/* Tant que le sémaphore n'est pas libre */
while (Semaphore != 0); // Prendra 100 % d'un CPU tant que Semaphore ne vaudra pas 0
/* On prend le sémaphore */
Semaphore = 1;
}
LibererSemaphore ()
{
Semaphore = 0;
}
Ensuite, il faut appeler PrendreSemaphore avant chaque requête et LibererSemaphore après que le résultat de la requête a été utilisé.
Attention toutefois, avec un sémaphore, si on code de travers, il est possible que le serveur reste bloqué à jamais (dead lock). Notamment dans le cas où on oublie de libérer le sémaphore.
De plus, la fonction PrendreSemaphore va consommer 100 % du CPU tant que le sémaphore ne sera pas libre (=0). C'est moyennement grave sur les machine avec plusieurs cœurs (ou plusieurs CPU) mais il ne faut surtout pas le faire sur une machine avec un seul processeur.
Autre inconvénient, les requêtes sont exécutées les unes après les autres et si, par exemple, 4 joueurs se connectent en même temps, le 4° risque d'attendre plus longtemps que prévu.
++
Syg
-
Je suis desoler de remonter post. Mais que veut dire "si on code de travers" ?
Et franchement je vois pas comment fonctionne ton code, enfaite je vois rien qui dit de faire patienter la requette en attendant la fin de l'autre requette.
-
Mon code est très simple :
Juste avant une requête SQL, tu appelles PrendreSemaphore ().
Et juste après avoir fini d'utiliser le résultat de la requête, tu appelles LibererSemaphore ().
La fonction PrendreSemaphore ne te rendra la main que lorsque la variable MonSemaphore sera à 0 (à cause du while). Donc si une autre requête est en cours, toutes les autres requêtes seront suspendues.
Quand je dit "coder de travers", je veux dire que si on oublie un seul LibererSemaphore, toutes les requêtes seront suspendue (car MonSemaphore ne reprendra jamais la valeur 0) et donc ton script ne fonctionnera plus.
Il y a d'ailleurs une grosse erreur dans mon bout de script (fait vite fait sur le forum) :
new MonSemaphore = 0;devrait être
new Semaphore = 0;
++
Syg