\section{Transaktionen} \subsection{Allgemein} \subsubsection{Was sind Transaktionen?} Transaktionen sind eine logische Arbeitseinheit, die mehrere DB Schritte zusammenfassen.\\ Z.B. einfügen eines neuen Mitarbeiters besteht aus vielen kleinen DB Befehlen, bis Datenbank wieder konsistent ist \subsubsection{Wofür sind sie gut?} Sie überleiten von einem konsistenten Zustand in den nächsten. Im Fehlerfall muss die Möglichkeit gegeben werden, wieder in einen konsistenten Zustand zu finden. Im Mehrfachbetrieb muss gewährleistet werden, dass keine Nebenläufigkeitsprobleme auftauchen. \subsubsection{ACID Eigenschaften von Transaktionen:} \begin{itemize} \item \textbf{Atomic:} Alle Änderungen von TA werden aktiv oder keine \item \textbf{Consistency:} TA überführt DB von konsistent in konsistenten Zustand \item \textbf{Isolation:} TA wird nicht von anderer TA beeinflusst \item \textbf{Durability:} Änderungen sind Dauerhaft in DB übernommen \end{itemize} \subsection{Konsistenzen:} \subsubsection{Physische Konsistenz:} Alle Speicheurngsstrukturen sind korrekt. Alle TID's stimmen etc. \subsubsection{Logische Konsistenz:} Setzt Physische Konsistenz voraus.\\ Korrektheit der Dateninhalte.\\ Alle Bedingungen des Datenmodells und alle Benutzerdefinierten Bedingungen sind erfüllt (Assertions). \subsection{Synchronisation} \subsubsection{Zustandsdiagramm TA} \begin{figure}[H] \begin{center} \includegraphics[scale=0.6]{pics/TA_status.png} \caption{Transaktionszustände} \end{center} \end{figure} \subsubsection{Anomalien ohne Synchronisation} \begin{itemize} \item \textbf{lost updates}\\ $r_1(x) r_2(x) w_1(x) w_2(x)$ \item Abhängigkeiten von nicht freigegeben Änderungen \begin{itemize} \item \textbf{dirty read}\\ $w_1(x)r_2(x)a_1 c_2$\\ Änderung wird noch nicht freigegeben (ggf abgebrochen) aber trotzdem gelesen \item \textbf{dirty write}\\ $w_1(x)r_2(x)w_2(x)a_1 c_2$\\ Änderung wird noch nicht freigegeben (ggf abgebrochen) aber trotzdem geschrieben \end{itemize} \item \textbf{Non Repeatable Read}\\ $r_1(x)w_2(x)r_1(x)$\\ T1 sieht beim erneuten lesen einen anderen Wert als zuvor \item \textbf{Phantom}\\ $r_1(P)w_2(x in P)r_1(P)$\\ Wie bei \textit{Non Repeatable Read} nur Prädikat statt einzelnes Element \end{itemize} \textit{Legende: c = commit, a = abort, w = write, r = read} \subsubsection{Serialisierung} Hintereinanderausführung aller TA's. Problem werden sehr große Wartezeiten. Allgemein ist deine Datenbank für Mehrbenutzerbetrieb ausgelegt, dies würde ab adsurdum geführt durch Serialisierung. Was tun im Fehlerfall \subsubsection{Serialisierbarkeit} Ziel:\\TA's laufen \textit{verzahnt} ab, aber ihr Ergebnis gleicht dem eines seriellen Ablaufes.\\ $\rightarrow$ Ein Schedule von TA's ist \textbf{serialisierbar}, wenn es einen äquivalten \textbf{seriellen} Ablauf gibt. \subsubsection{Implementierung von Sperren} \textbf{Wann sperren?}\\ Statisch:\\ Alles sperren was evtl gebraucht wir (preclaiming) Dynamisch:\\ Zur Laufzeit von TA nach Bedarf sperren\\ $\rightarrow$ Gefahr von Verklemmungen! Sperrgranulat:\\ Warum nicht Tupel: \begin{itemize} \item Nicht immer effizient, bei großen Mengen \item Phantom Tupel; es können nur bereits existente Tupel gesperrt werden. \end{itemize} Deshalb wird \textit{hierarchische Schachtelung} der Datenobjekte:\\ \begin{figure}[H] \begin{center} \includegraphics[scale=0.8]{pics/sperrgranulat.png} \caption{Sperrgranulate} \end{center} \end{figure} Für jedes Objekt kann man nun einen Sperrmodus vergeben. Andere TA können daran erkennen, ob sie ihre Aktion ausführen dürfen. \begin{figure}[H] \begin{center} \includegraphics[scale=0.6]{pics/komp_matrix.png} \caption{Kompatibilitätsmatrix} \end{center} \end{figure} Das Problem an dieser Art der Sperrung ist, dass \begin{itemize} \item Alle Nachfolgeknoten implizit mitgesperrt werden \item Alle Vorgängerknoten auch gesperrt werden müssen \end{itemize} Daher werden sogenannte \textbf{(Intention) Anwartschaftssperren} eingeführt: \begin{itemize} \item {IS Sperre:\\ falls auf untergeordnete Objekte lesend zugegriffen wird} \item {IX Sperre:\\ falls auf untergeordnete schreibend zugegriffen wird} \end{itemize} $\rightarrow$ Benutzung von Untersperre wird angezeigt, aber nochmal explizit weiter unten gesetzt! \paragraph{TOP-DOWN bei Sperre} \begin{itemize} \item Bevor ein Knoten mit S oder IS gesperrt werden darf, müssen alle Vorgänger in der Hierarchie im IX- oder im IS-Modus gesperrt worden sein. \item Bevor ein Knoten mit X oder IX gesperrt werden darf, müssen alle Vorgänger in der Hierarchie im IX-Modus gesperrt worden sein. \end{itemize} \paragraph{BOTTOM-UP bei Freigabe} \begin{itemize} \item Freigabe von unten nach oben \item kein Knoten darf entsperrt werden, wenn noch andere Nachfolger dieses Knotens gesperrt sind \end{itemize} Als Optimierung gibt es noch die \textbf{SIX} Sperre. Alles wird lesend gesperrt und eine Menge an Nachfolgern schreibend. Das lohnt sich z.B. wenn aus einer Relation nur wenige Tupel verändert werden. \subsubsection{Probleme beim Sperren} \begin{itemize} \item Sperren muss sehr schnell gehen, da Anforderungen sehr hoch \item halten von Sperren bis TA-ende führt zu langen Wartezeiten \item Eigenschaften des Schemas können \glqq hotspots\grqq erzeugen \item {Optimierungen: \begin{itemize} \item Nutzung mehrere Objektversionen \item spezialisiertes Sperren \item Änderungen auf privaten Objektkopien \end{itemize} } \end{itemize} \subsubsection{Verklemmungen} Lösungsmöglichkeiten: \begin{itemize} \item{\textbf{Timout:}\\ Transaktion nach bestimmter Wartezeit zurücksetzen.\\ $\rightarrow$ problematisch Länge des Timeouts zu bestimmen } \item{\textbf{Verhütung (Prevention)}\\ Durch Preclaiming (s.o.) keine Deadlock Verhinderung zur Laufzeit notwenig.} \item{\textbf{Vermeidung (Avoidance)}\\ Potentielle Deadlocks im vorhinein erkennen und vermeiden\\ $\rightarrow$ Laufzeitunterstützung notwendig } \item{\textbf{Erkennung (Detection)}\\ Explizites führen eines Wartegraphen und darin Zyklensuche. Im Zyklus dann eine oder mehrere (am besten billigste) TA zurücksetzen.} \end{itemize} \textbox{Deadlock - nicht serialisierbarer Schedule}{ Nicht serialisierbare Schedules, beschreibt Abläufe die zu keinem seriellen Ablauf äquivalent sind. Die somit zu Deadlocks führen. Führt man diese mit \textit{dynamischen} Sperren aus, muss es aber nicht zwangsläufig auch zu Deadlocks kommen! } \subsection{Recovery} \textbf{Recovery Klassen:} \begin{itemize} \item {Partial Undo (R1-Recover) \begin{itemize} \item nach Transaktionsfehler \item isoliertes und vollständiges Zurücksetzen der Daten in Anfangszustand \item beeinflusst andere TA nicht \end{itemize} } \item {Partial Redo (R2-Recover) \begin{itemize} \item nach Systemfehler (mit Verlust von HS) \item Wiederhlung aller verlorengegangenen Änderungen (waren nur im Puffer) von abgeschlossenen TA \end{itemize} } \item {Global Undo (R3-Recover) \begin{itemize} \item nach Systemfehler (mit Verlust von HS) \item Zurücksetzen aller durch Ausfall unterbrochenen TA \end{itemize} } \item {Global Redo (R4-Recover) \begin{itemize} \item nach Gerätefehler \item Einspielen von Archivkopie und nachvollziehen aller beendeten TA's \end{itemize} } \end{itemize} \subsubsection{Archivkopien} Arten: \begin{itemize} \item \glqq cold backup\grqq: DBS muss au"ser Betrieb sein \item \glqq hot backup\grqq: Beeinträchtigung des laufenden Betriebs \end{itemize} \subsubsection{Einbringstrategien} Wann werden geänderte Daten aus dem Puffer auf die Platte geschrieben? \begin{itemize} \item {STEAL:\\ Bei Verdrängung au dem Puffer, auch vor ende der Transaktion} \item {NO STEAL:\\ Frühestens am Ende der Transaktion $\rightarrow$ kein UNDO erfoderlich (aber großen Puffer)} \item {FORCE:\\ Spätestens am Ende der Transaktion $\rightarrow$ kein Partial Redo erfoderlich} \item {NO FORCE:\\ Erst bei Verdränung aus dem Puffer} \end{itemize} Wie werden geänderte Daten aus dem Puffer auf Platte geschrieben? \begin{itemize} \item{ATOMIC:\\ Indirekte Einbringstrategie.\\ Ununterbrechbares Umschalten} \item{NOT ATOMIC: Direkte Einbringstrategie.\\ Ist nicht ununterbrechbar. } \end{itemize} \subsubsection{Protokolldaten} Als Protollinformation zählt was über die Einbringungsstrategie hinaus benötigt wird, um nach einem Systemausfall den jüngsten konsisten Zustand wiederherzustellen. \begin{figure}[H] \begin{center} \includegraphics[scale=0.6]{pics/protokoll2.png} \caption{Protokollinformationen} \end{center} \end{figure} \paragraph{Wann wird in Protokolldatei geschrieben?} \begin{itemize} \item{UNDO-Information:\\ \begin{itemize} \item bevor die zugehörigen Änderungen in Datenbestand eingebracht werden \item sonst rücksetzen unmöglich \end{itemize} } \item{REDO-Information:\\ \begin{itemize} \item muss geschrieben sein (in tmp Log Datei und Archivdatei), bevor der Abschluss der TA an Programm bzw Benutzer gemeldet wird \item sonst Wiederherstellung nicht möglich \end{itemize} } \end{itemize} \subsubsection{Backward-/Forward Recovery} \begin{enumerate} \item{ Forward:\\ Änderungen sind noch nicht in DB, aber schon in Log. Bevor diese auf DB geschrieben werden, wird ein Commit-Record in Log File geschrieben. Falls was schief geht und der Commit Record noch da ist, werden alle diese Änderungen wiedehrolt und ansonsten nichts getan, da alte Version noch in DB steht.} \item{ Backward:\\ Ins Log kommt immer \textbf{alte} Version eines Wertes. Bei einem Commit wird gewartet bis alle neuen werte in DB stehen. Danach erst wird CommitRecord erstellt und eine Bestätigung signalisiert. Bei Verlust werden entweder alte Daten hergestellt oder nichts getan.} \end{enumerate} \paragraph{Vergleich} \begin{itemize} \item{ Forward Recovery: Hoher Speicherplatzbedarf! Daten werden erst nach Beendigung der TA in DB geschrieben und deswegen solange in Puffer behalten} \item{ Backward-Recovery: Hoher I/O Aufwand! Alle Änderungen müssen vor TA-Ende in Datenfiles stehen.} \end{itemize} \subsubsection{Undo-/Redo Logging} Verbesserung zu Backward-/Forward Recovery. \begin{figure}[H] \begin{center} \includegraphics[scale=0.8]{pics/protokoll.png} \caption{Physische Protokollierung} \end{center} \end{figure} Zustände vor bzw nach einer Änderungen werden protokolliert: \begin{itemize} \item alter Zustand: Before Image (BI) für UNDO \item neuer Zustand: After Image (AI) für REDO \item für jede veränderte Seite (3) wird jeweils eine vollständige Kopie vor (2) und nach (4) der Änderung in den Log geschrieben.\\ $+$ schnelle Recovery\\ $-$ hoher E/A Aufwand \end{itemize} \paragraph{Optimierungen} Um Log-Aufwand zu reduzieren nur geänderte \textbf{Teile einer Seite} protokollieren.\\ Sammlung und Pufferung im HS: \begin{itemize} \item $+$ reduzierter E/A Aufwand \item $-$ komplexeres und zeitaufwändigeres Recovery\\ Zurückspeichern gleicht eher dem Neu einfügen (freien Platz suchen, TID vergeben), da Stelle von wo Einträge stammen andersweitig genutzt werden können \end{itemize} \subsubsection{Sicherungspunkte} Ma"snahmen zur Begrenzung des REDO Aufwands nach Systemfehlern (alle erfolgreichen Änderungen die im Puffer verloren gegangen sind müssen wiederholt werden $\rightarrow$ nicht praktikabel! \paragraph*{Methoden} \begin{itemize} \item{ \textbf{Transaction-Oriented Checkpoint}\\ Geänderte Seiten einer TA nach TA-ende sofort in DB bringen (siehe FORCE) $\rightarrow$ zu hohe Belastung} \item{ \textbf{ Transaction-COnsisten Checkpoint} \begin{itemize} \item Einbringung aller Änderung erfolgreicher TA's \item Lesesperee auf ganzer DB zum Zeitpunkt des Sicherungspunktes \item Verzögerung von TA's \item Sicherungspunkt begrenzt Undo und Redo Recovery \end{itemize} } \item{ \textbf{Action-Consisten Checkpoint} \begin{itemize} \item Zum Zeitpunkt des Sicherungspunktes dürfen keine Änderunen aktiv sein \item Begünstigt nur Recovery, dafür kürzere Totzeit von System \end{itemize} } \end{itemize} \subsubsection{Allgemeine Restart Prozedur} \textbf{3-phasiger Ansatz} \begin{enumerate} \item Analyse Lauf Vom letzten Checkpoint bis zum Log Ende. Bestimmung von Gewinner und Verlierer TA's, sowie Seiten, die von ihnen geändert wurden \item Undo Lauf \\ Rücksetzen der Verlierer TA's durch Rückwärtslesen des Logs bis zum BOT Satz der ältesten Verlierer TA \item Redo Lauf \\ Vorwärtslesen des Logs (Startpunkt abhängig von Checkpoint Typ) und Änderungen der Gewinner TA's wiederholen \end{enumerate}