Racecondition, die faule Ausrede
Geschehen eigentlich unmögliche Dinge in einem komplexen System, so schiebt man die Schuld gern auf Raceconditions. Bei Raceconditions kann praktisch alles geschehen. Alles? Nein, auch in solchen Fällen muß das Ergebnis logisch konsistent sein.
Kürzlich trat ein Verhalten an einem produktiven System auf, das völlig unerklärlich schien. Es konnte gezeigt werden, daß das Verhalten zum Zeitpunkt einer mißlungenen Synchonisation konkurrierender Ereignisse auftrat. Was lag also näher als die beobachteten Phänomene diesem Programmierfehler zuzuschreiben?
Menschen sind faul und neigen zur Monokausalität. Nur Wenige haben den unstillbaren Drang, den Dingen wirklich auf den Grund zu gehen. Viel zu oft werden solche Personen als anstrengend oder krank eingestuft, obwohl Sie ungewöhnliche Fähigkeiten aufweisen. Aber genau diese Gründlichkeit war jetzt gefragt.
Wie konnte das nur geschehen?
In dem konkreten Fall sollte die fehlerhafte Konfigurationsdatei das Muster "ABCD" enhalten, wobei die Buchstaben für längere Zeichenketten stehen. Tatsächlich fand sich aber das Muster "ABBDACD". Ganz offensichtlich haben zwei Prozesse parallel und überlapped geschrieben.
Im Bewustsein, in konkurrierenden Umgebungen laufen zu müssen, wurden auch bereits mehrere Vorkehrungen getroffen:
- Die Datei wird linear gelesen, verarbeitet und linear geschrieben.
- Die neue Datei wird atomar angelegt. Dieser Prozeß liefert gleichzeitig das Locking.
- Die aktive Datei wird atomar ersetzt. Alle Prozesse, die die Datei gerade benutzen, lesen also nur einen - in sich konsistenten - Stand.
Wie erklärt sich also das Muster "ABBDACD"?
- Es ist möglich, daß ein Prozeß, der in seine eigene Datei schreibt, nicht alle Daten schreiben kann. Das Fehlen von "C" kann einer unerkannten Blockade zum Opfer gefallen sein. Schreiben zwei Prozesse, so kann der Block überschrieben werden.
- Es ist nicht möglich, daß zwei Prozesse in die gleiche Datei schreiben. Dafür müßten sie die gleiche Datei anlegen. Dies wird aber von O_CREAT und O_EXCL verhindert.
- Es ist nicht möglich, daß ein Prozeß dieses Muster aus zwei verschiedenen Dateien liest. Die Umbenennung verhindert, daß sich der Inhalt der bereits offenen Datei ändert.
- Es ist nicht möglich, zwei Prozesse zeitlich so zu verschachteln, daß sich die Reihenfolge der Schreiboperationen umkehrt.
Alles zusammengenommen, kann der Fehler nicht von einer Racecondition verursacht worden sein.
Ist man soweit gekommen, die Euphorie über den schon gefundenen Fehler überstanden zu haben, so kann man endlich diesem Fehler auf den Grund gehen. Es stellte sich dabei heraus:
- Der Generator für die Konfiguration verläßt sich auf einen funktionierenden Parser.
- Der Parser verläßt sich auf eine maschinell erzeugte Datei und prüft nicht alle zulässigen Syntaxmöglichkeiten ab.
- Die Datei wurde außerplanmäßig manuell angefaßt und dabei die Struktur der Leerzeichen so verändert, daß der Parser durcheinander kam.
- Die Prüfprogramme für syntaktische Zulässigkeit der Dateien sind laxer als die darauf aufsetzenden Programme.
Konsequenzen
Menschen sind faul. Es wurde - neben der Fehlerbehebung des Parsers:
- eine Schnittstelle für manuelle Änderungen eingerichtet, die leichter zu benutzen ist, als die Dateien direkt zu editieren.
- das Prüfkonzept für Konfigurationen drastisch ausgeweitet. Eine Funktionalprüfung im Testsystem ist nun jederzeit und automatisiert möglich.
- Aufgrund der nun verfügbaren Funktionalprüfung kann bei Bedarf automatisch ein Rollback zu einem funktionierenden Stand durchgeführt werden.