{"id":36650,"date":"2019-10-31T22:12:54","date_gmt":"2019-10-31T19:12:54","guid":{"rendered":"https:\/\/prohoster.info\/blog\/tranzaktsii-v-globalah-intersystems-iris\/"},"modified":"2019-10-31T22:12:54","modified_gmt":"2019-10-31T19:12:54","slug":"tranzaktsii-v-globalah-intersystems-iris","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/tranzaktsii-v-globalah-intersystems-iris","title":{"rendered":"Transaktionen in globalen InterSystems IRIS","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Transaktionen in globalen InterSystems IRIS\" src=\"\/wp-content\/uploads\/2019\/07\/ee4e58369616511dc213f94158b04e4f.jpg\" style=\"display:block;margin: 0 auto;\" \/>Die InterSystems IRIS-Datenbank unterst\u00fctzt interessante Datenstrukturen \u2013 Global-Variablen. Im Grunde handelt es sich dabei um mehrstufige Schl\u00fcssel mit verschiedenen zus\u00e4tzlichen Funktionen wie Transaktionen, schnellen Methoden zur Navigierung in Datenb\u00e4umen, Sperrmechanismen und einer eigenen Sprache, ObjectScript.<\/p>\n<p>Mehr zu Global-Variablen finden Sie in der Artikelreihe \u201eGlobal-Variablen \u2013 die Sch\u00e4tze der Datenspeicherung\u201c:<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/intersystems\/blog\/263791\/\">B\u00e4ume. Teil 1<\/a><\/noindex> <br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/intersystems\/blog\/264173\/\">B\u00e4ume. Teil 2<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/intersystems\/blog\/268465\/\">Sparsame Arrays. Teil 3<\/a><\/noindex><\/p>\n<p>Ich war neugierig, wie Transaktionen in Global-Variablen umgesetzt sind und welche Besonderheiten es dabei gibt. Schlie\u00dflich handelt es sich um eine v\u00f6llig andere Struktur zur Datenspeicherung als die uns vertrauten Tabellen \u2013 viel tiefer in der Ebene.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nWie aus der Theorie relationaler Datenbanken bekannt ist, sollte eine gute Implementierung von Transaktionen die Anforderungen erf\u00fcllen <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/ACID\">ACID<\/a><\/noindex>:<\/p>\n<p><b>A \u2014 Atomic (Atomarit\u00e4t).<\/b> Alle \u00c4nderungen, die in einer Transaktion vorgenommen werden, m\u00fcssen entweder vollst\u00e4ndig erfasst oder gar nicht gespeichert werden.<\/p>\n<p><b>C \u2014 Consistency (Konsistenz).<\/b> Nach Abschluss der Transaktion muss der logische Zustand der Datenbank intern widerspruchsfrei sein. Dieses Erfordernis betrifft in hohem Ma\u00dfe den Programmierer, ist aber auch f\u00fcr relationale SQL-Datenbanken relevant und betrifft die externen Schl\u00fcssel.<\/p>\n<p><b>I \u2014 Isolation (Isolation).<\/b> Parallel ausgef\u00fchrte Transaktionen d\u00fcrfen sich nicht gegenseitig beeinflussen.<\/p>\n<p><b>D \u2014 Durable (Best\u00e4ndigkeit).<\/b> Nach dem erfolgreichen Abschluss einer Transaktion sollten Probleme auf unteren Ebenen (zum Beispiel Stromausf\u00e4lle) keinen Einfluss auf die durch die Transaktion ge\u00e4nderten Daten haben.<\/p>\n<p>Globals sind nicht-relationale Datenstrukturen. Sie wurden f\u00fcr eine extrem schnelle Ausf\u00fchrung auf sehr begrenzter Hardware entwickelt. Lassen Sie uns die Implementierung von Transaktionen in Globals mithilfe von <noindex><a rel=\"nofollow\" href=\"https:\/\/hub.docker.com\/_\/intersystems-iris-data-platform\/plans\/222f869e-567c-4928-b572-eb6a29706fbd?tab=instructions\">dem offiziellen Docker-Image von IRIS<\/a><\/noindex>.<\/p>\n<p>F\u00fcr die Unterst\u00fctzung von Transaktionen in IRIS werden die folgenden Befehle verwendet: <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.intersystems.com\/irislatest\/csp\/docbook\/DocBook.UI.Page.cls?KEY=RCOS_ctstart\">TSTART<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.intersystems.com\/irislatest\/csp\/docbook\/DocBook.UI.Page.cls?KEY=RCOS_ctcommit\">TCOMMIT<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.intersystems.com\/irislatest\/csp\/docbook\/DocBook.UI.Page.cls?KEY=RCOS_ctrollback\">TROLLBACK<\/a><\/noindex>.<\/p>\n<h2>1. Atomarit\u00e4t<\/h2>\n<p>\nDie \u00dcberpr\u00fcfung der Atomarit\u00e4t ist am einfachsten. Wir \u00fcberpr\u00fcfen dies \u00fcber die Datenbankkonsole.<\/p>\n<pre><code class=\"bash\">Kill ^a\nTSTART\nSet ^a(1) = 1\nSet ^a(2) = 2\nSet ^a(3) = 3\nTCOMMIT<\/code><\/pre>\n<p>\nDann ziehen wir folgende Schlussfolgerung:<\/p>\n<pre><code class=\"bash\">Write ^a(1), \u201c \u201d, ^a(2), \u201c \u201d, ^a(3)<\/code><\/pre>\n<p>\nWir erhalten:<\/p>\n<pre><code class=\"bash\">1 2 3<\/code><\/pre>\n<p>\nAlles in Ordnung. Die Atomarit\u00e4t wurde gewahrt: Alle \u00c4nderungen wurden gespeichert.<\/p>\n<p>Lassen Sie uns die Aufgabe erschweren, einen Fehler einf\u00fchren und sehen, wie die Transaktion gespeichert wird, teilweise oder gar nicht.<\/p>\n<p>\u00dcberpr\u00fcfen wir erneut die Atomarit\u00e4t:<\/p>\n<pre><code class=\"bash\">Kill ^A\nTSTART\nSet ^a(1) = 1\nSet ^a(2) = 2\nSet ^a(3) = 3<\/code><\/pre>\n<p>\nDanach stoppen wir den Container gewaltsam, starten ihn neu und schauen nach. <\/p>\n<pre><code class=\"bash\">docker kill my-iris<\/code><\/pre>\n<p>\nDieser Befehl ist praktisch das \u00c4quivalent zu einem gewaltsamen Ausschalten des Stroms, da er ein sofortiges Stoppsignal f\u00fcr den Prozess SIGKILL sendet.<\/p>\n<p>K\u00f6nnte die Transaktion teilweise gespeichert worden sein?<\/p>\n<pre><code class=\"bash\">WRITE ^a(1), ^a(2), ^a(3)\n^\n ^a(1)<\/code><\/pre>\n<p>\n \u2014 Nein, es wurde nichts gespeichert.<\/p>\n<p>Testen wir den Rollback-Befehl:<\/p>\n<pre><code class=\"bash\">Kill ^A\nTSTART\nSet ^a(1) = 1\nSet ^a(2) = 2\nSet ^a(3) = 3\nTROLLBACK\n\nWRITE ^a(1), ^a(2), ^a(3)\n^\n ^a(1)<\/code><\/pre>\n<p>\nEs wurde ebenfalls nichts gespeichert.<\/p>\n<h2>2. Konsistenz<\/h2>\n<p>\nDa in den Globals die Schl\u00fcssel ebenfalls auf den Globals basieren (ich erinnere daran, dass ein Global eine niedrigere Datenspeicherstruktur als eine relationale Tabelle ist), muss f\u00fcr die Einhaltung der Konsistenz die \u00c4nderung des Schl\u00fcssels in dieselbe Transaktion einbezogen werden, wie die \u00c4nderung des Globals.<\/p>\n<p>Zum Beispiel haben wir ein Global ^person, in dem wir Personen speichern, und als Schl\u00fcssel verwenden wir die Steueridentifikationsnummer.<\/p>\n<pre><code class=\"bash\">^person(1234567, 'firstname') = 'Sergey'\n^person(1234567, 'lastname') = 'Kamenev'\n^person(1234567, 'phone') = '+74995555555\n...<\/code><\/pre>\n<p>\nUm eine schnelle Suche nach Nachnamen und Vornamen zu erm\u00f6glichen, haben wir den Schl\u00fcssel ^index erstellt.<\/p>\n<pre><code class=\"bash\">^index('Kamenev', 'Sergey', 1234567) = 1<\/code><\/pre>\n<p>\nDamit die Datenbank konsistent bleibt, m\u00fcssen wir die Person so hinzuf\u00fcgen:<\/p>\n<pre><code class=\"bash\">TSTART\n^person(1234567, \u2018firstname\u2019) = \u2018Sergey\u2019\n^person(1234567, \u2018lastname\u2019) = \u2018Kamenev\u2019\n^person(1234567, \u2018phone\u2019) = \u2018+74995555555\n^index(\u2018Kamenev\u2019, \u2018Sergey\u2019, 1234567) = 1\nTCOMMIT<\/code><\/pre>\n<p>\nDaher m\u00fcssen wir bei einer L\u00f6schung ebenfalls eine Transaktion verwenden:<\/p>\n<pre><code class=\"bash\">TSTART\nKill ^person(1234567)\nZKill ^index(\u2018Kamenev\u2019, \u2018Sergey\u2019, 1234567)\nTCOMMIT<\/code><\/pre>\n<p>\nMit anderen Worten, die Einhaltung des Konsistenzanspruchs liegt vollst\u00e4ndig in der Verantwortung des Programmierers. Wenn es um globale Variablen geht, ist das jedoch in Ordnung, aufgrund ihrer niedrigen Abstraktionsebene.<\/p>\n<h2>3. Isolation<\/h2>\n<p>\nHier wird es kompliziert. Viele Benutzer arbeiten gleichzeitig an derselben Datenbank und \u00e4ndern dieselben Daten.<\/p>\n<p>Die Situation ist vergleichbar mit vielen Benutzern, die gleichzeitig an demselben Code-Repository arbeiten und versuchen, gleichzeitig \u00c4nderungen an vielen Dateien zu committen.<\/p>\n<p>Die Datenbank muss all dies in Echtzeit bew\u00e4ltigen. In ernsthaften Unternehmen gibt es sogar spezielle Personen, die f\u00fcr die Versionskontrolle (f\u00fcr das Zusammenf\u00fchren von Branches, das L\u00f6sen von Konflikten usw.) zust\u00e4ndig sind, w\u00e4hrend die Datenbank all dies in Echtzeit erledigen muss. Daher wird die Komplexit\u00e4t der Aufgabe und die Richtigkeit des Datenbankdesigns sowie des Codes, der sie betreut, offensichtlich.<\/p>\n<p>Die Datenbank kann den Sinn der von den Nutzern durchgef\u00fchrten Aktionen nicht verstehen, um Konflikte zu vermeiden, wenn sie an denselben Daten arbeiten. Sie kann lediglich eine Transaktion, die einer anderen widerspricht, zur\u00fccknehmen oder diese nacheinander ausf\u00fchren.<\/p>\n<p>Ein weiteres Problem besteht darin, dass w\u00e4hrend der Ausf\u00fchrung einer Transaktion (vor dem Commit) der Zustand der Datenbank inkonsistent sein kann. Daher ist es w\u00fcnschenswert, dass andere Transaktionen keinen Zugriff auf einen inkonsistenten Zustand der Datenbank haben, was in relationalen Datenbanken auf verschiedene Weise erreicht wird: durch das Erstellen von Snapshots, Mehrversionen von Zeilen usw.<\/p>\n<p>Bei der parallelen Ausf\u00fchrung von Transaktionen ist es wichtig, dass sie sich nicht gegenseitig st\u00f6ren. Das ist das Isolationsmerkmal.<\/p>\n<p>SQL definiert 4 Isolationsebenen:<\/p>\n<ul>\n<li>READ UNCOMMITTED<\/li>\n<li>READ COMMITTED<\/li>\n<li>REPEATABLE READ<\/li>\n<li>SERIALIZABLE<\/li>\n<\/ul>\n<p>\nBetrachten wir jede Ebene einzeln. Die Implementierungskosten jeder Ebene steigen beinahe exponentiell.<\/p>\n<p><b>READ UNCOMMITTED<\/b> \u2014 dies ist die niedrigste Isolationsebene, aber gleichzeitig die schnellste. Transaktionen k\u00f6nnen \u00c4nderungen lesen, die von anderen vorgenommen wurden.<\/p>\n<p><b>READ COMMITTED<\/b> \u2014 dies ist die n\u00e4chste Isolationsebene, die einen Kompromiss darstellt. Transaktionen k\u00f6nnen keine \u00c4nderungen lesen, die von anderen vorgenommen wurden, bis diese festgeschrieben sind, aber sie k\u00f6nnen alle \u00c4nderungen lesen, die nach dem Commit vorgenommen wurden.<\/p>\n<p>Wenn wir eine lange Transaktion T1 haben, w\u00e4hrend der Commits in den Transaktionen T2, T3 \u2026 Tn stattfinden, die mit denselben Daten arbeiten wie T1, werden wir bei einer Abfrage von Daten in T1 jedes Mal ein anderes Ergebnis erhalten. Dieses Ph\u00e4nomen wird als nicht wiederholbare Lesung bezeichnet.<\/p>\n<p><b>REPEATABLE READ<\/b> \u2014 In diesem Isolationsniveau gibt es kein Ph\u00e4nomen des wiederholten Lesens, da f\u00fcr jede Datenleseanfrage eine Momentaufnahme der Daten erstellt wird und bei der erneuten Verwendung in derselben Transaktion die Daten aus der Momentaufnahme verwendet werden. Allerdings ist in diesem Isolationsniveau das Lesen von Phantomdaten m\u00f6glich. Das bedeutet das Lesen neuer Zeilen, die von parallel fixierten Transaktionen hinzugef\u00fcgt wurden.<\/p>\n<p><b>SERIALIZABLE<\/b> \u2014 Die h\u00f6chste Stufe der Isolation. Sie zeichnet sich dadurch aus, dass Daten, die in einer Transaktion auf irgendeine Weise verwendet werden (lesen oder \u00e4ndern), f\u00fcr andere Transaktionen erst nach Abschluss der ersten Transaktion verf\u00fcgbar sind.<\/p>\n<p>Lassen Sie uns zun\u00e4chst herausfinden, ob es eine Isolation der Operationen in der Transaktion vom Hauptthread gibt. \u00d6ffnen wir 2 Terminalfenster.<\/p>\n<pre><code class=\"bash\">Kill ^t\n\nWrite ^t(1)\n2<\/code><\/pre>\n<pre><code class=\"bash\">\nTSTART\nSet ^t(1)=2<\/code><\/pre>\n<p>\nEs gibt keine Isolation. Ein Thread sieht, was der andere, der die Transaktion er\u00f6ffnet hat, macht.<\/p>\n<p>Lassen Sie uns \u00fcberpr\u00fcfen, ob die Transaktionen unterschiedlicher Threads das sehen, was innerhalb von ihnen passiert. <\/p>\n<p>\u00d6ffnen wir 2 Terminalfenster und initiieren wir 2 Transaktionen parallel.<\/p>\n<pre><code class=\"bash\">kill ^t\nTSTART\nWrite ^t(1)\n3<\/code><\/pre>\n<pre><code class=\"bash\">\nTSTART\nSet ^t(1)=3\n<\/code><\/pre>\n<p>\nParallele Transaktionen sehen einander die Daten. Daher haben wir die einfachste, aber auch schnellste Isolationsstufe READ UNCOMMITTED erreicht.<\/p>\n<p>Das war grunds\u00e4tzlich f\u00fcr globale Transaktionen zu erwarten, bei denen die Leistung stets im Vordergrund steht. <\/p>\n<p>Was ist, wenn wir ben\u00f6tigen, eine h\u00f6here Isolationsstufe f\u00fcr die Operationen auf den globalen Transaktionen?<\/p>\n<p>Hier sollten wir dar\u00fcber nachdenken, warum Isolationsstufen \u00fcberhaupt notwendig sind und wie sie funktionieren.<\/p>\n<p>Die h\u00f6chste Isolationsstufe SERIALIZE bedeutet, dass das Ergebnis parallel ausgef\u00fchrter Transaktionen dem sequenziellen Ablauf entspricht, was Kollisionen ausschlie\u00dft.<\/p>\n<p>Das k\u00f6nnen wir mit geeigneten Sperren in ObjectScript erreichen, die zahlreiche Anwendungsm\u00f6glichkeiten bieten: man kann einfache, inkrementelle oder multiple Sperren mit dem Befehl <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.intersystems.com\/latest\/csp\/docbook\/DocBook.UI.Page.cls?KEY=RCOS_clock\">LOCK<\/a><\/noindex>.<\/p>\n<p>Niedrigere Isolationsstufen sind Kompromisse, die dazu dienen, die Geschwindigkeit der Datenbank zu erh\u00f6hen.<\/p>\n<p>Schauen wir uns an, wie wir verschiedene Isolationsstufen mit Hilfe von Sperren erreichen k\u00f6nnen.<\/p>\n<p>Dieser Operator erm\u00f6glicht nicht nur exklusive Sperren, die f\u00fcr die Daten\u00e4nderung erforderlich sind, sondern auch sogenannte Shared-Sperren, die parallel von mehreren Threads genutzt werden k\u00f6nnen, wenn sie Daten lesen m\u00fcssen, die von anderen Prozessen w\u00e4hrend des Lesens nicht ver\u00e4ndert werden d\u00fcrfen.<\/p>\n<p>Mehr \u00fcber das Zwei-Phasen-Sperrverfahren in russischer und englischer Sprache:<\/p>\n<p>\u2192 <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%94%D0%B2%D1%83%D1%85%D1%84%D0%B0%D0%B7%D0%BD%D0%B0%D1%8F_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0\">Zwei-Phasen-Sperrverfahren<\/a><\/noindex><br \/>\n\u2192 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Two-phase_locking\">Two-phase locking<\/a><\/noindex><\/p>\n<p>Die Schwierigkeit besteht darin, dass der Zustand der Datenbank w\u00e4hrend einer Transaktion inkonsistent sein kann, jedoch sind diese inkonsistenten Daten f\u00fcr andere Prozesse sichtbar. Wie kann man das vermeiden?<\/p>\n<p>Wir erstellen mithilfe von Sperren Sichtfenster, in denen der Datenbankzustand konsistent ist. Und alle Zugriffe auf solche Sichtfenster des konsistenten Zustands werden durch Sperren kontrolliert.<\/p>\n<p>Shared-Sperren f\u00fcr dieselben Daten sind wiederverwendbar \u2013 sie k\u00f6nnen von mehreren Prozessen beansprucht werden. Diese Sperren verhindern, dass andere Prozesse die Daten \u00e4ndern, d.h. sie werden verwendet, um Fenster des konsistenten Datenbankzustands zu bilden.<\/p>\n<p>Exklusive Sperren werden verwendet, um Daten\u00e4nderungen zu steuern \u2013 eine solche Sperre kann nur von einem Prozess \u00fcbernommen werden. Eine exklusive Sperre kann \u00fcbernommen werden von:<\/p>\n<ol>\n<li>Jedem Prozess, wenn die Daten verf\u00fcgbar sind<\/li>\n<li>Nur dem Prozess, der eine Shared-Sperre f\u00fcr diese Daten hat und der als Erster eine exklusive Sperre angefordert hat.<\/li>\n<\/ol>\n<p>\n<img decoding=\"async\" alt=\"Transaktionen in globalen InterSystems IRIS\" src=\"\/wp-content\/uploads\/2019\/07\/bb91ed1268925bc1b9266763ab82646a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJe enger das Sichtfenster, desto l\u00e4nger m\u00fcssen andere Prozesse warten, doch desto konsistenter kann der Zustand der Datenbank darin sein.<\/p>\n<p><b>READ_COMMITED<\/b> Der Kern dieses Niveaus ist, dass wir nur die von anderen Streams committeten Daten sehen. Wenn die Daten in einer anderen Transaktion noch nicht committet sind, sehen wir ihre alte Version.<\/p>\n<p>Das erm\u00f6glicht uns, die Arbeit zu parallelisieren, anstatt auf das Freigeben der Sperre zu warten.<\/p>\n<p>Ohne spezielle Tricks k\u00f6nnen wir die alte Datenversion in IRIS nicht sehen, daher m\u00fcssen wir mit Sperren arbeiten.<\/p>\n<p>Daher m\u00fcssen wir mithilfe von Shared-Sperren das Lesen von Daten nur in Momenten der Konsistenz erlauben.<\/p>\n<p>Angenommen, wir haben eine Benutzerdatenbank ^person, in der Nutzer Geld untereinander \u00fcberweisen.<\/p>\n<p>Der Moment der \u00dcberweisung von Person 123 zu Person 242:<\/p>\n<pre><code class=\"bash\">LOCK +^person(123), +^person(242)\nSet ^person(123, amount) = ^person(123, amount) - amount\nSet ^person(242, amount) = ^person(242, amount) + amount\nLOCK -^person(123), -^person(242)<\/code><\/pre>\n<p>\nDer Moment der Abfrage des Geldbetrags bei Person 123 vor der Abbuchung muss mit einer exklusiven Sperre (standardm\u00e4\u00dfig) einhergehen:<\/p>\n<pre><code class=\"bash\">LOCK +^person(123)\nWrite ^person(123)<\/code><\/pre>\n<p>\nWenn Sie den Kontostand im Kundenportal anzeigen m\u00fcssen, k\u00f6nnen Sie eine gemeinsame Sperre verwenden oder sie sogar ganz weglassen:<\/p>\n<pre><code class=\"bash\">LOCK +^person(123)#\u201dS\u201d\nWrite ^person(123)<\/code><\/pre>\n<p>\nAllerdings, wenn man annimmt, dass Datenbankoperationen nahezu sofort durchgef\u00fchrt werden (ich erinnere daran, dass Globals eine viel niedrigere Struktur sind als relationale Tabellen), sinkt die Notwendigkeit dieses Levels.<\/p>\n<p><b>REPEATABLE READ<\/b> \u2014 auf diesem Isolationslevel ist es zul\u00e4ssig, dass mehrere Lesevorg\u00e4nge auf Daten durchgef\u00fchrt werden, die durch parallele Transaktionen ge\u00e4ndert werden k\u00f6nnen. <\/p>\n<p>Deshalb m\u00fcssen wir eine gemeinsame Sperre f\u00fcr das Lesen von Daten setzen, die wir \u00e4ndern, und exklusive Sperren f\u00fcr die Daten, die wir \u00e4ndern.<\/p>\n<p>Zum Gl\u00fcck erlaubt der LOCK-Befehl, in einem einzigen Befehl alle erforderlichen Sperren detailliert aufzulisten, was sehr viele sein k\u00f6nnen.<\/p>\n<pre><code class=\"bash\">LOCK +^person(123, amount)#\u201dS\u201d\nLesen von ^person(123, amount)<\/code><\/pre>\n<p>\nandere Operationen (parallel versuchen w\u00e4hrenddessen andere Threads ^person(123, amount) zu \u00e4ndern, k\u00f6nnen dies jedoch nicht)<\/p>\n<pre><code class=\"bash\">LOCK +^person(123, amount)\n\u00c4nderung von ^person(123, amount)\nLOCK -^person(123, amount)\n\nLesen von ^person(123, amount)\nLOCK -^person(123, amount)#\u201dS\u201d<\/code><\/pre>\n<p>\nBei der Auflistung von Sperren durch Kommas werden diese nacheinander behandelt, und wenn man es so macht:<\/p>\n<pre><code class=\"bash\">LOCK +(^person(123),^person(242))<\/code><\/pre>\n<p>\nwerden sie atomar alle sofort behandelt.<\/p>\n<p><b>SERIALIZE<\/b> \u2014 wir m\u00fcssen die Sperren so setzen, dass am Ende alle Transaktionen, die gemeinsame Daten haben, nacheinander ausgef\u00fchrt werden. F\u00fcr diesen Ansatz sollten die meisten Sperren exklusiv sein und auf die kleinsten Bereiche des Globals f\u00fcr die Leistung gesetzt werden.<\/p>\n<p>Spricht man jedoch von Abhebungen im Global ^person, ist nur das Isolationsniveau SERIALIZE akzeptabel, da Geld strikt nacheinander ausgegeben werden muss, sonst k\u00f6nnte der gleiche Betrag mehrere Male ausgegeben werden.<\/p>\n<h2>4. Best\u00e4ndigkeit<\/h2>\n<p>\nIch habe Tests mit abruptem Herunterfahren des Containers durchgef\u00fchrt durch<\/p>\n<pre><code class=\"bash\">docker kill my-iris<\/code><\/pre>\n<p>\nDie Basis hat das gut verkraftet. Es wurden keine Probleme festgestellt.<\/p>\n<h2>Fazit<\/h2>\n<p>\nF\u00fcr Globalen bietet InterSystems IRIS Unterst\u00fctzung f\u00fcr Transaktionen. Diese sind tats\u00e4chlich atomar und zuverl\u00e4ssig. Um jedoch die Konsistenz der Datenbank in diesen Globalen zu gew\u00e4hrleisten, sind Programmieraufwand und der Einsatz von Transaktionen erforderlich, da es keine komplexen eingebauten Strukturen wie Fremdschl\u00fcssel gibt.<\/p>\n<p>Das Isolationsniveau bei Globalen ohne Verwendung von Sperren ist READ UNCOMMITTED, w\u00e4hrend bei Verwendung von Sperren auch SERIALIZE als Isolationsniveau erreicht werden kann.<\/p>\n<p>Die Korrektheit und Geschwindigkeit von Transaktionen in Globalen h\u00e4ngen stark von der Kompetenz des Programmierers ab: Je breiter Shared-Sperren beim Lesen eingesetzt werden, desto h\u00f6her ist das Isolationsniveau, w\u00e4hrend eine engere Verwendung exklusiver Sperren die Geschwindigkeit erh\u00f6ht.<br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/461753\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u0423\u0411\u0414 InterSystems IRIS \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0433\u043b\u043e\u0431\u0430\u043b\u044b. \u041f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0448\u043a\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439, \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a \u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430 ObjectScript. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 \u0432 \u0446\u0438\u043a\u043b\u0435 \u0441\u0442\u0430\u0442\u0435\u0439 \u00ab\u0413\u043b\u043e\u0431\u0430\u043b\u044b \u2014 \u043c\u0435\u0447\u0438-\u043a\u043b\u0430\u0434\u0435\u043d\u0446\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445\u00bb: \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 1 \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 2 \u0420\u0430\u0437\u0440\u0435\u0436\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b. \u0427\u0430\u0441\u0442\u044c [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":27448,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-36650","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u0423\u0411\u0414 InterSystems IRIS \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0433\u043b\u043e\u0431\u0430\u043b\u044b. \u041f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0448\u043a\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439, \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a \u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430 ObjectScript. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 \u0432 \u0446\u0438\u043a\u043b\u0435 \u0441\u0442\u0430\u0442\u0435\u0439 \u00ab\u0413\u043b\u043e\u0431\u0430\u043b\u044b \u2014 \u043c\u0435\u0447\u0438-\u043a\u043b\u0430\u0434\u0435\u043d\u0446\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445\u00bb: \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 1 \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 2 \u0420\u0430\u0437\u0440\u0435\u0436\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b. \u0427\u0430\u0441\u0442\u044c\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/tranzaktsii-v-globalah-intersystems-iris\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 InterSystems IRIS | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u0423\u0411\u0414 InterSystems IRIS \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0433\u043b\u043e\u0431\u0430\u043b\u044b. \u041f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0448\u043a\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439, \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a \u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430 ObjectScript. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 \u0432 \u0446\u0438\u043a\u043b\u0435 \u0441\u0442\u0430\u0442\u0435\u0439 \u00ab\u0413\u043b\u043e\u0431\u0430\u043b\u044b \u2014 \u043c\u0435\u0447\u0438-\u043a\u043b\u0430\u0434\u0435\u043d\u0446\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445\u00bb: \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 1 \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 2 \u0420\u0430\u0437\u0440\u0435\u0436\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b. \u0427\u0430\u0441\u0442\u044c\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/tranzaktsii-v-globalah-intersystems-iris\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:12:54+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:12:54+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Transaktionen in den Globals von InterSystems IRIS | ProHoster","description":"Die Datenbank InterSystems IRIS unterst\u00fctzt interessante Strukturen zur Datenspeicherung \u2013 die Globals. Im Grunde handelt es sich dabei um mehrstufige Schl\u00fcssel mit verschiedenen zus\u00e4tzlichen Funktionen wie Transaktionen, schnellen Funktionen zum Durchlaufen von Datenb\u00e4umen, Sperren und der eigenen Sprache ObjectScript. Erfahren Sie mehr \u00fcber Globals in der Artikelreihe \u201eGlobals \u2013 die Sch\u00e4tze zur Datenspeicherung\u201c: B\u00e4ume. Teil 1 B\u00e4ume. Teil 2 Verdichtete Arrays. Teil","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/tranzaktsii-v-globalah-intersystems-iris","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 InterSystems IRIS | ProHoster","og:description":"\u0421\u0423\u0411\u0414 InterSystems IRIS \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0433\u043b\u043e\u0431\u0430\u043b\u044b. \u041f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0448\u043a\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439, \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a \u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430 ObjectScript. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0433\u043b\u043e\u0431\u0430\u043b\u0430\u0445 \u0432 \u0446\u0438\u043a\u043b\u0435 \u0441\u0442\u0430\u0442\u0435\u0439 \u00ab\u0413\u043b\u043e\u0431\u0430\u043b\u044b \u2014 \u043c\u0435\u0447\u0438-\u043a\u043b\u0430\u0434\u0435\u043d\u0446\u044b \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445\u00bb: \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 1 \u0414\u0435\u0440\u0435\u0432\u044c\u044f. \u0427\u0430\u0441\u0442\u044c 2 \u0420\u0430\u0437\u0440\u0435\u0436\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b. \u0427\u0430\u0441\u0442\u044c","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/tranzaktsii-v-globalah-intersystems-iris","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:12:54+00:00","article:modified_time":"2019-10-31T19:12:54+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"36650","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 04:17:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:41:52","updated":"2026-01-22 04:17:19"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/36650","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=36650"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/36650\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/27448"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=36650"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=36650"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=36650"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}