summaryrefslogtreecommitdiffstats
path: root/proto/LMDB_README.html
blob: a9794cca6aee9b7f37d047eeeb9358bbabd52bc4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Postfix OpenLDAP LMDB Howto</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>

<body>

<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix OpenLDAP LMDB Howto</h1>

<hr>

<h2>Introduction</h2>

<p> Postfix uses databases of various kinds to store and look up
information. Postfix databases are specified as "type:name".  OpenLDAP
LMDB (called "LMDB" from here on) implements the Postfix database
type "lmdb".  The name of a Postfix LMDB database is the name of
the database file without the ".lmdb" suffix. </p>

<p> This document describes: </p>

<ul>

<li> <p> <a href="#with_lmdb">Building Postfix with LMDB support</a>.
</p>

<li> <p> <a href="#configure">Configuring LMDB settings</a>. </p>

<li> <p> <a href="#locking">Using LMDB maps with non-Postfix programs</a>. </p>

<li> <p> <a href="#supported"> Required minimum LMDB patchlevel</a>. </p>

<li> <p> <a href="#credits"> Credits</a>. </p>

</ul>

<h2><a name="with_lmdb">Building Postfix with LMDB support</a></h2>

<p> Postfix normally does not enable LMDB support.  To
build Postfix with LMDB support, use something like: </p>

<blockquote>
<pre>
% make makefiles CCARGS="-DHAS_LMDB -I/usr/local/include" \
    AUXLIBS_LMDB="-L/usr/local/lib -llmdb"
% make
</pre>
</blockquote>

<p> If your LMDB shared library is in a directory that the RUN-TIME
linker does not know about, add a "-Wl,-R,/path/to/directory" option after
"-llmdb". </p>

<p> Postfix versions before 3.0 use AUXLIBS instead of AUXLIBS_LMDB.
With Postfix 3.0 and later, the old AUXLIBS variable still supports
building a statically-loaded LMDB database client, but only the new
AUXLIBS_LMDB variable supports building a dynamically-loaded or 
statically-loaded LMDB database client.  </p>

<blockquote>
 
<p> Failure to use the AUXLIBS_LMDB variable will defeat the purpose
of dynamic database client loading. Every Postfix executable file
will have LMDB database library dependencies. And that was exactly
what dynamic database client loading was meant to avoid. </p>
 
</blockquote>


<p> Solaris may need this: </p>

<blockquote>
<pre>
% make makefiles CCARGS="-DHAS_LMDB -I/usr/local/include" \
    AUXLIBS_LMDB="-R/usr/local/lib -L/usr/local/lib -llmdb"
% make
</pre>
</blockquote>

<p> The exact pathnames depend on how LMDB was installed. </p>

<p> When building Postfix fails with: </p>

