mmofacts.com

Ungewollt Doppelt ....

gepostet vor 17 Jahre, 8 Monate von Makconner
Hallo, ich habe ein doch recht großes Problem und hoffe das einer was gutes dazu sagen kann...
Damit ich das nicht in jedem Forum neu schreibe hier der Direktlink...
Ich hoffe das das OK ist...
www.apachefriends.org/f/viewtopic.php?t=23578
Bitte um Hilfe
gepostet vor 17 Jahre, 8 Monate von Drezil
erstmal klassische race-conditions ... (nachzulesen auch unter dem theme nebenläufigkeit .. gibt tonnen von material, u.a. auch in der wikipedia)
frage: was passiert, wenn $_GET['Apfel'] == 'id' ist?
wenn du verstanden hast, was race-coditions sind, dann schau dir mal "lock table" resp. "begin transaction"/"commit"/"rollback" (sofern du innodb-tabellen nutzt) in der mysql-doku an.
Locking allgemein (myisam, denke ich): dev.mysql.com/doc/refman/5.1/en/locking-issues.html
InnoDB: dev.mysql.com/doc/refman/5.1/en/innodb.html
InnoDB Transaktionen + Locking: dev.mysql.com/doc/refman/5.1/en/innodb-transaction-model.html
gepostet vor 17 Jahre, 8 Monate von Makconner
Ok..
WIKI zu Race Condition:
Unbeabsichtigte Wettlaufsituationen sind ein häufiger Grund für schwer auffindbare Programmfehler; bezeichnend für solche Situationen ist nämlich, dass bereits die veränderten Bedingungen zum Programmtest zu einem völligen Verschwinden der Symptome führen können.
0 Punkte für den Kandidaten... sofern er das meinte... denn es wird nur von einer person ausgefürt... das bin ich... und die Bedigungen sind IMMER gleich...
Für weitere derartige Beiträge wäre es schön wenn du von deinem Hohen Ross etwas mehr Deutsch sprichst...
Danke
gepostet vor 17 Jahre, 8 Monate von tkdmatze
1. ich glaube mit besserer stuktur dadrin wäre das problem auch nicht so böse
abfrage 1:
UPDATE noma_account set Inge=Inge+30 where Inge>0 and id=Apfel;

wird intern umgewandelt in
(Pseudo-SQL)

tmp = SELECT * FROM noma_account where Inge>0
(schon ein paar lösungen)
tmp2 = SELECT * FROM tmp WHERE id=Apfel
(genau eine lösung, wenn id schlüsselattribut)
UPDATE tmp2 set Inge=Inge+30
richtiger und schöner wäre
UPDATE noma_account set Inge=Inge+30 where id=Apfel and Inge>0;

2. versuchst du eine fallunterscheidung in sql zu machen
dafür gibt es spezielle wörter, und bessere varianten
zB
UPDATE noma_account set Inge=Inge+IF(Inge>0,30,31) where  id=Apfel;

