9
/* int slmdb_init(slmdb, curr_limit, size_incr, hard_limit)
15
/* int slmdb_open(slmdb, path, open_flags, lmdb_flags, slmdb_flags)
22
/* int slmdb_close(slmdb)
25
/* int slmdb_get(slmdb, mdb_key, mdb_value)
28
/* MDB_val *mdb_value;
30
/* int slmdb_put(slmdb, mdb_key, mdb_value, flags)
33
/* MDB_val *mdb_value;
36
/* int slmdb_del(slmdb, mdb_key)
40
/* int slmdb_cursor_get(slmdb, mdb_key, mdb_value, op)
43
/* MDB_val *mdb_value;
45
/* AUXILIARY FUNCTIONS
46
/* int slmdb_fd(slmdb)
49
/* size_t slmdb_curr_limit(slmdb)
52
/* int slmdb_control(slmdb, request, ...)
56
/* This module simplifies the LMDB API by hiding recoverable
57
/* errors from the application. Details are given in the
58
/* section "ERROR RECOVERY".
60
/* slmdb_init() performs mandatory initialization before opening
61
/* an LMDB database. The result value is an LMDB status code
62
/* (zero in case of success).
64
/* slmdb_open() opens an LMDB database. The result value is
65
/* an LMDB status code (zero in case of success).
67
/* slmdb_close() finalizes an optional bulk-mode transaction
68
/* and closes a successfully-opened LMDB database. The result
69
/* value is an LMDB status code (zero in case of success).
71
/* slmdb_get() is an mdb_get() wrapper with automatic error
72
/* recovery. The result value is an LMDB status code (zero
73
/* in case of success).
75
/* slmdb_put() is an mdb_put() wrapper with automatic error
76
/* recovery. The result value is an LMDB status code (zero
77
/* in case of success).
79
/* slmdb_del() is an mdb_del() wrapper with automatic error
80
/* recovery. The result value is an LMDB status code (zero
81
/* in case of success).
83
/* slmdb_cursor_get() is an mdb_cursor_get() wrapper with
84
/* automatic error recovery. The result value is an LMDB
85
/* status code (zero in case of success). This wrapper supports
86
/* only one cursor per database.
88
/* slmdb_fd() returns the file descriptor for the specified
89
/* database. This may be used for file status queries or
90
/* application-controlled locking.
92
/* slmdb_curr_limit() returns the current database size limit
93
/* for the specified database.
95
/* slmdb_control() specifies optional features. The result is
96
/* an LMDB status code (zero in case of success).
100
/* Pointer to caller-provided storage.
102
/* The initial memory mapping size limit. This limit is
103
/* automatically increased when the database becomes full.
105
/* An integer factor by which the memory mapping size limit
106
/* is increased when the database becomes full.
108
/* The upper bound for the memory mapping size limit.
110
/* LMDB database pathname.
112
/* Flags that control file open operations. Do not specify
113
/* locking flags here.
115
/* Flags that control the LMDB environment. If MDB_NOLOCK is
116
/* specified, then each slmdb_get() or slmdb_cursor_get() call
117
/* must be protected with a shared (or exclusive) external lock,
118
/* and each slmdb_put() or slmdb_del() call must be protected
119
/* with an exclusive external lock. A lock may be released
120
/* after the call returns. A writer may atomically downgrade
121
/* an exclusive lock to shared, but it must obtain an exclusive
122
/* lock before making another slmdb(3) write request.
124
/* Note: when a database is opened with MDB_NOLOCK, external
125
/* locks such as fcntl() do not protect slmdb(3) requests
126
/* within the same process against each other. If a program
127
/* cannot avoid making simultaneous slmdb(3) requests, then
128
/* it must synchronize these requests with in-process locks,
129
/* in addition to the per-process fcntl(2) locks.
131
/* Bit-wise OR of zero or more of the following:
133
/* .IP SLMDB_FLAG_BULK
134
/* Open the database and create a "bulk" transaction that is
135
/* committed when the database is closed. If MDB_NOLOCK is
136
/* specified, then the entire transaction must be protected
137
/* with a persistent external lock. All slmdb_get(), slmdb_put()
138
/* and slmdb_del() requests will be directed to the "bulk"
142
/* Pointer to caller-provided lookup key storage.
144
/* Pointer to caller-provided value storage.
146
/* LMDB cursor operation.
148
/* The start of a list of (name, value) pairs, terminated with
149
/* SLMDB_CTL_END. The following text enumerates the symbolic
150
/* request names and the corresponding value types.
152
/* .IP "SLMDB_CTL_LONGJMP_FN (void (*)(void *, int))
153
/* Call-back function pointer. The function is called to repeat
154
/* a failed bulk-mode transaction from the start. The arguments
155
/* are the application context and the setjmp() or sigsetjmp()
157
/* .IP "SLMDB_CTL_NOTIFY_FN (void (*)(void *, int, ...))"
158
/* Call-back function pointer. The function is called to report
159
/* succesful error recovery. The arguments are the application
160
/* context, the MDB error code, and additional arguments that
161
/* depend on the error code. Details are given in the section
163
/* .IP "SLMDB_CTL_ASSERT_FN (void (*)(void *, const char *))"
164
/* Call-back function pointer. The function is called to
165
/* report an LMDB internal assertion failure. The arguments
166
/* are the application context, and text that describes the
168
/* .IP "SLMDB_CTL_CB_CONTEXT (void *)"
169
/* Application context that is passed in call-back function
171
/* .IP "SLMDB_CTL_API_RETRY_LIMIT (int)"
172
/* How many times to recover from LMDB errors within the
173
/* execution of a single slmdb(3) API call before giving up.
174
/* .IP "SLMDB_CTL_BULK_RETRY_LIMIT (int)"
175
/* How many times to recover from a bulk-mode transaction
181
/* This module automatically repeats failed requests after
182
/* recoverable errors, up to the limits specified with
185
/* Recoverable errors are reported through an optional
186
/* notification function specified with slmdb_control(). With
187
/* recoverable MDB_MAP_FULL and MDB_MAP_RESIZED errors, the
188
/* additional argument is a size_t value with the updated
189
/* current database size limit; with recoverable MDB_READERS_FULL
190
/* errors there is no additional argument.
192
/* Recovery from MDB_MAP_FULL involves resizing the database
193
/* memory mapping. According to LMDB documentation this
194
/* requires that there is no concurrent activity in the same
195
/* database by other threads in the same memory address space.
197
/* lmdb(3) API manpage (currently, non-existent).
203
/* IBM T.J. Watson Research
205
/* Yorktown Heights, NY 10598, USA
209
* DO NOT include other Postfix-specific header files. This LMDB wrapper
210
* must be usable outside Postfix.
215
/* System library. */
217
#include <sys/stat.h>
227
/* Application-specific. */
232
* Minimum LMDB patchlevel.
234
* LMDB 0.9.11 allows Postfix daemons to log an LMDB error message instead of
235
* falling out of the sky without any explanation. Without such logging,
236
* Postfix with LMDB would be too hard to support.
238
* LMDB 0.9.10 fixes an information leak where LMDB wrote chunks of up to 4096
239
* bytes of uninitialized heap memory to a database. This was a security
240
* violation because it made information persistent that was not meant to be
241
* persisted, or it was sharing information that was not meant to be shared.
243
* LMDB 0.9.9 allows Postfix to use external (fcntl()-based) locks, instead of
244
* having to use world-writable LMDB lock files.
246
* LMDB 0.9.8 allows Postfix to update the database size limit on-the-fly, so
247
* that it can recover from an MDB_MAP_FULL error without having to close
248
* the database. It also allows an application to "pick up" a new database
249
* size limit on-the-fly, so that it can recover from an MDB_MAP_RESIZED
250
* error without having to close the database.
252
* The database size limit that remains is imposed by the hardware memory
253
* address space (31 or 47 bits, typically) or file system. The LMDB
254
* implementation is supposed to handle databases larger than physical
255
* memory. However, this is not necessarily guaranteed for (bulk)
256
* transactions larger than physical memory.
258
#if MDB_VERSION_FULL < MDB_VERINT(0, 9, 11)
259
#error "This Postfix version requires LMDB version 0.9.11 or later"
265
* The purpose of the slmdb(3) API is to hide LMDB quirks (recoverable
266
* MAP_FULL, MAP_RESIZED, or MDB_READERS_FULL errors). With these out of the
267
* way, applications can pretend that those quirks don't exist, and focus on
270
* - To recover from a single-transaction LMDB error, each wrapper function
271
* uses tail recursion instead of goto. Since LMDB errors are rare, code
272
* clarity is more important than speed.
274
* - To recover from a bulk-transaction LMDB error, the error-recovery code
275
* triggers a long jump back into the caller to some pre-arranged point (the
276
* closest thing that C has to exception handling). The application is then
277
* expected to repeat the bulk transaction from scratch.
281
* Our default retry attempt limits. We allow a few retries per slmdb(3) API
282
* call for non-bulk transactions. We allow a number of bulk-transaction
283
* retries that is proportional to the memory address space.
285
#define SLMDB_DEF_API_RETRY_LIMIT 30 /* Retries per slmdb(3) API call */
286
#define SLMDB_DEF_BULK_RETRY_LIMIT \
287
(2 * sizeof(size_t) * CHAR_BIT) /* Retries per bulk-mode transaction */
290
* We increment the recursion counter each time we try to recover from
291
* error, and reset the recursion counter when returning to the application
292
* from the slmdb(3) API.
294
#define SLMDB_API_RETURN(slmdb, status) do { \
295
(slmdb)->api_retry_count = 0; \
300
* With MDB_NOLOCK, the application uses an external lock for inter-process
301
* synchronization. Because the caller may release the external lock after
302
* an SLMDB API call, each SLMDB API function must use a short-lived
303
* transaction unless the transaction is a bulk-mode transaction.
306
/* slmdb_cursor_close - close cursor and its read transaction */
308
static void slmdb_cursor_close(SLMDB *slmdb)
313
* Close the cursor and its read transaction. We can restore it later
314
* from the saved key information.
316
txn = mdb_cursor_txn(slmdb->cursor);
317
mdb_cursor_close(slmdb->cursor);
322
/* slmdb_saved_key_init - initialize saved key info */
324
static void slmdb_saved_key_init(SLMDB *slmdb)
326
slmdb->saved_key.mv_data = 0;
327
slmdb->saved_key.mv_size = 0;
328
slmdb->saved_key_size = 0;
331
/* slmdb_saved_key_free - destroy saved key info */
333
static void slmdb_saved_key_free(SLMDB *slmdb)
335
free(slmdb->saved_key.mv_data);
336
slmdb_saved_key_init(slmdb);
339
#define HAVE_SLMDB_SAVED_KEY(s) ((s)->saved_key.mv_data != 0)
341
/* slmdb_saved_key_assign - copy the saved key */
343
static int slmdb_saved_key_assign(SLMDB *slmdb, MDB_val *key_val)
347
* Extend the buffer to fit the key, so that we can avoid malloc()
348
* overhead most of the time.
350
if (slmdb->saved_key_size < key_val->mv_size) {
351
if (slmdb->saved_key.mv_data == 0)
352
slmdb->saved_key.mv_data = malloc(key_val->mv_size);
354
slmdb->saved_key.mv_data =
355
realloc(slmdb->saved_key.mv_data, key_val->mv_size);
356
if (slmdb->saved_key.mv_data == 0) {
357
slmdb_saved_key_init(slmdb);
360
slmdb->saved_key_size = key_val->mv_size;
365
* Copy the key under the cursor.
367
memcpy(slmdb->saved_key.mv_data, key_val->mv_data, key_val->mv_size);
368
slmdb->saved_key.mv_size = key_val->mv_size;
372
/* slmdb_prepare - LMDB-specific (re)initialization before actual access */
374
static int slmdb_prepare(SLMDB *slmdb)
379
* This is called before accessing the database, or after recovery from
380
* an LMDB error. Note: this code cannot recover from errors itself.
381
* slmdb->txn is either the database open() transaction or a
382
* freshly-created bulk-mode transaction.
384
* - With O_TRUNC we make a "drop" request before updating the database.
386
* - With a bulk-mode transaction we commit when the database is closed.
388
if (slmdb->open_flags & O_TRUNC) {
389
if ((status = mdb_drop(slmdb->txn, slmdb->dbi, 0)) != 0)
391
if ((slmdb->slmdb_flags & SLMDB_FLAG_BULK) == 0) {
392
if ((status = mdb_txn_commit(slmdb->txn)) != 0)
396
} else if ((slmdb->lmdb_flags & MDB_RDONLY) != 0
397
|| (slmdb->slmdb_flags & SLMDB_FLAG_BULK) == 0) {
398
mdb_txn_abort(slmdb->txn);
401
slmdb->api_retry_count = 0;
405
/* slmdb_recover - recover from LMDB errors */
407
static int slmdb_recover(SLMDB *slmdb, int status)
412
* This may be needed in non-MDB_NOLOCK mode. Recovery is rare enough
413
* that we don't care about a few wasted cycles.
415
if (slmdb->cursor != 0)
416
slmdb_cursor_close(slmdb);
419
* Recover bulk transactions only if they can be restarted. Limit the
420
* number of recovery attempts per slmdb(3) API request.
422
if ((slmdb->txn != 0 && slmdb->longjmp_fn == 0)
423
|| ((slmdb->api_retry_count += 1) >= slmdb->api_retry_limit))
427
* If we can recover from the error, we clear the error condition and the
428
* caller should retry the failed operation immediately. Otherwise, the
429
* caller should terminate with a fatal run-time error and the program
430
* should be re-run later.
432
* slmdb->txn must be either null (non-bulk transaction error), or an
433
* aborted bulk-mode transaction.
438
* As of LMDB 0.9.8 when a non-bulk update runs into a "map full"
439
* error, we can resize the environment's memory map and clear the
440
* error condition. The caller should retry immediately.
443
/* Can we increase the memory map? Give up if we can't. */
444
if (slmdb->curr_limit < slmdb->hard_limit / slmdb->size_incr) {
445
slmdb->curr_limit = slmdb->curr_limit * slmdb->size_incr;
446
} else if (slmdb->curr_limit < slmdb->hard_limit) {
447
slmdb->curr_limit = slmdb->hard_limit;
449
/* Sorry, we are already maxed out. */
452
if (slmdb->notify_fn)
453
slmdb->notify_fn(slmdb->cb_context, MDB_MAP_FULL,
455
status = mdb_env_set_mapsize(slmdb->env, slmdb->curr_limit);
459
* When a writer resizes the database, read-only applications must
460
* increase their LMDB memory map size limit, too. Otherwise, they
461
* won't be able to read a table after it grows.
463
* As of LMDB 0.9.8 we can import the new memory map size limit into the
464
* database environment by calling mdb_env_set_mapsize() with a zero
465
* size argument. Then we extract the map size limit for later use.
466
* The caller should retry immediately.
468
case MDB_MAP_RESIZED:
469
if ((status = mdb_env_set_mapsize(slmdb->env, 0)) == 0) {
470
/* Do not panic. Maps may shrink after bulk update. */
471
mdb_env_info(slmdb->env, &info);
472
slmdb->curr_limit = info.me_mapsize;
473
if (slmdb->notify_fn)
474
slmdb->notify_fn(slmdb->cb_context, MDB_MAP_RESIZED,
480
* What is it with these built-in hard limits that cause systems to
481
* stop when demand is at its highest? When the system is under
482
* stress it should slow down and keep making progress.
484
case MDB_READERS_FULL:
485
if (slmdb->notify_fn)
486
slmdb->notify_fn(slmdb->cb_context, MDB_READERS_FULL);
492
* We can't solve this problem. The application should terminate with
493
* a fatal run-time error and the program should be re-run later.
500
* If a bulk-transaction error is recoverable, build a new bulk
501
* transaction from scratch, by making a long jump back into the caller
502
* at some pre-arranged point. In MDB_NOLOCK mode, there is no need to
503
* upgrade the lock to "exclusive", because the failed write transaction
504
* has no side effects.
506
if (slmdb->txn != 0 && status == 0 && slmdb->longjmp_fn != 0
507
&& (slmdb->bulk_retry_count += 1) <= slmdb->bulk_retry_limit) {
508
if ((status = mdb_txn_begin(slmdb->env, (MDB_txn *) 0,
509
slmdb->lmdb_flags & MDB_RDONLY,
511
&& (status = slmdb_prepare(slmdb)) == 0)
512
slmdb->longjmp_fn(slmdb->cb_context, 1);
517
/* slmdb_txn_begin - mdb_txn_begin() wrapper with LMDB error recovery */
519
static int slmdb_txn_begin(SLMDB *slmdb, int rdonly, MDB_txn **txn)
523
if ((status = mdb_txn_begin(slmdb->env, (MDB_txn *) 0, rdonly, txn)) != 0
524
&& (status = slmdb_recover(slmdb, status)) == 0)
525
status = slmdb_txn_begin(slmdb, rdonly, txn);
530
/* slmdb_get - mdb_get() wrapper with LMDB error recovery */
532
int slmdb_get(SLMDB *slmdb, MDB_val *mdb_key, MDB_val *mdb_value)
538
* Start a read transaction if there's no bulk-mode txn.
542
else if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
543
SLMDB_API_RETURN(slmdb, status);
548
if ((status = mdb_get(txn, slmdb->dbi, mdb_key, mdb_value)) != 0
549
&& status != MDB_NOTFOUND) {
551
if ((status = slmdb_recover(slmdb, status)) == 0)
552
status = slmdb_get(slmdb, mdb_key, mdb_value);
553
SLMDB_API_RETURN(slmdb, status);
557
* Close the read txn if it's not the bulk-mode txn.
562
SLMDB_API_RETURN(slmdb, status);
565
/* slmdb_put - mdb_put() wrapper with LMDB error recovery */
567
int slmdb_put(SLMDB *slmdb, MDB_val *mdb_key,
568
MDB_val *mdb_value, int flags)
574
* Start a write transaction if there's no bulk-mode txn.
578
else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
579
SLMDB_API_RETURN(slmdb, status);
584
if ((status = mdb_put(txn, slmdb->dbi, mdb_key, mdb_value, flags)) != 0) {
586
if (status != MDB_KEYEXIST) {
587
if ((status = slmdb_recover(slmdb, status)) == 0)
588
status = slmdb_put(slmdb, mdb_key, mdb_value, flags);
589
SLMDB_API_RETURN(slmdb, status);
594
* Commit the transaction if it's not the bulk-mode txn.
596
if (status == 0 && slmdb->txn == 0 && (status = mdb_txn_commit(txn)) != 0
597
&& (status = slmdb_recover(slmdb, status)) == 0)
598
status = slmdb_put(slmdb, mdb_key, mdb_value, flags);
600
SLMDB_API_RETURN(slmdb, status);
603
/* slmdb_del - mdb_del() wrapper with LMDB error recovery */
605
int slmdb_del(SLMDB *slmdb, MDB_val *mdb_key)
611
* Start a write transaction if there's no bulk-mode txn.
615
else if ((status = slmdb_txn_begin(slmdb, 0, &txn)) != 0)
616
SLMDB_API_RETURN(slmdb, status);
621
if ((status = mdb_del(txn, slmdb->dbi, mdb_key, (MDB_val *) 0)) != 0) {
623
if (status != MDB_NOTFOUND) {
624
if ((status = slmdb_recover(slmdb, status)) == 0)
625
status = slmdb_del(slmdb, mdb_key);
626
SLMDB_API_RETURN(slmdb, status);
631
* Commit the transaction if it's not the bulk-mode txn.
633
if (status == 0 && slmdb->txn == 0 && (status = mdb_txn_commit(txn)) != 0
634
&& (status = slmdb_recover(slmdb, status)) == 0)
635
status = slmdb_del(slmdb, mdb_key);
637
SLMDB_API_RETURN(slmdb, status);
640
/* slmdb_cursor_get - mdb_cursor_get() wrapper with LMDB error recovery */
642
int slmdb_cursor_get(SLMDB *slmdb, MDB_val *mdb_key,
643
MDB_val *mdb_value, MDB_cursor_op op)
649
* Open a read transaction and cursor if needed.
651
if (slmdb->cursor == 0) {
652
if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
653
SLMDB_API_RETURN(slmdb, status);
654
if ((status = mdb_cursor_open(txn, slmdb->dbi, &slmdb->cursor)) != 0) {
656
if ((status = slmdb_recover(slmdb, status)) == 0)
657
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
658
SLMDB_API_RETURN(slmdb, status);
662
* Restore the cursor position from the saved key information.
664
if (HAVE_SLMDB_SAVED_KEY(slmdb) && op != MDB_FIRST)
665
status = mdb_cursor_get(slmdb->cursor, &slmdb->saved_key,
666
(MDB_val *) 0, MDB_SET);
673
status = mdb_cursor_get(slmdb->cursor, mdb_key, mdb_value, op);
676
* Save the cursor position if successful. This can fail only with
679
* Close the cursor read transaction if in MDB_NOLOCK mode, because the
680
* caller may release the external lock after we return.
683
status = slmdb_saved_key_assign(slmdb, mdb_key);
684
if (slmdb->lmdb_flags & MDB_NOLOCK)
685
slmdb_cursor_close(slmdb);
689
* Handle end-of-database or other error.
692
/* Do not hand-optimize out the slmdb_cursor_close() calls below. */
693
if (status == MDB_NOTFOUND) {
694
slmdb_cursor_close(slmdb);
695
if (HAVE_SLMDB_SAVED_KEY(slmdb))
696
slmdb_saved_key_free(slmdb);
698
slmdb_cursor_close(slmdb);
699
if ((status = slmdb_recover(slmdb, status)) == 0)
700
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
701
SLMDB_API_RETURN(slmdb, status);
702
/* Do not hand-optimize out the above return statement. */
705
SLMDB_API_RETURN(slmdb, status);
708
/* slmdb_assert_cb - report LMDB assertion failure */
710
static void slmdb_assert_cb(MDB_env *env, const char *text)
712
SLMDB *slmdb = (SLMDB *) mdb_env_get_userctx(env);
714
if (slmdb->assert_fn)
715
slmdb->assert_fn(slmdb->cb_context, text);
718
/* slmdb_control - control optional settings */
720
int slmdb_control(SLMDB *slmdb, int first,...)
728
for (reqno = first; status == 0 && reqno != SLMDB_CTL_END; reqno = va_arg(ap, int)) {
730
case SLMDB_CTL_LONGJMP_FN:
731
slmdb->longjmp_fn = va_arg(ap, SLMDB_LONGJMP_FN);
733
case SLMDB_CTL_NOTIFY_FN:
734
slmdb->notify_fn = va_arg(ap, SLMDB_NOTIFY_FN);
736
case SLMDB_CTL_ASSERT_FN:
737
slmdb->assert_fn = va_arg(ap, SLMDB_ASSERT_FN);
738
if ((rc = mdb_env_set_userctx(slmdb->env, (void *) slmdb)) != 0
739
|| (rc = mdb_env_set_assert(slmdb->env, slmdb_assert_cb)) != 0)
742
case SLMDB_CTL_CB_CONTEXT:
743
slmdb->cb_context = va_arg(ap, void *);
745
case SLMDB_CTL_API_RETRY_LIMIT:
746
slmdb->api_retry_limit = va_arg(ap, int);
748
case SLMDB_CTL_BULK_RETRY_LIMIT:
749
slmdb->bulk_retry_limit = va_arg(ap, int);
752
status = errno = EINVAL;
760
/* slmdb_close - wrapper with LMDB error recovery */
762
int slmdb_close(SLMDB *slmdb)
767
* Finish an open bulk transaction. If slmdb_recover() returns after a
768
* bulk-transaction error, then it was unable to recover.
771
&& (status = mdb_txn_commit(slmdb->txn)) != 0)
772
status = slmdb_recover(slmdb, status);
775
* Clean up after an unfinished sequence() operation.
777
if (slmdb->cursor != 0)
778
slmdb_cursor_close(slmdb);
780
mdb_env_close(slmdb->env);
783
* Clean up the saved key information.
785
if (HAVE_SLMDB_SAVED_KEY(slmdb))
786
slmdb_saved_key_free(slmdb);
788
SLMDB_API_RETURN(slmdb, status);
791
/* slmdb_init - mandatory initialization */
793
int slmdb_init(SLMDB *slmdb, size_t curr_limit, int size_incr,
798
* This is a separate operation to keep the slmdb_open() API simple.
799
* Don't allocate resources here. Just store control information,
801
slmdb->curr_limit = curr_limit;
802
slmdb->size_incr = size_incr;
803
slmdb->hard_limit = hard_limit;
805
return (MDB_SUCCESS);
808
/* slmdb_open - open wrapped LMDB database */
810
int slmdb_open(SLMDB *slmdb, const char *path, int open_flags,
811
int lmdb_flags, int slmdb_flags)
821
* Create LMDB environment.
823
if ((status = mdb_env_create(&env)) != 0)
827
* Make sure that the memory map has room to store and commit an initial
828
* "drop" transaction as well as fixed database metadata. We have no way
829
* to recover from errors before the first application-level I/O request.
831
#define SLMDB_FUDGE 10240
833
if (slmdb->curr_limit < SLMDB_FUDGE)
834
slmdb->curr_limit = SLMDB_FUDGE;
835
if (stat(path, &st) == 0
836
&& st.st_size > slmdb->curr_limit - SLMDB_FUDGE) {
837
if (st.st_size > slmdb->hard_limit)
838
slmdb->hard_limit = st.st_size;
839
if (st.st_size < slmdb->hard_limit - SLMDB_FUDGE)
840
slmdb->curr_limit = st.st_size + SLMDB_FUDGE;
842
slmdb->curr_limit = slmdb->hard_limit;
846
* mdb_open() requires a txn, but since the default DB always exists in
847
* an LMDB environment, we usually don't need to do anything else with
848
* the txn. It is currently used for truncate and for bulk transactions.
850
if ((status = mdb_env_set_mapsize(env, slmdb->curr_limit)) != 0
851
|| (status = mdb_env_open(env, path, lmdb_flags, 0644)) != 0
852
|| (status = mdb_txn_begin(env, (MDB_txn *) 0,
853
lmdb_flags & MDB_RDONLY, &txn)) != 0
854
|| (status = mdb_open(txn, (const char *) 0, 0, &dbi)) != 0
855
|| (status = mdb_env_get_fd(env, &db_fd)) != 0) {
863
slmdb->open_flags = open_flags;
864
slmdb->lmdb_flags = lmdb_flags;
865
slmdb->slmdb_flags = slmdb_flags;
868
slmdb->db_fd = db_fd;
870
slmdb_saved_key_init(slmdb);
871
slmdb->api_retry_count = 0;
872
slmdb->bulk_retry_count = 0;
873
slmdb->api_retry_limit = SLMDB_DEF_API_RETRY_LIMIT;
874
slmdb->bulk_retry_limit = SLMDB_DEF_BULK_RETRY_LIMIT;
875
slmdb->longjmp_fn = 0;
876
slmdb->notify_fn = 0;
877
slmdb->assert_fn = 0;
878
slmdb->cb_context = 0;
881
if ((status = slmdb_prepare(slmdb)) != 0)