<blockquote>
<pre>
undefined reference to `pthread_mutexattr_destroy'
undefined reference to `pthread_mutexattr_init'
undefined reference to `pthread_mutex_lock'
</pre>
</blockquote>

<p> Add the "-lpthread" library to the "make makefiles" command. </p>

<blockquote>
<pre>
% make makefiles .... AUXLIBS_LMDB="... -lpthread"
</pre>
</blockquote>

<h2><a name="configure">Configuring LMDB settings</a></h2>

<p> Postfix provides one configuration parameter that controls
LMDB database behavior. </p>

<ul>

<li> <p> lmdb_map_size (default: 16777216).  This setting specifies
the initial LMDB database size limit in bytes.  Each time a database
becomes "full", its size limit is doubled. The maximum size is the
largest signed integer value of "long". </p>

</ul>

<h2> <a name="locking">Using LMDB maps with non-Postfix programs</a> </h2>

<p> Programs that use LMDB's built-in locking protocol will corrupt
a Postfix LMDB database or will read garbage. </p>

<p> Postfix does not use LMDB's built-in locking protocol, because
that would require world-writable lockfiles, and would violate
Postfix security policy.  Instead, Postfix uses external locks based
on fcntl(2) to prevent writers from corrupting the database, and
to prevent readers from receiving garbage.  </p>

<p> See lmdb_table(5) for a detailed description of the locking
protocol that all programs must use when they access a Postfix LMDB
database. </p>

<h2> <a name="supported"> Required minimum LMDB patchlevel </a> </h2>

<p> Currently, Postfix requires LMDB 0.9.11 or later. The required
minimum LMDB patchlevel has evolved over time, as the result of
Postfix deployment experience: </p>

<ul>

<li> <p> LMDB 0.9.11 allows Postfix daemons to log an LMDB error
message, instead of falling out of the sky without any notification.
</p>

<li> <p> LMDB 0.9.10 closes an information leak where LMDB was
writing up to 4-kbyte chunks of uninitialized heap memory to the
database. This would persist information that was not meant to be
persisted, or share information that was not meant to be shared.
</p>

<li> <p> LMDB 0.9.9 allows Postfix to use external (fcntl()-based)
locks, instead of having to use world-writable LMDB lock files,
violating the Postfix security model in multiple ways. </p>

<li> <p> LMDB 0.9.8 allows Postfix to recover from a "database full"
error without having to close the database. This version adds support
to update the database size limit on-the-fly.  This is necessary
because Postfix database sizes vary with mail server load. </p>

<li> <p> LMDB 0.9.7 allows the postmap(1) and postalias(1) commands
to use a bulk-mode transaction larger than the amount of physical
memory. This is necessary because LMDB supports databases larger
than physical memory. </p>

</ul>

<h2> <a name="credits"> Credits</a> </h2>

<ul>

<li> <p> Howard Chu contributed the initial Postfix dict_lmdb driver.
</p>

<li> <p> Wietse Venema wrote an abstraction layer (slmdb) that
behaves more like Berkeley DB, NDBM, etc.  This layer automatically
retries an LMDB request when a database needs to be resized, or
after a database was resized by a different process.  </p>

<li> <p> Howard and Wietse went through many iterations with changes
to both LMDB and Postfix, with input from Viktor Dukhovni. </p>

</ul>

<!--

<h2><a name="limitations">Unexpected failure modes of Postfix LMDB
databases.  </a> </h2>

<p> As documented below, conversion to LMDB introduces a number of
failure modes that don't exist with other Postfix databases.  Some
failure modes have been eliminated in the course of time.
The writeup below reflects the status as of LMDB 0.9.9. </p>

-->

<!--

<p> <strong>Unexpected "Permission denied" errors. </strong></p>

<dl>

<dt> Problem: </dt> <dd> <p> A world-readable LMDB database cannot
be opened by a process with a UID that differs from the database
file owner, even when an attempt is made to open the database
read-only.  This problem does not exist with other Postfix databases.
</p> </dd>

<dt> Background: </dt> <dd> <p> The LMDB implementation requires 
write access to maintain read locks, and perhaps for other purposes.
</p> </dd>

<dt> Solution: </dt> <dd> <p> Consider using cdb: to manage root-owned
databases under the root-owned <tt>/etc</tt> or config_directory
(default: <tt>/etc/postfix</tt>) such as access(5), virtual(5),
transport(5). Support to create LMDB databases is available only
for unprivileged Postfix daemon processes such as postscreen(8),
tlsmgr(8) and verify(8) that manage postfix-owned databases under
the postfix-owned data_directory (default: <tt>/var/lib/postfix</tt>).
</p> </dd>

</dl>

-->

<!--

<p> <strong>Unexpected "readers full" errors. </strong></p>

<dl>

<dt> Problem: </dt> <dd> <p> Under heavy load, database read
operations fail with MDB_READERS_FULL errors. This problem does not
exist with other Postfix databases. </p> </dd>

<dt> Background: </dt> <dd> <p> The LMDB implementation enforces a
hard limit on the number of simultaneous read requests for the same
database environment. This limit must be specified in advance with
the lmdb_max_readers configuration parameter. </p> </dd>

<dt> Mitigation: </dt> <dd> <p> Postfix logs a warning suggesting
that the lmdb_max_readers parameter value be increased, and retries
the failed operation for a limited number of times while running
with reduced performance.  </p> </dd>

<dt> Prevention: </dt> <dd> <p> Monitor your LMDB files for
MDB_READERS_FULL errors. After making the necessary adjustments,
restart Postfix. </p> </dd>

</dl>

-->

<!--

<p> <strong>Unexpected postmap(1)/postalias(1) "database full"
errors.  </strong></p>

<dl>

<dt> Problem: </dt> <dd> <p> The "postmap lmdb:filename" command
fails with an MDB_TXN_FULL error.  This problem does not exist with
other Postfix databases. </p> </dd>

<dt> Background: </dt>

<dd>

<p> The LMDB implementation has a hard limit on the total transaction
size. This limit is independent of the LMDB database size. Therefore,
the problem cannot be resolved by increasing the lmdb_map_size
value. </p>

<p> This symptom is indicative of a flawed design.  All LMDB data
structures should share the same storage pool so that they can scale
with the database size, and so that all "out of storage" errors are
resolved by increasing the database size. </p> </dd>

-->

<!--

<p> Problem: </dt> <dd> <p> The "postmap lmdb:filename" command
fails with an MDB_MAP_FULL error.  This problem does not exist with
other Postfix databases. </p> </dd>

<dl>

<dt> Background: </dt>

<dd> 

<p> LMDB databases have a hard size limit (configured with the
lmdb_map_size configuration parameter). </p>

<p> When executing "postmap lmdb:filename", the Postfix LMDB database
client stores the new data in a transaction which takes up space
in addition to the existing data, and commits the transaction when
it closes the database.  Only then can the space for old data be
reused.  </p>

</dd>

<dt> Impact: </dt> <dd> <p> This failure does not affect Postfix
availability, because the old data still exists in the database.
</p> </dd>

<dt> Mitigation: </dt> <dd>

<p> When the postmap(1) or postalias(1) command fails with an
MDB_MAP_FULL error, it expands the database file size to the current
LMDB map size limit before terminating.  </p>

<p> Next, when you re-run the postmap(1) or postalias(1) command,
it discovers that the LMDB file is larger than lmdb_map_size/3,
logs a warning, and uses a larger LMDB map size limit instead: </p>

<p> <tt> warning: <i>filename</i>.lmdb: file size 15024128 &ge;
(lmdb map size limit 16777216)/3<br> warning: <i>filename</i>.lmdb:
using map size limit 45072384</tt> </p>

<p> By repeating the two steps above you can automate recovery and
avoid the need for human intervention. Just repeat "postmap
lmdb:filename" (up to some limit).  After each failure it will use
a 3x larger size limit, and eventually the "database full" error
should disappear. This fails only when the disk is full or when
the LMDB map size limit would exceed the memory address space size
limit.  </p>

<dt> Prevention: </dt> <dd> <p> Monitor your LMDB files and make
sure that in main.cf, lmdb_map_size &gt; 3x the largest LMDB file
size. </p> </dd> </dl>

</dl>

-->

<!--

<p> <strong>Unexpected Postfix daemon "database full" errors.
</strong></p>

<dl>

<dt> Problem: </dt> <dd> <p> Postfix daemon programs fail with
"database full" errors, such as postscreen(8), tlsmgr(8) or verify(8).
This problem does not exist with other Postfix databases.  </p>
</dd>

<dt> Impact: </dt> <dd> <p> This failure temporarily affects Postfix
availability. The daemon restarts automatically and tries to open
the database again as described next.  </p> </dd>

<dt> Mitigation: </dt> <dd> <p> When a Postfix daemon opens an LMDB
file larger than lmdb_map_size/3, it logs a warning and uses a
larger size limit instead: </p>

<p> <tt> warning: <i>filename</i>.lmdb: file size 15024128 &ge;
(lmdb map size limit 16777216)/3 <br>warning: <i>filename</i>.lmdb:
using map size limit 45072384</tt> </p>

<p> This can be used to automate recovery and avoid the need for
human intervention. Each time the daemon runs into a "database full"
error, it restarts and uses a 3x larger size limit. The "database
full" error will disappear, at least for a while.  </p>

<dt> Prevention: </dt> <dd> <p> Monitor your LMDB files and make
sure that lmdb_map_size &gt; 3x the largest LMDB file size. </p>
</dd> </dl>

-->

<!--

<p> <strong>Non-obvious recovery with postmap(1), postalias(1), or
tlsmgr(8) from a corrupted database.  </strong></p>

<dl>

<dt> Problem: </dt> <dd> <p> A corrupted LMDB database can't be
rebuilt simply by re-running postmap(1) or postalias(1), or by
waiting until a tlsmgr(8) daemon restarts.  This problem does not
exist with other Postfix databases.  </p> </dd>

<dt> Background: </dt> <dd> <p> The Postfix LMDB database client
does not truncate the database file.  Instead it attempts to create
a transaction for a "drop" request plus subsequent "store" requests.
That is obviously not possible with a corrupted database file. </p>
</dd>

<dt> Impact: </dt> <dd> <p> Postfix does not process mail until
someone fixes the problem.  </p> </dd>

<dt> Recovery: </dt> <dd> <p> First delete the ".lmdb" file by hand.
Then rebuild the file with the postmap(1) or postalias(1)
command if the file was created with those commands, or restart
postfix daemons if the file is maintained by tlsmgr(8).
</p> </dd>

<dt> Prevention: </dt> <dd>

<p> Arrange your file systems such that they never run out of free
space. </p>

<p> Use ECC memory to detect and correct silent corruption of
in-memory file system data and metadata. </p>

<p> Use a file system such as ZFS to detect and correct silent
corruption of on-disk file system data and metadata. DO NOT
use ZFS on systems without ECC memory error correction. </p>

</dd> </dl>

-->

</body>

</html>