Merge pull request #339

54c785d fixed ARM arch test to prevent breaking on short arch strings (Riccardo Spagni)
a4254a4 updated vl32 to current (Riccardo Spagni)
e6ab2df updated in-source lmdb (Riccardo Spagni)
ea08c76 open() flag O_DSYNC isn't on BSD, use O_SYNC (Thomas Winget)
This commit is contained in:
Riccardo Spagni 2015-07-16 12:48:55 +02:00
commit dc624849bf
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
36 changed files with 586 additions and 295 deletions

View file

@ -46,20 +46,25 @@ function (die msg)
endfunction () endfunction ()
if (NOT ${ARCH} STREQUAL "") if (NOT ${ARCH} STREQUAL "")
string(SUBSTRING ${ARCH} 0 5 ARM_TEST) string(SUBSTRING ${ARCH} 0 3 IS_ARM)
string(TOLOWER ${ARM_TEST} ARM_TEST) string(TOLOWER ${IS_ARM} IS_ARM)
if (${IS_ARM} STREQUAL "arm")
string(SUBSTRING ${ARCH} 0 5 ARM_TEST)
string(TOLOWER ${ARM_TEST} ARM_TEST)
if (${ARM_TEST} STREQUAL "armv6") if (${ARM_TEST} STREQUAL "armv6")
set(ARM6 1) set(ARM6 1)
else() else()
set(ARM6 0) set(ARM6 0)
endif() endif()
if (${ARM_TEST} STREQUAL "armv7") if (${ARM_TEST} STREQUAL "armv7")
set(ARM7 1) set(ARM7 1)
else() else()
set(ARM7 0) set(ARM7 0)
endif() endif()
endif()
endif() endif()
if(WIN32 OR ARM7 OR ARM6) if(WIN32 OR ARM7 OR ARM6)

View file

