Skip to content

Commit cec6537

Browse files
committed
[Sync EN] Restructure persistent connections chapter
Brings features/persistent-connections.xml up to date with the upstream rewrite (EN-Revision ee5ee84013f11aaaf01b09484bc9aa3225379748): - Page is restructured into named <simplesect> blocks instead of one long flow: Was sind persistente Verbindungen?, Web-Anfragen, Kommandozeilen-Prozesse, Wozu sie verwenden?, Mögliche Nachteile (Verbindungslimits, Verwaltung des Verbindungszustands), Schlussbemerkungen, Siehe auch. - New CLI section explains that command-line PHP does not share persistent connections between invocations. - New note about phpinfo / PHP_SAPI to check the Server API and which values ("Apache 2 Handler", "FPM/FastCGI") actually keep persistent connections alive. - Drawbacks section expanded: explicit list of connection-state items to clean up (selected database, table locks, uncommitted transactions, temporary tables, profiling-style settings), guidance on connection limits with PHP-FPM workers, cleanup via destructors or register_shutdown_function(). - New final-words section recommending alternatives such as fixing connection-creation overheads (e.g. reverse DNS), dedicated connection pooling proxies, or long-running application servers for high-volume APIs. - See-also block converted to a proper simplelist with all the _pconnect functions plus MySQLi and PDO connection-management links. - The obsolete IIS/NSAPI/WebSite-Pro paragraph is dropped (matches EN). - The obsolete <!-- $Revision$ --> SVN marker is dropped. Existing Maintainer (hholzgra) and Credits (tom) are kept.
1 parent 00047d5 commit cec6537

1 file changed

Lines changed: 230 additions & 141 deletions

File tree

features/persistent-connections.xml

Lines changed: 230 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,237 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<!-- $Revision$ -->
3-
<!-- EN-Revision: 0799f7789c50a11b746ad713cc8787e4b04dd926 Maintainer: hholzgra Status: ready -->
2+
<!-- EN-Revision: ee5ee84013f11aaaf01b09484bc9aa3225379748 Maintainer: hholzgra Status: ready -->
43
<!-- Credits: tom -->
5-
<chapter xml:id="features.persistent-connections" xmlns="http://docbook.org/ns/docbook">
6-
<title>Persistente Datenbankverbindungen</title>
4+
<chapter xml:id="features.persistent-connections" xmlns="http://docbook.org/ns/docbook">
5+
<title>Persistente Datenbankverbindungen</title>
76