€: zügele mal deinen ton, er hatte völlig recht, schau dir punkt 1 bei mir an,
wenn du entsprechend mehr datensätze hast, wo (inge=0) gilt, als jene, wo es nicht gilt, liefert die erste abfrage im zwischenschritt mehr ergebnisse, bei denen es länger dauert diese zu bearbeiten, es kann also sein, das abfrage 2 schon fertig ist, während abfrage 1 noch arbeitet, und genau das ist eine race-condition
gepostet vor 17 Jahre, 8 Monate von Teonas
Irgendwie denke ich, das Problem ist noch nicht ausreichend klar (zumindest mir).
Das Skript enthält 3 SQL-Updates - werden alle 3 doppelt ausgeführt oder nur eins? Letzteres halte ich für unwahrscheinlich. Wenn ersteres der Fall ist, würde ich mal im Req-Log des Servers schauen, ob zwei Requests vom Browser kommen.
Wenn ja, mutex für den User oder die Session setzen (ich hab keine Ahnung von Php, deshalb sollte das bei Interesse ein anderer erklären - die Chance steht aber hoch, dass es schon erklärt wurde --> Suche ).
gepostet vor 17 Jahre, 8 Monate von Makconner
1. ich habe das Script nochmal voll zusammengestaucht... da ist kaum noch code. Schaut jetzt nochmal rein, eventuell is es dann klarer... und danke für die Tips mit der Fallunterscheidung
2. Es ist egal wie viele mysql anweisungen darin stehen... jede einzelne wird 2 mal ausgeführt
Danke für die Anteilnahme
gepostet vor 17 Jahre, 8 Monate von Todi42
Mir wird aus Deiner Meldung nicht ganz klar, ob Du aus dem Inhalt der Datenbank schließt, das das Skript zwei mal gelaufen ist (weil die SQL-Statments zwei mal ausgeführt scheinen), oder ob Du dem Inhalt des Logfile des Webservers entnimmst, das das Skript zwei mal ausgeführt wurde.
gepostet vor 17 Jahre, 8 Monate von Todi42
Was soll diese Zeitabfrage? Die erlaubt ja dann, das die Abfrage so häufig ausgeführt wird, wie der Client in der Lage ist, diese innerhalb der halben (im Mittel) Timer-Auflösung auszuführen. Sprich der FF ist evtl. schneller als der IE. Ist da irgend etwas auf dem Client, das die Anfrage doppelt senden kann, je nach Browser? Schon mal z.B. wget probiert und das auszuschließen?
gepostet vor 17 Jahre, 8 Monate von tkdmatze
das einige was mich wundert ist, dass firefox schuld sein soll
das prinzip von php ist doch folgendes
-irgendwo sitzt ein user und stellt eine anfrage an einen server
-der server erstellt gemäss den php-vorgaben eine html-seite und liefert die zurück
-dabei ist doch unerheblich, welchen browser man besitzt
2. Es ist egal wie viele mysql anweisungen darin stehen... jede einzelne wird 2 mal ausgeführt

bei der dritten wirds sehr schwer zu beweisen sein
und nun nenn mal fakten
PHP-version, mysql-version, testdaten und testergebnisse
wenn aus inge = 0 inge = 61 wird, ist es höchstwahrscheinlich das angesprochene problem, nur warum der IE es richtig ausspuckt ist komisch
€:@Todi
das hab ich gleich komplett igniert, weil ich nicht verstanden habe was das dort zu suchen hat
gepostet vor 17 Jahre, 8 Monate von blum
Wenn Du sagst, dass nur der FF den Code 2mal ausführt und der IE nicht, liegt es sicher nicht am SQL-Code. Denn dahin kommt der Browser nicht.
Also muss der Fehler woanders liegen, wird die Datei vielleicht 2mal inkludiert, hast du irgendwelche Header-redirects drin etc?
Wie rufst Du die Seite auf, über ein Formular, AJAX-Request?
Hast du irgendwelche Addons im FF geladen, so dass der Fehler nur bei Deinem FF auftaucht?
Fragen über Fragen.
gepostet vor 17 Jahre, 8 Monate von TBT
Hackt doch nicht auf irgendwelchen nicht vorhandenen Race Konditions rum,
wenn die Lösung doch so einfach ist. Es ist ganz einfach ein Preload vom Firefox.
Mach aus deinem Link (GET) einen kleinen Button( POST) und das Problem ist weg.
Das selbe Phänomen ist beim Konqueror zu beobachten.
gepostet vor 17 Jahre, 8 Monate von Makconner
Ok nochmal...
1. Fakt ist... das Bild im Browser wird nur ein mal angezeigt.. also keine doppelte Rückmeldung an dem Browser
2. Fakt ist... das man das nicht abfangen kann, hab ich versucht mit mehreren Sachen... also das hat nix mit dem Script zu tun... denn das wird nur ein mal ausgeführt.
3. Fakt ist... das Problem taucht bei Firefox auf aber bei IE nicht
4. Fakt ist ... die (EXAKT) selbe mysql Anweisung wird bei einer zweiten Anfrage an den Server nur noch EIN mal ausgeführt (als ob der sich das merkt)
5. Fakt ist ... das dieses Problem von vielen Usern beschrieben wird.. also nicht von meinem Rechner abhängt und alle diese Leute nutzen FF (hat eine Umfrage ergeben)
6. Fakt ist... das ich diesen kleinen Scriptteil selektiert habe und dieser ausreicht das Problem zu verursachen, demnach es nicht im übrigen programm zu suchen ist und es nun andem Script oder dem mysql-Server liegt....(Server von Strato... standart VServer)
gepostet vor 17 Jahre, 8 Monate von Teonas
Original von Makconner
1. Fakt ist... das Bild im Browser wird nur ein mal angezeigt.. also keine doppelte Rückmeldung an dem Browser

