/*++ /* NAME /* slmdb 3 /* SUMMARY /* Simplified LMDB API /* SYNOPSIS /* #include <slmdb.h> /* /* int slmdb_init(slmdb, curr_limit, size_incr, hard_limit) /* SLMDB *slmdb; /* size_t curr_limit; /* int size_incr; /* size_t hard_limit; /* /* int slmdb_open(slmdb, path, open_flags, lmdb_flags, slmdb_flags) /* SLMDB *slmdb; /* const char *path; /* int open_flags; /* int lmdb_flags; /* int slmdb_flags; /* /* int slmdb_close(slmdb) /* SLMDB *slmdb; /* /* int slmdb_get(slmdb, mdb_key, mdb_value) /* SLMDB *slmdb; /* MDB_val *mdb_key; /* MDB_val *mdb_value; /* /* int slmdb_put(slmdb, mdb_key, mdb_value, flags) /* SLMDB *slmdb; /* MDB_val *mdb_key; /* MDB_val *mdb_value; /* int flags; /* /* int slmdb_del(slmdb, mdb_key) /* SLMDB *slmdb; /* MDB_val *mdb_key; /* /* int slmdb_cursor_get(slmdb, mdb_key, mdb_value, op) /* SLMDB *slmdb; /* MDB_val *mdb_key; /* MDB_val *mdb_value; /* MDB_cursor_op op; /* AUXILIARY FUNCTIONS /* int slmdb_fd(slmdb) /* SLMDB *slmdb; /* /* size_t slmdb_curr_limit(slmdb) /* SLMDB *slmdb; /* /* int slmdb_control(slmdb, request, ...) /* SLMDB *slmdb; /* int request; /* DESCRIPTION /* This module simplifies the LMDB API by hiding recoverable /* errors from the application. Details are given in the /* section "ERROR RECOVERY". /* /* slmdb_init() performs mandatory initialization before opening /* an LMDB database. The result value is an LMDB status code /* (zero in case of success). /* /* slmdb_open() opens an LMDB database. The result value is /* an LMDB status code (zero in case of success). /* /* slmdb_close() finalizes an optional bulk-mode transaction /* and closes a successfully-opened LMDB database. The result /* value is an LMDB status code (zero in case of success). /* /* slmdb_get() is an mdb_get() wrapper with automatic error /* recovery. The result value is an LMDB status code (zero /* in case of success). /* /* slmdb_put() is an mdb_put() wrapper with automatic error /* recovery. The result value is an LMDB status code (zero /* in case of success). /* /* slmdb_del() is an mdb_del() wrapper with automatic error /* recovery. The result value is an LMDB status code (zero /* in case of success). /* /* slmdb_cursor_get() is an mdb_cursor_get() wrapper with /* automatic error recovery. The result value is an LMDB /* status code (zero in case of success). This wrapper supports /* only one cursor per database. /* /* slmdb_fd() returns the file descriptor for the specified /* database. This may be used for file status queries or /* application-controlled locking. /* /* slmdb_curr_limit() returns the current database size limit /* for the specified database. /* /* slmdb_control() specifies optional features. The result is /* an LMDB status code (zero in case of success). /* /* Arguments: /* .IP slmdb /* Pointer to caller-provided storage. /* .IP curr_limit /* The initial memory mapping size limit. This limit is /* automatically increased when the database becomes full. /* .IP size_incr /* An integer factor by which the memory mapping size limit /* is increased when the database becomes full. /* .IP hard_limit /* The upper bound for the memory mapping size limit. /* .IP path /* LMDB database pathname. /* .IP open_flags /* Flags that control file open operations. Do not specify /* locking flags here. /* .IP lmdb_flags /* Flags that control the LMDB environment. If MDB_NOLOCK is /* specified, then each slmdb_get() or slmdb_cursor_get() call /* must be protected with a shared (or exclusive) external lock, /* and each slmdb_put() or slmdb_del() call must be protected /* with an exclusive external lock. A lock may be released /* after the call returns. A writer may atomically downgrade /* an exclusive lock to shared, but it must obtain an exclusive /* lock before making another slmdb(3) write request. /* .sp /* Note: when a database is opened with MDB_NOLOCK, external /* locks such as fcntl() do not protect slmdb(3) requests /* within the same process against each other. If a program /* cannot avoid making simultaneous slmdb(3) requests, then /* it must synchronize these requests with in-process locks, /* in addition to the per-process fcntl(2) locks. /* .IP slmdb_flags /* Bit-wise OR of zero or more of the following: /* .RS /* .IP SLMDB_FLAG_BULK /* Open the database and create a "bulk" transaction that is /* committed when the database is closed. If MDB_NOLOCK is /* specified, then the entire transaction must be protected /* with a persistent external lock. All slmdb_get(), slmdb_put() /* and slmdb_del() requests will be directed to the "bulk" /* transaction. /* .RE /* .IP mdb_key /* Pointer to caller-provided lookup key storage. /* .IP mdb_value /* Pointer to caller-provided value storage. /* .IP op /* LMDB cursor operation. /* .IP request /* The start of a list of (name, value) pairs, terminated with /* CA_SLMDB_CTL_END. The following text enumerates the symbolic /* request names and the corresponding argument types. /* .RS /* .IP "CA_SLMDB_CTL_LONGJMP_FN(void (*)(void *, int))" /* Call-back function pointer. The function is called to repeat /* a failed bulk-mode transaction from the start. The arguments /* are the application context and the setjmp() or sigsetjmp() /* result value. /* .IP "CA_SLMDB_CTL_NOTIFY_FN(void (*)(void *, int, ...))" /* Call-back function pointer. The function is called to report /* successful error recovery. The arguments are the application /* context, the MDB error code, and additional arguments that /* depend on the error code. Details are given in the section /* "ERROR RECOVERY". /* .IP "CA_SLMDB_CTL_ASSERT_FN(void (*)(void *, const char *))" /* Call-back function pointer. The function is called to /* report an LMDB internal assertion failure. The arguments /* are the application context, and text that describes the /* problem. /* .IP "CA_SLMDB_CTL_CB_CONTEXT(void *)" /* Application context that is passed in call-back function /* calls. /* .IP "CA_SLMDB_CTL_API_RETRY_LIMIT(int)" /* How many times to recover from LMDB errors within the /* execution of a single slmdb(3) API call before giving up. /* .IP "CA_SLMDB_CTL_BULK_RETRY_LIMIT(int)" /* How many times to recover from a bulk-mode transaction /* before giving up. /* .RE /* ERROR RECOVERY /* .ad /* .fi /* This module automatically repeats failed requests after /* recoverable errors, up to the limits specified with /* slmdb_control(). /* /* Recoverable errors are reported through an optional /* notification function specified with slmdb_control(). With /* recoverable MDB_MAP_FULL and MDB_MAP_RESIZED errors, the /* additional argument is a size_t value with the updated /* current database size limit; with recoverable MDB_READERS_FULL /* errors there is no additional argument. /* BUGS /* Recovery from MDB_MAP_FULL involves resizing the database /* memory mapping. According to LMDB documentation this /* requires that there is no concurrent activity in the same /* database by other threads in the same memory address space. /* SEE ALSO /* lmdb(3) API manpage (currently, non-existent). /* AUTHOR(S) /* Howard Chu /* Symas Corporation /* /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA
/*--*/
/* *AsofLMDB0.9.8whenanon-bulkupdaterunsintoa"mapfull" *error,wecanresizetheenvironment'smemorymapandclearthe *errorcondition.Thecallershouldretryimmediately.
*/ case MDB_MAP_FULL: /* Can we increase the memory map? Give up if we can't. */ if (slmdb->curr_limit < slmdb->hard_limit / slmdb->size_incr) {
slmdb->curr_limit = slmdb->curr_limit * slmdb->size_incr;
} elseif (slmdb->curr_limit < slmdb->hard_limit) {
slmdb->curr_limit = slmdb->hard_limit;
} else { /* Sorry, we are already maxed out. */ break;
} if (slmdb->notify_fn)
slmdb->notify_fn(slmdb->cb_context, MDB_MAP_FULL,
slmdb->curr_limit);
status = mdb_env_set_mapsize(slmdb->env, slmdb->curr_limit); break;
/* *Whenawriterresizesthedatabase,read-onlyapplicationsmust *increasetheirLMDBmemorymapsizelimit,too.Otherwise,they *won'tbeabletoreadatableafteritgrows. * *AsofLMDB0.9.8wecanimportthenewmemorymapsizelimitintothe *databaseenvironmentbycallingmdb_env_set_mapsize()withazero *sizeargument.Thenweextractthemapsizelimitforlateruse. *Thecallershouldretryimmediately.
*/ case MDB_MAP_RESIZED: if ((status = mdb_env_set_mapsize(slmdb->env, 0)) == 0) { /* Do not panic. Maps may shrink after bulk update. */
mdb_env_info(slmdb->env, &info);
slmdb->curr_limit = info.me_mapsize; if (slmdb->notify_fn)
slmdb->notify_fn(slmdb->cb_context, MDB_MAP_RESIZED,
slmdb->curr_limit);
} break;
/* *Whatisitwiththesebuilt-inhardlimitsthatcausesystemsto *stopwhendemandisatitshighest?Whenthesystemisunder *stressitshouldslowdownandkeepmakingprogress.
*/ case MDB_READERS_FULL: if (slmdb->notify_fn)
slmdb->notify_fn(slmdb->cb_context, MDB_READERS_FULL);
sleep(1);
status = 0; break;
/* slmdb_cursor_get - mdb_cursor_get() wrapper with LMDB error recovery */
int slmdb_cursor_get(SLMDB *slmdb, MDB_val *mdb_key,
MDB_val *mdb_value, MDB_cursor_op op)
{
MDB_txn *txn; int status = 0;
/* *TODO:figurehowwewouldrecoverafailingbulktransaction.
*/ if ((slmdb->slmdb_flags & SLMDB_FLAG_BULK) != 0) { if (slmdb->assert_fn)
slmdb->assert_fn(slmdb->cb_context, "slmdb_cursor_get: bulk transaction is not supported"); return (MDB_PANIC);
}
/* *Openareadtransactionandcursorifneeded.
*/ if (slmdb->cursor == 0) { if ((status = slmdb_txn_begin(slmdb, MDB_RDONLY, &txn)) != 0)
SLMDB_API_RETURN(slmdb, status); if ((status = mdb_cursor_open(txn, slmdb->dbi, &slmdb->cursor)) != 0) {
mdb_txn_abort(txn); if ((status = slmdb_recover(slmdb, status)) == 0)
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
SLMDB_API_RETURN(slmdb, status);
}
/* *Restorethecursorpositionfromthesavedkeyinformation.
*/ if (HAVE_SLMDB_SAVED_KEY(slmdb) && op != MDB_FIRST)
status = mdb_cursor_get(slmdb->cursor, &slmdb->saved_key,
(MDB_val *) 0, MDB_SET);
}
/* *Databaselookup.
*/ if (status == 0)
status = mdb_cursor_get(slmdb->cursor, mdb_key, mdb_value, op);
/* *Savethecursorpositionifsuccessful.Thiscanfailonlywith *ENOMEM. * *ClosethecursorreadtransactionifinMDB_NOLOCKmode,becausethe *callermayreleasetheexternallockafterwereturn.
*/ if (status == 0) {
status = slmdb_saved_key_assign(slmdb, mdb_key); if (slmdb->lmdb_flags & MDB_NOLOCK)
slmdb_cursor_close(slmdb);
}
/* *Handleend-of-databaseorothererror.
*/ else { /* Do not hand-optimize out the slmdb_cursor_close() calls below. */ if (status == MDB_NOTFOUND) {
slmdb_cursor_close(slmdb); if (HAVE_SLMDB_SAVED_KEY(slmdb))
slmdb_saved_key_free(slmdb);
} else {
slmdb_cursor_close(slmdb); if ((status = slmdb_recover(slmdb, status)) == 0)
status = slmdb_cursor_get(slmdb, mdb_key, mdb_value, op);
SLMDB_API_RETURN(slmdb, status); /* Do not hand-optimize out the above return statement. */
}
}
SLMDB_API_RETURN(slmdb, status);
}
int slmdb_open(SLMDB *slmdb, constchar *path, int open_flags, int lmdb_flags, int slmdb_flags)
{ struct stat st;
MDB_env *env;
MDB_txn *txn;
MDB_dbi dbi; int db_fd; int status;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.