Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Zuverlässigkeit und Recovery in der Segmentschicht

Ähnliche Präsentationen


Präsentation zum Thema: "Zuverlässigkeit und Recovery in der Segmentschicht"—  Präsentation transkript:

1 Zuverlässigkeit und Recovery in der Segmentschicht
Kapitel 4 Zuverlässigkeit und Recovery in der Segmentschicht

2 Transaktionen in der Architektur
Eine vom Benutzer als abgeschlossene Arbeitseinheit definierte Folge von Anfragen (Operatoren auf Mengen) Mengenorientiertes Datenmodell Anfragebearbeitung Satzorientiertes Datenmodell Satz- u. Satzmengenverwaltung Satzzugriffsstrukturen Zugriffsschicht Hauptspeicherseiten u. Segmente Scheduler Recovery-Verwalter Segment- u. Pufferverwaltung Dateien Dateiverwaltung Geräteschnittstelle

3 Architektur im Detail – 2. Schritt
Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Schedule 1 Schedule n Scheduler Sperren-Verwalter Konflikt-resistenter Gesamt-Schedule dieses Kapitel eigene Vorlesung Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Protokoll- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter Performanz Persistenz Fehler-Resistenz Protokoll- datei Daten- basis letztes Kapitel Recovery

4 Kapitel 4.1 Fehlermodell

5 Normalbetrieb Eine Operation auf Schicht i löst i.A. eine Folge von Operationen auf Schicht i-1 aus. Aus der letzten dieser (i-1)-Operationen wird der Endzustand der i-Operation über t konstruiert. 1-konsistenter Zustand s 1 (0) 2 (2) j (1) i p n+1 n m k op k-1 i-1 t 01 12 1-Operation Konstruktion 0-Operationen 0-konsistente Zustände

6 Gestörter Betrieb Kommt nicht zum erfolgreichen Ende Eine Operation auf Schicht i löst i.A. eine Folge von Operationen auf Schicht i-1 aus. Aus der letzten dieser (i-1)-Operationen wird der Endzustand der i-Operation über t konstruiert. Gilt also nicht mehr Letzter 1-konsistenter Zustand s 1 (0) 2 (2) j (1) i p n+1 n m k op k-1 i-1 t 01 12 1-Operation 0-Operationen Letzter 0-konsistenter Zustand

7 Recovery (1) Folge: Letzter konsistenter Zustand n wird aus einem (i-1) -konsistenten Zustand q durch Recoveryfunktionen i und i-1,i konstruiert: (i) (i-1) Letzter 1-konsistenter Zustand Kompensation s 1 (0) 2 (2) j (1) i p n+1 n m k op k-1 i-1 t 01 12 1-Operation Rekonstruktion 0-Operationen Kompensation r 1 Letzter 1-konsistenter 0-Zustand Letzter 0-konsistenter Zustand

8 Recovery (2) Kompensation i
Inverse Funktionen (Kompensationsfunktionen): Kompensationen von Operationen der Ebene i, die vor dem Abbruch abgeschlossen waren, sind zulässig, falls 1. Operationen der Ebene i sind atomar, d.h. sie bewirken stets i-konsistente Zustände. 2. Die Kompensationsfunktion zu jeder Operation der Ebene i ist idempotent, d.h. sie stellt den Ausgangszustand her, auch wenn sie unterbrochen wurde. Rekonstruktion i-1,i Aus gespeicherten Werten der Ebene i-1 wird der Originalzustand von i-Objekten ermittelt. Rekonstruktion von Zuständen der Ebene i ist zulässig, falls der zugrundegelegte Zustand der Ebene i-1 (i-1)-konsistent ist. Rekonstruktion meist identisch mit Konstruktion.

9 Recovery in Schichten Beginne auf Ebene 0 und bestimme dort 0-konsistenten Zustand. Bestimme auf Ebene 1 den zuletzt erreichten 1-konsistenten Zustand. Bestimme den hierzu gehörigen 0-konsistenten Zustand. Stelle ihn wieder her über Kompensation der Ebene 0. Rekonstruiere über t den angestrebten 1-konsistenten Zustand. Setze diesen Prozess nach oben fort. s 1 (0) 2 (2) j (1) i p n+1 n m k op k-1 i-1 r t 01 12

10 Recovery in der Segmentschicht
Entwurfsentscheidung: Wahl von j (1) ? s 1 (0) j (1) i 2 p n+1 n m k op k-1 i-1 t 01 Rekonstruktion Seiten 0-Konsistenz durch RAID usw. gesichert. r 1 Kompensation

11 Transaktionale Zuverlässigkeit
Kapitel 4.2 Transaktionale Zuverlässigkeit

12 Transaktionale Zuverlässigkeit
Entwurfsentscheidung: Alle Zuverlässigkeitsmaßnahmen orientieren sich an den Transaktionsgrenzen. Transaktionen sind atomar („alles-oder-nichts“). Der alte Zustand jeder involvierten Seite bleibt mindestens bis zum Transaktionsende erhalten. Zum Transaktionsende muss der neue Zustand gesichert sein. Pufferverwaltung kennt vom Grundsatz her keine Transaktionen. Erfordert Systemkomponenten außerhalb der Pufferverwaltung.

13 Transaktionale Architektur d. Segmentschicht
... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Isolation Recovery Backup- Verwalter restart read, write, allocate, unfix Atomizität Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter Einbring-Strategien fetch, flush Log- datei Daten- basis