@ -1,5 +1,33 @@
LMDB 0.9 Change Log LMDB 0.9 Change Log
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) LMDB 0.9.14 Release (2014/09/20)
Fix to support 64K page size (ITS#7713) Fix to support 64K page size (ITS#7713)
Fix to persist decreased as well as increased mapsizes (ITS#7789) Fix to persist decreased as well as increased mapsizes (ITS#7789)

View file

@ -26,6 +26,13 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if(FREEBSD)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMDB_DSYNC=O_SYNC")
endif()
# pass the VL32 flag so that we actually invoke the VL32 extensions
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVL32")
set (lmdb_sources set (lmdb_sources
mdb.c mdb.c
midl.c) midl.c)

View file

@ -1,4 +1,4 @@
Copyright 2011-2014 Howard Chu, Symas Corp. Copyright 2011-2015 Howard Chu, Symas Corp.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View file

@ -11,6 +11,7 @@
# - MDB_USE_POSIX_SEM # - MDB_USE_POSIX_SEM
# - MDB_DSYNC # - MDB_DSYNC
# - MDB_FDATASYNC # - MDB_FDATASYNC
# - MDB_FDATASYNC_WORKS
# - MDB_USE_PWRITEV # - MDB_USE_PWRITEV
# #
# There may be other macros in mdb.c of interest. You should # There may be other macros in mdb.c of interest. You should
@ -42,18 +43,18 @@ install: $(ILIBS) $(IPROGS) $(IHDRS)
for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done
clean: clean:
rm -rf $(PROGS) *.[ao] *.so *~ testdb rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb
test: all test: all
mkdir testdb rm -rf testdb && mkdir testdb
./mtest && ./mdb_stat testdb ./mtest && ./mdb_stat testdb
liblmdb.a: mdb.o midl.o liblmdb.a: mdb.o midl.o
ar rs $@ mdb.o midl.o ar rs $@ mdb.o midl.o
liblmdb.so: mdb.o midl.o liblmdb.so: mdb.lo midl.lo
# $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) # $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS)
$(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.o midl.o $(SOLIBS) $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS)
mdb_stat: mdb_stat.o liblmdb.a mdb_stat: mdb_stat.o liblmdb.a
mdb_copy: mdb_copy.o liblmdb.a mdb_copy: mdb_copy.o liblmdb.a
@ -67,10 +68,16 @@ mtest5: mtest5.o liblmdb.a
mtest6: mtest6.o liblmdb.a mtest6: mtest6.o liblmdb.a
mdb.o: mdb.c lmdb.h midl.h mdb.o: mdb.c lmdb.h midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c $(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c
midl.o: midl.c midl.h midl.o: midl.c midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c $(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c
mdb.lo: mdb.c lmdb.h midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@
midl.lo: midl.c midl.h
$(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@
%: %.o %: %.o
$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@

View file

@ -119,7 +119,7 @@
* *
* @author Howard Chu, Symas Corporation. * @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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP * modification, are permitted only as authorized by the OpenLDAP
@ -184,7 +184,7 @@ typedef int mdb_filehandle_t;
/** Library minor version */ /** Library minor version */
#define MDB_VERSION_MINOR 9 #define MDB_VERSION_MINOR 9
/** Library patch version */ /** Library patch version */
#define MDB_VERSION_PATCH 14 #define MDB_VERSION_PATCH 15
/** Combine args a,b,c into a single integer for easy version comparisons */ /** Combine args a,b,c into a single integer for easy version comparisons */
#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
@ -194,7 +194,7 @@ typedef int mdb_filehandle_t;
MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
/** The release date of this library version */ /** The release date of this library version */
#define MDB_VERSION_DATE "September 20, 2014" #define MDB_VERSION_DATE "June 19, 2015"
/** A stringifier for the version info */ /** A stringifier for the version info */
#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
@ -296,12 +296,12 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
#define MDB_REVERSEKEY 0x02 #define MDB_REVERSEKEY 0x02
/** use sorted duplicates */ /** use sorted duplicates */
#define MDB_DUPSORT 0x04 #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. */ * The keys must all be of the same size. */
#define MDB_INTEGERKEY 0x08 #define MDB_INTEGERKEY 0x08
/** with #MDB_DUPSORT, sorted dup items have fixed size */ /** with #MDB_DUPSORT, sorted dup items have fixed size */
#define MDB_DUPFIXED 0x10 #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 #define MDB_INTEGERDUP 0x20
/** with #MDB_DUPSORT, use reverse string dups */ /** with #MDB_DUPSORT, use reverse string dups */
#define MDB_REVERSEDUP 0x40 #define MDB_REVERSEDUP 0x40
@ -516,8 +516,8 @@ int mdb_env_create(MDB_env **env);
* and uses fewer mallocs, but loses protection from application bugs * and uses fewer mallocs, but loses protection from application bugs
* like wild pointer writes and other bad updates into the database. * like wild pointer writes and other bad updates into the database.
* Incompatible with nested transactions. * Incompatible with nested transactions.
* Processes with and without MDB_WRITEMAP on the same environment do * Do not mix processes with and without MDB_WRITEMAP on the same
* not cooperate well. * environment. This can defeat durability (#mdb_env_sync etc).
* <li>#MDB_NOMETASYNC * <li>#MDB_NOMETASYNC
* Flush system buffers to disk only once per transaction, omit the * Flush system buffers to disk only once per transaction, omit the
* metadata flush. Defer that until the system flushes files to disk, * metadata flush. Defer that until the system flushes files to disk,
@ -588,8 +588,8 @@ int mdb_env_create(MDB_env **env);
* reserved in that case. * reserved in that case.
* This flag may be changed at any time using #mdb_env_set_flags(). * This flag may be changed at any time using #mdb_env_set_flags().
* </ul> * </ul>
* @param[in] mode The UNIX permissions to set on created files. This parameter * @param[in] mode The UNIX permissions to set on created files and semaphores.
* is ignored on Windows. * This parameter is ignored on Windows.
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
* errors are: * errors are:
* <ul> * <ul>
@ -698,7 +698,8 @@ int mdb_env_info(MDB_env *env, MDB_envinfo *stat);
* Data is always written to disk when #mdb_txn_commit() is called, * Data is always written to disk when #mdb_txn_commit() is called,
* but the operating system may keep it buffered. LMDB always flushes * but the operating system may keep it buffered. LMDB always flushes
* the OS buffers upon commit as well, unless the environment was * the OS buffers upon commit as well, unless the environment was
* opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. This call is
* not valid if the environment was opened with #MDB_RDONLY.
* @param[in] env An environment handle returned by #mdb_env_create() * @param[in] env An environment handle returned by #mdb_env_create()
* @param[in] force If non-zero, force a synchronous flush. Otherwise * @param[in] force If non-zero, force a synchronous flush. Otherwise
* if the environment has the #MDB_NOSYNC flag set the flushes * if the environment has the #MDB_NOSYNC flag set the flushes
@ -706,6 +707,7 @@ int mdb_env_info(MDB_env *env, MDB_envinfo *stat);
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
* errors are: * errors are:
* <ul> * <ul>
* <li>EACCES - the environment is read-only.
* <li>EINVAL - an invalid parameter was specified. * <li>EINVAL - an invalid parameter was specified.
* <li>EIO - an error occurred during synchronization. * <li>EIO - an error occurred during synchronization.
* </ul> * </ul>
@ -1019,15 +1021,17 @@ int mdb_txn_renew(MDB_txn *txn);
* The database handle may be discarded by calling #mdb_dbi_close(). * The database handle may be discarded by calling #mdb_dbi_close().
* The old database handle is returned if the database was already open. * The old database handle is returned if the database was already open.
* The handle may only be closed once. * The handle may only be closed once.
*
* The database handle will be private to the current transaction until * The database handle will be private to the current transaction until
* the transaction is successfully committed. If the transaction is * the transaction is successfully committed. If the transaction is
* aborted the handle will be closed automatically. * aborted the handle will be closed automatically.
* After a successful commit the * After a successful commit the handle will reside in the shared
* handle will reside in the shared environment, and may be used * environment, and may be used by other transactions.
* by other transactions. This function must not be called from *
* multiple concurrent transactions. A transaction that uses this function * This function must not be called from multiple concurrent
* must finish (either commit or abort) before any other transaction may * transactions in the same process. A transaction that uses
* use this function. * 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() * To use named databases (with name != NULL), #mdb_env_set_maxdbs()
* must be called before opening the environment. Database names * must be called before opening the environment. Database names
@ -1048,9 +1052,9 @@ int mdb_txn_renew(MDB_txn *txn);
* keys may have multiple data items, stored in sorted order.) By default * keys may have multiple data items, stored in sorted order.) By default
* keys must be unique and may have only a single data item. * keys must be unique and may have only a single data item.
* <li>#MDB_INTEGERKEY * <li>#MDB_INTEGERKEY
* Keys are binary integers in native byte order. Setting this option * Keys are binary integers in native byte order, either unsigned int
* requires all keys to be the same size, typically sizeof(int) * or size_t, and will be sorted as such.
* or sizeof(size_t). * The keys must all be of the same size.
* <li>#MDB_DUPFIXED * <li>#MDB_DUPFIXED
* This flag may only be used in combination with #MDB_DUPSORT. This option * 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 * tells the library that the data items for this database are all the same
@ -1058,8 +1062,8 @@ int mdb_txn_renew(MDB_txn *txn);
* all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE * 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. * cursor operations may be used to retrieve multiple items at once.
* <li>#MDB_INTEGERDUP * <li>#MDB_INTEGERDUP
* This option specifies that duplicate data items are also integers, and * This option specifies that duplicate data items are binary integers,
* should be sorted as such. * similar to #MDB_INTEGERKEY keys.
* <li>#MDB_REVERSEDUP * <li>#MDB_REVERSEDUP
* This option specifies that duplicate data items should be compared as * This option specifies that duplicate data items should be compared as
* strings in reverse order. * strings in reverse order.
@ -1270,10 +1274,9 @@ int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
* LMDB does nothing else with this memory, the caller is expected * LMDB does nothing else with this memory, the caller is expected
* to modify all of the space requested. * to modify all of the space requested.
* <li>#MDB_APPEND - append the given key/data pair to the end of the * <li>#MDB_APPEND - append the given key/data pair to the end of the
* database. No key comparisons are performed. This option allows * database. This option allows fast bulk loading when keys are
* fast bulk loading when keys are already known to be in the * already known to be in the correct order. Loading unsorted keys
* correct order. Loading unsorted keys with this flag will cause * with this flag will cause a #MDB_KEYEXIST error.
* data corruption.
* <li>#MDB_APPENDDUP - as above, but for sorted dup data. * <li>#MDB_APPENDDUP - as above, but for sorted dup data.
* </ul> * </ul>
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
@ -1449,7 +1452,7 @@ int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
* <ul> * <ul>
* <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). * <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
* <li>#MDB_TXN_FULL - the transaction has too many dirty pages. * <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
* <li>EACCES - an attempt was made to modify a read-only database. * <li>EACCES - an attempt was made to write in a read-only transaction.
* <li>EINVAL - an invalid parameter was specified. * <li>EINVAL - an invalid parameter was specified.
* </ul> * </ul>
*/ */
@ -1469,7 +1472,7 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
* errors are: * errors are:
* <ul> * <ul>
* <li>EACCES - an attempt was made to modify a read-only database. * <li>EACCES - an attempt was made to write in a read-only transaction.
* <li>EINVAL - an invalid parameter was specified. * <li>EINVAL - an invalid parameter was specified.
* </ul> * </ul>
*/ */

View file

@ -5,7 +5,7 @@
* BerkeleyDB API, but much simplified. * BerkeleyDB API, but much simplified.
*/ */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -79,6 +79,14 @@ extern int cacheflush(char *addr, int nbytes, int cache);
#define CACHEFLUSH(addr, bytes, cache) #define CACHEFLUSH(addr, bytes, cache)
#endif #endif
#if defined(__linux) && !defined(MDB_FDATASYNC_WORKS)
/** fdatasync is broken on ext3/ext4fs on older kernels, see
* description in #mdb_env_open2 comments. You can safely
* define MDB_FDATASYNC_WORKS if this code will only be run
* on kernels 3.6 and newer.
*/
#define BROKEN_FDATASYNC
#endif
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -438,12 +446,17 @@ static txnid_t mdb_debug_start;
/** The version number for a database's lockfile format. */ /** The version number for a database's lockfile format. */
#define MDB_LOCK_VERSION 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 * This macro should normally be left alone or set to 0.
* is default for backwards compat: liblmdb <= 0.9.10 can break * Note that a database with big keys or dupsort data cannot be
* when modifying a DB with keys/dupsort data bigger than its max. * reliably modified by a liblmdb which uses a smaller max.
* #MDB_DEVEL sets the default to 0. * 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 * Data items in an #MDB_DUPSORT database are also limited to
* this size, since they're actually keys of a sub-DB. Keys and * this size, since they're actually keys of a sub-DB. Keys and
@ -580,11 +593,11 @@ typedef struct MDB_rxbody {
* started from so we can avoid overwriting any data used in that * started from so we can avoid overwriting any data used in that
* particular version. * particular version.
*/ */
txnid_t mrb_txnid; volatile txnid_t mrb_txnid;
/** The process ID of the process owning this reader txn. */ /** The process ID of the process owning this reader txn. */
MDB_PID_T mrb_pid; volatile MDB_PID_T mrb_pid;
/** The thread ID of the thread owning this txn. */ /** The thread ID of the thread owning this txn. */
MDB_THR_T mrb_tid; volatile MDB_THR_T mrb_tid;
} MDB_rxbody; } MDB_rxbody;
/** The actual reader record, with cacheline padding. */ /** The actual reader record, with cacheline padding. */
@ -632,12 +645,12 @@ typedef struct MDB_txbody {
* This is recorded here only for convenience; the value can always * This is recorded here only for convenience; the value can always
* be determined by reading the main database meta pages. * be determined by reading the main database meta pages.
*/ */
txnid_t mtb_txnid; volatile txnid_t mtb_txnid;
/** The number of slots that have been used in the reader table. /** The number of slots that have been used in the reader table.
* This always records the maximum count, it is not decremented * This always records the maximum count, it is not decremented
* when readers release their slots. * when readers release their slots.
*/ */
unsigned mtb_numreaders; volatile unsigned mtb_numreaders;
} MDB_txbody; } MDB_txbody;
/** The actual reader table definition. */ /** The actual reader table definition. */
@ -898,7 +911,7 @@ typedef struct MDB_meta {
/** Stamp identifying this as an LMDB file. It must be set /** Stamp identifying this as an LMDB file. It must be set
* to #MDB_MAGIC. */ * to #MDB_MAGIC. */
uint32_t mm_magic; uint32_t mm_magic;
/** Version number of this lock file. Must be set to #MDB_DATA_VERSION. */ /** Version number of this file. Must be set to #MDB_DATA_VERSION. */
uint32_t mm_version; uint32_t mm_version;
void *mm_address; /**< address for fixed mapping */ void *mm_address; /**< address for fixed mapping */
size_t mm_mapsize; /**< size of mmap region */ size_t mm_mapsize; /**< size of mmap region */
@ -908,7 +921,7 @@ typedef struct MDB_meta {
/** Any persistent environment flags. @ref mdb_env */ /** Any persistent environment flags. @ref mdb_env */
#define mm_flags mm_dbs[0].md_flags #define mm_flags mm_dbs[0].md_flags
pgno_t mm_last_pg; /**< last used page in file */ pgno_t mm_last_pg; /**< last used page in file */
txnid_t mm_txnid; /**< txnid that committed this page */ volatile txnid_t mm_txnid; /**< txnid that committed this page */
} MDB_meta; } MDB_meta;
/** Buffer for a stack-allocated meta page. /** Buffer for a stack-allocated meta page.
@ -991,7 +1004,7 @@ struct MDB_txn {
#ifdef VL32 #ifdef VL32
/** List of read-only pages */ /** List of read-only pages */
MDB_ID2L mt_rpages; MDB_ID2L mt_rpages;
#endif #endif
/** Number of DB records in use. This number only ever increments; /** Number of DB records in use. This number only ever increments;
* we don't decrement it when individual DB handles are closed. * we don't decrement it when individual DB handles are closed.
*/ */
@ -1103,6 +1116,8 @@ struct MDB_env {
#define MDB_ENV_ACTIVE 0x20000000U #define MDB_ENV_ACTIVE 0x20000000U
/** me_txkey is set */ /** me_txkey is set */
#define MDB_ENV_TXKEY 0x10000000U #define MDB_ENV_TXKEY 0x10000000U
/** fdatasync is unreliable */
#define MDB_FSYNCONLY 0x08000000U
uint32_t me_flags; /**< @ref mdb_env */ uint32_t me_flags; /**< @ref mdb_env */
unsigned int me_psize; /**< DB page size, inited from me_os_psize */ 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_os_psize; /**< OS page size, from #GET_PAGESIZE */
@ -1242,6 +1257,13 @@ static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long;
/** @endcond */ /** @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 #ifdef _WIN32
static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_DESCRIPTOR mdb_null_sd;
static SECURITY_ATTRIBUTES mdb_all_sa; static SECURITY_ATTRIBUTES mdb_all_sa;
@ -1323,7 +1345,7 @@ mdb_strerror(int err)
buf[0] = 0; buf[0] = 0;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, 0, ptr, sizeof(buf), pad); NULL, err, 0, ptr, sizeof(buf), (va_list *)pad);
return ptr; return ptr;
#else #else
return strerror(err); return strerror(err);
@ -1555,7 +1577,12 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
int int
mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) 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. /** Allocate memory for a page.
@ -2323,6 +2350,8 @@ int
mdb_env_sync(MDB_env *env, int force) mdb_env_sync(MDB_env *env, int force)
{ {
int rc = 0; int rc = 0;
if (env->me_flags & MDB_RDONLY)
return EACCES;
if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) {
if (env->me_flags & MDB_WRITEMAP) { if (env->me_flags & MDB_WRITEMAP) {
int flags = ((env->me_flags & MDB_MAPASYNC) && !force) int flags = ((env->me_flags & MDB_MAPASYNC) && !force)
@ -2334,6 +2363,12 @@ mdb_env_sync(MDB_env *env, int force)
rc = ErrCode(); rc = ErrCode();
#endif #endif
} else { } else {
#ifdef BROKEN_FDATASYNC
if (env->me_flags & MDB_FSYNCONLY) {
if (fsync(env->me_fd))
rc = ErrCode();
} else
#endif
if (MDB_FDATASYNC(env->me_fd)) if (MDB_FDATASYNC(env->me_fd))
rc = ErrCode(); rc = ErrCode();
} }
@ -2489,15 +2524,11 @@ mdb_txn_renew0(MDB_txn *txn)
MDB_env *env = txn->mt_env; MDB_env *env = txn->mt_env;
MDB_txninfo *ti = env->me_txns; MDB_txninfo *ti = env->me_txns;
MDB_meta *meta; MDB_meta *meta;
unsigned int i, nr; unsigned int i, nr, flags = txn->mt_flags;
uint16_t x; uint16_t x;
int rc, new_notls = 0; int rc, new_notls = 0;
/* Setup db info */ if ((flags &= MDB_TXN_RDONLY) != 0) {
txn->mt_numdbs = env->me_numdbs;
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
if (txn->mt_flags & MDB_TXN_RDONLY) {
if (!ti) { if (!ti) {
meta = env->me_metas[ mdb_env_pick_meta(env) ]; meta = env->me_metas[ mdb_env_pick_meta(env) ];
txn->mt_txnid = meta->mm_txnid; txn->mt_txnid = meta->mm_txnid;
@ -2543,10 +2574,14 @@ mdb_txn_renew0(MDB_txn *txn)
return rc; return rc;
} }
} }
txn->mt_txnid = r->mr_txnid = ti->mti_txnid; do /* LY: Retry on a race, ITS#7970. */
r->mr_txnid = ti->mti_txnid;
while(r->mr_txnid != ti->mti_txnid);
txn->mt_txnid = r->mr_txnid;
txn->mt_u.reader = r; txn->mt_u.reader = r;
meta = env->me_metas[txn->mt_txnid & 1]; meta = env->me_metas[txn->mt_txnid & 1];
} }
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
} else { } else {
if (ti) { if (ti) {
LOCK_MUTEX_W(env); LOCK_MUTEX_W(env);
@ -2562,6 +2597,9 @@ mdb_txn_renew0(MDB_txn *txn)
if (txn->mt_txnid == mdb_debug_start) if (txn->mt_txnid == mdb_debug_start)
mdb_debug = 1; mdb_debug = 1;
#endif #endif
txn->mt_child = NULL;
txn->mt_loose_pgs = NULL;
txn->mt_loose_count = 0;
txn->mt_dirty_room = MDB_IDL_UM_MAX; txn->mt_dirty_room = MDB_IDL_UM_MAX;
txn->mt_u.dirty_list = env->me_dirty_list; txn->mt_u.dirty_list = env->me_dirty_list;
txn->mt_u.dirty_list[0].mid = 0; txn->mt_u.dirty_list[0].mid = 0;
@ -2578,6 +2616,10 @@ mdb_txn_renew0(MDB_txn *txn)
/* Moved to here to avoid a data race in read TXNs */ /* Moved to here to avoid a data race in read TXNs */
txn->mt_next_pgno = meta->mm_last_pg+1; 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; i<txn->mt_numdbs; i++) { for (i=2; i<txn->mt_numdbs; i++) {
x = env->me_dbflags[i]; x = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
@ -2643,18 +2685,16 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
} }
tsize = sizeof(MDB_ntxn); tsize = sizeof(MDB_ntxn);
} }
size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1); size = tsize;
if (!(flags & MDB_RDONLY)) { if (!(flags & MDB_RDONLY)) {
if (!parent) { if (!parent) {
txn = env->me_txn0; txn = env->me_txn0; /* just reuse preallocated write txn */
txn->mt_flags = 0;
goto ok; goto ok;
} }
/* child txns use own copy of cursors */
size += env->me_maxdbs * sizeof(MDB_cursor *); size += env->me_maxdbs * sizeof(MDB_cursor *);
/* child txns use parent's dbiseqs */
if (!parent)
size += env->me_maxdbs * sizeof(unsigned int);
} }
size += env->me_maxdbs * (sizeof(MDB_db)+1);
if ((txn = calloc(1, size)) == NULL) { if ((txn = calloc(1, size)) == NULL) {
DPRINTF(("calloc: %s", strerror(errno))); DPRINTF(("calloc: %s", strerror(errno)));
@ -2807,31 +2847,33 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
txn->mt_numdbs = 0; /* close nothing if called again */ txn->mt_numdbs = 0; /* close nothing if called again */
txn->mt_dbxs = NULL; /* mark txn as reset */ txn->mt_dbxs = NULL; /* mark txn as reset */
} else { } else {
mdb_cursors_close(txn, 0); pgno_t *pghead = env->me_pghead;
mdb_cursors_close(txn, 0);
if (!(env->me_flags & MDB_WRITEMAP)) { if (!(env->me_flags & MDB_WRITEMAP)) {
mdb_dlist_free(txn); mdb_dlist_free(txn);
} }
mdb_midl_free(env->me_pghead);
if (txn->mt_parent) { if (!txn->mt_parent) {
if (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;
env->me_txn = NULL;
/* The writer mutex was locked in mdb_txn_begin. */
if (env->me_txns)
UNLOCK_MUTEX_W(env);
} else {
txn->mt_parent->mt_child = NULL; txn->mt_parent->mt_child = NULL;
env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate;
mdb_midl_free(txn->mt_free_pgs); mdb_midl_free(txn->mt_free_pgs);
mdb_midl_free(txn->mt_spill_pgs); mdb_midl_free(txn->mt_spill_pgs);
free(txn->mt_u.dirty_list); free(txn->mt_u.dirty_list);
return;
} }
if (mdb_midl_shrink(&txn->mt_free_pgs)) mdb_midl_free(pghead);
env->me_free_pgs = txn->mt_free_pgs;
env->me_pghead = NULL;
env->me_pglast = 0;
env->me_txn = NULL;
/* The writer mutex was locked in mdb_txn_begin. */
if (env->me_txns)
UNLOCK_MUTEX_W(env);
} }
#ifdef VL32 #ifdef VL32
{ {
@ -3159,6 +3201,7 @@ mdb_page_flush(MDB_txn *txn, int keep)
/* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */
if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) {
if (n) { if (n) {
retry_write:
/* Write previous page(s) */ /* Write previous page(s) */
#ifdef MDB_USE_PWRITEV #ifdef MDB_USE_PWRITEV
wres = pwritev(env->me_fd, iov, n, wpos); wres = pwritev(env->me_fd, iov, n, wpos);
@ -3166,8 +3209,11 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (n == 1) { if (n == 1) {
wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos);
} else { } else {
retry_seek:
if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { if (lseek(env->me_fd, wpos, SEEK_SET) == -1) {
rc = ErrCode(); rc = ErrCode();
if (rc == EINTR)
goto retry_seek;
DPRINTF(("lseek: %s", strerror(rc))); DPRINTF(("lseek: %s", strerror(rc)));
return rc; return rc;
} }
@ -3177,6 +3223,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (wres != wsize) { if (wres != wsize) {
if (wres < 0) { if (wres < 0) {
rc = ErrCode(); rc = ErrCode();
if (rc == EINTR)
goto retry_write;
DPRINTF(("Write error: %s", strerror(rc))); DPRINTF(("Write error: %s", strerror(rc)));
} else { } else {
rc = EIO; /* TODO: Use which error code? */ rc = EIO; /* TODO: Use which error code? */
@ -3546,7 +3594,8 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
int len; int len;
#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \
len = pwrite(fd, ptr, size, pos); \ len = pwrite(fd, ptr, size, pos); \
rc = (len >= 0); } while(0) if (len == -1 && ErrCode() == EINTR) continue; \
rc = (len >= 0); break; } while(1)
#endif #endif
DPUTS("writing new meta page"); DPUTS("writing new meta page");
@ -3651,6 +3700,7 @@ mdb_env_write_meta(MDB_txn *txn)
/* Write to the SYNC fd */ /* Write to the SYNC fd */
mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ? mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ?
env->me_fd : env->me_mfd; env->me_fd : env->me_mfd;
retry_write:
#ifdef _WIN32 #ifdef _WIN32
{ {
memset(&ov, 0, sizeof(ov)); memset(&ov, 0, sizeof(ov));
@ -3663,6 +3713,8 @@ mdb_env_write_meta(MDB_txn *txn)
#endif #endif
if (rc != len) { if (rc != len) {
rc = rc < 0 ? ErrCode() : EIO; rc = rc < 0 ? ErrCode() : EIO;
if (rc == EINTR)
goto retry_write;
DPUTS("write failed, disk error?"); DPUTS("write failed, disk error?");
/* On a failure, the pagecache still contains the new data. /* On a failure, the pagecache still contains the new data.
* Write some old data back, to prevent it from being used. * Write some old data back, to prevent it from being used.
@ -3894,6 +3946,32 @@ mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers)
return MDB_SUCCESS; return MDB_SUCCESS;
} }
static int ESECT
mdb_fsize(HANDLE fd, size_t *size)
{
#ifdef _WIN32
LARGE_INTEGER fsize;
if (!GetFileSizeEx(fd, &fsize))
return ErrCode();
*size = fsize.QuadPart;
#else
struct stat st;
if (fstat(fd, &st))
return ErrCode();
*size = st.st_size;
#endif
return MDB_SUCCESS;
}
#ifdef BROKEN_FDATASYNC
#include <sys/utsname.h>
#include <sys/vfs.h>
#endif
/** Further setup required for opening an LMDB environment /** Further setup required for opening an LMDB environment
*/ */
static int ESECT static int ESECT
@ -3911,6 +3989,53 @@ mdb_env_open2(MDB_env *env)
else else
env->me_pidquery = PROCESS_QUERY_INFORMATION; env->me_pidquery = PROCESS_QUERY_INFORMATION;
#endif /* _WIN32 */ #endif /* _WIN32 */
#ifdef BROKEN_FDATASYNC
/* ext3/ext4 fdatasync is broken on some older Linux kernels.
* https://lkml.org/lkml/2012/9/3/83
* Kernels after 3.6-rc6 are known good.
* https://lkml.org/lkml/2012/9/10/556
* See if the DB is on ext3/ext4, then check for new enough kernel
* Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known
* to be patched.
*/
{
struct statfs st;
fstatfs(env->me_fd, &st);
while (st.f_type == 0xEF53) {
struct utsname uts;
int i;
uname(&uts);
if (uts.release[0] < '3') {
if (!strncmp(uts.release, "2.6.32.", 7)) {
i = atoi(uts.release+7);
if (i >= 60)
break; /* 2.6.32.60 and newer is OK */
} else if (!strncmp(uts.release, "2.6.34.", 7)) {
i = atoi(uts.release+7);
if (i >= 15)
break; /* 2.6.34.15 and newer is OK */
}
} else if (uts.release[0] == '3') {
i = atoi(uts.release+2);
if (i > 5)
break; /* 3.6 and newer is OK */
if (i == 5) {
i = atoi(uts.release+4);
if (i >= 4)
break; /* 3.5.4 and newer is OK */
} else if (i == 2) {
i = atoi(uts.release+4);
if (i >= 30)
break; /* 3.2.30 and newer is OK */
}
} else { /* 4.x and newer is OK */
break;
}
env->me_flags |= MDB_FSYNCONLY;
break;
}
}
#endif
memset(&meta, 0, sizeof(meta)); memset(&meta, 0, sizeof(meta));
@ -4042,7 +4167,7 @@ PIMAGE_TLS_CALLBACK mdb_tls_cbp __attribute__((section (".CRT$XLB"))) = mdb_tls_
extern const PIMAGE_TLS_CALLBACK mdb_tls_cbp; extern const PIMAGE_TLS_CALLBACK mdb_tls_cbp;
const PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback; const PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback;
#pragma const_seg() #pragma const_seg()
#else /* WIN32 */ #else /* _WIN32 */
#pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:__tls_used")
#pragma comment(linker, "/INCLUDE:_mdb_tls_cbp") #pragma comment(linker, "/INCLUDE:_mdb_tls_cbp")
#pragma data_seg(".CRT$XLB") #pragma data_seg(".CRT$XLB")
@ -4092,7 +4217,7 @@ mdb_env_share_locks(MDB_env *env, int *excl)
return rc; return rc;
} }
/** Try to get exlusive lock, otherwise shared. /** Try to get exclusive lock, otherwise shared.
* Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive. * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive.
*/ */
static int ESECT static int ESECT
@ -4233,7 +4358,6 @@ mdb_hash_enc(MDB_val *val, char *encbuf)
* @param[in] env The LMDB environment. * @param[in] env The LMDB environment.
* @param[in] lpath The pathname of the file used for the lock region. * @param[in] lpath The pathname of the file used for the lock region.
* @param[in] mode The Unix permissions for the file, if we create it. * @param[in] mode The Unix permissions for the file, if we create it.
* @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive
* @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
* @return 0 on success, non-zero on failure. * @return 0 on success, non-zero on failure.
*/ */
@ -4599,7 +4723,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
if (!(flags & MDB_RDONLY)) { if (!(flags & MDB_RDONLY)) {
MDB_txn *txn; MDB_txn *txn;
int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs * int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs *
(sizeof(MDB_db)+sizeof(MDB_cursor)+sizeof(unsigned int)+1); (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1);
txn = calloc(1, size); txn = calloc(1, size);
if (txn) { if (txn) {
txn->mt_dbs = (MDB_db *)((char *)txn + tsize); txn->mt_dbs = (MDB_db *)((char *)txn + tsize);
@ -4607,6 +4731,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs); txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs);
txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs); txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs);
txn->mt_env = env; txn->mt_env = env;
txn->mt_dbxs = env->me_dbxs;
#ifdef VL32 #ifdef VL32
txn->mt_rpages = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)); txn->mt_rpages = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2));
if (!txn->mt_rpages) { if (!txn->mt_rpages) {
@ -4639,13 +4764,15 @@ mdb_env_close0(MDB_env *env, int excl)
return; return;
/* Doing this here since me_dbxs may not exist during mdb_env_close */ /* Doing this here since me_dbxs may not exist during mdb_env_close */
for (i = env->me_maxdbs; --i > MAIN_DBI; ) if (env->me_dbxs) {
free(env->me_dbxs[i].md_name.mv_data); for (i = env->me_maxdbs; --i > MAIN_DBI; )
free(env->me_dbxs[i].md_name.mv_data);
free(env->me_dbxs);
}
free(env->me_pbuf); free(env->me_pbuf);
free(env->me_dbiseqs); free(env->me_dbiseqs);
free(env->me_dbflags); free(env->me_dbflags);
free(env->me_dbxs);
free(env->me_path); free(env->me_path);
free(env->me_dirty_list); free(env->me_dirty_list);
free(env->me_txn0); free(env->me_txn0);
@ -4752,7 +4879,11 @@ mdb_cmp_long(const MDB_val *a, const MDB_val *b)
*(size_t *)a->mv_data > *(size_t *)b->mv_data; *(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 static int
mdb_cmp_int(const MDB_val *a, const MDB_val *b) mdb_cmp_int(const MDB_val *a, const MDB_val *b)
{ {
@ -4790,13 +4921,6 @@ mdb_cmp_cint(const MDB_val *a, const MDB_val *b)
#endif #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 */ /** Compare two items lexically */
static int static int
mdb_cmp_memn(const MDB_val *a, const MDB_val *b) mdb_cmp_memn(const MDB_val *a, const MDB_val *b)
@ -5432,6 +5556,7 @@ mdb_cursor_sibling(MDB_cursor *mc, int move_right)
#ifdef VL32 #ifdef VL32
op = mc->mc_pg[mc->mc_top]; op = mc->mc_pg[mc->mc_top];
#endif #endif
mdb_cursor_pop(mc); mdb_cursor_pop(mc);
DPRINTF(("parent page is page %"Z"u, index %u", DPRINTF(("parent page is page %"Z"u, index %u",
mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top])); mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top]));
@ -5590,11 +5715,11 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
} }
return rc; return rc;
} }
} else {
mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
if (op == MDB_PREV_DUP)
return MDB_NOTFOUND;
} }
} else {
mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
if (op == MDB_PREV_DUP)
return MDB_NOTFOUND;
} }
} }
@ -5806,15 +5931,21 @@ set1:
return rc; return rc;
} }
} else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) {
MDB_val d2; MDB_val olddata;
if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS) MDB_cmp_func *dcmp;
if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS)
return rc; 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 (rc) {
if (op == MDB_GET_BOTH || rc > 0) if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND; return MDB_NOTFOUND;
rc = 0; rc = 0;
*data = d2; *data = olddata;
} }
} else { } else {
@ -6324,16 +6455,17 @@ more:
/* Was a single item before, must convert now */ /* Was a single item before, must convert now */
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
MDB_cmp_func *dcmp;
/* Just overwrite the current item */ /* Just overwrite the current item */
if (flags == MDB_CURRENT) if (flags == MDB_CURRENT)
goto current; goto current;
dcmp = mc->mc_dbx->md_dcmp;
#if UINT_MAX < SIZE_MAX #if UINT_MAX < SIZE_MAX
if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
mc->mc_dbx->md_dcmp = mdb_cmp_clong; dcmp = mdb_cmp_clong;
#endif #endif
/* does data match? */ /* does data match? */
if (!mc->mc_dbx->md_dcmp(data, &olddata)) { if (!dcmp(data, &olddata)) {
if (flags & MDB_NODUPDATA) if (flags & MDB_NODUPDATA)
return MDB_KEYEXIST; return MDB_KEYEXIST;
/* overwrite it */ /* overwrite it */
@ -7153,6 +7285,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
mc->mc_snum = 0; mc->mc_snum = 0;
mc->mc_top = 0; mc->mc_top = 0;
mc->mc_pg[0] = 0; mc->mc_pg[0] = 0;
mc->mc_ki[0] = 0;
mc->mc_flags = 0; mc->mc_flags = 0;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
mdb_tassert(txn, mx != NULL); mdb_tassert(txn, mx != NULL);
@ -7526,7 +7659,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst)
cdst->mc_ki[cdst->mc_top] = 0; cdst->mc_ki[cdst->mc_top] = 0;
rc = mdb_update_key(cdst, &nullkey); rc = mdb_update_key(cdst, &nullkey);
cdst->mc_ki[cdst->mc_top] = ix; cdst->mc_ki[cdst->mc_top] = ix;
mdb_cassert(csrc, rc == MDB_SUCCESS); mdb_cassert(cdst, rc == MDB_SUCCESS);
} }
} }
@ -7782,12 +7915,12 @@ mdb_rebalance(MDB_cursor *mc)
m3 = m2; m3 = m2;
if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; if (m3 == mc || m3->mc_snum < mc->mc_snum) continue;
if (m3->mc_pg[0] == mp) { if (m3->mc_pg[0] == mp) {
m3->mc_snum--;
m3->mc_top--;
for (i=0; i<m3->mc_snum; i++) { for (i=0; i<m3->mc_snum; i++) {
m3->mc_pg[i] = m3->mc_pg[i+1]; m3->mc_pg[i] = m3->mc_pg[i+1];
m3->mc_ki[i] = m3->mc_ki[i+1]; m3->mc_ki[i] = m3->mc_ki[i+1];
} }
m3->mc_snum--;
m3->mc_top--;
} }
} }
} }
@ -7855,9 +7988,23 @@ mdb_rebalance(MDB_cursor *mc)
if (mc->mc_ki[ptop] == 0) { if (mc->mc_ki[ptop] == 0) {
rc = mdb_page_merge(&mn, mc); rc = mdb_page_merge(&mn, mc);
} else { } else {
MDB_cursor dummy;
oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; 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); 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); mdb_cursor_copy(&mn, mc);
} }
mc->mc_flags &= ~C_EOF; mc->mc_flags &= ~C_EOF;
@ -7884,6 +8031,13 @@ mdb_cursor_del0(MDB_cursor *mc)
MDB_cursor *m2, *m3; MDB_cursor *m2, *m3;
MDB_dbi dbi = mc->mc_dbi; 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]; mp = mc->mc_pg[mc->mc_top];
nkeys = NUMKEYS(mp); nkeys = NUMKEYS(mp);
@ -8751,8 +8905,12 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd)
/* Set metapage 1 */ /* Set metapage 1 */
mm->mm_last_pg = txn->mt_next_pgno - freecount - 1; mm->mm_last_pg = txn->mt_next_pgno - freecount - 1;
mm->mm_dbs[1] = txn->mt_dbs[1]; mm->mm_dbs[1] = txn->mt_dbs[1];
mm->mm_dbs[1].md_root = mm->mm_last_pg; if (mm->mm_last_pg > 1) {
mm->mm_txnid = 1; mm->mm_dbs[1].md_root = mm->mm_last_pg;
mm->mm_txnid = 1;
} else {
mm->mm_dbs[1].md_root = P_INVALID;
}
} }
my.mc_wlen[0] = env->me_psize * 2; my.mc_wlen[0] = env->me_psize * 2;
my.mc_txn = txn; my.mc_txn = txn;
@ -8847,21 +9005,13 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd)
goto leave; goto leave;
w2 = txn->mt_next_pgno * env->me_psize; w2 = txn->mt_next_pgno * env->me_psize;
#ifdef WIN32
{ {
LARGE_INTEGER fsize; size_t fsize = 0;
GetFileSizeEx(env->me_fd, &fsize); if ((rc = mdb_fsize(env->me_fd, &fsize)))
if (w2 > fsize.QuadPart) goto leave;
w2 = fsize.QuadPart; if (w2 > fsize)
w2 = fsize;
} }
#else
{
struct stat st;
fstat(env->me_fd, &st);
if (w2 > (size_t)st.st_size)
w2 = st.st_size;
}
#endif
wsize = w2 - wsize; wsize = w2 - wsize;
while (wsize > 0) { while (wsize > 0) {
if (wsize > MAX_WRITE) if (wsize > MAX_WRITE)

View file

@ -1,5 +1,5 @@
.TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14" .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. .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME .SH NAME
mdb_copy \- LMDB environment copy tool mdb_copy \- LMDB environment copy tool

View file

@ -1,6 +1,6 @@
/* mdb_copy.c - memory-mapped database backup tool */ /* mdb_copy.c - memory-mapped database backup tool */
/* /*
* Copyright 2012 Howard Chu, Symas Corp. * Copyright 2012-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -64,7 +64,7 @@ int main(int argc,char * argv[])
act = "opening environment"; act = "opening environment";
rc = mdb_env_create(&env); rc = mdb_env_create(&env);
if (rc == MDB_SUCCESS) { if (rc == MDB_SUCCESS) {
rc = mdb_env_open(env, argv[1], flags, 0664); rc = mdb_env_open(env, argv[1], flags, 0600);
} }
if (rc == MDB_SUCCESS) { if (rc == MDB_SUCCESS) {
act = "copying"; act = "copying";

View file

@ -1,5 +1,5 @@
.TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14" .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. .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME .SH NAME
mdb_dump \- LMDB environment export tool mdb_dump \- LMDB environment export tool

View file

@ -1,6 +1,6 @@
/* mdb_dump.c - memory-mapped database dump tool */ /* 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View file

@ -1,5 +1,5 @@
.TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14" .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. .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME .SH NAME
mdb_load \- LMDB environment import tool mdb_load \- LMDB environment import tool

View file

@ -1,6 +1,6 @@
/* mdb_load.c - memory-mapped database load tool */ /* 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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) static int readline(MDB_val *out, MDB_val *buf)
{ {
unsigned char *c1, *c2, *end; unsigned char *c1, *c2, *end;
size_t len; size_t len, l2;
int c; int c;
if (!(mode & NOHDR)) { if (!(mode & NOHDR)) {
@ -206,6 +206,7 @@ badend:
c1 = buf->mv_data; c1 = buf->mv_data;
len = strlen((char *)c1); len = strlen((char *)c1);
l2 = len;
/* Is buffer too short? */ /* Is buffer too short? */
while (c1[len-1] != '\n') { while (c1[len-1] != '\n') {
@ -217,17 +218,18 @@ badend:
return EOF; return EOF;
} }
c1 = buf->mv_data; c1 = buf->mv_data;
c1 += buf->mv_size; c1 += l2;
if (fgets((char *)c1, buf->mv_size, stdin) == NULL) { if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) {
Eof = 1; Eof = 1;
badend(); badend();
return EOF; return EOF;
} }
buf->mv_size *= 2; buf->mv_size *= 2;
len = strlen((char *)c1); len = strlen((char *)c1);
l2 += len;
} }
c1 = c2 = buf->mv_data; c1 = c2 = buf->mv_data;
len = strlen((char *)c1); len = l2;
c1[--len] = '\0'; c1[--len] = '\0';
end = c1 + len; end = c1 + len;