Ich bin jetzt weder intimer Freund noch Kenner des FF, aber dass da mal (vermutlich ab Version 2.0) was von Preloading im Gespräch war, kann ich mich auch erinnern - der Browser parst ausgehende Links und läd Content (Bilder etc.) vor, um dann beim Klick schneller Ergebnisse liefern zu können. Würde für mich das Verhalten logisch erklären (und ich hab schon in die Richtung vermutet). Die Widerlegung per POST oder Daten aus den Logs bleibst du uns bisher schuldig.
2. Fakt ist... das man das nicht abfangen kann, hab ich versucht mit mehreren Sachen... also das hat nix mit dem Script zu tun... denn das wird nur ein mal ausgeführt.

Den Absatz kannst du dir sparen, wenn man dir helfen soll - du sagst damit, du hast ALLES probiert - also kann man dir nicht helfen...
4. Fakt ist ... die (EXAKT) selbe mysql Anweisung wird bei einer zweiten Anfrage an den Server nur noch EIN mal ausgeführt (als ob der sich das merkt)

Naja, o.g. Preloading ist nur einmal nötig, wenn der Browser die URLs cacht...
gepostet vor 17 Jahre, 8 Monate von Drezil
Original von Makconner
Ok..
WIKI zu Race Condition:
Unbeabsichtigte Wettlaufsituationen sind ein häufiger Grund für schwer auffindbare Programmfehler; bezeichnend für solche Situationen ist nämlich, dass bereits die veränderten Bedingungen zum Programmtest zu einem völligen Verschwinden der Symptome führen können.
0 Punkte für den Kandidaten... sofern er das meinte... denn es wird nur von einer person ausgefürt... das bin ich... und die Bedigungen sind IMMER gleich...
Für weitere derartige Beiträge wäre es schön wenn du von deinem Hohen Ross etwas mehr Deutsch sprichst...
Danke

du scheinst es nicht verstanden zu haben..
wenn du sagst, im ie geht es, im ff nicht, dann veränderst du die testbedingungen.
desweiteren kann ich bei dir keine art eines lockings feststellen.
sollte der ff aus IRGENDEINEM grund (sei es chaching, prefetching oder was auch immer ..) die anfrage 2x senden, dann kommt es intern fast immer zu möglichen race-conditions .. (gerade auf v-servern ..)
was ist so schwer daran, da vorher mal ein mysql_query("lock table blah, bli blup");, dann die anweisungen und dann ein mysql_query("unlock tables"); zu machen?
wenn du dann keine probs mehr hast, könnte es das gewesen sein ..
aber nein .. statt sich die angegebene literatur in den links mal zu herzen zu nehmen, wird man hier gleich angepflaumt "auf seimen hohen ross" zu sitzen .. so macht das echt kein spass und die diskussion ist an dieser stelle für mich erledigt.
streitet euch weiter, ich habe gesagt, was ich von diesem problem halte. wenn dies nicht erwünscht ist/war, dann bitte ich das zu verzeihen und werde euch nicht weiter belästigen ..
gepostet vor 17 Jahre, 8 Monate von Teonas
Original von Drezil
sollte der ff aus IRGENDEINEM grund (sei es chaching, prefetching oder was auch immer ..) die anfrage 2x senden, dann kommt es intern fast immer zu möglichen race-conditions .. (gerade auf v-servern ..)
was ist so schwer daran, da vorher mal ein mysql_query("lock table blah, bli blup");, dann die anweisungen und dann ein mysql_query("unlock tables"); zu machen?