14 Kapitel 4.2.1 Segment-Verwalter

15 Einbringstrategien Die Zuverlässigkeitsmaßnahmen richten sich nach der Einbringstrategie, und umgekehrt. Einbringstrategie: Grundsätze, nach denen Änderungen in die Datei eingebracht werden. Statischer Aspekt (Speicherstrategie): Ortswahl = Wahl eines Blocks, auf dem eine Änderung gespeichert werden soll. Sache der Segmentverwaltung. Dynamischer Aspekt (Verdrängen/Auslagern): Wahl des Zeitpunkts, zu dem eine Änderung gespeichert werden soll. Die Pufferverwaltung agiert autonom und entscheidet daher nach eigenen Optimierungskriterien über den Zeitpunkt. Die Segmentverwaltung muss also gezielt von außen Einfluss nehmen, wenn sie dies für notwendig erachtet.

16 Speicherstrategien Direkte Strategie (update-in-place)
Eine Seite wird nach jeder Änderung in ihren einmal zugeordneten Block zurückgeschrieben. Die Direkte Einbringstrategie ist mit der direkten und der indirekten Seitenabbildung verträglich. Indirekte Einbringstrategie (shadowing): Änderungen der Seite werden auf einem zweiten Block gespeichert; geänderten Seiten sind somit zwei Blöcke zugeordnet. Die natürliche Seitenabbildung ist die indirekte.

17 Verdrängungs- und Auslagerungsstrategie (1)
Verdrängungsstrategie bestimmt, wann Puffer-Verwalter geänderte Datenelemente frühestens auf den Hintergrundspeicher schreiben darf: Steal: Segment-Verwalter veranlasst sofortiges unpin(x) auf write(x)/unfix(x) hin. Nosteal: Segment-Verwalter kann bis zum commit der Transaktion für kein geändertes x ein unpin(x) geben. Verwalter mit Nosteal-Strategie unpin(a,b,c) Verwalter mit Steal-Strategie unpin(a) unpin(b) unpin(c) Transaktions- verhalten read(a,b,c) write(a) unfix(a) write(b) unfix(b) write(c) unfix(c) commit

18 Verdrängungs- und Auslagerungsstrategie (2)
Auslagerungsstrategie bestimmt, wann Puffer-Verwalter geänderte Datenelemente spätestens auf den Hintergrundspeicher schreiben muss: Force: Beim commit der Transaktion zwingt Segment-Verwalter den Puffer-Verwalter zum flush(x) für alle geänderten x. Noforce: Puffer-Verwalter entscheidet eigenständig über flush(x) irgendwann nach dem commit der Transaktion (falls nicht Schreiben durch Verdrängen bereits erfolgt). Transaktions- verhalten write(a) unfix(a)) write(b) unfix(b) write(c) unfix(c) flush(a) flush(b) flush(c) flush(a,b,c) commit Verwalter mit Noforce-Strategie Verwalter mit Force-Strategie read(a,b,c)

19 Verdrängungs- und Auslagerungsstrategie (3)
Verdrängungs- und Auslagerungsstrategie lassen sich beliebig kombinieren. unpin(a,b,c) flush(a,b,c) Verwalter mit Nosteal/Force-Strategie Verwalter mit Steal/Force-Strategie unpin(a) unpin(b) unpin(c) flush(a,b,c) flush(a) flush(b) flush(c) Verwalter mit Nosteal/Noforce-Strategie unpin(a,b,c) flush(a) flush(b) flush(c) Verwalter mit Steal/Noforce-Strategie unpin(a) unpin(b) unpin(c) Transaktions- verhalten write(a) unfix(a) write(b) unfix(b) write(c) unfix(c) commit read(a,b,c) natürliche Autonomie der Pufferverwaltung

20 Konsequenzen für Crash-Recovery
crash recovery algorithms steal update-in-place nosteal or shadowing with-undo no-undo noforce force noforce force with-undo/with-redo with-undo/no-redo no-undo/with-redo no-undo/no-redo undo: Beseitige Wirkung der Transaktion redo: Stelle Wirkung der Transaktion wieder her

21 Vorgehen bei Update-in-place
Kapitel 4.2.2 Vorgehen bei Update-in-place

22 Grundlage der Recovery
Basis-Fehler-Resistenz: undo: Um im Fehlerfall die Transaktion zurücksetzen zu können, muss der alte Zustand jeder betroffenen Seite (before image) auf einem anderen Block gesichert werden. Dies geschieht über eine eigene logische Datei, die Logdatei. Dort muss zusätzlich vermerkt werden, zu welcher Seite das before image gehört. Zusätzlich ist das WAL (write-ahead Log)-Protokoll einzuhalten. redo: Um im Fehlerfall die Transaktion wieder herstellen zu können, muss der neue Zustand jeder betroffenen Seite (after image) gesichert werden. Dies geschieht ebenfalls über die Logdatei.