View file

@ -1,5 +1,5 @@
.TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14" .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. .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.SH NAME .SH NAME
mdb_stat \- LMDB environment status tool mdb_stat \- LMDB environment status tool

View file

@ -1,6 +1,6 @@
/* mdb_stat.c - memory-mapped database status tool */ /* 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View file

@ -3,7 +3,7 @@
/* $OpenLDAP$ */ /* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
* *
* Copyright 2000-2014 The OpenLDAP Foundation. * Copyright 2000-2015 The OpenLDAP Foundation.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View file

@ -11,7 +11,7 @@
/* $OpenLDAP$ */ /* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
* *
* Copyright 2000-2014 The OpenLDAP Foundation. * Copyright 2000-2015 The OpenLDAP Foundation.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -58,7 +58,7 @@ typedef MDB_ID *MDB_IDL;
#ifdef VL32 #ifdef VL32
#define MDB_IDL_LOGN 10 /* DB_SIZE is 2^10, UM_SIZE is 2^11 */ #define MDB_IDL_LOGN 10 /* DB_SIZE is 2^10, UM_SIZE is 2^11 */
#else #else
#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
#endif #endif
#define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN) #define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
#define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1)) #define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))

View file

@ -1,6 +1,6 @@
/* mtest.c - memory-mapped database tester/toy */ /* mtest.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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_create(&env));
E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_open(env, "./testdb", 0 /* MDB_FIXEDMAP |MDB_NOSYNC*/, 0664)); E(mdb_env_open(env, "./testdb", 0 /* MDB_FIXEDMAP |MDB_NOSYNC*/, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); 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_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
data.mv_size = sizeof(sval);
data.mv_data = sval;
printf("Adding %d values\n", count); printf("Adding %d values\n", count);
for (i=0;i<count;i++) { for (i=0;i<count;i++) {
sprintf(sval, "%03x %d foo bar", values[i], values[i]); sprintf(sval, "%03x %d foo bar", values[i], values[i]);
/* Set <data> 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))) { if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
j++; j++;
data.mv_size = sizeof(sval); data.mv_size = sizeof(sval);
@ -68,7 +71,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -97,7 +100,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 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) key.mv_size, (char *) key.mv_data,
(int) data.mv_size, (char *) data.mv_data); (int) data.mv_size, (char *) data.mv_data);
mdb_cursor_close(cursor);
mdb_txn_abort(txn); mdb_txn_abort(txn);
printf("Deleting with cursor\n"); 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); data.mv_data, (int) data.mv_size, (char *) data.mv_data);
} }
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(env, dbi);
mdb_env_close(env); mdb_env_close(env);
return 0; return 0;

View file

@ -1,6 +1,6 @@
/* mtest2.c - memory-mapped database tester/toy */ /* mtest2.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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_create(&env));
E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); 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_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
data.mv_size = sizeof(sval);
data.mv_data = sval;
printf("Adding %d values\n", count); printf("Adding %d values\n", count);
for (i=0;i<count;i++) { for (i=0;i<count;i++) {
sprintf(sval, "%03x %d foo bar", values[i], values[i]); sprintf(sval, "%03x %d foo bar", values[i], values[i]);
data.mv_size = sizeof(sval);
data.mv_data = sval;
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE)))
j++; j++;
} }
@ -68,7 +70,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -97,7 +99,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -114,10 +116,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -1,6 +1,6 @@
/* mtest3.c - memory-mapped database tester/toy */ /* mtest3.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -53,8 +53,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = kval; key.mv_data = kval;
@ -73,7 +74,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -107,7 +108,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -124,10 +125,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -1,6 +1,6 @@
/* mtest4.c - memory-mapped database tester/toy */ /* mtest4.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -51,8 +51,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi)); E(mdb_dbi_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = kval; key.mv_data = kval;
@ -72,7 +73,7 @@ int main(int argc,char * argv[])
/* there should be one full page of dups now. /* there should be one full page of dups now.
*/ */
E(mdb_txn_begin(env, NULL, 1, &txn)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -142,7 +143,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -159,10 +160,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -1,6 +1,6 @@
/* mtest5.c - memory-mapped database tester/toy */ /* mtest5.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -53,8 +53,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
@ -75,7 +76,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -109,7 +110,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -126,10 +127,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -1,6 +1,6 @@
/* mtest6.c - memory-mapped database tester/toy */ /* mtest6.c - memory-mapped database tester/toy */
/* /*
* Copyright 2011-2014 Howard Chu, Symas Corp. * Copyright 2011-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,7 +31,7 @@ int main(int argc,char * argv[])
int i = 0, j = 0, rc; int i = 0, j = 0, rc;
MDB_env *env; MDB_env *env;
MDB_dbi dbi; MDB_dbi dbi;
MDB_val key, data; MDB_val key, data, sdata;
MDB_txn *txn; MDB_txn *txn;
MDB_stat mst; MDB_stat mst;
MDB_cursor *cursor; MDB_cursor *cursor;
@ -46,33 +46,37 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
E(mdb_stat(txn, dbi, &mst)); E(mdb_stat(txn, dbi, &mst));
sval = calloc(1, mst.ms_psize / 4); sval = calloc(1, mst.ms_psize / 4);
key.mv_size = sizeof(long); key.mv_size = sizeof(long);
key.mv_data = &kval; key.mv_data = &kval;
data.mv_size = mst.ms_psize / 4 - 30; sdata.mv_size = mst.ms_psize / 4 - 30;
data.mv_data = sval; sdata.mv_data = sval;
printf("Adding 12 values, should yield 3 splits\n"); printf("Adding 12 values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5; kval = i*5;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
printf("Adding 12 more values, should yield 3 splits\n"); printf("Adding 12 more values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5+4; kval = i*5+4;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
printf("Adding 12 more values, should yield 3 splits\n"); printf("Adding 12 more values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5+1; kval = i*5+1;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST));
@ -110,7 +114,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -127,9 +131,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(env, dbi);
#endif #endif
mdb_env_close(env); mdb_env_close(env);

View file

@ -3,7 +3,7 @@
* Do a line-by-line comparison of this and sample-mdb.txt * Do a line-by-line comparison of this and sample-mdb.txt
*/ */
/* /*
* Copyright 2012 Howard Chu, Symas Corp. * Copyright 2012-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View file

@ -3,7 +3,7 @@
* Do a line-by-line comparison of this and sample-bdb.txt * Do a line-by-line comparison of this and sample-bdb.txt
*/ */
/* /*
* Copyright 2012 Howard Chu, Symas Corp. * Copyright 2012-2015 Howard Chu, Symas Corp.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@ int main(int argc,char * argv[])
rc = mdb_env_create(&env); rc = mdb_env_create(&env);
rc = mdb_env_open(env, "./testdb", 0, 0664); rc = mdb_env_open(env, "./testdb", 0, 0664);
rc = mdb_txn_begin(env, NULL, 0, &txn); rc = mdb_txn_begin(env, NULL, 0, &txn);
rc = mdb_open(txn, NULL, 0, &dbi); rc = mdb_dbi_open(txn, NULL, 0, &dbi);
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
@ -56,7 +56,7 @@ int main(int argc,char * argv[])
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_txn_abort(txn); mdb_txn_abort(txn);
leave: leave:
mdb_close(env, dbi); mdb_dbi_close(env, dbi);
mdb_env_close(env); mdb_env_close(env);
return 0; return 0;
} }

View file

@ -1,18 +1,31 @@
LMDB 0.9 Change Log LMDB 0.9 Change Log
LMDB 0.9.15 Release Engineering LMDB 0.9.15 Release (2015/06/19)
Fix txn init (ITS#7961,#7987) Fix txn init (ITS#7961,#7987)
Fix MDB_PREV_DUP (ITS#7955,#7671) Fix MDB_PREV_DUP (ITS#7955,#7671)
Fix compact of empty env (ITS#7956) 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 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 Added workaround for fdatasync bug in ext3fs
Build Build
Don't use -fPIC for static lib Don't use -fPIC for static lib
Update .gitignore (ITS#7952,#7953) Update .gitignore (ITS#7952,#7953)
Cleanup for "make test" (ITS#7841) Cleanup for "make test" (ITS#7841), "make clean", mtest*.c
Misc. Android/Windows cleanup Misc. Android/Windows cleanup
Documentation Documentation
Fix MDB_APPEND doc 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 Clarify mdb_dbi_open doc
LMDB 0.9.14 Release (2014/09/20) LMDB 0.9.14 Release (2014/09/20)

View file

@ -26,6 +26,10 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if(FREEBSD)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMDB_DSYNC=O_SYNC")
endif()
set (lmdb_sources set (lmdb_sources
mdb.c mdb.c
midl.c) midl.c)

View file

@ -184,7 +184,7 @@ typedef int mdb_filehandle_t;
/** Library minor version */ /** Library minor version */
#define MDB_VERSION_MINOR 9 #define MDB_VERSION_MINOR 9
/** Library patch version */ /** Library patch version */
#define MDB_VERSION_PATCH 14 #define MDB_VERSION_PATCH 15
/** Combine args a,b,c into a single integer for easy version comparisons */ /** Combine args a,b,c into a single integer for easy version comparisons */
#define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
@ -194,7 +194,7 @@ typedef int mdb_filehandle_t;
MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
/** The release date of this library version */ /** The release date of this library version */
#define MDB_VERSION_DATE "September 20, 2014" #define MDB_VERSION_DATE "June 19, 2015"
/** A stringifier for the version info */ /** A stringifier for the version info */
#define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
@ -296,12 +296,12 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel
#define MDB_REVERSEKEY 0x02 #define MDB_REVERSEKEY 0x02
/** use sorted duplicates */ /** use sorted duplicates */
#define MDB_DUPSORT 0x04 #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. */ * The keys must all be of the same size. */
#define MDB_INTEGERKEY 0x08 #define MDB_INTEGERKEY 0x08
/** with #MDB_DUPSORT, sorted dup items have fixed size */ /** with #MDB_DUPSORT, sorted dup items have fixed size */
#define MDB_DUPFIXED 0x10 #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 #define MDB_INTEGERDUP 0x20
/** with #MDB_DUPSORT, use reverse string dups */ /** with #MDB_DUPSORT, use reverse string dups */
#define MDB_REVERSEDUP 0x40 #define MDB_REVERSEDUP 0x40
@ -588,8 +588,8 @@ int mdb_env_create(MDB_env **env);
* reserved in that case. * reserved in that case.
* This flag may be changed at any time using #mdb_env_set_flags(). * This flag may be changed at any time using #mdb_env_set_flags().
* </ul> * </ul>
* @param[in] mode The UNIX permissions to set on created files. This parameter * @param[in] mode The UNIX permissions to set on created files and semaphores.
* is ignored on Windows. * This parameter is ignored on Windows.
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
* errors are: * errors are:
* <ul> * <ul>
@ -1021,14 +1021,16 @@ int mdb_txn_renew(MDB_txn *txn);
* The database handle may be discarded by calling #mdb_dbi_close(). * The database handle may be discarded by calling #mdb_dbi_close().
* The old database handle is returned if the database was already open. * The old database handle is returned if the database was already open.
* The handle may only be closed once. * The handle may only be closed once.
*
* The database handle will be private to the current transaction until * The database handle will be private to the current transaction until
* the transaction is successfully committed. If the transaction is * the transaction is successfully committed. If the transaction is
* aborted the handle will be closed automatically. * aborted the handle will be closed automatically.
* After a successful commit the * After a successful commit the handle will reside in the shared
* handle will reside in the shared environment, and may be used * environment, and may be used by other transactions.
* by other transactions. This function must not be called from *
* multiple concurrent transactions in the same process. A transaction * This function must not be called from multiple concurrent
* that uses this function must finish (either commit or abort) before * 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. * any other transaction in the process may use this function.
* *
* To use named databases (with name != NULL), #mdb_env_set_maxdbs() * To use named databases (with name != NULL), #mdb_env_set_maxdbs()
@ -1050,9 +1052,9 @@ int mdb_txn_renew(MDB_txn *txn);
* keys may have multiple data items, stored in sorted order.) By default * keys may have multiple data items, stored in sorted order.) By default
* keys must be unique and may have only a single data item. * keys must be unique and may have only a single data item.
* <li>#MDB_INTEGERKEY * <li>#MDB_INTEGERKEY
* Keys are binary integers in native byte order. Setting this option * Keys are binary integers in native byte order, either unsigned int
* requires all keys to be the same size, typically sizeof(int) * or size_t, and will be sorted as such.
* or sizeof(size_t). * The keys must all be of the same size.
* <li>#MDB_DUPFIXED * <li>#MDB_DUPFIXED
* This flag may only be used in combination with #MDB_DUPSORT. This option * 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 * tells the library that the data items for this database are all the same
@ -1060,8 +1062,8 @@ int mdb_txn_renew(MDB_txn *txn);
* all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE * 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. * cursor operations may be used to retrieve multiple items at once.
* <li>#MDB_INTEGERDUP * <li>#MDB_INTEGERDUP
* This option specifies that duplicate data items are also integers, and * This option specifies that duplicate data items are binary integers,
* should be sorted as such. * similar to #MDB_INTEGERKEY keys.
* <li>#MDB_REVERSEDUP * <li>#MDB_REVERSEDUP
* This option specifies that duplicate data items should be compared as * This option specifies that duplicate data items should be compared as
* strings in reverse order. * strings in reverse order.
@ -1450,7 +1452,7 @@ int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
* <ul> * <ul>
* <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). * <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize().
* <li>#MDB_TXN_FULL - the transaction has too many dirty pages. * <li>#MDB_TXN_FULL - the transaction has too many dirty pages.
* <li>EACCES - an attempt was made to modify a read-only database. * <li>EACCES - an attempt was made to write in a read-only transaction.
* <li>EINVAL - an invalid parameter was specified. * <li>EINVAL - an invalid parameter was specified.
* </ul> * </ul>
*/ */
@ -1470,7 +1472,7 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
* @return A non-zero error value on failure and 0 on success. Some possible * @return A non-zero error value on failure and 0 on success. Some possible
* errors are: * errors are:
* <ul> * <ul>
* <li>EACCES - an attempt was made to modify a read-only database. * <li>EACCES - an attempt was made to write in a read-only transaction.
* <li>EINVAL - an invalid parameter was specified. * <li>EINVAL - an invalid parameter was specified.
* </ul> * </ul>
*/ */

View file

@ -446,12 +446,17 @@ static txnid_t mdb_debug_start;
/** The version number for a database's lockfile format. */ /** The version number for a database's lockfile format. */
#define MDB_LOCK_VERSION 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 * This macro should normally be left alone or set to 0.
* is default for backwards compat: liblmdb <= 0.9.10 can break * Note that a database with big keys or dupsort data cannot be
* when modifying a DB with keys/dupsort data bigger than its max. * reliably modified by a liblmdb which uses a smaller max.
* #MDB_DEVEL sets the default to 0. * 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 * Data items in an #MDB_DUPSORT database are also limited to
* this size, since they're actually keys of a sub-DB. Keys and * this size, since they're actually keys of a sub-DB. Keys and
@ -1245,6 +1250,13 @@ static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long;
/** @endcond */ /** @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 #ifdef _WIN32
static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_DESCRIPTOR mdb_null_sd;
static SECURITY_ATTRIBUTES mdb_all_sa; static SECURITY_ATTRIBUTES mdb_all_sa;
@ -1558,7 +1570,12 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
int int
mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) 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. /** Allocate memory for a page.
@ -2486,14 +2503,11 @@ mdb_txn_renew0(MDB_txn *txn)
MDB_env *env = txn->mt_env; MDB_env *env = txn->mt_env;
MDB_txninfo *ti = env->me_txns; MDB_txninfo *ti = env->me_txns;
MDB_meta *meta; MDB_meta *meta;
unsigned int i, nr; unsigned int i, nr, flags = txn->mt_flags;
uint16_t x; uint16_t x;
int rc, new_notls = 0; int rc, new_notls = 0;
if (txn->mt_flags & MDB_TXN_RDONLY) { if ((flags &= MDB_TXN_RDONLY) != 0) {
/* Setup db info */
txn->mt_numdbs = env->me_numdbs;
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
if (!ti) { if (!ti) {
meta = env->me_metas[ mdb_env_pick_meta(env) ]; meta = env->me_metas[ mdb_env_pick_meta(env) ];
txn->mt_txnid = meta->mm_txnid; txn->mt_txnid = meta->mm_txnid;
@ -2546,6 +2560,7 @@ mdb_txn_renew0(MDB_txn *txn)
txn->mt_u.reader = r; txn->mt_u.reader = r;
meta = env->me_metas[txn->mt_txnid & 1]; meta = env->me_metas[txn->mt_txnid & 1];
} }
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
} else { } else {
if (ti) { if (ti) {
LOCK_MUTEX_W(env); LOCK_MUTEX_W(env);
@ -2556,14 +2571,11 @@ mdb_txn_renew0(MDB_txn *txn)
meta = env->me_metas[ mdb_env_pick_meta(env) ]; meta = env->me_metas[ mdb_env_pick_meta(env) ];
txn->mt_txnid = meta->mm_txnid; txn->mt_txnid = meta->mm_txnid;
} }
/* Setup db info */
txn->mt_numdbs = env->me_numdbs;
txn->mt_txnid++; txn->mt_txnid++;
#if MDB_DEBUG #if MDB_DEBUG
if (txn->mt_txnid == mdb_debug_start) if (txn->mt_txnid == mdb_debug_start)
mdb_debug = 1; mdb_debug = 1;
#endif #endif
txn->mt_flags = 0;
txn->mt_child = NULL; txn->mt_child = NULL;
txn->mt_loose_pgs = NULL; txn->mt_loose_pgs = NULL;
txn->mt_loose_count = 0; txn->mt_loose_count = 0;
@ -2583,6 +2595,10 @@ mdb_txn_renew0(MDB_txn *txn)
/* Moved to here to avoid a data race in read TXNs */ /* Moved to here to avoid a data race in read TXNs */
txn->mt_next_pgno = meta->mm_last_pg+1; 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; i<txn->mt_numdbs; i++) { for (i=2; i<txn->mt_numdbs; i++) {
x = env->me_dbflags[i]; x = env->me_dbflags[i];
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS;
@ -3132,6 +3148,7 @@ mdb_page_flush(MDB_txn *txn, int keep)
/* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */
if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) {
if (n) { if (n) {
retry_write:
/* Write previous page(s) */ /* Write previous page(s) */
#ifdef MDB_USE_PWRITEV #ifdef MDB_USE_PWRITEV
wres = pwritev(env->me_fd, iov, n, wpos); wres = pwritev(env->me_fd, iov, n, wpos);
@ -3139,8 +3156,11 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (n == 1) { if (n == 1) {
wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos);
} else { } else {
retry_seek:
if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { if (lseek(env->me_fd, wpos, SEEK_SET) == -1) {
rc = ErrCode(); rc = ErrCode();
if (rc == EINTR)
goto retry_seek;
DPRINTF(("lseek: %s", strerror(rc))); DPRINTF(("lseek: %s", strerror(rc)));
return rc; return rc;
} }
@ -3150,6 +3170,8 @@ mdb_page_flush(MDB_txn *txn, int keep)
if (wres != wsize) { if (wres != wsize) {
if (wres < 0) { if (wres < 0) {
rc = ErrCode(); rc = ErrCode();
if (rc == EINTR)
goto retry_write;
DPRINTF(("Write error: %s", strerror(rc))); DPRINTF(("Write error: %s", strerror(rc)));
} else { } else {
rc = EIO; /* TODO: Use which error code? */ rc = EIO; /* TODO: Use which error code? */
@ -3519,7 +3541,8 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
int len; int len;
#define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \
len = pwrite(fd, ptr, size, pos); \ len = pwrite(fd, ptr, size, pos); \
rc = (len >= 0); } while(0) if (len == -1 && ErrCode() == EINTR) continue; \
rc = (len >= 0); break; } while(1)
#endif #endif
DPUTS("writing new meta page"); DPUTS("writing new meta page");
@ -3624,6 +3647,7 @@ mdb_env_write_meta(MDB_txn *txn)
/* Write to the SYNC fd */ /* Write to the SYNC fd */
mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ? mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ?
env->me_fd : env->me_mfd; env->me_fd : env->me_mfd;
retry_write:
#ifdef _WIN32 #ifdef _WIN32
{ {
memset(&ov, 0, sizeof(ov)); memset(&ov, 0, sizeof(ov));
@ -3636,6 +3660,8 @@ mdb_env_write_meta(MDB_txn *txn)
#endif #endif
if (rc != len) { if (rc != len) {
rc = rc < 0 ? ErrCode() : EIO; rc = rc < 0 ? ErrCode() : EIO;
if (rc == EINTR)
goto retry_write;
DPUTS("write failed, disk error?"); DPUTS("write failed, disk error?");
/* On a failure, the pagecache still contains the new data. /* On a failure, the pagecache still contains the new data.
* Write some old data back, to prevent it from being used. * Write some old data back, to prevent it from being used.
@ -4761,7 +4787,11 @@ mdb_cmp_long(const MDB_val *a, const MDB_val *b)
*(size_t *)a->mv_data > *(size_t *)b->mv_data; *(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 static int
mdb_cmp_int(const MDB_val *a, const MDB_val *b) mdb_cmp_int(const MDB_val *a, const MDB_val *b)
{ {
@ -4799,13 +4829,6 @@ mdb_cmp_cint(const MDB_val *a, const MDB_val *b)
#endif #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 */ /** Compare two items lexically */
static int static int
mdb_cmp_memn(const MDB_val *a, const MDB_val *b) mdb_cmp_memn(const MDB_val *a, const MDB_val *b)
@ -5741,15 +5764,21 @@ set1:
return rc; return rc;
} }
} else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) {
MDB_val d2; MDB_val olddata;
if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS) MDB_cmp_func *dcmp;
if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS)
return rc; 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 (rc) {
if (op == MDB_GET_BOTH || rc > 0) if (op == MDB_GET_BOTH || rc > 0)
return MDB_NOTFOUND; return MDB_NOTFOUND;
rc = 0; rc = 0;
*data = d2; *data = olddata;
} }
} else { } else {
@ -6259,16 +6288,17 @@ more:
/* Was a single item before, must convert now */ /* Was a single item before, must convert now */
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
MDB_cmp_func *dcmp;
/* Just overwrite the current item */ /* Just overwrite the current item */
if (flags == MDB_CURRENT) if (flags == MDB_CURRENT)
goto current; goto current;
dcmp = mc->mc_dbx->md_dcmp;
#if UINT_MAX < SIZE_MAX #if UINT_MAX < SIZE_MAX
if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
mc->mc_dbx->md_dcmp = mdb_cmp_clong; dcmp = mdb_cmp_clong;
#endif #endif
/* does data match? */ /* does data match? */
if (!mc->mc_dbx->md_dcmp(data, &olddata)) { if (!dcmp(data, &olddata)) {
if (flags & MDB_NODUPDATA) if (flags & MDB_NODUPDATA)
return MDB_KEYEXIST; return MDB_KEYEXIST;
/* overwrite it */ /* overwrite it */
@ -7088,6 +7118,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
mc->mc_snum = 0; mc->mc_snum = 0;
mc->mc_top = 0; mc->mc_top = 0;
mc->mc_pg[0] = 0; mc->mc_pg[0] = 0;
mc->mc_ki[0] = 0;
mc->mc_flags = 0; mc->mc_flags = 0;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
mdb_tassert(txn, mx != NULL); mdb_tassert(txn, mx != NULL);
@ -7717,12 +7748,12 @@ mdb_rebalance(MDB_cursor *mc)
m3 = m2; m3 = m2;
if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; if (m3 == mc || m3->mc_snum < mc->mc_snum) continue;
if (m3->mc_pg[0] == mp) { if (m3->mc_pg[0] == mp) {
m3->mc_snum--;
m3->mc_top--;
for (i=0; i<m3->mc_snum; i++) { for (i=0; i<m3->mc_snum; i++) {
m3->mc_pg[i] = m3->mc_pg[i+1]; m3->mc_pg[i] = m3->mc_pg[i+1];
m3->mc_ki[i] = m3->mc_ki[i+1]; m3->mc_ki[i] = m3->mc_ki[i+1];
} }
m3->mc_snum--;
m3->mc_top--;
} }
} }
} }
@ -7790,9 +7821,23 @@ mdb_rebalance(MDB_cursor *mc)
if (mc->mc_ki[ptop] == 0) { if (mc->mc_ki[ptop] == 0) {
rc = mdb_page_merge(&mn, mc); rc = mdb_page_merge(&mn, mc);
} else { } else {
MDB_cursor dummy;
oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; 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); 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); mdb_cursor_copy(&mn, mc);
} }
mc->mc_flags &= ~C_EOF; mc->mc_flags &= ~C_EOF;
@ -7819,6 +7864,13 @@ mdb_cursor_del0(MDB_cursor *mc)
MDB_cursor *m2, *m3; MDB_cursor *m2, *m3;
MDB_dbi dbi = mc->mc_dbi; 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]; mp = mc->mc_pg[mc->mc_top];
nkeys = NUMKEYS(mp); nkeys = NUMKEYS(mp);

