Verlorene Updates
aus Wikipedia, der freien Enzyklopädie
Verlorenes Update (auch engl. Lost Update) bezeichnet in der Informatik einen Fehler, der bei mehreren parallelen Schreibzugriffen auf eine gemeinsam genutzte Information auftreten kann. Wenn zwei Transaktionen die selbe Information verändern, dann können die Änderungen der ersten sofort durch die Änderungen der zweiten überschrieben werden.
Dabei spielt es keine Rolle, ob die „gemeinsam genutzte Information“ in einer Datei, in einer Datenbanktabelle oder im Arbeitsspeicher steht.
Inhaltsverzeichnis |
[Bearbeiten] A: Lesen und Schreiben ohne Interaktion mit einem Benutzer
[Bearbeiten] Beispiel
Eine Kette von Vorverkaufsstellen speichert für jede Veranstaltung die Anzahl der verkauften Karten. Es wurden bereits 100 Karten verkauft, als an einer Kasse fünf Karten zurückgegeben werden. Zur gleichen Zeit werden an einer zweiten Kasse drei Karten gekauft. Das System der ersten Kasse zieht die 5 zurückgegebenen Karten von den 100 ab und schreibt den neuen Wert - 95 - wieder in die Datenbank. Das zweite Kassensystem addiert die drei soeben verkauften Karten zu der 100 dazu und schreibt diesen Wert (103) ebenfalls in die Datenbank. Der zuerst geschriebene Wert geht dabei verloren, das Endergebnis ist falsch (103 verkaufte Karten, obwohl es tatsächlich nur 98 sind).
Zeitpunkt | Programm 1
5 Karten zurücknehmen |
Gespeicherte Anzahl
verkaufter Karten |
Programm 2
3 Karten verkaufen |
---|---|---|---|
0 | 100 | ||
1 | Anzahl der verkauften Karten lesen
Ergebnis: 100 |
100 | |
2 | 100 | Anzahl der verkauften Karten lesen
Ergebnis: 100 |
|
3 | 5 Karten werden zurückgenommen
Neuen Wert berechnen: 100-5=95 Neuen Wert (95) schreiben |
95 | |
4 | 103 | 3 Karten werden verkauft
Neuen Wert berechnen: 100+3=103 Neuen Wert (103) schreiben |
[Bearbeiten] Welche Sperrmechanismen stehen zur Verfügung?
Bei der Ausführung des Lesezugriffs wird die gemeinsam genutzte Information gesperrt, damit ein zwischenzeitliches Abändern durch ein anderes Programm nicht möglich ist.
Die dafür benötigten Sperrmechanismen werden von den verschiedenen Datenverwaltungssystemen bereitgestellt:
- der Share-Lock ermöglicht beliebig vielen Transaktionen einen Lesezugriff.
- der Exclusiv-Lock ermöglicht nur einer einzigen Transaktion einen schreibenden Zugriff.
Diese Sperrmechanismen werden sowohl von den meisten Betriebssystemen und Datenbanken als auch von Buffer-Managern verwendet, um konkurrierende Zugriffe zu handhaben.
[Bearbeiten] Der Isolationlevel RR
Oft wird der Isolationlevel RR als die Lösung das Lost-Update-Problem genannt.
Die meisten RDBMS bieten verschiedene Isolationlevel an. RR bedeutet, dass ein Share-Lock bis zum Ende einer Transaktion bestehen bleibt und nicht (wie z.B. bei Isolationlevel CS ) direkt nach dem Lesezugriff wieder verschwindet.
Wenn man den Isolationlevel RR verwendet, dann muss man darauf achten, dass keine Deadlocks entstehen.
Das erste Programm schreibt einen Share-Lock, der nicht wieder entfernt wird. Das zweite Programm schreibt auch einen Share-Lock. Nun will das erste Programm den Share-Lock in einen Exclusiv-Lock umwandeln, doch das geht nicht, solange das zweite Programm noch seinen Share-Lock aufrechterhält. Etwas später will das zweite Programm ebenfalls seinen Share-Lock in einen Exclusiv-Lock umwandeln. Nun wartet jeder auf den anderen. Das ist die klassische Deadlock-Situation.
Zeitpunkt | Programm 1
5 Karten zurücknehmen |
Locks von
Prog. 1 |
Gespeicherte Anzahl
verkaufter Karten |
Locks von
Prog. 2 |
Programm 2
3 neue Karten verkaufen |
---|---|---|---|---|---|
0 | 100 | ||||
1 | Anzahl der verkauften Karten lesen
Ergebnis: 100 |
S-Lock
von P1 |
100 | ||
2 | S-Lock
von P1 |
100 | S-Lock
von P2 |
Anzahl der verkauften Karten lesen
Ergebnis: 100 |
|
3 | 5 Karten werden zurückgenommen
Neuen Wert berechnen: 100-5=95 Exclusive-Lock anfordern warten auf P2 |
S-Lock
von P1 |
100 | S-Lock
von P2 |
|
4 | warten auf P2 | S-Lock
von P1 |
100 | S-Lock
von P2 |
3 Karten werden verkauft
Neuen Wert berechnen: 100+3=103 Exclusive-Lock anfordern warten auf P1 |
5 | warten auf P2 | S-Lock
von P1 |
100 | S-Lock
von P2 |
warten auf P1 |
Nun kommt es darauf an, wie das RDBMS in so einem Fall reagiert. Einige RDBMS z.B. DB2 kann man so parametrisieren, dass eine Transaktion nur eine bestimmte Zeit auf gesperrte Ressourcen wartet. Wenn die Zeit verstrichen ist und die Ressource immer noch gesperrt ist, dann wird die Transaktion zurückgerollt und das Programm erhält eine Fehlermeldung (SQLCODE -911). Das wäre eine Lösung für das Problem, denn durch den Rollback z.B. der ersten Transaktion ist auch der Share-Lock entfernt worden und die zweite Transaktion bekommt nun den Exclusiv-Lock, auf den sie gewartet hat. Wenn im Programm der SQLCODE -911 gezielt abgefragt wird, dann kann das Programm in einem solchen Fall den Satz erneut lesen und erhält nun den Wert, den das andere Programm gerade geschrieben hat. So geht kein Update verloren.
Zeitpunkt | Programm 1
5 Karten zurücknehmen |
Locks von
Prog. 1 |
Gespeicherte Anzahl
verkaufter Karten |
Locks von
Prog. 2 |
Programm 2
3 neue Karten verkaufen |
---|---|---|---|---|---|
6 | SQLCODE -911
Rollback |
100 | S-Lock
von P2 |
warten auf P1 | |
7 | 103 | X-Lock
von P2 |
Neuen Wert (103) schreiben | ||
8 | Anzahl der verkauften Karten lesen
Share-Lock anfordern warten auf P2 |
103 | X-Lock
von P2 |
||
9 | Share-Lock anfordern
warten auf P2 |
103 | commit | ||
10 | Share-Lock erhalten
Anzahl der verkauften Karten lesen Ergebnis: 103 |
S-Lock
von P1 |
103 | ||
11 | 5 Karten werden zurückgenommen
Neuen Wert berechnen: 103-5=98 X-Lock anfordern Neuen Wert (98) schreiben |
X-Lock
von P1 |
98 | ||
12 | Commit | 98 |
Der zweite Versuch kann genauso wie der erste Versuch misslingen, weil inzwischen ein drittes Programm einen Share-Lock auf den Satz gelegt hat. Daher muss das Lesen und Schreiben im Programm in einer Schleife ausgeführt werden.
Nun kann man sich überlegen, ob die Schleife biliebig oft wiederholt werden soll, oder ob nach n Versuchen die Verarbeitung dann doch aufgegeben und mit einer Fehlermeldung beendet werden soll.
Schleife Select ... Neuen Wert berechnen Update ... if (sqlcode not in (0, -911)) return(FEHLER) Until (sqlcode = 0 or Anz_Schleifen_Durchlaeufe > n) if (sqlcode <> 0) return(FEHLER)
Falls das RDBMS im Fall eines Deadlock so lange wartet, bis ein Administrator eingreift, dann ist diese Variante keine gute Lösung.
[Bearbeiten] Verarbeitung serialisieren
Wenn das erste Programm die Information schon gleich beim Lese-Zugriff exclusiv sperrt, dann muss das zweite Programm schon mit seinem Lese-Zugriff warten. Sobald das erste Programm auch den Schreib-Zugriff ausgeführt hat und die Ressource wieder freigibt, kann das zweite Programm seine Verarbeitung fortsetzen. Diese Variante ist eine erzwungene Serialisierung der Verarbeitung.
Wenn die Information in einer Datei gespeichert wird, dann muss das Programm die Datei gleich zum Schreiben öffnen.
Wenn die Information in einer Datenbank-Tabelle gespeichert wird, dann kann der Satz z.B. durch einen CURSOR FOR UPDATE gelesen werden oder die gesamte Tabelle kann durch LOCK TABLE IN EXCLUSIVE MODE gesperrt werden.
[Bearbeiten] Lese- und Schreibzugriff atomisieren
Wenn zwischen dem Lesezugriff und dem Schreibzugriff keine weitere Verarbeitung erforderlich ist, dann kann man diese beiden Zugriffe auch zusammenfassen (Siehe Atomare Operation).
Bei einem RDBMS könnte der Zugriff für das Beispiel lauten:
update Tab set Anzahl_verkaufte_Karten = Anzahl_verkaufte_Karten + :Aktueller_Verkauf
Dadurch entfällt ein gesonderter Lese-Zugriff. Ein verlorener Update kann nicht mehr vorkommen.
[Bearbeiten] B: Lesen und Schreiben mit Interaktion mit einem Benutzer
In der Praxis kommt das „verlorener Update-Problem“ auch häufig in Verbindung mit Benutzer-Interaktionen vor. Damit ist gemeint, dass die gelesenen Informationen an den Benutzer ausgegeben werden und von ihm verändert werden können. Danach werden die geänderten Informationen zurückgeschrieben. Wenn ein anderer Benutzer die selben Informationen ändern will, dann kann es sein, dass die Änderungen des ersten Benutzers verloren gehen. Folgendes ist bei Benutzerinteraktion anders, als im Fall A:
- Lesen und Schreiben können nicht verschmolzen werden
- Lesen und Schreiben werden in den meisten Fällen als zwei unabhängige Transaktionen ausgeführt
- Es muss berücksichtigt werden, dass sich der Benutzer möglicherweise viel Zeit lässt mit der Eingabe (z.B. Mittagspause) Das bedeutet, dass viel Zeit zwischen Lesen und Schreiben vergehen kann.
- Während der Benutzerinteraktion kann die Verbindung abbrechen (Netzwerk-Problem, das Programm wird beendet)