23 Write-ahead Log-Protokoll
Ti Datenbasis 1. write P 2. Speichere P P Puffer 3. Speichere P`s Before-image Log Systemzusammenbruch nach (2): (3) wird nicht ausgeführt Bei Abbruch kann die Änderung von Ti nicht rückgängig gemacht werden, da das Before-image verlorengegangen ist. WAL: Reihenfolge

24 Beispiel für Steal/Force und Update-in-place
read (P13) t2 fetch/pin (P13) read(P45) t5 fetch/pin(P45) write/unfix(P13) t7 unpin(P13) BOT t1 EOT t10 Segment-Verwalter für T4711 write/unfix(P13) t3 unpin(P13) read(P13) t6 fetch/pin(P13) commit t8 t9 flush(P13) t4 steal(P13) Puffer- Verwaltung t6:fetch/pin(P13) Log Platte t9:flush(P13) P13 P13 t4:Sichern des Before image von P13 auf die Log-Datei t4:flush(P13) t5: fetch/pin(P45) P45 P45 t2:fetch/pin(P13) P13 P13 Systempuffer

25 Optionen bei Crash-Recovery
undo kann notwendig sein um zu garantieren dass sich eine Aktion der Transaktion t nur in der Datenbasis auswirkt, wenn commit von t im Log vermerkt ist. Keine Recovery-Aktionen falls sich eine Aktion der Transaktion t nur in der Datenbasis auswirkt, wenn commit von t im Log vermerkt ist. crash recovery algorithms steal update-in-place no-steal or shadowing with-undo no-undo noforce force noforce force with-undo/with-redo with-undo/no-redo no-undo/with-redo no-undo/no-redo redo kann notwendig sein um zu garantieren dass sofern falls commit von t im Log vermerkt ist, sich auch alle Aktionen von t in der Datenbasis widerspiegeln. Keine Recovery-Aktionen sofern falls commit von t im Log vermerkt ist, sich auch alle Aktionen von t in der Datenbasis widerspiegeln.

26 Von einer Transaktion bewirkter Endzustand
undo Von einer Transaktion bewirkter Endzustand Transaktionen s 1 (0) j (1) i 2 p n+1 n m k op k-1 i-1 t 01 Rekonstruktion Seiten 0-Konsistenz durch RAID usw. gesichert. r 1 Kompensation

27 Von einer Transaktion bewirkter Endzustand
redo Von einer Transaktion bewirkter Endzustand Transaktionen s 1 (0) j (1) i 2 p n+1 n m k op k-1 i-1 t 01 Rekonstruktion Seiten 0-Konsistenz durch RAID usw. gesichert. r 1 Kompensation

28 Bewertung Option Kosten no-undo
Im Normalbetrieb sehr aufwendig wegen Pufferüberlastung. no-redo Hohe Seitentransferrate bei commit, dagegen ist force ins Log weitaus schneller. no-undo / no-redo Sofortiger Neustart möglich, aber im Normalbetrieb sehr aufwendig! Bei endlicher commit-Dauer physisch unmöglich!  Zusatzmaßnahmen with-undo / with-redo Übliche Wahl, da im Normalbetrieb am wenigsten aufwendig. Aufwand fällt stattdessen beim Neustart an.

29 Logging im Normalbetrieb
Kapitel 4.2.3 Logging im Normalbetrieb

30 Rolle des Backup-Verwalters
Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter restart read, write, allocate, unfix Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) fetch, flush Log- datei Daten- basis

31 Transaktionale Auswirkungen
Zentrale Voraussetzung Serialisierbarkeit: Operatoren verschiedener Transaktionen beeinflussen sich gegenseitig nicht, Sperrende Scheduler: Transaktionen könnten auch sequenziell in der Reihenfolge ihrer commits ablaufen. Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter restart read, write, allocate, unfix Folge: Commit-Operation muss als letzte Operation im Log vermerkt werden, Commit-Operationen sind somit in der Serialisierbarkeits- Reihenfolge vermerkt. Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) fetch, flush Log- datei Daten- basis

32 Transaktionale Auswirkungen
Zentrale Voraussetzung Serialisierbarkeit: Operatoren verschiedener Transaktionen beeinflussen sich gegenseitig nicht, Sperrende Scheduler: Transaktionen könnten auch sequenziell in der Reihenfolge ihrer commits ablaufen. Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter Jede für das Logging bedeutsame Operation (bot, write, commit) wird mit einer monoton steigenden Sequenznummer (die Historie widerspiegelnd) markiert. restart read, write, allocate, unfix Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) fetch, flush Jede Datenseite trägt in ihrem Kopf eine Seiten-Sequenznummer (PSN). Dies ist die LSN der letzten write-Operation. Log entspricht Historie: Jeder Log-Eintrag wird mit dieser Nummer (Log-Sequenznummer (LSN)) versehen. Log- datei Daten- basis

33 Schreiben des Log Transaktionsverwaltung ...
Transaktion n Transaktionsverwaltung Würde man bis flush warten, so könnte ein Daten-Eintrag nach dem commit-Eintrag zu liegen kommen! Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Mit Beginn einer neuen Transaktion wird ein begin-Eintrag in den Log-Puffer geschrieben. Bei write wird ein write-Eintrag in den Log-Puffer geschrieben. Bei commit wird ein commit-Eintrag in den Log-Puffer geschrieben und dann der Pufferinhalt in den Log überführt (force). Recovery Backup- Verwalter restart read, write, allocate, unfix Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) Würde man noch zuwarten, so hätte commit keine persistente Wirkung! fetch, flush Log- datei Daten- basis

34 Beispiel für die Sequenznummern
Database Cache page b 4215 Log Buffer 4219 page q page p 3155 4220 begin(t20) nil 4217 page z 4219 write(q,t17) 4217 Volatile Memory (page/log) sequence numbers Stable Storage page b 4215 4218 commit(t19) 4216 page q 2788 4217 write(z,t17) 4215 4216 write(q,t19) 4199 3155 page p 4158 page z Stable Database Stable Log 4215 write(b,t17) 4208 ...

35 Datenstrukturen var DatabaseCache: set of Page indexed by PageNo;
type Page: record of PageNo: identifier; PageSeqNo: identifier; Status: (clean, dirty) /* only cache*/; Contents: array [PageSize] of char; end; var LogBuffer: ordered set of LogEntry indexed by LogSeqNo; type LogEntry: record of LogSeqNo: identifier; TransId: identifier; ActionType: (write, full-write, begin, commit, rollback); UndoInfo: array of char; RedoInfo: array of char; PreviousSeqNo: identifier; PSN. LSN. Höchste für die Transaktion vergebene LSN type TransInfo: record of TransId: identifier; LastSeqNo: identifier; end; var ActiveTrans: set of TransInfo indexed by TransId Verkettung innerhalb der Transaktion

36 Umsetzung im Backup-Verwalter (1)
write (pageno, transid): %DatabaseCache[pageno].Contents := modified contents; s := current sequence number; DatabaseCache[pageno].PageSeqNo := s; DatabaseCache[pageno].Status := dirty; newlogentry.LogSeqNo := s; newlogentry.ActionType := write; newlogentry.TransId := transid; newlogentry.PageNo := pageno; newlogentry.UndoInfo := information to undo update (before-image for full-write); newlogentry.RedoInfo := information to redo update (after-image for full-write); newlogentry.PreviousSeqNo := ActiveTrans[transid].LastSeqNo; ActiveTrans[transid].LastSeqNo := s; LogBuffer += newlogentry; already done log data entry

37 Umsetzung im Puffer-Verwalter
fetch (pageno): Find slot in DatabaseCache and set its PageNo := pageno; DatabaseCache[pageno].Contents := StableDatabase[pageno].Contents; DatabaseCache[pageno].PageSeqNo := StableDatabase[pageno].PageSeqNo; DatabaseCache[pageno].Status := clean; flush (pageno): if there is logentry in LogBuffer with logentry.PageNo = pageno then force ( ); end /*if*/; StableDatabase[pageno].Contents := DatabaseCache[pageno].Contents; StableDatabase[pageno].PageSeqNo := DatabaseCache[pageno].PageSeqNo; force ( ): StableLog += LogBuffer; LogBuffer := empty; write-ahead flush auf Eintrag möglicherweise bereits früher erfolgt!

38 Umsetzung im Backup-Verwalter (2)
begin (transid): s := current sequence number; newtransentry.TransId := transid; ActiveTrans += newtransentry; ActiveTrans[transid].LastSeqNo := s; newlogentry.LogSeqNo := s; newlogentry.ActionType := begin; newlogentry.TransId := transid; newlogentry.PreviousSeqNo := nil; LogBuffer += newlogentry; commit (transid): newlogentry.ActionType := commit; newlogentry.PreviousSeqNo := ActiveTrans[transid].LastSeqNo; ActiveTrans -= transid; force ( ); log BOT entry log commit entry

39 Recovery am Beispiel Redo-Winners
Kapitel 4.2.4 Recovery am Beispiel Redo-Winners

40 Rolle des Recovery-Verwalters
Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter restart read, write, allocate, unfix Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) fetch, flush Log- datei Daten- basis

41 Aufgabenverteilung Transaktionsverwaltung ...
Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter restart read, write, allocate, unfix Enges Zusammenwirken erforderlich! Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter pin, unpin fetch, flush Log- datei Daten- basis

42 Winners and losers Winner: Winner transactions are those transactions for which a commit log entry is encountered. Loser: Loser transactions are those transactions for which no commit entry exists in the log, i.e., that were still active during system crash. Assumptions: All write actions during normal operation write entire pages (“full-write”). Transactions that have been aborted have been rolled back during normal operation and, hence, can be disregarded.

43 Simple Three-Pass Algorithm
Analysis pass: Determine start of log from master record. Perform forward scan to determine winners and losers. Redo pass: Perform forward scan to redo all winner actions in chronological (LSN) order (until end of log is reached). Undo pass: Perform backward scan to traverse all loser log entries in reverse chronological order and undo the corresponding actions. Since these transactions must follow the last committed transaction in the serial order, their effects can be undone without endangering the committed transactions.

44 Simple Three-Pass Algorithm
restart ( ): analysis pass ( ) returns losers; redo pass ( ); undo pass ( ); for each page p in DatabaseCache do if DatabaseCache[p].Status = dirty then flush (p); end /*if/; end /*for*/; reinitialize StableLog; Three passes Because undo/redo use the cache, the cache must be cleared before resuming normal operation.

45 Analysis Pass We register losers only. Each ta is a potential loser.
analysis pass ( ) returns losers: var losers: set of record TransId: identifier; LastSeqNo: identifier; end /*indexed by TransId*/; losers := empty; min := LogSeqNo of oldest log entry in StableLog; max := LogSeqNo of most recent log entry in StableLog; for i := min to max do case StableLog[i].ActionType: begin: losers += StableLog[i].TransId; losers[StableLog[i].TransId].LastSeqNo := nil; commit: losers -= StableLog[i].TransId; write: losers[StableLog[i].TransId].LastSeqNo := i; end /*case*/; end /*for*/; We register losers only. Each ta is a potential loser. ta is a winner! Forward scan

46 Redo Pass redo pass ( ): min := LogSeqNo of oldest log entry in StableLog; max := LogSeqNo of most recent log entry in StableLog; for i := min to max do if StableLog[i].ActionType = write and StableLog[i].TransId not in losers then pageno = StableLog[i].PageNo; fetch (pageno); full-write (pageno) with contents from StableLog[i].RedoInfo; end /*if*/; end /*for*/; Forward scan: restore latest valid state according to history Restore the winner no matter how much of it is already in stable database!

47 Undo Pass Set of losers not yet exhausted?
while there exists t in losers such that losers[t].LastSeqNo <> nil do nexttrans = TransId in losers such that losers[nexttrans].LastSeqNo = max {losers[x].LastSeqNo | x in losers}; nextentry = losers[nexttrans].LastSeqNo; if StableLog[nextentry].ActionType = write then pageno = StableLog[nextentry].PageNo; fetch (pageno); full-write (pageno) with contents from StableLog[nextentry].UndoInfo; losers[nexttrans].LastSeqNo := StableLog[nextentry].PreviousSeqNo; end /*if*/; end /*while*/; Set of losers not yet exhausted? Simulate backward scan on actions Restore loser’s latest state no matter how much of it still is in stable database! Losers’ next entry

48 Sample Scenario 1st crash 2nd crash resume normal operation restart
complete analysis pass redo undo t1 t2 t3 t4 t5 flush(d) 1st restart (incomplete) 2nd restart (complete) w(a) w(b) w(c) w(d) w(e) flush(b) w(f)

49 Sample Scenario Data Structures
Sequence number: action Change of cached database [PageNo: SeqNo] Change of stable database [PageNo: SeqNo] Log entry added to log buffer [LogSeqNo: action Log entries added to stable log [LogSeqNo‘s] 1: begin (t1) 2: begin (t2) 3: write (a, t1) a: 3 4: begin (t3) 5: begin (t4) 6: write (b, t3) b: 6 7: write (c, t2) c: 7 8: write (d, t1) d: 8 9: commit (t1) 1, 2, 3, 4, 5, 6, 7, 8, 9 10: flush (d) 11: write (d, t3) d: 11 12: begin (t5) 13: write (a, t5) a: 13 14: commit (t3) 11, 12, 13, 14 15: flush (d) 16: write (d, t4) d: 16 17: write (e, t2) e: 17 18: write (b, t5) b: 18 19: flush (b) 16, 17, 18 20: commit (t4) 20 21: write (f, t5) f: 21  SYSTEM CRASH

50 First restart Analysis pass: losers = {t2, t5} Redo pass +  :
Sequence number: action Change of cached database [PageNo: SeqNo] Change of stable database [PageNo: SeqNo] Log entry added to log buffer [LogSeqNo: action Log entries added to stable log [LogSeqNo‘s] redo (3) a: 3 redo (6) b: 6 flush (a) redo (8) d: 8 flush (d) redo (11) d: 11  SECOND SYSTEM CRASH

51 Second restart Analysis pass: losers = {t2, t5} Redo pass + undo pass:
Sequence number: action Change of cached database [PageNo: SeqNo] Change of stable database [PageNo: SeqNo] Log entry added to log buffer [LogSeqNo: action Log entries added to stable log [LogSeqNo‘s] redo (3) a: 3 redo (6) b: 6 redo (8) d: 8 redo (11) d: 11 redo(16) d: 16 undo(18) undo(17) e: 0 undo(13) undo(7) c: 0 SECOND RESTART COMPLETE: RESUME NORMAL OPERATION

52 Transaction aborts Problem: Write actions are logged before the outcome of the transaction becomes known. Transaction abort requires a rollback. All logging information would then have to be removed. Otherwise the assumption that losers follow winners in the serial order would no longer apply. A system crash may occur during rollback, and the abort would have to recover from this crash.

53 Transaction rollback Solution: Treat a rolled back transaction as a winner. Create compensation log entries for inverse operations during transaction rollback. Complete rollback by creating rollback log entry. During crash recovery, aborted transactions with complete rollback are winners (and are redone in the right serial order), incomplete aborted transactions are losers.

54 Transaction rollback abort (transid):
logentry := ActiveTrans[transid].LastSeqNo; while logentry is not nil and logentry.ActionType = write do newlogentry.LogSeqNo := new sequence number; newlogentry.ActionType := compensation; newlogentry.PreviousSeqNo := ActiveTrans[transid].LastSeqNo; newlogentry.RedoInfo := inverse action of the action in logentry; newlogentry.UndoInfo := inverse action of inverse action of action in logentry; ActiveTrans[transid].LastSeqNo := newlogentry.LogSeqNo; LogBuffer += newlogentry; write (logentry.PageNo) according to logentry.UndoInfo; logentry := logentry.PreviousSeqNo; end /*while*/ newlogentry.ActionType := rollback; newlogentry.TransId := transid; LogBuffer += newlogentry; ActiveTrans -= transid; force ( );

55 Sample Scenario crash t1 w(a) flush(a) t2 t3 t4 w(b) rollback

56 Sample Scenario Data Structures
Sequence number: action Change of cached database [PageNo: SeqNo] Change of stable database [PageNo: SeqNo] Log entry added to log buffer [LogSeqNo: action Log entries added to stable log [LogSeqNo‘s] 1: begin (t1) 2: write (a, t1) a: 2 3: commit (t1) 1, 2, 3 4: begin (t2) 5: write (a, t2) a: 5 6: abort (t2) 7: compensate(5) a: 7 7: compensate (a, t2) 8: rollback (t2) 4, 5, 7, 8 9: begin (t3) 10: write (a, t3) a: 10 11: commit (t3) 9, 10, 11 12: begin (t4) 13: write (b, t4) b: 13 14: write (a, t4) a: 14 15: abort (t4) 16: compensate(14) a: 16 16: compensate (a, t4) 17: flush (a) 12, 13, 14, 16  SYSTEM CRASH

57 Restart Analysis pass: losers = {t4} Redo pass + undo pass:
Sequence number: action Change of cached database [PageNo: SeqNo] Change of stable database [PageNo: SeqNo] Log entry added to log buffer [LogSeqNo: action Log entries added to stable log [LogSeqNo‘s] redo (2) a: 2 redo (5) a: 5 redo (7) a: 7 redo (10) a: 10 undo(16) a: 14 undo(14) undo(13) b: 0 RESTART COMPLETE: RESUME NORMAL OPERATION

58 Alternativen Der einfache redo-winners Algorithmus ist für praktische Zwecke meist zu ineffizient. Weitere grundsätzliche Ansätze in der Vorlesung “Transaktionsverwaltung”.

59 Nicht-Transaktionale Zuverlässigkeit
Kapitel 4.3 Nicht-Transaktionale Zuverlässigkeit

60 Recovery in der Segmentschicht
Segmentspezifischer Sicherungspunkt Segmente s 1 (0) j (1) i 2 p n+1 n m k op k-1 i-1 t 01 Rekonstruktion Seiten 0-Konsistenz durch RAID usw. gesichert. r 1 Kompensation

61 Rolle des Backup-Verwalters
Transaktion 1 Transaktion 2 ... Transaktion n Transaktionsverwaltung Historie 1 Historie n Scheduler Sperren-Verwalter Globale Historie aus read, write, allocate, unfix, commit, abort Recovery Backup- Verwalter restart Ignoriert (zunächst) Transaktionsgrenzen read, write, allocate, unfix entfällt Puffer- Verwalter p3 p2 p17 p24 p18 p57 p42 p8 p67 p19 p33 p81 p46 p25 p54 p66 p9 p91 p14 p68 p31 p29 p48 p47 p1 p5 p99 p23 p56 p62 p15 p49 p36 p93 p7 Log- seiten d4 d43 d17 d15 d2 d58 d5 d9 d26 d69 d6 d16 d46 d68 d55 d32 d97 d49 d25 d20 d67 d30 d37 d19 d34 d10 d24 d94 d63 d82 d92 d57 d8 Daten- seiten Segment-Verwalter unpin do(flush) fetch, flush Log- datei Daten- basis

62 Erinnerung: Indirekte Seitenabbildung
Segment S1 Segment S2 P1 P2 P3 ... Pk P1‘ P2‘ P3‘ ... Pn‘ B2 B4 B5 ... Bk+2 B1 Bk B3 ... Bk+3 Seitentabelle von S2 Seitentabelle von S1 B1 B2 B3 B4 B5 ... Bk Bk+1 Bk+2 Bk+3 ... Bk+n

63 Schattenspeicher-Verfahren (1)
Zuverlässigkeit, indem in bestimmten zeitlichen Abständen Sicherungspunkte durchgeführt werden. Bei einer zwischenzeitlichen Änderung einer Seite wird die Version des letzten Sicherungspunktes aufbewahrt (Schattenseite), und die geänderte Seite wird in einem neuen Block gespeichert. Es existieren zwei Seitentabellen: Die aktuelle Seitentabelle verweist auf die Blöcke, die die aktuellen Versionen der Seiten enthalten. Die Schattenseitentabelle verweist auf die Schattenseiten (also die Blöcke, die die Versionen der Seiten vom letzten Sicherungspunkt enthalten).

64 Schattenspeicher-Verfahren (2)
... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 3 5 ... j B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei 15 = Schattenbit Anzeige der Modifikation einer Seite seit dem letzten Sicherungspunkt

65 Schattenspeicher-Verfahren (3)
... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... Bei einem Sicherungspunkt werden die Blöcke der Schattenseiten freigegeben, und die Einträge der aktuellen Seitentabelle werden in die Schattenseitentabelle kopiert. aktuelle Seitentabelle 3 5 ... j B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei 15 = Schattenbit

66 Schattenspeicher-Verfahren (4)
... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... Bei Störungen wird auf den letzten Sicherungspunkt zurückgesetzt. Das Rücksetzen auf den Zustand des letzten Sicherungspunktes erfolgt durch Freigabe der seit dem letzten Sicherungspunkt modifizierten Seiten und Kopieren der Einträge der Schattenseitentabelle in die aktuelle Seitentabelle. aktuelle Seitentabelle 3 5 ... j B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei 15 = Schattenbit

67 Schattenspeicher-Algorithmen (1)
... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 2 5 ... j ... B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 algorithm read_page input Seitennummer P; output Nummer des Blocks mit der aktuellen Version von P; begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; return B; end;

68 Schattenspeicher-Algorithmen (2)
algorithm write_page input Seitennummer P; begin if das Schattenbit zu Seite P ist gesetzt ** P wurde seit dem letzten Sicherungspunkt modifiziert then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; ** Es wird stets in existierende Seiten geschrieben Schreibe die neue Version von P in Block B; end; else begin ** P wurde seit dem letzten Sicherungspunkt nicht modifiziert Allokiere einen neuen Block B'; Trage Block B' in die aktuelle Seitentabelle in den Eintrag für Seite P ein; Schreibe die neue Version von P in den Block B'; Setze das Schattenbit zu Seite P in der aktuellen Seitentabelle;

69 Schattenspeicher-Algorithmen (2)
write_page(P1); P1 P2 P3 P4 P5 ... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 2 5 ... j 3 5 ... j x B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 = Schattenbit

70 Schattenspeicher-Algorithmen (3)
algorithm delete_page input Nummer P der zu löschenden Seite begin if Schattenbit zu Seite P ist gesetzt then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; Gib Block B frei; end; Trage 0 in die aktuelle Seitentabelle in den Eintrag für Seite P ein; Setze das Schattenbit zu Seite P in der aktuellen Seitentabelle;

71 Schattenspeicher-Algorithmen (3)
delete_page(P4); P1 P2 P3 P4 P5 ... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 3 ... k 3 5 ... k x B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 = Schattenbit

72 Schattenspeicher-Algorithmen (4)
algorithm create_page output Nummer P der neuen Seite begin Suche eine Seitennummer P, der kein Block zugeordnet ist (Blocknummer 0 in beiden Seitentabellen); Allokiere einen neuen Block B; Trage Block B in die aktuelle Seitentabelle in den Eintrag für Seite P ein; Setze das Schattenbit zu Seite P in der aktuellen Seitentabelle; return P; end;

73 Schattenspeicher-Algorithmen (4)
create_page; P1 P2 P3 P4 P5 ... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 3 1 ... k 3 ... k B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 = Schattenbit

74 Setzen eines Sicherungspunktes (1)
algorithm Checkpoint input Nummer S des Segments, das gesichert werden soll; begin foreach Seite P des Segments S do if Schattenbit zu Seite P ist gesetzt then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; Sei B' der Eintrag zu P in der Schattenseitentabelle; if B‘0 then Gib Block B‘ frei; Trage Block B in die Schattenseitentabelle in den Eintrag für Seite P ein; Lösche das Schattenbit zu Seite P; end;

75 Setzen eines Sicherungspunktes (2)
1. Gib die Blöcke der Schattenseiten frei P1 P2 P3 P4 P5 ... Pi ... Segment 4711 Schatten-seitentabelle 2 5 ... j ... aktuelle Seitentabelle 3 1 ... k B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 F F F = Schattenbit

76 Setzen eines Sicherungspunktes (2)
2. Kopieren der Einträge der aktuellen Seitentabelle und Löschen der Schattenbits: P1 P2 P3 P4 P5 ... Pi ... Segment 4711 Schatten-seitentabelle 3 1 ... k 2 5 ... j ... aktuelle Seitentabelle 3 1 ... k 3 1 ... k B1 B2 B3 B4 B5 ... Bj ... Bk ... Datei15 = Schattenbit

77 Sicherungspunkt: Zustand peripher zu sichern
Atomares Sichern (1) Sicherungspunkt: Zustand peripher zu sichern ResetToLastCheckpoint s (2) Transaktion s (1) Checkpoint segment S checkpoint(S1) write_page(P1) write_page(P1) s (0)

78 Atomares Sichern (1) algorithm CheckpointMitSicherungDurchRekonstruktion input Nummer S des Segments, das zurückgesetzt werden soll; begin Kopiere die Schatten- und aktuelle Seitentabelle; Kopiere die Blöcke, die im weiteren freigegeben werden; foreach Seite P des Segments S do if Schattenbit zu Seite P ist gesetzt then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; Sei B' der Eintrag zu P in der Schattenseitentabelle; if B‘0 then Gib Block B‘ frei; Trage Block B in die Schattenseitentabelle in den Eintrag für Seite P ein; Lösche das Schattenbit zu Seite P; end; Werfe Kopien weg;

79 Sicherungspunkt: Zustand peripher zu sichern
Atomares Sichern (2) Sicherungspunkt: Zustand peripher zu sichern ResetToLastCheckpoint s (2) Transaktion s (1) Checkpoint segment S checkpoint(S1) write_page(P1) write_page(P1) s (0)

80 Atomares Sichern (2) algorithm CheckpointMitSicherungDurchKompensation
input Nummer S des Segments, das zurückgesetzt werden soll; begin Lege eine Log-Datei an; foreach Seite P des Segments S do if Schattenbit zu Seite P ist gesetzt then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; Sei B' der Eintrag zu P in der Schattenseitentabelle; Protokolliere Eintrag von Block B‘ für Seite P in der Log-Datei; if B‘0 then begin Protokolliere Freigabe und Inhalt von B' in der Log-Datei; Gib Block B‘ frei; end; Trage Block B in die aktuelle Schattenseitentabelle in den Eintrag für Seite P ein; Lösche das Schattenbit zu Seite P; Lösche Log-Datei;

81 Rücksetzen auf letzten Sicherungspunkt
algorithm ResetToLastCheckpoint input S ist Segment, das zurückgesetzt werden soll; begin foreach Seite P des Segments S do if Schattenbit zu Seite P ist gesetzt then begin Sei B der Eintrag zu P in der aktuellen Seitentabelle; Sei B' der Eintrag zu P in der Schattenseitentabelle; if B0 then Gib Block B frei; Trage Block B' in die aktuelle Seitentabelle in den Eintrag für Seite P ein; Lösche das Schattenbit zu Seite P; end;

82 Freispeicherverwaltung
Häufig wird die Freispeicherverwaltung für die Datei an das Schattenspeicher-Verfahren angepasst. Es werden dabei zwei Datenstrukturen (bspw. Freispeicherlisten oder Bitleisten) für die Markierung der freien Blöcke einer Platte geführt: eine aktuelle und eine Schattenversion. Die aktuelle Version führt die Belegungen beider Segmentversionen  vereinfachte Prüfung auf freien Block! Zum Ende des Durchführens eines Sicherungspunktes wird die aktuelle Version auf die Schattenversion kopiert, zum Ende des Rücksetzens auf einen Sicherungspunkt wird die Schattenversion auf die aktuelle Version kopiert.

83 Bewertung des Schattenspeicherkonzepts
Vorteile: Einfaches Zurücksetzen auf Sicherungspunkt. Einfacher Wiederanlauf nach Fehlerfall, da mit Schattenseiten ein konsistenter Zustand der DB vorliegt. Nachteile: Zerstörung von Nachbarschaften: Durch die Allokation neuer Blöcke bei Änderungen ist es nicht möglich, häufig gemeinsam benötigte Seiten in benachbarten Blöcken zu halten. Sicherungspunkte verursachen punktuell hohe E/A. Zwischen zwei Sicherungspunkten belegen geänderte Seiten zwei Blöcke (hoher Speicherbedarf; mögliche Reduktion durch kürzere Sicherungsintervalle). Zusammenhang zwischen Transaktionen und Sicherungspunkten nur mit hohem Zusatzaufwand herstellbar. Recovery beschränkt durch maximal 2 Zustände pro Seite.

84 Twin-Block-Verfahren (1)
Vereinfachtes Shadowing mit direkter Seitenabbildung. Jeder Seite Pi werden zwei benachbarte Blöcke zugeordnet, d.h. die Übergang zwischen den beiden logischen Blöcken ist minimal. Beispiel: B8 B1 B2 B3 B4 B5 B6 B7 P1 P1‘ P2 P2‘ P3 P3‘ P4 P4‘

85 Twin-Block-Verfahren (2)
Auf den beiden einer Seite zugeordneten Blöcken sind zwei verschiedene Versionen der Seite gespeichert: die aktuelle Version der Seite, die von der letzten schreibenden Aktion (aktuelle oder letzte abgeschlossene) erzeugt wurde, die Version, die von der vorletzten schreibenden Aktion erzeugt wurde. Seien Bj und Bj+1 die Blöcke zu Seite Pi. Auf Block Bj wird ein Markierungsbit gespeichert: enthält Bj die aktuelle Version der Seite, dann ist das Bit 1, ansonsten 0. B8 B1 B2 B3 B4 B5 B6 B7 P1 P1‘ P2 P2‘ P3 P3‘ P4 P4‘

86 Twin-Block-Verfahren (3)
Ursprünglich nicht transaktionsbezogen, lässt sich aber so abwickeln: read: Es werden beide Blöcke eingelagert. Anhand des Bits wird die aktuelle Version festgestellt. Lese- und Schreiboperationen werden auf dem Seitenrahmen durchgeführt, der die aktuelle Version der Seite enthält. Bei flush oder spätestens bei commit einer schreibenden Transaktion wird der neue Zustand der Seite auf den Block zurückgeschrieben, der die ältere Version der Seite enthält, und das Markierungsbit auf dem ersten Block invertiert. Das Before image der Seite bleibt somit auf dem anderen Block erhalten.

87 Beispiel für das Twin-Block-Verfahren
Transaktion T4712 fixiert Seite Pi (auf Bj + Bj+1) zum Lesen read(Pi) EOT T4712 commit Systempuffer Einlagern von Bj und Bj+1 Pi0 Platte Pi1 (Da das Markierungsbit nicht gesetzt ist, enthält Bj+1 die aktuelle Version der Seite Pi) Bj Bj+1 = Markierungsbit gesetzt = Markierungsbit nicht gesetzt

88 Beispiel für das Twin-Block-Verfahren
Transaktion T4712 fixiert Seite Pi (auf Bj + Bj+1) zum Lesen und Schreiben BOT read (Pi) write(Pi) speichere(Pi) EOT T4713 Modifizieren des aktuellen Zustands Systempuffer Einlagern von Bj und Bj+1 Pi0 Platte Pi1 Einbringen des neuen Zustands in Block Bj und Setzen des Markierungsbits (Da das Markierungsbit nicht gesetzt ist, enthält Bj+1 die aktuelle Version der Seite Pi) Bj+1 Bj Bj+1 = Markierungsbit gesetzt = Markierungsbit nicht gesetzt

89 Beurteilung Vorteile Geringer Verwaltungsaufwand.
Einfache Implementierung. Schnelle Zugriffe, da die Blöcke zu einer Seite benachbart sind. Nachteile Doppelter Speicherplatzbedarf für die Datenbasis unabhängig von der Häufigkeit von Änderungen an Seiten. Pro fetch einer Seite zwei Blockzugriffe. Nur transaktionsbezogen wenn (wegen Markierungsbit) Striktes 2-Phasen-Sperrprotokoll mit force (nur 2 Zustände!), bei abort Rücksetzen des Bit bei geänderten Seiten.


Herunterladen ppt "Zuverlässigkeit und Recovery in der Segmentschicht"

Ähnliche Präsentationen


Google-Anzeigen