View file

@ -45,19 +45,22 @@ int main(int argc,char * argv[])
} }
E(mdb_env_create(&env)); E(mdb_env_create(&env));
E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); 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_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
data.mv_size = sizeof(sval);
data.mv_data = sval;
printf("Adding %d values\n", count); printf("Adding %d values\n", count);
for (i=0;i<count;i++) { for (i=0;i<count;i++) {
sprintf(sval, "%03x %d foo bar", values[i], values[i]); sprintf(sval, "%03x %d foo bar", values[i], values[i]);
/* Set <data> 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))) { if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
j++; j++;
data.mv_size = sizeof(sval); data.mv_size = sizeof(sval);
@ -68,7 +71,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -97,7 +100,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 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) key.mv_size, (char *) key.mv_data,
(int) data.mv_size, (char *) data.mv_data); (int) data.mv_size, (char *) data.mv_data);
mdb_cursor_close(cursor);
mdb_txn_abort(txn); mdb_txn_abort(txn);
printf("Deleting with cursor\n"); 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); data.mv_data, (int) data.mv_size, (char *) data.mv_data);
} }
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(env, dbi);
mdb_env_close(env); mdb_env_close(env);
return 0; return 0;

View file

@ -47,20 +47,22 @@ int main(int argc,char * argv[])
} }
E(mdb_env_create(&env)); E(mdb_env_create(&env));
E(mdb_env_set_maxreaders(env, 1));
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); 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_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
data.mv_size = sizeof(sval);
data.mv_data = sval;
printf("Adding %d values\n", count); printf("Adding %d values\n", count);
for (i=0;i<count;i++) { for (i=0;i<count;i++) {
sprintf(sval, "%03x %d foo bar", values[i], values[i]); sprintf(sval, "%03x %d foo bar", values[i], values[i]);
data.mv_size = sizeof(sval);
data.mv_data = sval;
if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE)))
j++; j++;
} }
@ -68,7 +70,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -97,7 +99,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -114,10 +116,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -53,8 +53,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = kval; key.mv_data = kval;
@ -73,7 +74,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -107,7 +108,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -124,10 +125,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -51,8 +51,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi)); E(mdb_dbi_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = kval; key.mv_data = kval;
@ -72,7 +73,7 @@ int main(int argc,char * argv[])
/* there should be one full page of dups now. /* there should be one full page of dups now.
*/ */
E(mdb_txn_begin(env, NULL, 1, &txn)); E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -142,7 +143,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -159,10 +160,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -53,8 +53,9 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
@ -75,7 +76,7 @@ int main(int argc,char * argv[])
E(mdb_txn_commit(txn)); E(mdb_txn_commit(txn));
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
printf("key: %p %.*s, data: %p %.*s\n", printf("key: %p %.*s, data: %p %.*s\n",
@ -109,7 +110,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -126,10 +127,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_env_close(env);
mdb_dbi_close(env, dbi);
mdb_env_close(env);
return 0; return 0;
} }

View file

@ -31,7 +31,7 @@ int main(int argc,char * argv[])
int i = 0, j = 0, rc; int i = 0, j = 0, rc;
MDB_env *env; MDB_env *env;
MDB_dbi dbi; MDB_dbi dbi;
MDB_val key, data; MDB_val key, data, sdata;
MDB_txn *txn; MDB_txn *txn;
MDB_stat mst; MDB_stat mst;
MDB_cursor *cursor; MDB_cursor *cursor;
@ -46,33 +46,37 @@ int main(int argc,char * argv[])
E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_mapsize(env, 10485760));
E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_set_maxdbs(env, 4));
E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_txn_begin(env, NULL, 0, &txn));
E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi));
E(mdb_cursor_open(txn, dbi, &cursor)); E(mdb_cursor_open(txn, dbi, &cursor));
E(mdb_stat(txn, dbi, &mst)); E(mdb_stat(txn, dbi, &mst));
sval = calloc(1, mst.ms_psize / 4); sval = calloc(1, mst.ms_psize / 4);
key.mv_size = sizeof(long); key.mv_size = sizeof(long);
key.mv_data = &kval; key.mv_data = &kval;
data.mv_size = mst.ms_psize / 4 - 30; sdata.mv_size = mst.ms_psize / 4 - 30;
data.mv_data = sval; sdata.mv_data = sval;
printf("Adding 12 values, should yield 3 splits\n"); printf("Adding 12 values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5; kval = i*5;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
printf("Adding 12 more values, should yield 3 splits\n"); printf("Adding 12 more values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5+4; kval = i*5+4;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
printf("Adding 12 more values, should yield 3 splits\n"); printf("Adding 12 more values, should yield 3 splits\n");
for (i=0;i<12;i++) { for (i=0;i<12;i++) {
kval = i*5+1; kval = i*5+1;
sprintf(sval, "%08x", kval); sprintf(sval, "%08x", kval);
data = sdata;
(void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
} }
E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST));
@ -110,7 +114,7 @@ int main(int argc,char * argv[])
printf("Deleted %d values\n", j); printf("Deleted %d values\n", j);
E(mdb_env_stat(env, &mst)); 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)); E(mdb_cursor_open(txn, dbi, &cursor));
printf("Cursor next\n"); printf("Cursor next\n");
while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
@ -127,9 +131,9 @@ int main(int argc,char * argv[])
} }
CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn); mdb_txn_abort(txn);
mdb_dbi_close(env, dbi);
#endif #endif
mdb_env_close(env); mdb_env_close(env);

View file

@ -32,7 +32,7 @@ int main(int argc,char * argv[])
rc = mdb_env_create(&env); rc = mdb_env_create(&env);
rc = mdb_env_open(env, "./testdb", 0, 0664); rc = mdb_env_open(env, "./testdb", 0, 0664);
rc = mdb_txn_begin(env, NULL, 0, &txn); rc = mdb_txn_begin(env, NULL, 0, &txn);
rc = mdb_open(txn, NULL, 0, &dbi); rc = mdb_dbi_open(txn, NULL, 0, &dbi);
key.mv_size = sizeof(int); key.mv_size = sizeof(int);
key.mv_data = sval; key.mv_data = sval;
@ -56,7 +56,7 @@ int main(int argc,char * argv[])
mdb_cursor_close(cursor); mdb_cursor_close(cursor);
mdb_txn_abort(txn); mdb_txn_abort(txn);
leave: leave:
mdb_close(env, dbi); mdb_dbi_close(env, dbi);
mdb_env_close(env); mdb_env_close(env);
return 0; return 0;
} }