diff --git a/liblmdb/CHANGES b/liblmdb/CHANGES
index 34049ba7..bc39d82a 100644
--- a/liblmdb/CHANGES
+++ b/liblmdb/CHANGES
@@ -1,5 +1,38 @@
LMDB 0.9 Change Log
+LMDB 0.9.16 Release (2015/08/14)
+ Fix cursor EOF bug (ITS#8190)
+ Fix handling of subDB records (ITS#8181)
+ Fix mdb_midl_shrink() usage (ITS#8200)
+
+LMDB 0.9.15 Release (2015/06/19)
+ Fix txn init (ITS#7961,#7987)
+ Fix MDB_PREV_DUP (ITS#7955,#7671)
+ Fix compact of empty env (ITS#7956)
+ Fix mdb_copy file mode
+ Fix mdb_env_close() after failed mdb_env_open()
+ Fix mdb_rebalance collapsing root (ITS#8062)
+ Fix mdb_load with large values (ITS#8066)
+ Fix to retry writes on EINTR (ITS#8106)
+ Fix mdb_cursor_del on empty DB (ITS#8109)
+ Fix MDB_INTEGERDUP key compare (ITS#8117)
+ Fix error handling (ITS#7959,#8157,etc.)
+ Fix race conditions (ITS#7969,7970)
+ Added workaround for fdatasync bug in ext3fs
+ Build
+ Don't use -fPIC for static lib
+ Update .gitignore (ITS#7952,#7953)
+ Cleanup for "make test" (ITS#7841), "make clean", mtest*.c
+ Misc. Android/Windows cleanup
+ Documentation
+ Fix MDB_APPEND doc
+ Fix MDB_MAXKEYSIZE doc (ITS#8156)
+ Fix mdb_cursor_put,mdb_cursor_del EACCES description
+ Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021)
+ Clarify MDB_WRITEMAP doc (ITS#8021)
+ Clarify mdb_env_open doc
+ Clarify mdb_dbi_open doc
+
LMDB 0.9.14 Release (2014/09/20)
Fix to support 64K page size (ITS#7713)
Fix to persist decreased as well as increased mapsizes (ITS#7789)
diff --git a/liblmdb/COPYRIGHT b/liblmdb/COPYRIGHT
index e0eb484c..722d1a51 100644
--- a/liblmdb/COPYRIGHT
+++ b/liblmdb/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2011-2014 Howard Chu, Symas Corp.
+Copyright 2011-2015 Howard Chu, Symas Corp.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/liblmdb/lmdb.h b/liblmdb/lmdb.h
index 61318ffd..762dba2e 100644
--- a/liblmdb/lmdb.h
+++ b/liblmdb/lmdb.h
@@ -49,15 +49,11 @@
* stale locks can block further operation.
*
* Fix: Check for stale readers periodically, using the
- * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool.
- * Stale writers will be cleared automatically on most systems:
- * - Windows - automatic
- * - BSD, systems using SysV semaphores - automatic
- * - Linux, systems using POSIX mutexes with Robust option - automatic
- * Otherwise just make all programs using the database close it;
- * the lockfile is always reset on first open of the environment.
+ * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool. Or just
+ * make all programs using the database close it; the lockfile
+ * is always reset on first open of the environment.
*
- * - On BSD systems or others configured with MDB_USE_SYSV_SEM,
+ * - On BSD systems or others configured with MDB_USE_POSIX_SEM,
* startup can fail due to semaphores owned by another userid.
*
* Fix: Open and close the database as the user which owns the
@@ -110,9 +106,6 @@
* for stale readers is performed or the lockfile is reset,
* since the process may not remove it from the lockfile.
*
- * This does not apply to write transactions if the system clears
- * stale writers, see above.
- *
* - If you do that anyway, do a periodic check for stale readers. Or
* close the environment once in a while, so the lockfile can get reset.
*
@@ -126,7 +119,7 @@
*
* @author Howard Chu, Symas Corporation.
*
- * @copyright Copyright 2011-2014 Howard Chu, Symas Corp. All rights reserved.
+ * @copyright Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
@@ -191,7 +184,7 @@ typedef int mdb_filehandle_t;
/** Library minor version */
#define MDB_VERSION_MINOR 9
/** Library patch version */
-#define MDB_VERSION_PATCH 14
+#define MDB_VERSION_PATCH 16
/** Combine args a,b,c into a single integer for easy version comparisons */
#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
@@ -201,7 +194,7 @@ typedef int mdb_filehandle_t;
MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
/** The release date of this library version */
-#define MDB_VERSION_DATE "September 20, 2014"
+#define MDB_VERSION_DATE "August 14, 2015"
/** A stringifier for the version info */
#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
@@ -303,12 +296,12 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
#define MDB_REVERSEKEY 0x02
/** use sorted duplicates */
#define MDB_DUPSORT 0x04
- /** numeric keys in native byte order.
+ /** numeric keys in native byte order: either unsigned int or size_t.
* The keys must all be of the same size. */
#define MDB_INTEGERKEY 0x08
/** with #MDB_DUPSORT, sorted dup items have fixed size */
#define MDB_DUPFIXED 0x10
- /** with #MDB_DUPSORT, dups are numeric in native byte order */
+ /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */
#define MDB_INTEGERDUP 0x20
/** with #MDB_DUPSORT, use reverse string dups */
#define MDB_REVERSEDUP 0x40
@@ -398,7 +391,7 @@ typedef enum MDB_cursor_op {
#define MDB_PAGE_NOTFOUND (-30797)
/** Located page was wrong type */
#define MDB_CORRUPTED (-30796)
- /** Update of meta page failed or environment had fatal error */
+ /** Update of meta page failed, probably I/O error */
#define MDB_PANIC (-30795)
/** Environment version mismatch */
#define MDB_VERSION_MISMATCH (-30794)
@@ -420,7 +413,14 @@ typedef enum MDB_cursor_op {
#define MDB_PAGE_FULL (-30786)
/** Database contents grew beyond environment mapsize */
#define MDB_MAP_RESIZED (-30785)
- /** MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed */
+ /** Operation and DB incompatible, or DB type changed. This can mean:
+ *
+ * - The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database.
+ *
- Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY.
+ *
- Accessing a data record as a database, or vice versa.
+ *
- The database was dropped and recreated with different flags.
+ *
+ */
#define MDB_INCOMPATIBLE (-30784)
/** Invalid reuse of reader locktable slot */
#define MDB_BAD_RSLOT (-30783)
@@ -595,8 +595,8 @@ int mdb_env_create(MDB_env **env);
* reserved in that case.
* This flag may be changed at any time using #mdb_env_set_flags().
*
- * @param[in] mode The UNIX permissions to set on created files. This parameter
- * is ignored on Windows.
+ * @param[in] mode The UNIX permissions to set on created files and semaphores.
+ * This parameter is ignored on Windows.
* @return A non-zero error value on failure and 0 on success. Some possible
* errors are:
*
@@ -930,8 +930,6 @@ int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
*
* - #MDB_RDONLY
* This transaction will not perform any write operations.
- *
- #MDB_NOSYNC
- * Don't flush system buffers to disk when committing this transaction.
*
* @param[out] txn Address where the new #MDB_txn handle will be stored
* @return A non-zero error value on failure and 0 on success. Some possible
@@ -955,17 +953,6 @@ int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **
*/
MDB_env *mdb_txn_env(MDB_txn *txn);
- /** @brief Return the transaction's ID.
- *
- * This returns the identifier associated with this transaction. For a
- * read-only transaction, this corresponds to the snapshot being read;
- * concurrent readers will frequently have the same transaction ID.
- *
- * @param[in] txn A transaction handle returned by #mdb_txn_begin()
- * @return A transaction ID, valid if input is an active transaction.
- */
-size_t mdb_txn_id(MDB_txn *txn);
-
/** @brief Commit all the operations of a transaction into the database.
*
* The transaction handle is freed. It and its cursors must not be used
@@ -1041,19 +1028,22 @@ int mdb_txn_renew(MDB_txn *txn);
* The database handle may be discarded by calling #mdb_dbi_close().
* The old database handle is returned if the database was already open.
* The handle may only be closed once.
+ *
* The database handle will be private to the current transaction until
* the transaction is successfully committed. If the transaction is
* aborted the handle will be closed automatically.
- * After a successful commit the
- * handle will reside in the shared environment, and may be used
- * by other transactions. This function must not be called from
- * multiple concurrent transactions in the same process. A transaction
- * that uses this function must finish (either commit or abort) before
+ * After a successful commit the handle will reside in the shared
+ * environment, and may be used by other transactions.
+ *
+ * This function must not be called from multiple concurrent
+ * transactions in the same process. A transaction that uses
+ * this function must finish (either commit or abort) before
* any other transaction in the process may use this function.
*
* To use named databases (with name != NULL), #mdb_env_set_maxdbs()
- * must be called before opening the environment. Database names
- * are kept as keys in the unnamed database.
+ * must be called before opening the environment. Database names are
+ * keys in the unnamed database, and may be read but not written.
+ *
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
* @param[in] name The name of the database to open. If only a single
* database is needed in the environment, this value may be NULL.
@@ -1070,9 +1060,9 @@ int mdb_txn_renew(MDB_txn *txn);
* keys may have multiple data items, stored in sorted order.) By default
* keys must be unique and may have only a single data item.
* - #MDB_INTEGERKEY
- * Keys are binary integers in native byte order. Setting this option
- * requires all keys to be the same size, typically sizeof(int)
- * or sizeof(size_t).
+ * Keys are binary integers in native byte order, either unsigned int
+ * or size_t, and will be sorted as such.
+ * The keys must all be of the same size.
*
- #MDB_DUPFIXED
* This flag may only be used in combination with #MDB_DUPSORT. This option
* tells the library that the data items for this database are all the same
@@ -1080,8 +1070,8 @@ int mdb_txn_renew(MDB_txn *txn);
* all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE
* cursor operations may be used to retrieve multiple items at once.
*
- #MDB_INTEGERDUP
- * This option specifies that duplicate data items are also integers, and
- * should be sorted as such.
+ * This option specifies that duplicate data items are binary integers,
+ * similar to #MDB_INTEGERKEY keys.
*
- #MDB_REVERSEDUP
* This option specifies that duplicate data items should be compared as
* strings in reverse order.
diff --git a/liblmdb/mdb.c b/liblmdb/mdb.c
index 98b69fcc..b5d59bcd 100644
--- a/liblmdb/mdb.c
+++ b/liblmdb/mdb.c
@@ -5,7 +5,7 @@
* BerkeleyDB API, but much simplified.
*/
/*
- * Copyright 2011-2014 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -110,7 +110,7 @@ extern int cacheflush(char *addr, int nbytes, int cache);
#endif
#if defined(__APPLE__) || defined (BSD)
-# define MDB_USE_SYSV_SEM 1
+# define MDB_USE_POSIX_SEM 1
# define MDB_FDATASYNC fsync
#elif defined(ANDROID)
# define MDB_FDATASYNC fsync
@@ -118,18 +118,11 @@ extern int cacheflush(char *addr, int nbytes, int cache);
#ifndef _WIN32
#include
-#ifdef MDB_USE_SYSV_SEM
-#include
-#include
-#ifdef _SEM_SEMUN_UNDEFINED
-union semun {
- int val;
- struct semid_ds *buf;
- unsigned short *array;
-};
-#endif /* _SEM_SEMUN_UNDEFINED */
-#endif /* MDB_USE_SYSV_SEM */
-#endif /* !_WIN32 */
+#ifdef MDB_USE_POSIX_SEM
+# define MDB_USE_HASH 1
+#include
+#endif
+#endif
#ifdef USE_VALGRIND
#include
@@ -206,10 +199,6 @@ union semun {
/** Features under development */
#ifndef MDB_DEVEL
#define MDB_DEVEL 0
-#endif
-
-#if defined(_WIN32) || defined(MDB_USE_SYSV_SEM) || defined(EOWNERDEAD)
-#define MDB_ROBUST_SUPPORTED 1
#endif
/** Wrapper around __func__, which is a C99 feature */
@@ -222,16 +211,6 @@ union semun {
# define mdb_func_ ""
#endif
-/* Internal error codes, not exposed outside liblmdb */
-#define MDB_NO_ROOT (MDB_LAST_ERRCODE + 10)
-#ifdef _WIN32
-#define MDB_OWNERDEAD ((int) WAIT_ABANDONED)
-#elif defined MDB_USE_SYSV_SEM
-#define MDB_OWNERDEAD (MDB_LAST_ERRCODE + 11)
-#else
-#define MDB_OWNERDEAD EOWNERDEAD
-#endif
-
#ifdef _WIN32
#define MDB_USE_HASH 1
#define MDB_PIDLOCK 0
@@ -239,7 +218,6 @@ union semun {
#define pthread_t HANDLE
#define pthread_mutex_t HANDLE
#define pthread_cond_t HANDLE
-typedef HANDLE mdb_mutex_t;
#define pthread_key_t DWORD
#define pthread_self() GetCurrentThreadId()
#define pthread_key_create(x,y) \
@@ -253,10 +231,10 @@ typedef HANDLE mdb_mutex_t;
#define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0)
#define THREAD_CREATE(thr,start,arg) thr=CreateThread(NULL,0,start,arg,0,NULL)
#define THREAD_FINISH(thr) WaitForSingleObject(thr, INFINITE)
-#define MDB_MUTEX(env, rw) ((env)->me_##rw##mutex)
-#define LOCK_MUTEX0(mutex) WaitForSingleObject(mutex, INFINITE)
-#define UNLOCK_MUTEX(mutex) ReleaseMutex(mutex)
-#define mdb_mutex_consistent(mutex) 0
+#define LOCK_MUTEX_R(env) pthread_mutex_lock(&(env)->me_rmutex)
+#define UNLOCK_MUTEX_R(env) pthread_mutex_unlock(&(env)->me_rmutex)
+#define LOCK_MUTEX_W(env) pthread_mutex_lock(&(env)->me_wmutex)
+#define UNLOCK_MUTEX_W(env) pthread_mutex_unlock(&(env)->me_wmutex)
#define getpid() GetCurrentProcessId()
#define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd))
#define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len))
@@ -279,59 +257,38 @@ typedef HANDLE mdb_mutex_t;
/** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */
#define MDB_PIDLOCK 1
-#ifdef MDB_USE_SYSV_SEM
+#ifdef MDB_USE_POSIX_SEM
-typedef struct mdb_mutex {
- int semid;
- int semnum;
- int *locked;
-} mdb_mutex_t;
-
-#define MDB_MUTEX(env, rw) (&(env)->me_##rw##mutex)
-#define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex)
-#define UNLOCK_MUTEX(mutex) do { \
- struct sembuf sb = { 0, 1, SEM_UNDO }; \
- sb.sem_num = (mutex)->semnum; \
- *(mutex)->locked = 0; \
- semop((mutex)->semid, &sb, 1); \
-} while(0)
+#define LOCK_MUTEX_R(env) mdb_sem_wait((env)->me_rmutex)
+#define UNLOCK_MUTEX_R(env) sem_post((env)->me_rmutex)
+#define LOCK_MUTEX_W(env) mdb_sem_wait((env)->me_wmutex)
+#define UNLOCK_MUTEX_W(env) sem_post((env)->me_wmutex)
static int
-mdb_sem_wait(mdb_mutex_t *sem)
+mdb_sem_wait(sem_t *sem)
{
- int rc, *locked = sem->locked;
- struct sembuf sb = { 0, -1, SEM_UNDO };
- sb.sem_num = sem->semnum;
- do {
- if (!semop(sem->semid, &sb, 1)) {
- rc = *locked ? MDB_OWNERDEAD : MDB_SUCCESS;
- *locked = 1;
- break;
- }
- } while ((rc = errno) == EINTR);
- return rc;
+ int rc;
+ while ((rc = sem_wait(sem)) && (rc = errno) == EINTR) ;
+ return rc;
}
-#define mdb_mutex_consistent(mutex) 0
-
#else
- /** Pointer/HANDLE type of shared mutex/semaphore.
+ /** Lock the reader mutex.
*/
-typedef pthread_mutex_t mdb_mutex_t;
- /** Mutex for the reader table (rw = r) or write transaction (rw = w).
+#define LOCK_MUTEX_R(env) pthread_mutex_lock(&(env)->me_txns->mti_mutex)
+ /** Unlock the reader mutex.
*/
-#define MDB_MUTEX(env, rw) (&(env)->me_txns->mti_##rw##mutex)
- /** Lock the reader or writer mutex.
- * Returns 0 or a code to give #mdb_mutex_failed(), as in #LOCK_MUTEX().
+#define UNLOCK_MUTEX_R(env) pthread_mutex_unlock(&(env)->me_txns->mti_mutex)
+
+ /** Lock the writer mutex.
+ * Only a single write transaction is allowed at a time. Other writers
+ * will block waiting for this mutex.
*/
-#define LOCK_MUTEX0(mutex) pthread_mutex_lock(mutex)
- /** Unlock the reader or writer mutex.
+#define LOCK_MUTEX_W(env) pthread_mutex_lock(&(env)->me_txns->mti_wmutex)
+ /** Unlock the writer mutex.
*/
-#define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex)
- /** Mark mutex-protected data as repaired, after death of previous owner.
- */
-#define mdb_mutex_consistent(mutex) pthread_mutex_consistent(mutex)
-#endif /* MDB_USE_SYSV_SEM */
+#define UNLOCK_MUTEX_W(env) pthread_mutex_unlock(&(env)->me_txns->mti_wmutex)
+#endif /* MDB_USE_POSIX_SEM */
/** Get the error code for the last failed system function.
*/
@@ -356,35 +313,14 @@ typedef pthread_mutex_t mdb_mutex_t;
#define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE))
#endif
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
#define MNAME_LEN 32
-#elif defined(MDB_USE_SYSV_SEM)
-#define MNAME_LEN (sizeof(int))
#else
#define MNAME_LEN (sizeof(pthread_mutex_t))
#endif
-#ifdef MDB_USE_SYSV_SEM
-#define SYSV_SEM_FLAG 1 /**< SysV sems in lockfile format */
-#else
-#define SYSV_SEM_FLAG 0
-#endif
-
/** @} */
-#ifdef MDB_ROBUST_SUPPORTED
- /** Lock mutex, handle any error, set rc = result.
- * Return 0 on success, nonzero (not rc) on error.
- */
-#define LOCK_MUTEX(rc, env, mutex) \
- (((rc) = LOCK_MUTEX0(mutex)) && \
- ((rc) = mdb_mutex_failed(env, mutex, rc)))
-static int mdb_mutex_failed(MDB_env *env, mdb_mutex_t *mutex, int rc);
-#else
-#define LOCK_MUTEX(rc, env, mutex) ((rc) = LOCK_MUTEX0(mutex))
-#define mdb_mutex_failed(env, mutex, rc) (rc)
-#endif
-
#ifndef _WIN32
/** A flag for opening a file and requesting synchronous data writes.
* This is only used when writing a meta page. It's not strictly needed;
@@ -508,14 +444,19 @@ static txnid_t mdb_debug_start;
/** The version number for a database's datafile format. */
#define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1)
/** The version number for a database's lockfile format. */
-#define MDB_LOCK_VERSION ((MDB_DEVEL) ? 999 : 1)
+#define MDB_LOCK_VERSION 1
- /** @brief The max size of a key we can write, or 0 for dynamic max.
+ /** @brief The max size of a key we can write, or 0 for computed max.
*
- * Define this as 0 to compute the max from the page size. 511
- * is default for backwards compat: liblmdb <= 0.9.10 can break
- * when modifying a DB with keys/dupsort data bigger than its max.
- * #MDB_DEVEL sets the default to 0.
+ * This macro should normally be left alone or set to 0.
+ * Note that a database with big keys or dupsort data cannot be
+ * reliably modified by a liblmdb which uses a smaller max.
+ * The default is 511 for backwards compat, or 0 when #MDB_DEVEL.
+ *
+ * Other values are allowed, for backwards compat. However:
+ * A value bigger than the computed max can break if you do not
+ * know what you are doing, and liblmdb <= 0.9.10 can break when
+ * modifying a DB with keys/dupsort data bigger than its max.
*
* Data items in an #MDB_DUPSORT database are also limited to
* this size, since they're actually keys of a sub-DB. Keys and
@@ -692,16 +633,13 @@ typedef struct MDB_txbody {
uint32_t mtb_magic;
/** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */
uint32_t mtb_format;
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
char mtb_rmname[MNAME_LEN];
-#elif defined(MDB_USE_SYSV_SEM)
- int mtb_semid;
- int mtb_rlocked;
#else
/** Mutex protecting access to this table.
- * This is the #MDB_MUTEX(env,r) reader table lock.
+ * This is the reader lock that #LOCK_MUTEX_R acquires.
*/
- pthread_mutex_t mtb_rmutex;
+ pthread_mutex_t mtb_mutex;
#endif
/** The ID of the last transaction committed to the database.
* This is recorded here only for convenience; the value can always
@@ -721,23 +659,16 @@ typedef struct MDB_txninfo {
MDB_txbody mtb;
#define mti_magic mt1.mtb.mtb_magic
#define mti_format mt1.mtb.mtb_format
-#define mti_rmutex mt1.mtb.mtb_rmutex
+#define mti_mutex mt1.mtb.mtb_mutex
#define mti_rmname mt1.mtb.mtb_rmname
#define mti_txnid mt1.mtb.mtb_txnid
#define mti_numreaders mt1.mtb.mtb_numreaders
-#ifdef MDB_USE_SYSV_SEM
-#define mti_semid mt1.mtb.mtb_semid
-#define mti_rlocked mt1.mtb.mtb_rlocked
-#endif
char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)];
} mt1;
union {
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM)
char mt2_wmname[MNAME_LEN];
#define mti_wmname mt2.mt2_wmname
-#elif defined MDB_USE_SYSV_SEM
- int mt2_wlocked;
-#define mti_wlocked mt2.mt2_wlocked
#else
pthread_mutex_t mt2_wmutex;
#define mti_wmutex mt2.mt2_wmutex
@@ -752,7 +683,6 @@ typedef struct MDB_txninfo {
((uint32_t) \
((MDB_LOCK_VERSION) \
/* Flags which describe functionality */ \
- + (SYSV_SEM_FLAG << 18) \
+ (((MDB_PIDLOCK) != 0) << 16)))
/** @} */
@@ -1084,7 +1014,6 @@ struct MDB_txn {
#define MDB_TXN_ERROR 0x02 /**< txn is unusable after an error */
#define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */
#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */
-#define MDB_TXN_NOSYNC 0x10 /**< don't sync this txn on commit */
/** @} */
unsigned int mt_flags; /**< @ref mdb_txn */
/** #dirty_list room: Array size - \#dirty pages visible to this txn.
@@ -1186,8 +1115,7 @@ struct MDB_env {
unsigned int me_psize; /**< DB page size, inited from me_os_psize */
unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */
unsigned int me_maxreaders; /**< size of the reader table */
- /** Max #MDB_txninfo.%mti_numreaders of interest to #mdb_env_close() */
- volatile int me_close_readers;
+ unsigned int me_numreaders; /**< max numreaders set by this env */
MDB_dbi me_numdbs; /**< number of DBs opened */
MDB_dbi me_maxdbs; /**< size of the DB table */
MDB_PID_T me_pid; /**< process ID of this env */
@@ -1224,11 +1152,11 @@ struct MDB_env {
int me_live_reader; /**< have liveness lock in reader table */
#ifdef _WIN32
int me_pidquery; /**< Used in OpenProcess */
-#endif
-#if defined(_WIN32) || defined(MDB_USE_SYSV_SEM)
- /* Windows mutexes/SysV semaphores do not reside in shared mem */
- mdb_mutex_t me_rmutex;
- mdb_mutex_t me_wmutex;
+ HANDLE me_rmutex; /* Windows mutexes don't reside in shared mem */
+ HANDLE me_wmutex;
+#elif defined(MDB_USE_POSIX_SEM)
+ sem_t *me_rmutex; /* Shared mutexes are not supported */
+ sem_t *me_wmutex;
#endif
void *me_userctx; /**< User-settable context */
MDB_assert_func *me_assert_func; /**< Callback for assertion failures */
@@ -1280,7 +1208,7 @@ static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
static int mdb_env_pick_meta(const MDB_env *env);
static int mdb_env_write_meta(MDB_txn *txn);
-#if !(defined(_WIN32) || defined(MDB_USE_SYSV_SEM)) /* Drop unused excl arg */
+#if !(defined(_WIN32) || defined(MDB_USE_POSIX_SEM)) /* Drop unused excl arg */
# define mdb_env_close0(env, excl) mdb_env_close1(env)
#endif
static void mdb_env_close0(MDB_env *env, int excl);
@@ -1317,12 +1245,18 @@ static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node);
static int mdb_drop0(MDB_cursor *mc, int subs);
static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
-static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead);
/** @cond */
static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long;
/** @endcond */
+/** Compare two items pointing at size_t's of unknown alignment. */
+#ifdef MISALIGNED_OK
+# define mdb_cmp_clong mdb_cmp_long
+#else
+# define mdb_cmp_clong mdb_cmp_cint
+#endif
+
#ifdef _WIN32
static SECURITY_DESCRIPTOR mdb_null_sd;
static SECURITY_ATTRIBUTES mdb_all_sa;
@@ -1345,7 +1279,7 @@ static char *const mdb_errstr[] = {
"MDB_NOTFOUND: No matching key/data pair found",
"MDB_PAGE_NOTFOUND: Requested page not found",
"MDB_CORRUPTED: Located page was wrong type",
- "MDB_PANIC: Update of meta page failed or environment had fatal error",
+ "MDB_PANIC: Update of meta page failed",
"MDB_VERSION_MISMATCH: Database environment version mismatch",
"MDB_INVALID: File is not an LMDB file",
"MDB_MAP_FULL: Environment mapsize limit reached",
@@ -1636,7 +1570,12 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
int
mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
{
- return txn->mt_dbxs[dbi].md_dcmp(a, b);
+ MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp;
+#if UINT_MAX < SIZE_MAX
+ if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
+#endif
+ return dcmp(a, b);
}
/** Allocate memory for a page.
@@ -2564,14 +2503,11 @@ mdb_txn_renew0(MDB_txn *txn)
MDB_env *env = txn->mt_env;
MDB_txninfo *ti = env->me_txns;
MDB_meta *meta;
- unsigned int i, nr;
+ unsigned int i, nr, flags = txn->mt_flags;
uint16_t x;
int rc, new_notls = 0;
- if (txn->mt_flags & MDB_TXN_RDONLY) {
- /* Setup db info */
- txn->mt_numdbs = env->me_numdbs;
- txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
+ if ((flags &= MDB_TXN_RDONLY) != 0) {
if (!ti) {
meta = env->me_metas[ mdb_env_pick_meta(env) ];
txn->mt_txnid = meta->mm_txnid;
@@ -2585,7 +2521,6 @@ mdb_txn_renew0(MDB_txn *txn)
} else {
MDB_PID_T pid = env->me_pid;
MDB_THR_T tid = pthread_self();
- mdb_mutex_t *rmutex = MDB_MUTEX(env, r);
if (!env->me_live_reader) {
rc = mdb_reader_pid(env, Pidset, pid);
@@ -2594,32 +2529,24 @@ mdb_txn_renew0(MDB_txn *txn)
env->me_live_reader = 1;
}
- if (LOCK_MUTEX(rc, env, rmutex))
- return rc;
+ LOCK_MUTEX_R(env);
nr = ti->mti_numreaders;
for (i=0; imti_readers[i].mr_pid == 0)
break;
if (i == env->me_maxreaders) {
- UNLOCK_MUTEX(rmutex);
+ UNLOCK_MUTEX_R(env);
return MDB_READERS_FULL;
}
- r = &ti->mti_readers[i];
- /* Claim the reader slot, carefully since other code
- * uses the reader table un-mutexed: First reset the
- * slot, next publish it in mti_numreaders. After
- * that, it is safe for mdb_env_close() to touch it.
- * When it will be closed, we can finally claim it.
- */
- r->mr_pid = 0;
- r->mr_txnid = (txnid_t)-1;
- r->mr_tid = tid;
+ ti->mti_readers[i].mr_pid = pid;
+ ti->mti_readers[i].mr_tid = tid;
if (i == nr)
ti->mti_numreaders = ++nr;
- env->me_close_readers = nr;
- r->mr_pid = pid;
- UNLOCK_MUTEX(rmutex);
+ /* Save numreaders for un-mutexed mdb_env_close() */
+ env->me_numreaders = nr;
+ UNLOCK_MUTEX_R(env);
+ r = &ti->mti_readers[i];
new_notls = (env->me_flags & MDB_NOTLS);
if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) {
r->mr_pid = 0;
@@ -2633,24 +2560,22 @@ mdb_txn_renew0(MDB_txn *txn)
txn->mt_u.reader = r;
meta = env->me_metas[txn->mt_txnid & 1];
}
+ txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
} else {
if (ti) {
- if (LOCK_MUTEX(rc, env, MDB_MUTEX(env, w)))
- return rc;
+ LOCK_MUTEX_W(env);
+
txn->mt_txnid = ti->mti_txnid;
meta = env->me_metas[txn->mt_txnid & 1];
} else {
meta = env->me_metas[ mdb_env_pick_meta(env) ];
txn->mt_txnid = meta->mm_txnid;
}
- /* Setup db info */
- txn->mt_numdbs = env->me_numdbs;
txn->mt_txnid++;
#if MDB_DEBUG
if (txn->mt_txnid == mdb_debug_start)
mdb_debug = 1;
#endif
- txn->mt_flags = 0;
txn->mt_child = NULL;
txn->mt_loose_pgs = NULL;
txn->mt_loose_count = 0;
@@ -2670,6 +2595,10 @@ mdb_txn_renew0(MDB_txn *txn)
/* Moved to here to avoid a data race in read TXNs */
txn->mt_next_pgno = meta->mm_last_pg+1;
+ txn->mt_flags = flags;
+
+ /* Setup db info */
+ txn->mt_numdbs = env->me_numdbs;
for (i=2; imt_numdbs; i++) {
x = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
@@ -2756,8 +2685,6 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
txn->mt_dbflags = (unsigned char *)(txn->mt_dbs + env->me_maxdbs);
txn->mt_dbiseqs = env->me_dbiseqs;
} else {
- if (flags & MDB_NOSYNC)
- txn->mt_flags |= MDB_TXN_NOSYNC;
txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
if (parent) {
txn->mt_dbiseqs = parent->mt_dbiseqs;
@@ -2832,13 +2759,6 @@ mdb_txn_env(MDB_txn *txn)
return txn->mt_env;
}
-size_t
-mdb_txn_id(MDB_txn *txn)
-{
- if(!txn) return 0;
- return txn->mt_txnid;
-}
-
/** Export or close DBI handles opened in this txn. */
static void
mdb_dbis_update(MDB_txn *txn, int keep)
@@ -2902,8 +2822,8 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
}
if (!txn->mt_parent) {
- if (mdb_midl_shrink(&txn->mt_free_pgs))
- env->me_free_pgs = txn->mt_free_pgs;
+ mdb_midl_shrink(&txn->mt_free_pgs);
+ env->me_free_pgs = txn->mt_free_pgs;
/* me_pgstate: */
env->me_pghead = NULL;
env->me_pglast = 0;
@@ -2911,7 +2831,7 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
env->me_txn = NULL;
/* The writer mutex was locked in mdb_txn_begin. */
if (env->me_txns)
- UNLOCK_MUTEX(MDB_MUTEX(env, w));
+ UNLOCK_MUTEX_W(env);
} else {
txn->mt_parent->mt_child = NULL;
env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate;
@@ -3228,6 +3148,7 @@ mdb_page_flush(MDB_txn *txn, int keep)
/* Write up to MDB_COMMIT_PAGES dirty pages at a time. */
if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) {
if (n) {
+retry_write:
/* Write previous page(s) */
#ifdef MDB_USE_PWRITEV
wres = pwritev(env->me_fd, iov, n, wpos);
@@ -3235,8 +3156,11 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (n == 1) {
wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos);
} else {
+retry_seek:
if (lseek(env->me_fd, wpos, SEEK_SET) == -1) {
rc = ErrCode();
+ if (rc == EINTR)
+ goto retry_seek;
DPRINTF(("lseek: %s", strerror(rc)));
return rc;
}
@@ -3246,6 +3170,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (wres != wsize) {
if (wres < 0) {
rc = ErrCode();
+ if (rc == EINTR)
+ goto retry_write;
DPRINTF(("Write error: %s", strerror(rc)));
} else {
rc = EIO; /* TODO: Use which error code? */
@@ -3469,7 +3395,8 @@ mdb_txn_commit(MDB_txn *txn)
goto fail;
}
data.mv_data = &txn->mt_dbs[i];
- rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, 0);
+ rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data,
+ F_SUBDATA);
if (rc)
goto fail;
}
@@ -3482,19 +3409,16 @@ mdb_txn_commit(MDB_txn *txn)
mdb_midl_free(env->me_pghead);
env->me_pghead = NULL;
- if (mdb_midl_shrink(&txn->mt_free_pgs))
- env->me_free_pgs = txn->mt_free_pgs;
+ mdb_midl_shrink(&txn->mt_free_pgs);
+ env->me_free_pgs = txn->mt_free_pgs;
#if (MDB_DEBUG) > 2
mdb_audit(txn);
#endif
- if ((rc = mdb_page_flush(txn, 0)))
- goto fail;
- if (!F_ISSET(txn->mt_flags, MDB_TXN_NOSYNC) &&
- (rc = mdb_env_sync(env, 0)))
- goto fail;
- if ((rc = mdb_env_write_meta(txn)))
+ if ((rc = mdb_page_flush(txn, 0)) ||
+ (rc = mdb_env_sync(env, 0)) ||
+ (rc = mdb_env_write_meta(txn)))
goto fail;
/* Free P_LOOSE pages left behind in dirty_list */
@@ -3507,7 +3431,7 @@ done:
mdb_dbis_update(txn, 1);
if (env->me_txns)
- UNLOCK_MUTEX(MDB_MUTEX(env, w));
+ UNLOCK_MUTEX_W(env);
if (txn != env->me_txn0)
free(txn);
@@ -3582,7 +3506,6 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta)
return 0;
}
-/** Fill in most of the zeroed #MDB_meta for an empty database environment */
static void ESECT
mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
{
@@ -3599,7 +3522,7 @@ mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
/** Write the environment parameters of a freshly created DB environment.
* @param[in] env the environment handle
- * @param[in] meta the #MDB_meta to write
+ * @param[out] meta address of where to store the meta information
* @return 0 on success, non-zero on failure.
*/
static int ESECT
@@ -3619,13 +3542,16 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
int len;
#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \
len = pwrite(fd, ptr, size, pos); \
- rc = (len >= 0); } while(0)
+ if (len == -1 && ErrCode() == EINTR) continue; \
+ rc = (len >= 0); break; } while(1)
#endif
DPUTS("writing new meta page");
psize = env->me_psize;
+ mdb_env_init_meta0(env, meta);
+
p = calloc(2, psize);
p->mp_pgno = 0;
p->mp_flags = P_META;
@@ -3683,13 +3609,7 @@ mdb_env_write_meta(MDB_txn *txn)
mp->mm_dbs[0] = txn->mt_dbs[0];
mp->mm_dbs[1] = txn->mt_dbs[1];
mp->mm_last_pg = txn->mt_next_pgno - 1;
-#if !(defined(_MSC_VER) || defined(__i386__) || defined(__x86_64__))
- /* LY: issue a memory barrier, if not x86. ITS#7969 */
- __sync_synchronize();
-#endif
mp->mm_txnid = txn->mt_txnid;
- if (F_ISSET(txn->mt_flags, MDB_TXN_NOSYNC))
- goto done;
if (!(env->me_flags & (MDB_NOMETASYNC|MDB_NOSYNC))) {
unsigned meta_size = env->me_psize;
rc = (env->me_flags & MDB_MAPASYNC) ? MS_ASYNC : MS_SYNC;
@@ -3726,8 +3646,7 @@ mdb_env_write_meta(MDB_txn *txn)
off += PAGEHDRSZ;
/* Write to the SYNC fd */
- mfd = ((env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC)) ||
- (txn->mt_flags & MDB_TXN_NOSYNC)) ?
+ mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ?
env->me_fd : env->me_mfd;
#ifdef _WIN32
{
@@ -3737,10 +3656,15 @@ mdb_env_write_meta(MDB_txn *txn)
rc = -1;
}
#else
+retry_write:
rc = pwrite(mfd, ptr, len, off);
#endif
if (rc != len) {
rc = rc < 0 ? ErrCode() : EIO;
+#ifndef _WIN32
+ if (rc == EINTR)
+ goto retry_write;
+#endif
DPUTS("write failed, disk error?");
/* On a failure, the pagecache still contains the new data.
* Write some old data back, to prevent it from being used.
@@ -3799,9 +3723,9 @@ mdb_env_create(MDB_env **env)
e->me_fd = INVALID_HANDLE_VALUE;
e->me_lfd = INVALID_HANDLE_VALUE;
e->me_mfd = INVALID_HANDLE_VALUE;
-#ifdef MDB_USE_SYSV_SEM
- e->me_rmutex.semid = -1;
- e->me_wmutex.semid = -1;
+#ifdef MDB_USE_POSIX_SEM
+ e->me_rmutex = SEM_FAILED;
+ e->me_wmutex = SEM_FAILED;
#endif
e->me_pid = getpid();
GET_PAGESIZE(e->me_os_psize);
@@ -3902,16 +3826,16 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
*/
if (env->me_map) {
int rc;
- MDB_meta *meta;
void *old;
if (env->me_txn)
return EINVAL;
- meta = env->me_metas[mdb_env_pick_meta(env)];
if (!size)
- size = meta->mm_mapsize;
- {
- /* Silently round up to minimum if the size is too small */
- size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
+ size = env->me_metas[mdb_env_pick_meta(env)]->mm_mapsize;
+ else if (size < env->me_mapsize) {
+ /* If the configured size is smaller, make sure it's
+ * still big enough. Silently round up to minimum if not.
+ */
+ size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize;
if (size < minsize)
size = minsize;
}
@@ -3998,7 +3922,6 @@ mdb_env_open2(MDB_env *env)
else
env->me_pidquery = PROCESS_QUERY_INFORMATION;
#endif /* _WIN32 */
-
#ifdef BROKEN_FDATASYNC
/* ext3/ext4 fdatasync is broken on some older Linux kernels.
* https://lkml.org/lkml/2012/9/3/83
@@ -4047,6 +3970,8 @@ mdb_env_open2(MDB_env *env)
}
#endif
+ memset(&meta, 0, sizeof(meta));
+
if ((i = mdb_env_read_header(env, &meta)) != 0) {
if (i != ENOENT)
return i;
@@ -4055,40 +3980,24 @@ mdb_env_open2(MDB_env *env)
env->me_psize = env->me_os_psize;
if (env->me_psize > MAX_PAGESIZE)
env->me_psize = MAX_PAGESIZE;
- memset(&meta, 0, sizeof(meta));
- mdb_env_init_meta0(env, &meta);
- meta.mm_mapsize = DEFAULT_MAPSIZE;
} else {
env->me_psize = meta.mm_psize;
}
/* Was a mapsize configured? */
if (!env->me_mapsize) {
- env->me_mapsize = meta.mm_mapsize;
- }
- {
- /* Make sure mapsize >= committed data size. Even when using
- * mm_mapsize, which could be broken in old files (ITS#7789).
+ /* If this is a new environment, take the default,
+ * else use the size recorded in the existing env.
+ */
+ env->me_mapsize = newenv ? DEFAULT_MAPSIZE : meta.mm_mapsize;
+ } else if (env->me_mapsize < meta.mm_mapsize) {
+ /* If the configured size is smaller, make sure it's
+ * still big enough. Silently round up to minimum if not.
*/
size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize;
if (env->me_mapsize < minsize)
env->me_mapsize = minsize;
}
- meta.mm_mapsize = env->me_mapsize;
-
- if (newenv && !(flags & MDB_FIXEDMAP)) {
- /* mdb_env_map() may grow the datafile. Write the metapages
- * first, so the file will be valid if initialization fails.
- * Except with FIXEDMAP, since we do not yet know mm_address.
- * We could fill in mm_address later, but then a different
- * program might end up doing that - one with a memory layout
- * and map address which does not suit the main program.
- */
- rc = mdb_env_init_meta(env, &meta);
- if (rc)
- return rc;
- newenv = 0;
- }
rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL);
if (rc)
@@ -4272,8 +4181,8 @@ mdb_env_excl_lock(MDB_env *env, int *excl)
if (!rc) {
*excl = 1;
} else
-# ifdef MDB_USE_SYSV_SEM
- if (*excl < 0) /* always true when !MDB_USE_SYSV_SEM */
+# ifdef MDB_USE_POSIX_SEM
+ if (*excl < 0) /* always true when !MDB_USE_POSIX_SEM */
# endif
{
lock_info.l_type = F_RDLCK;
@@ -4398,10 +4307,6 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
int fdflags;
# define MDB_CLOEXEC 0
#endif
-#endif
-#ifdef MDB_USE_SYSV_SEM
- int semid;
- union semun semu;
#endif
int rc;
off_t size, rsize;
@@ -4515,28 +4420,50 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
if (!env->me_rmutex) goto fail_errno;
env->me_wmutex = CreateMutex(&mdb_all_sa, FALSE, env->me_txns->mti_wmname);
if (!env->me_wmutex) goto fail_errno;
-#elif defined(MDB_USE_SYSV_SEM)
- unsigned short vals[2] = {1, 1};
- semid = semget(IPC_PRIVATE, 2, mode);
- if (semid < 0)
- goto fail_errno;
- semu.array = vals;
- if (semctl(semid, 0, SETALL, semu) < 0)
- goto fail_errno;
- env->me_txns->mti_semid = semid;
-#else /* MDB_USE_SYSV_SEM */
+#elif defined(MDB_USE_POSIX_SEM)
+ struct stat stbuf;
+ struct {
+ dev_t dev;
+ ino_t ino;
+ } idbuf;
+ MDB_val val;
+ char encbuf[11];
+
+#if defined(__NetBSD__)
+#define MDB_SHORT_SEMNAMES 1 /* limited to 14 chars */
+#endif
+ if (fstat(env->me_lfd, &stbuf)) goto fail_errno;
+ idbuf.dev = stbuf.st_dev;
+ idbuf.ino = stbuf.st_ino;
+ val.mv_data = &idbuf;
+ val.mv_size = sizeof(idbuf);
+ mdb_hash_enc(&val, encbuf);
+#ifdef MDB_SHORT_SEMNAMES
+ encbuf[9] = '\0'; /* drop name from 15 chars to 14 chars */
+#endif
+ sprintf(env->me_txns->mti_rmname, "/MDBr%s", encbuf);
+ sprintf(env->me_txns->mti_wmname, "/MDBw%s", encbuf);
+ /* Clean up after a previous run, if needed: Try to
+ * remove both semaphores before doing anything else.
+ */
+ sem_unlink(env->me_txns->mti_rmname);
+ sem_unlink(env->me_txns->mti_wmname);
+ env->me_rmutex = sem_open(env->me_txns->mti_rmname,
+ O_CREAT|O_EXCL, mode, 1);
+ if (env->me_rmutex == SEM_FAILED) goto fail_errno;
+ env->me_wmutex = sem_open(env->me_txns->mti_wmname,
+ O_CREAT|O_EXCL, mode, 1);
+ if (env->me_wmutex == SEM_FAILED) goto fail_errno;
+#else /* MDB_USE_POSIX_SEM */
pthread_mutexattr_t mattr;
if ((rc = pthread_mutexattr_init(&mattr))
|| (rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))
-#ifdef MDB_ROBUST_SUPPORTED
- || (rc = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST))
-#endif
- || (rc = pthread_mutex_init(&env->me_txns->mti_rmutex, &mattr))
+ || (rc = pthread_mutex_init(&env->me_txns->mti_mutex, &mattr))
|| (rc = pthread_mutex_init(&env->me_txns->mti_wmutex, &mattr)))
goto fail;
pthread_mutexattr_destroy(&mattr);
-#endif /* _WIN32 || MDB_USE_SYSV_SEM */
+#endif /* _WIN32 || MDB_USE_POSIX_SEM */
env->me_txns->mti_magic = MDB_MAGIC;
env->me_txns->mti_format = MDB_LOCK_FORMAT;
@@ -4544,9 +4471,6 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
env->me_txns->mti_numreaders = 0;
} else {
-#ifdef MDB_USE_SYSV_SEM
- struct semid_ds buf;
-#endif
if (env->me_txns->mti_magic != MDB_MAGIC) {
DPUTS("lock region has invalid magic");
rc = MDB_INVALID;
@@ -4567,26 +4491,13 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
if (!env->me_rmutex) goto fail_errno;
env->me_wmutex = OpenMutex(SYNCHRONIZE, FALSE, env->me_txns->mti_wmname);
if (!env->me_wmutex) goto fail_errno;
-#elif defined(MDB_USE_SYSV_SEM)
- semid = env->me_txns->mti_semid;
- semu.buf = &buf;
- /* check for read access */
- if (semctl(semid, 0, IPC_STAT, semu) < 0)
- goto fail_errno;
- /* check for write access */
- if (semctl(semid, 0, IPC_SET, semu) < 0)
- goto fail_errno;
+#elif defined(MDB_USE_POSIX_SEM)
+ env->me_rmutex = sem_open(env->me_txns->mti_rmname, 0);
+ if (env->me_rmutex == SEM_FAILED) goto fail_errno;
+ env->me_wmutex = sem_open(env->me_txns->mti_wmname, 0);
+ if (env->me_wmutex == SEM_FAILED) goto fail_errno;
#endif
}
-#ifdef MDB_USE_SYSV_SEM
- env->me_rmutex.semid = semid;
- env->me_wmutex.semid = semid;
- env->me_rmutex.semnum = 0;
- env->me_wmutex.semnum = 1;
- env->me_rmutex.locked = &env->me_txns->mti_rlocked;
- env->me_wmutex.locked = &env->me_txns->mti_wlocked;
-#endif
-
return MDB_SUCCESS;
fail_errno:
@@ -4606,8 +4517,8 @@ fail:
* environment and re-opening it with the new flags.
*/
#define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT)
-#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \
- MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD)
+#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY|MDB_WRITEMAP| \
+ MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD)
#if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS)
# error "Persistent DB flags & env flags overlap, but both go in mm_flags"
@@ -4682,10 +4593,6 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
mode = FILE_ATTRIBUTE_NORMAL;
env->me_fd = CreateFile(dpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, len, mode, NULL);
- DWORD actual;
- if (!DeviceIoControl(env->me_fd, FSCTL_SET_SPARSE, NULL, 0,
- NULL, 0, &actual, NULL))
- ; // If the file is not sparsed, it will allocate the full environment
#else
if (F_ISSET(flags, MDB_RDONLY))
oflags = O_RDONLY;
@@ -4810,12 +4717,8 @@ mdb_env_close0(MDB_env *env, int excl)
MDB_PID_T pid = env->me_pid;
/* Clearing readers is done in this function because
* me_txkey with its destructor must be disabled first.
- *
- * We skip the the reader mutex, so we touch only
- * data owned by this process (me_close_readers and
- * our readers), and clear each reader atomically.
*/
- for (i = env->me_close_readers; --i >= 0; )
+ for (i = env->me_numreaders; --i >= 0; )
if (env->me_txns->mti_readers[i].mr_pid == pid)
env->me_txns->mti_readers[i].mr_pid = 0;
#ifdef _WIN32
@@ -4826,15 +4729,20 @@ mdb_env_close0(MDB_env *env, int excl)
/* Windows automatically destroys the mutexes when
* the last handle closes.
*/
-#elif defined(MDB_USE_SYSV_SEM)
- if (env->me_rmutex.semid != -1) {
+#elif defined(MDB_USE_POSIX_SEM)
+ if (env->me_rmutex != SEM_FAILED) {
+ sem_close(env->me_rmutex);
+ if (env->me_wmutex != SEM_FAILED)
+ sem_close(env->me_wmutex);
/* If we have the filelock: If we are the
* only remaining user, clean up semaphores.
*/
if (excl == 0)
mdb_env_excl_lock(env, &excl);
- if (excl > 0)
- semctl(env->me_rmutex.semid, 0, IPC_RMID);
+ if (excl > 0) {
+ sem_unlink(env->me_txns->mti_rmname);
+ sem_unlink(env->me_txns->mti_wmname);
+ }
}
#endif
munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo));
@@ -4854,6 +4762,7 @@ mdb_env_close0(MDB_env *env, int excl)
env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY);
}
+
void ESECT
mdb_env_close(MDB_env *env)
{
@@ -4881,7 +4790,11 @@ mdb_cmp_long(const MDB_val *a, const MDB_val *b)
*(size_t *)a->mv_data > *(size_t *)b->mv_data;
}
-/** Compare two items pointing at aligned unsigned int's */
+/** Compare two items pointing at aligned unsigned int's.
+ *
+ * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp,
+ * but #mdb_cmp_clong() is called instead if the data type is size_t.
+ */
static int
mdb_cmp_int(const MDB_val *a, const MDB_val *b)
{
@@ -4919,13 +4832,6 @@ mdb_cmp_cint(const MDB_val *a, const MDB_val *b)
#endif
}
-/** Compare two items pointing at size_t's of unknown alignment. */
-#ifdef MISALIGNED_OK
-# define mdb_cmp_clong mdb_cmp_long
-#else
-# define mdb_cmp_clong mdb_cmp_cint
-#endif
-
/** Compare two items lexically */
static int
mdb_cmp_memn(const MDB_val *a, const MDB_val *b)
@@ -5311,6 +5217,8 @@ mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags)
&mc->mc_dbx->md_name, &exact);
if (!exact)
return MDB_NOTFOUND;
+ if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
+ return MDB_INCOMPATIBLE; /* not a named DB */
rc = mdb_node_read(mc->mc_txn, leaf, &data);
if (rc)
return rc;
@@ -5822,8 +5730,10 @@ set2:
if (leaf == NULL) {
DPUTS("===> inexact leaf not found, goto sibling");
- if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS)
+ if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) {
+ mc->mc_flags |= C_EOF;
return rc; /* no entries matched */
+ }
mp = mc->mc_pg[mc->mc_top];
mdb_cassert(mc, IS_LEAF(mp));
leaf = NODEPTR(mp, 0);
@@ -5861,15 +5771,21 @@ set1:
return rc;
}
} else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) {
- MDB_val d2;
- if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS)
+ MDB_val olddata;
+ MDB_cmp_func *dcmp;
+ if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS)
return rc;
- rc = mc->mc_dbx->md_dcmp(data, &d2);
+ dcmp = mc->mc_dbx->md_dcmp;
+#if UINT_MAX < SIZE_MAX
+ if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
+#endif
+ rc = dcmp(data, &olddata);
if (rc) {
if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND;
rc = 0;
- *data = d2;
+ *data = olddata;
}
} else {
@@ -6188,6 +6104,7 @@ int
mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
unsigned int flags)
{
+ enum { MDB_NO_ROOT = MDB_LAST_ERRCODE+10 }; /* internal code */
MDB_env *env;
MDB_node *leaf = NULL;
MDB_page *fp, *mp;
@@ -6378,16 +6295,17 @@ more:
/* Was a single item before, must convert now */
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ MDB_cmp_func *dcmp;
/* Just overwrite the current item */
if (flags == MDB_CURRENT)
goto current;
-
+ dcmp = mc->mc_dbx->md_dcmp;
#if UINT_MAX < SIZE_MAX
- if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
- mc->mc_dbx->md_dcmp = mdb_cmp_clong;
+ if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
+ dcmp = mdb_cmp_clong;
#endif
/* does data match? */
- if (!mc->mc_dbx->md_dcmp(data, &olddata)) {
+ if (!dcmp(data, &olddata)) {
if (flags & MDB_NODUPDATA)
return MDB_KEYEXIST;
/* overwrite it */
@@ -6493,6 +6411,9 @@ prep_subDB:
goto new_sub;
}
current:
+ /* LMDB passes F_SUBDATA in 'flags' to write a DB record */
+ if ((leaf->mn_flags ^ flags) & F_SUBDATA)
+ return MDB_INCOMPATIBLE;
/* overflow page overwrites need special handling */
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
MDB_page *omp;
@@ -6763,6 +6684,11 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
goto fail;
}
}
+ /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */
+ else if ((leaf->mn_flags ^ flags) & F_SUBDATA) {
+ rc = MDB_INCOMPATIBLE;
+ goto fail;
+ }
/* add overflow pages to free list */
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
@@ -7207,6 +7133,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
mc->mc_snum = 0;
mc->mc_top = 0;
mc->mc_pg[0] = 0;
+ mc->mc_ki[0] = 0;
mc->mc_flags = 0;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
mdb_tassert(txn, mx != NULL);
@@ -7836,12 +7763,12 @@ mdb_rebalance(MDB_cursor *mc)
m3 = m2;
if (m3 == mc || m3->mc_snum < mc->mc_snum) continue;
if (m3->mc_pg[0] == mp) {
- m3->mc_snum--;
- m3->mc_top--;
for (i=0; imc_snum; i++) {
m3->mc_pg[i] = m3->mc_pg[i+1];
m3->mc_ki[i] = m3->mc_ki[i+1];
}
+ m3->mc_snum--;
+ m3->mc_top--;
}
}
}
@@ -7909,9 +7836,23 @@ mdb_rebalance(MDB_cursor *mc)
if (mc->mc_ki[ptop] == 0) {
rc = mdb_page_merge(&mn, mc);
} else {
+ MDB_cursor dummy;
oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1;
+ /* We want mdb_rebalance to find mn when doing fixups */
+ if (mc->mc_flags & C_SUB) {
+ dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi];
+ mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy;
+ dummy.mc_xcursor = (MDB_xcursor *)&mn;
+ } else {
+ mn.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi];
+ mc->mc_txn->mt_cursors[mc->mc_dbi] = &mn;
+ }
rc = mdb_page_merge(mc, &mn);
+ if (mc->mc_flags & C_SUB)
+ mc->mc_txn->mt_cursors[mc->mc_dbi] = dummy.mc_next;
+ else
+ mc->mc_txn->mt_cursors[mc->mc_dbi] = mn.mc_next;
mdb_cursor_copy(&mn, mc);
}
mc->mc_flags &= ~C_EOF;
@@ -7938,6 +7879,13 @@ mdb_cursor_del0(MDB_cursor *mc)
MDB_cursor *m2, *m3;
MDB_dbi dbi = mc->mc_dbi;
+ /* DB is totally empty now, just bail out.
+ * Other cursors adjustments were already done
+ * by mdb_rebalance and aren't needed here.
+ */
+ if (!mc->mc_snum)
+ return rc;
+
mp = mc->mc_pg[mc->mc_top];
nkeys = NUMKEYS(mp);
@@ -8846,7 +8794,6 @@ static int ESECT
mdb_env_copyfd0(MDB_env *env, HANDLE fd)
{
MDB_txn *txn = NULL;
- mdb_mutex_t *wmutex = NULL;
int rc;
size_t wsize;
char *ptr;
@@ -8871,13 +8818,11 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd)
mdb_txn_reset0(txn, "reset-stage1");
/* Temporarily block writers until we snapshot the meta pages */
- wmutex = MDB_MUTEX(env, w);
- if (LOCK_MUTEX(rc, env, wmutex))
- goto leave;
+ LOCK_MUTEX_W(env);
rc = mdb_txn_renew0(txn);
if (rc) {
- UNLOCK_MUTEX(wmutex);
+ UNLOCK_MUTEX_W(env);
goto leave;
}
}
@@ -8901,8 +8846,8 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd)
break;
}
}
- if (wmutex)
- UNLOCK_MUTEX(wmutex);
+ if (env->me_txns)
+ UNLOCK_MUTEX_W(env);
if (rc)
goto leave;
@@ -9134,7 +9079,11 @@ mdb_env_info(MDB_env *env, MDB_envinfo *arg)
arg->me_mapaddr = env->me_metas[toggle]->mm_address;
arg->me_mapsize = env->me_mapsize;
arg->me_maxreaders = env->me_maxreaders;
- arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : 0;
+
+ /* me_numreaders may be zero if this process never used any readers. Use
+ * the shared numreader count if it exists.
+ */
+ arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : env->me_numreaders;
arg->me_last_pgno = env->me_metas[toggle]->mm_last_pg;
arg->me_last_txnid = env->me_metas[toggle]->mm_txnid;
@@ -9235,7 +9184,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db
if (rc == MDB_SUCCESS) {
/* make sure this is actually a DB */
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
- if (!(node->mn_flags & F_SUBDATA))
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
return MDB_INCOMPATIBLE;
} else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
/* Create if requested */
@@ -9428,7 +9377,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
/* Can't delete the main DB */
if (del && dbi > MAIN_DBI) {
- rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, 0);
+ rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
if (!rc) {
txn->mt_dbflags[dbi] = DB_STALE;
mdb_dbi_close(txn->mt_env, dbi);
@@ -9575,22 +9524,17 @@ mdb_pid_insert(MDB_PID_T *ids, MDB_PID_T pid)
int ESECT
mdb_reader_check(MDB_env *env, int *dead)
{
+ unsigned int i, j, rdrs;
+ MDB_reader *mr;
+ MDB_PID_T *pids, pid;
+ int count = 0;
+
if (!env)
return EINVAL;
if (dead)
*dead = 0;
- return env->me_txns ? mdb_reader_check0(env, 0, dead) : MDB_SUCCESS;
-}
-
-/** As #mdb_reader_check(). rlocked = . */
-static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead)
-{
- mdb_mutex_t *rmutex = rlocked ? NULL : MDB_MUTEX(env, r);
- unsigned int i, j, rdrs;
- MDB_reader *mr;
- MDB_PID_T *pids, pid;
- int rc = MDB_SUCCESS, count = 0;
-
+ if (!env->me_txns)
+ return MDB_SUCCESS;
rdrs = env->me_txns->mti_numreaders;
pids = malloc((rdrs+1) * sizeof(MDB_PID_T));
if (!pids)
@@ -9598,32 +9542,22 @@ static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead)
pids[0] = 0;
mr = env->me_txns->mti_readers;
for (i=0; ime_pid) {
+ if (mr[i].mr_pid && mr[i].mr_pid != env->me_pid) {
+ pid = mr[i].mr_pid;
if (mdb_pid_insert(pids, pid) == 0) {
if (!mdb_reader_pid(env, Pidcheck, pid)) {
- /* Stale reader found */
- j = i;
- if (rmutex) {
- if ((rc = LOCK_MUTEX0(rmutex)) != 0) {
- if ((rc = mdb_mutex_failed(env, rmutex, rc)))
- break;
- rdrs = 0; /* the above checked all readers */
- } else {
- /* Recheck, a new process may have reused pid */
- if (mdb_reader_pid(env, Pidcheck, pid))
- j = rdrs;
- }
- }
- for (; jme_txns->mti_txnid = env->me_metas[toggle]->mm_txnid;
- /* env is hosed if the dead thread was ours */
- if (env->me_txn) {
- env->me_flags |= MDB_FATAL_ERROR;
- env->me_txn = NULL;
- rc = MDB_PANIC;
- }
- }
- DPRINTF(("%cmutex owner died, %s", (rlocked ? 'r' : 'w'),
- (rc ? "this process' env is hosed" : "recovering")));
- rc2 = mdb_reader_check0(env, rlocked, NULL);
- if (rc2 == 0)
- rc2 = mdb_mutex_consistent(mutex);
- if (rc || (rc = rc2)) {
- DPRINTF(("LOCK_MUTEX recovery failed, %s", mdb_strerror(rc)));
- UNLOCK_MUTEX(mutex);
- }
- } else {
-#ifdef _WIN32
- rc = ErrCode();
-#endif
- DPRINTF(("LOCK_MUTEX failed, %s", mdb_strerror(rc)));
- }
-
- return rc;
-}
-#endif /* MDB_ROBUST_SUPPORTED */
/** @} */
diff --git a/liblmdb/mdb_copy.1 b/liblmdb/mdb_copy.1
index 094b2605..1e2a9769 100644
--- a/liblmdb/mdb_copy.1
+++ b/liblmdb/mdb_copy.1
@@ -1,5 +1,5 @@
.TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14"
-.\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved.
+.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
mdb_copy \- LMDB environment copy tool
diff --git a/liblmdb/mdb_copy.c b/liblmdb/mdb_copy.c
index af0a9411..f37ccbcc 100644
--- a/liblmdb/mdb_copy.c
+++ b/liblmdb/mdb_copy.c
@@ -1,6 +1,6 @@
/* mdb_copy.c - memory-mapped database backup tool */
/*
- * Copyright 2012 Howard Chu, Symas Corp.
+ * Copyright 2012-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/liblmdb/mdb_dump.1 b/liblmdb/mdb_dump.1
index 6fcc9308..dd545049 100644
--- a/liblmdb/mdb_dump.1
+++ b/liblmdb/mdb_dump.1
@@ -1,5 +1,5 @@
.TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14"
-.\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved.
+.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
mdb_dump \- LMDB environment export tool
diff --git a/liblmdb/mdb_dump.c b/liblmdb/mdb_dump.c
index 0eb85fd2..7202d865 100644
--- a/liblmdb/mdb_dump.c
+++ b/liblmdb/mdb_dump.c
@@ -1,6 +1,6 @@
/* mdb_dump.c - memory-mapped database dump tool */
/*
- * Copyright 2011-2014 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/liblmdb/mdb_load.1 b/liblmdb/mdb_load.1
index 72802401..511ec552 100644
--- a/liblmdb/mdb_load.1
+++ b/liblmdb/mdb_load.1
@@ -1,5 +1,5 @@
.TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14"
-.\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved.
+.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
mdb_load \- LMDB environment import tool
diff --git a/liblmdb/mdb_load.c b/liblmdb/mdb_load.c
index e0d95e13..1f6ce0b7 100644
--- a/liblmdb/mdb_load.c
+++ b/liblmdb/mdb_load.c
@@ -1,6 +1,6 @@
/* mdb_load.c - memory-mapped database load tool */
/*
- * Copyright 2011-2014 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -176,7 +176,7 @@ static int unhex(unsigned char *c2)
static int readline(MDB_val *out, MDB_val *buf)
{
unsigned char *c1, *c2, *end;
- size_t len;
+ size_t len, l2;
int c;
if (!(mode & NOHDR)) {
@@ -206,6 +206,7 @@ badend:
c1 = buf->mv_data;
len = strlen((char *)c1);
+ l2 = len;
/* Is buffer too short? */
while (c1[len-1] != '\n') {
@@ -217,17 +218,18 @@ badend:
return EOF;
}
c1 = buf->mv_data;
- c1 += buf->mv_size;
- if (fgets((char *)c1, buf->mv_size, stdin) == NULL) {
+ c1 += l2;
+ if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) {
Eof = 1;
badend();
return EOF;
}
buf->mv_size *= 2;
len = strlen((char *)c1);
+ l2 += len;
}
c1 = c2 = buf->mv_data;
- len = strlen((char *)c1);
+ len = l2;
c1[--len] = '\0';
end = c1 + len;
diff --git a/liblmdb/mdb_stat.1 b/liblmdb/mdb_stat.1
index 3d8d461d..e6ee5ad5 100644
--- a/liblmdb/mdb_stat.1
+++ b/liblmdb/mdb_stat.1
@@ -1,5 +1,5 @@
.TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14"
-.\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved.
+.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME
mdb_stat \- LMDB environment status tool
diff --git a/liblmdb/mdb_stat.c b/liblmdb/mdb_stat.c
index 1e922929..210609b3 100644
--- a/liblmdb/mdb_stat.c
+++ b/liblmdb/mdb_stat.c
@@ -1,6 +1,6 @@
/* mdb_stat.c - memory-mapped database status tool */
/*
- * Copyright 2011-2013 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/liblmdb/midl.c b/liblmdb/midl.c
index 88a3aff1..57a9d492 100644
--- a/liblmdb/midl.c
+++ b/liblmdb/midl.c
@@ -3,7 +3,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
- * Copyright 2000-2014 The OpenLDAP Foundation.
+ * Copyright 2000-2015 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,7 +116,7 @@ void mdb_midl_free(MDB_IDL ids)
free(ids-1);
}
-int mdb_midl_shrink( MDB_IDL *idp )
+void mdb_midl_shrink( MDB_IDL *idp )
{
MDB_IDL ids = *idp;
if (*(--ids) > MDB_IDL_UM_MAX &&
@@ -124,9 +124,7 @@ int mdb_midl_shrink( MDB_IDL *idp )
{
*ids++ = MDB_IDL_UM_MAX;
*idp = ids;
- return 1;
}
- return 0;
}
static int mdb_midl_grow( MDB_IDL *idp, int num )
diff --git a/liblmdb/midl.h b/liblmdb/midl.h
index a7f25026..2331e783 100644
--- a/liblmdb/midl.h
+++ b/liblmdb/midl.h
@@ -11,7 +11,7 @@
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
- * Copyright 2000-2014 The OpenLDAP Foundation.
+ * Copyright 2000-2015 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -98,9 +98,8 @@ void mdb_midl_free(MDB_IDL ids);
/** Shrink an IDL.
* Return the IDL to the default size if it has grown larger.
* @param[in,out] idp Address of the IDL to shrink.
- * @return 0 on no change, non-zero if shrunk.
*/
-int mdb_midl_shrink(MDB_IDL *idp);
+void mdb_midl_shrink(MDB_IDL *idp);
/** Make room for num additional elements in an IDL.
* @param[in,out] idp Address of the IDL.
diff --git a/liblmdb/mtest.c b/liblmdb/mtest.c
index 79b4175e..9d15088b 100644
--- a/liblmdb/mtest.c
+++ b/liblmdb/mtest.c
@@ -1,6 +1,6 @@
/* mtest.c - memory-mapped database tester/toy */
/*
- * Copyright 2011-2014 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,19 +45,22 @@ int main(int argc,char * argv[])
}
E(mdb_env_create(&env));
+ E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
+
E(mdb_txn_begin(env, NULL, 0, &txn));
- E(mdb_open(txn, NULL, 0, &dbi));
+ E(mdb_dbi_open(txn, NULL, 0, &dbi));
key.mv_size = sizeof(int);
key.mv_data = sval;
- data.mv_size = sizeof(sval);
- data.mv_data = sval;
printf("Adding %d values\n", count);
for (i=0;i in each iteration, since MDB_NOOVERWRITE may modify it */
+ data.mv_size = sizeof(sval);
+ data.mv_data = sval;
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
j++;
data.mv_size = sizeof(sval);
@@ -68,7 +71,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst));
- E(mdb_txn_begin(env, NULL, 1, &txn));
+ E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n",
@@ -97,7 +100,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst));
- E(mdb_txn_begin(env, NULL, 1, &txn));
+ E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@@ -128,6 +131,7 @@ int main(int argc,char * argv[])
(int) key.mv_size, (char *) key.mv_data,
(int) data.mv_size, (char *) data.mv_data);
+ mdb_cursor_close(cursor);
mdb_txn_abort(txn);
printf("Deleting with cursor\n");
@@ -164,9 +168,9 @@ int main(int argc,char * argv[])
data.mv_data, (int) data.mv_size, (char *) data.mv_data);
}
mdb_cursor_close(cursor);
- mdb_close(env, dbi);
-
mdb_txn_abort(txn);
+
+ mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0;
diff --git a/liblmdb/mtest2.c b/liblmdb/mtest2.c
index f1a3dbd6..eacbe59d 100644
--- a/liblmdb/mtest2.c
+++ b/liblmdb/mtest2.c
@@ -1,6 +1,6 @@
/* mtest2.c - memory-mapped database tester/toy */
/*
- * Copyright 2011-2014 Howard Chu, Symas Corp.
+ * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,20 +47,22 @@ int main(int argc,char * argv[])
}
E(mdb_env_create(&env));
+ E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+
E(mdb_txn_begin(env, NULL, 0, &txn));
- E(mdb_open(txn, "id1", MDB_CREATE, &dbi));
+ E(mdb_dbi_open(txn, "id1", MDB_CREATE, &dbi));
key.mv_size = sizeof(int);
key.mv_data = sval;
- data.mv_size = sizeof(sval);
- data.mv_data = sval;
printf("Adding %d values\n", count);
for (i=0;i