7+
<simplesect>
8+
<title>Was sind persistente Verbindungen?</title>
89
<simpara>
9-
Persistente Verbindungen sind Verbindungen, die nach
10-
Abarbeitung des Skriptes nicht geschlossen werden. Wenn eine
11-
persistente Verbindung angefordert wird, prüft PHP zuerst, ob
12-
bereits eine identische persistente Verbindung (die vielleicht
13-
vorher offen geblieben ist) existiert und benutzt sie in diesem Fall.
14-
Sollte keine Verbindung existieren, wird eine hergestellt. Eine
15-
'identische' Verbindung ist eine Verbindung, die zu dem
16-
gleichen Host mit dem gleichen Usernamen und Passwort
17-
hergestellt wurde.</simpara>
18-
<simpara>
19-
Wer nicht durchgängig mit der Art und Weise vertraut ist, wie
20-
Webserver arbeiten und die Last verteilen, könnte missverstehen,
21-
wofür persistente Verbindungen gedacht sind. Im Besonderen bieten
22-
sie <emphasis>keine</emphasis> Möglichkeit, 'Benutzersitzungen'
23-
über die gleiche Verbindung zu öffnen und
24-
<emphasis>keine</emphasis> Möglichkeit, eine Transaktion effizient
25-
aufzubauen, und sie können auch viele andere Dinge nicht. Um
26-
absolute Klarheit zu schaffen: Persistente Verbindungen bieten
27-
<emphasis>keine</emphasis> Funktionalität, die nicht auch von
28-
nicht-persistenten Verbindungen bereitgestellt wird.
29-
</simpara>
30-
<simpara>
31-
Warum?
32-
</simpara>
33-
<simpara>
34-
Das hat mit der Arbeitsweise von Webservern zu tun. Es gibt drei
35-
Möglichkeiten, wie ein Webserver PHP zur Generierung von
36-
Webseiten einsetzen kann.
37-
</simpara>
38-
<simpara>
39-
Die erste Methode ist, PHP als CGI-'Wrapper' zu benutzen.
40-
Wenn diese Methode eingesetzt wird, wird für jede Anfrage
41-
nach einer PHP-Seite vom Webserver eine Instanz des PHP-
42-
Interpreters gestartet und anschließend wieder beendet.
43-
Durch die Beendigung des Interpreters nach abgeschlossener
44-
Anfrage werden alle Ressourcen, auf die zugegriffen wurde
45-
(wie beispielsweise eine Verbindung zu einem SQL-
46-
Datenbankserver) wieder geschlossen. In diesem Fall erreicht
47-
man nichts, wenn man persistente Verbindungen benutzt - sie
48-
sind eben nicht beständig.
49-
</simpara>
50-
<simpara>
51-
Die zweite und populärste Methode ist der Einsatz von PHP als
52-
Modul in einem Multiprozess-Webserver, was momentan nur auf den
53-
Apache zutrifft. Typischerweise hat ein Multiprozess-Webserver
54-
einen Prozess (den 'Eltern' Prozess), der einen Satz weiterer
55-
Prozesse (die 'Kinder') koordiniert, welche die eigentliche Arbeit
56-
des Bereitstellens der Seiten übernehmen. Jede Anfrage, die von
57-
einem Client erfolgt, wird an einen untergeordneten Prozess, der
58-
noch keine andere Anfrage bearbeitet, weitergereicht. Das bedeutet,
59-
dass eine zweite Anfrage des gleichen Clients an den Server unter
60-
Umständen von einem anderen untergeordneten Prozess als die
61-
erste Anfrage bearbeitet wird. Wurde eine persistente Verbindung
62-
einmal geöffnet kann jede danach folgende Seite innerhalb des
63-
gleichen Prozesses diese bereits zum Server bestehende Verbindung
64-
weiter verwenden.
65-
</simpara>
66-
<simpara>
67-
Die letzte Methode ist, PHP als Plug-in für einen Multithread-
68-
Webserver zu benutzen. Derzeit bietet PHP Unterstützung für
69-
WSAPI und NSAPI (unter Windows), wodurch die Nutzung von
70-
PHP mit Multithread-Serven wie Netscape Fast Track (iPlanet),
71-
Microsoft Internet Information Server (IIS) und O'Reilly's WebSite
72-
Pro ermöglicht wird. Das Verhalten entspricht im wesentlichen dem
73-
oben beschriebenen Multiprozess-Modell.
74-
</simpara>
75-
<simpara>
76-
Wozu dienen persistente Verbindungen, wenn sie keine
77-
zusätzliche Funktionalität bieten?
78-
</simpara>
79-
<simpara>
80-
Die Antwort ist außerordentlich einfach: Effizienz. Persistente
81-
Verbindungen sind nützlich, wenn der Aufwand für das Herstellen
82-
einer Verbindung zu einem SQL-Server hoch ist. Ob dies der Fall ist
83-
oder nicht, hängt von vielen Faktoren ab - zum Beispiel, um welche
84-
Datenbank es sich handelt, ob sie auf dem gleichen Rechner wie der
85-
Webserver läuft oder welche Last die SQL-Maschine zu bewältigen hat
86-
usw. Grundsätzlich gilt, dass, wenn viele Verbindungen hergestellt
87-
werden müssen, persistente Verbindungen außerordentlich hilfreich
88-
sind. Sie veranlassen den untergeordneten Prozess, sich während
89-
seiner gesamten Lebensdauer lediglich einmal mit dem SQL-Server zu
90-
verbinden, anstatt bei jedem Aufruf einer Seite, die eine Verbindung
91-
benötigt. Das heißt, dass jeder untergeordnete Prozess, der eine
92-
persistente Verbindung öffnet, seine eigene dauerhafte Verbindung
93-
zum Server hat. Bei 20 untergeordneten Prozessen, die ein Skript
94-
ausführen, das eine persistente Verbindung zum SQL-Server
95-
herstellt, hat man beispielsweise 20 verschiedene Verbindungen
96-
zum SQL-Server - eine für jeden untergeordneten Prozess.
97-
</simpara>
98-
<simpara>
99-
Beachten Sie jedoch, dass dies auch ein paar Nachteile haben kann,
100-
wenn Sie eine Datenbank mit limitierten Verbindungen benutzen, welche
101-
durch persistente Verbindungen überschritten werden. Wenn Ihre Datenbank
102-
ein Limit von 16 gleichzeitigen Verbindungen hat, und aufgrund einer
103-
stark ausgelasteten Server-Session 17 Kind-Prozesse versuchen, eine
104-
Verbindung herzustellen, wird es einem nicht gelingen. Sollten in
105-
Ihren Skripten Fehler bestehen, welche das Schließen der Verbindungen
106-
nicht erlauben (wie z.B. Endlosschleifen), kann das eine Datenbank
107-
mit mit nur 16 Verbindungen sehr schnell überschwemmen. Konsultieren
108-
Sie die Dokumentation Ihrer Datenbank bezüglich der Behandlung von
109-
aufgegebenen Verbindungen oder Verbindungen im Leerlauf.
110-
</simpara>
111-
<warning>
112-
<simpara>
113-
Sie sollten sich zur Vorsicht noch ein paar Gedanken machen, wenn
114-
Sie persistente Verbindungen benutzen. Einer ist, wenn Sie über eine
115-
persistente Verbindung Tabellen sperren und das Skript diese Sperre
116-
aus welchem Grund auch immer nicht mehr aufheben kann, nachfolgende
117-
Skripte, welche die selbe Verbindung benutzen, blockieren und den
118-
Neustart von entweder dem Webserver oder dem Datenbankserver
119-
verlangen. Ein weiterer ist, dass wenn Sie Transaktionen benutzen,
120-
ein Transaktionsblock zu dem nächsten die Verbindung nutzenden Skript
121-
übertragen wird, wenn die Ausführung des Skriptes vor dem
122-
Transaktionsblock gestoppt wird. In jedem Fall können Sie
123-
<function>register_shutdown_function</function> benutzen, um eine
124-
einfache Funktion zu registrieren, welche Ihre Tabellen wieder
125-
entsperrt, oder Ihre Transaktionen zurückstellt. Besser ist es, wenn
126-
Sie dieses Problem gänzlich vermeiden, indem keine persistenten
127-
Verbindungen in Skripten benutzen, welche Tabellen sperren oder
128-
Transaktionen verwenden (Sie können sie immer noch anderswo benutzen).
129-
</simpara>
130-
</warning>
131-
<simpara>
132-
Eine wichtige Zusammenfassung. Persistente Verbindungen wurden
133-
entwickelt, um eins-zu-eins Abbildungen auf reguläre Verbindungen
134-
zu haben. Das heißt, dass man <emphasis>immer</emphasis> in der Lage
135-
sein sollte, die persistenten Verbindungen durch nicht-persistente
136-
zu ersetzten, ohne dass dies den Skriptablauf verändert. Es <emphasis>
137-
kann</emphasis> (und wird vermutlich auch) die Effizienz des Skriptes
138-
beeinflussen, aber nicht dessen Verhalten.
139-
</simpara>
140-
<para>
141-
Siehe auch <function>ibase_pconnect</function>, <function>ociplogon</function>,
142-
<function>odbc_pconnect</function>, <function>oci_pconnect</function>,
143-
<function>pfsockopen</function> und <function>pg_pconnect</function>.
144-
</para>
145-
</chapter>
10+
Persistente Verbindungen sind Verbindungen, die nach Beendigung der
11+
Skriptausführung nicht geschlossen werden. Wird eine persistente
12+
Verbindung angefordert, prüft PHP, ob bereits eine identische persistente
13+
Verbindung (die von einem früheren Aufruf offen geblieben ist) existiert;
14+
ist dies der Fall, wird sie wiederverwendet, andernfalls wird eine neue
15+
Verbindung aufgebaut. Eine 'identische' Verbindung ist eine Verbindung,
16+
die zum gleichen Host mit demselben Benutzernamen und Passwort
17+
(sofern zutreffend) hergestellt wurde.
18+
</simpara>
19+
<simpara>
20+
Es gibt keine Möglichkeit, eine bestimmte Verbindung anzufordern oder zu
21+
garantieren, ob die zurückgegebene Verbindung eine bestehende oder eine
22+
ganz neue ist (etwa wenn alle bestehenden Verbindungen in Verwendung sind
23+
oder die Anfrage von einem anderen Worker bearbeitet wird, der einen
24+
eigenen Pool von Verbindungen besitzt).
25+
</simpara>
26+
<simpara>
27+
Die persistenten Verbindungen von PHP können daher beispielsweise nicht
28+
verwendet werden, um:
29+
</simpara>
30+
<simplelist>
31+
<member>eine bestimmte Datenbanksitzung einem bestimmten Web-Benutzer zuzuweisen</member>
32+
<member>eine umfangreiche Transaktion über mehrere Anfragen hinweg aufzubauen</member>
33+
<member>eine Abfrage in einer Anfrage zu starten und die Ergebnisse in einer anderen abzurufen</member>
34+
</simplelist>
35+
<simpara>
36+
Persistente Verbindungen bieten <emphasis>keinerlei</emphasis>
37+
Funktionalität, die nicht auch mit nicht-persistenten Verbindungen
38+
möglich wäre.
39+
</simpara>
40+
</simplesect>
41+
42+
<simplesect xml:id="persistent-connections.web">
43+
<title>Web-Anfragen</title>
44+
<simpara>
45+
Es gibt zwei Möglichkeiten, wie ein Webserver PHP zur Generierung von
46+
Webseiten einsetzen kann:
47+
</simpara>
48+
<simpara>
49+
Die erste Methode ist, PHP als CGI-"Wrapper" zu benutzen. Wenn diese
50+
Methode eingesetzt wird, wird für jede Anfrage nach einer PHP-Seite vom
51+
Webserver eine Instanz des PHP-Interpreters gestartet und anschließend
52+
wieder beendet. Durch die Beendigung des Interpreters nach jeder Anfrage
53+
werden alle Ressourcen, auf die zugegriffen wurde (wie beispielsweise
54+
eine Verbindung zu einem SQL-Datenbankserver), wieder geschlossen. In
55+
diesem Fall erreicht man nichts, wenn man persistente Verbindungen
56+
benutzt - sie sind eben nicht beständig.
57+
</simpara>
58+
<simpara>
59+
Die zweite und populärste Methode ist der Einsatz von PHP-FPM oder von
60+
PHP als Modul in einem Multiprozess-Webserver (derzeit nur Apache).
61+
Solche Setups haben typischerweise einen Prozess (den Eltern-Prozess),
62+
der eine Reihe weiterer Prozesse (seine Kinder) koordiniert, welche die
63+
eigentliche Arbeit des Bereitstellens der Webseiten übernehmen. Wenn
64+
eine Anfrage von einem Client eingeht, wird sie an eines der Kinder
65+
weitergereicht, das gerade keinen anderen Client bedient. Das bedeutet,
66+
dass eine zweite Anfrage desselben Clients an den Server unter Umständen
67+
von einem anderen Kindprozess als die erste Anfrage bearbeitet wird.
68+
Wurde eine persistente Verbindung einmal geöffnet, kann jede danach
69+
vom selben Kindprozess bediente Seite die bereits aufgebaute Verbindung
70+
zum SQL-Server weiterverwenden.
71+
</simpara>
72+
<note>
73+
<para>
74+
Die verwendete Methode lässt sich anhand des Werts von "Server API" in
75+
der Ausgabe von <function>phpinfo</function> oder anhand des Werts der
76+
Konstante <constant>PHP_SAPI</constant>, ausgeführt über eine
77+
Web-Anfrage, prüfen.
78+
</para>
79+
<para>
80+
Lautet die Server API "Apache 2 Handler" oder "FPM/FastCGI", werden
81+
persistente Verbindungen über Anfragen hinweg wiederverwendet, die vom
82+
selben Worker bedient werden. Bei jedem anderen Wert bleiben
83+
persistente Verbindungen nach jeder Anfrage nicht erhalten.
84+
</para>
85+
</note>
86+
</simplesect>
87+
88+
<simplesect xml:id="persistent-connections.cli">
89+
<title>Kommandozeilen-Prozesse</title>
90+
<simpara>
91+
Da PHP auf der Kommandozeile für jedes Skript einen neuen Prozess
92+
verwendet, werden persistente Verbindungen nicht zwischen
93+
Kommandozeilen-Skripten geteilt. Es bringt daher keinen Nutzen, sie in
94+
kurzlebigen Skripten wie Cronjobs oder Befehlen einzusetzen. Sie können
95+
jedoch zum Beispiel in einem langlaufenden Anwendungsserver nützlich
96+
sein, der viele Anfragen oder Aufgaben bedient, von denen jede ihre
97+
eigene Datenbankverbindung benötigen kann.
98+
</simpara>
99+
</simplesect>
100+
101+
<simplesect xml:id="persistent-connections.why">
102+
<title>Wozu sie verwenden?</title>
103+
<simpara>
104+
Persistente Verbindungen sind nützlich, wenn der Aufwand zum Aufbau
105+
einer Verbindung zu einem SQL-Server hoch ist. Ob dieser Aufwand
106+
signifikant ist, hängt von vielen Faktoren ab, etwa von der Art der
107+
Datenbank, davon, ob sie auf demselben Rechner wie der Webserver läuft,
108+
und davon, wie stark dieser Rechner ausgelastet ist. Ist der
109+
Verbindungsaufwand hoch, können persistente Verbindungen erheblich
110+
helfen: Jeder Kindprozess verbindet sich nur einmal während seiner
111+
gesamten Lebensdauer, statt jedes Mal, wenn er eine Seite verarbeitet,
112+
die eine Verbindung zum SQL-Server benötigt. Das bedeutet, dass jeder
113+
Kindprozess, der eine persistente Verbindung öffnet, seine eigene
114+
Verbindung zum Server unterhält. Bei beispielsweise 20 verschiedenen
115+
Kindprozessen, die jeweils ein Skript ausführen, das eine persistente
116+
Verbindung zum SQL-Server aufbaut, ergeben sich 20 separate
117+
Verbindungen zu diesem Server, eine pro Kind.
118+
</simpara>
119+
</simplesect>
120+
121+
<simplesect xml:id="persistent-connections.drawbacks.conn-limits">
122+
<title>Mögliche Nachteile: Verbindungslimits</title>
123+
<simpara>
124+
Es ist jedoch zu beachten, dass dies Nachteile haben kann, wenn eine
125+
Datenbank mit Verbindungslimits verwendet wird, die durch persistente
126+
Verbindungen der Kindprozesse überschritten werden. Hat die Datenbank
127+
ein Limit von 16 gleichzeitigen Verbindungen und versuchen während
128+
einer stark ausgelasteten Server-Sitzung 17 Kindprozesse, eine
129+
Verbindung herzustellen, wird einer von ihnen fehlschlagen. Bestehen in
130+
den Skripten Fehler, die das Schließen der Verbindungen verhindern
131+
(wie etwa Endlosschleifen), kann eine Datenbank mit nur 16 Verbindungen
132+
sehr schnell überschwemmt werden.
133+
</simpara>
134+
<simpara>
135+
Persistente Verbindungen erhöhen in der Regel die Anzahl der zu einem
136+
gegebenen Zeitpunkt geöffneten Verbindungen, da untätige Worker
137+
weiterhin die Verbindungen halten, die sie für vorherige Anfragen
138+
geöffnet haben. Werden viele Worker hochgefahren, um eine
139+
Lastspitze zu bewältigen, bleiben die von ihnen geöffneten Verbindungen
140+
bestehen, bis der Worker beendet wird oder der Datenbankserver die
141+
Verbindung schließt.
142+
</simpara>
143+
<simpara>
144+
Es ist sicherzustellen, dass die vom Datenbankserver erlaubte maximale
145+
Anzahl an Verbindungen größer ist als die maximale Anzahl der Worker
146+
für Web-Anfragen (zuzüglich aller weiteren Verwendungen wie Cronjobs
147+
oder administrativer Verbindungen).
148+
</simpara>
149+
<simpara>
150+
Es empfiehlt sich, in der Dokumentation der Datenbank Informationen zur
151+
Behandlung aufgegebener oder im Leerlauf befindlicher Verbindungen
152+
(Timeouts) nachzuschlagen. Lange Timeouts können die Anzahl der zu
153+
einem Zeitpunkt geöffneten persistenten Verbindungen erheblich
154+
erhöhen.
155+
</simpara>
156+
</simplesect>
157+
158+
<simplesect xml:id="persistent-connections.drawbacks.state">
159+
<title>Mögliche Nachteile: Verwaltung des Verbindungszustands</title>
160+
<simpara>
161+
Manche Datenbank-Extensions führen eine automatische Bereinigung
162+
durch, wenn die Verbindung wiederverwendet wird; andere überlassen
163+
diese Aufgabe dem Anwendungsentwickler. Je nach gewählter
164+
Datenbank-Extension und Anwendungsdesign kann eine manuelle Bereinigung
165+
vor Beendigung des Skripts erforderlich sein. Änderungen, die
166+
Verbindungen in einem unerwarteten Zustand zurücklassen können, sind
167+
unter anderem:
168+
</simpara>
169+
<simplelist>
170+
<member>Ausgewählte / voreingestellte Datenbank</member>
171+
<member>Tabellensperren</member>
172+
<member>Nicht abgeschlossene Transaktionen</member>
173+
<member>Temporäre Tabellen</member>
174+
<member>Verbindungsspezifische Einstellungen oder Funktionen wie Profiling</member>
175+
</simplelist>
176+
<simpara>
177+
Tabellensperren und Transaktionen, die nicht aufgeräumt oder
178+
abgeschlossen werden, können dazu führen, dass andere Abfragen
179+
unbegrenzt blockiert werden und/oder dass eine spätere
180+
Wiederverwendung der Verbindung unerwartete Änderungen verursacht.
181+
</simpara>
182+
<simpara>
183+
Ist die falsche Datenbank ausgewählt, kann eine spätere
184+
Wiederverwendung der Verbindung Abfragen nicht wie erwartet ausführen
185+
(oder führt sie auf der falschen Datenbank aus, wenn sich die Schemata
186+
ausreichend ähneln).
187+
</simpara>
188+
<simpara>
189+
Werden temporäre Tabellen nicht aufgeräumt, können nachfolgende
190+
Anfragen dieselbe Tabelle nicht erneut anlegen.
191+
</simpara>
192+
<simpara>
193+
Die Bereinigung kann mithilfe von Klassen-Destruktoren oder
194+
<function>register_shutdown_function</function> umgesetzt werden.
195+
Dedizierte Connection-Pooling-Proxies, die dies als Teil ihrer
196+
Funktionalität enthalten, können ebenfalls in Betracht gezogen werden.
197+
</simpara>
198+
</simplesect>
199+
200+
<simplesect xml:id="persistent-connections.final-words">
201+
<title>Schlussbemerkungen</title>
202+
<simpara>
203+
Aufgrund des oben beschriebenen Verhaltens und der potenziellen
204+
Nachteile sollten persistente Verbindungen nicht ohne sorgfältige
205+
Abwägung eingesetzt werden. Sie sollten nicht ohne zusätzliche
206+
Anpassungen der Anwendung sowie ohne sorgfältige Konfiguration von
207+
Datenbankserver und Webserver und/oder PHP-FPM verwendet werden.
208+
</simpara>
209+
<simpara>
210+
Es sollten alternative Lösungen in Betracht gezogen werden, etwa die
211+
Untersuchung und Behebung der Ursachen für den
212+
Verbindungsaufbau-Overhead (beispielsweise das Deaktivieren von
213+
Reverse-DNS-Lookups auf dem Datenbankserver) oder dedizierte
214+
Connection-Pooling-Proxies.
215+
</simpara>
216+
<simpara>
217+
Für Web-APIs mit hohem Anfragevolumen sollten alternative Runtimes oder
218+
langlaufende Anwendungsserver in Betracht gezogen werden.
219+
</simpara>
220+
</simplesect>
221+
222+
<simplesect role="seealso" xml:id="persistent-connections.seealso">
223+
&reftitle.seealso;
224+
<simplelist>
225+
<member><function>ibase_pconnect</function></member>
226+
<member><function>oci_pconnect</function></member>
227+
<member><function>odbc_pconnect</function></member>
228+
<member><function>pfsockopen</function></member>
229+
<member><function>pg_connect</function></member>
230+
<member><link linkend="mysqli.persistconns">MySQLi und persistente Verbindungen</link></member>
231+
<member><link linkend="pdo.connections">PDO-Verbindungsverwaltung</link></member>
232+
</simplelist>
233+
</simplesect>
234+
</chapter>
146235

147236
<!-- Keep this comment at the end of the file
148237
Local variables:

0 commit comments

Comments
 (0)