Drezil, ich sehe aber dennoch nicht, wie deine Beiträge das Thema lösen sollen. Du hast mit dem Lock die Requests schön serialisiert und dann trotzdem zweimal ausgeführt.
gepostet vor 17 Jahre, 8 Monate von Nuky
womit teonas recht hat
mak: das mit dem preloading klingt mir bis jetzt am interessantesten, ich würde das weiterverfolgen.
jm2c!
gepostet vor 17 Jahre, 8 Monate von Drezil
stimmt..
da bräuchte man z.b. ein update-flag. notfalls kann man es auch über file-locks lösen ..
ich kenn den genauen kontext der statements nicht.
am einfachsten wäre sicherlich ein flock zu holen, die datei zu prüfen, alles qrys ausführen, dann z.b. einen unix-timstamp in den file-deskriptor reinballern, und die dalei wieder releasen ..
die datei "prüfen" meint da z.b. sicherzigehen, dass z.b. der unix-timestame > 10 sec ist o.ä.
(ich weiss ist eine quick & dirty-lösung .. aber ich habe ihn so verstanden, dass er das ohnehin nur in einzelaktionen per hand aufrufen will) ..
wenns im produktivbetrieb ist, dann solltem man den ts z.b in einer db-spalte speichern .. ein "update bla where unix < unix_timestamp()" sorgt dann z.b. dafür, dass derselbe datensatz nur 1x/sec upgedated werden kann.. ob das sinnvoll ist oder nicht noch zu anderern problemen führt hägt von der implementation ab ..
allgemein bleibt mir der generelle sinn der o.g. statements verschlossen. bei mir hängt im where immer ein pk drin ..
--
außerdem sollte eine serialisierung reihchen .. ich mache doch nicht "auf gutdünken" ein update .. vorher ist für mich eine prüfung, ob das update überhaupt sinnig ist, pflicht.
und wenn der vorgang dann serialisiert ist, dann liefert z.b. ein vorheriges select keine treffer und so werden auch keine updates getriggert ..
$0.02
gepostet vor 17 Jahre, 8 Monate von Teonas
Schöne Skizze - wir kennen die Details allerdings nicht (und der Code verwendet IMO kreatives Foo-bar), so dass simples POST auch schon reichen könnte...
gepostet vor 17 Jahre, 8 Monate von Todi42
Ich würde auch einiges Wetten, das TBT das Problem erkannt hat und die Lösung ist natürlich, ein POST zu nehmen. Mit einer richtigen Datenbank braucht kein Mensch irgend welche Locks.
gepostet vor 17 Jahre, 8 Monate von Agmemon
Jeder Rails-Programmierer kennt folgende Code-Zeilen, die automatisch in jede Controller-Klasse eingefügt werden:

# GETs should be safe (see www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, nly => [ :destroy, :create, :update ]
Auf deutsch heißt das: Führe niemals Anweisungen, welche Daten ändern, wenn die Anfrage per GET kommt. Leider gibt es für PHP keine Direktive, die dies automatisch prüft. TBT hat mit seiner Vermutung also recht.
P.S.: Wann ist endlich dieser flock()-Ansatz aus den Köpfen der BG-Programmierer zu bekommen? Pessimistic Locking ist nicht für webbasierte Anwendungen geeignete und wird in der Literatur auch immer wieder transportiert.
gepostet vor 17 Jahre, 8 Monate von knalli
Bezgl. nur FF, kein IE: So ein ähnliches Problem hatte ich auch mal; zwar in einer Multiuserumgebung, aber scheinbar ähnlich. Problem war/ist Preloading des Firefox, ggg. verbunden mit einer Headerabfrage, die wohl den Server dazu veranlasst, das Script auszuführen :/
gepostet vor 17 Jahre, 8 Monate von Störti
Ich hatte das gleiche Problem, ebenfalls nur im FF.
Damals hatte ich provisorisch ein Bild in die Seite eingebaut, das src-Attribut war allerdings leer (Templatevariable noch nicht gefüllt). Das Ergebnis war, dass der FF diesen leeren Verweis relativ zur aktuellen Seite interpretiert hat und die Seite im Hintergrund einfach noch einmal aufgerufen hat, inkl. sämtlicher eventueller GET-Variablen.
Der IE und Opera haben durch das leere Attribut das Bild einfach als fehlend gekennzeichnet.
gepostet vor 17 Jahre, 8 Monate von knalli
Ganz vergessen: Das Verhalten trat aber auch erst auf (damals war das Fx 1.5, soweit ich mich erinnere) , nachdem ich irgendso eine schöne Optimierung aktiviert hatte. Entweder manuell, oder über diese Tools.

Auf diese Diskussion antworten