Codebase list lmdb / 4e9e47d
Merge tag 'upstream/0.9.14' Upstream version 0.9.14 Ondřej Surý 9 years ago
28 changed file(s) with 2998 addition(s) and 919 deletion(s). Raw diff Collapse all Expand all
44 mdb_stat
55 *.[ao]
66 *.so
7 *.exe
78 *[~#]
89 *.bak
910 *.orig
1011 *.rej
12 *.gcov
13 *.gcda
14 *.gcno
1115 core
1216 core.*
1317 valgrind.*
00 LMDB 0.9 Change Log
1
2 LMDB 0.9.14 Release (2014/09/20)
3 Fix to support 64K page size (ITS#7713)
4 Fix to persist decreased as well as increased mapsizes (ITS#7789)
5 Fix cursor bug when deleting last node of a DUPSORT key
6 Fix mdb_env_info to return FIXEDMAP address
7 Fix ambiguous error code from writing to closed DBI (ITS#7825)
8 Fix mdb_copy copying past end of file (ITS#7886)
9 Fix cursor bugs from page_merge/rebalance
10 Fix to dirty fewer pages in deletes (mdb_page_loose())
11 Fix mdb_dbi_open creating subDBs (ITS#7917)
12 Fix mdb_cursor_get(_DUP) with single value (ITS#7913)
13 Fix Windows compat issues in mtests (ITS#7879)
14 Add compacting variant of mdb_copy
15 Add BigEndian integer key compare code
16 Add mdb_dump/mdb_load utilities
17
18 LMDB 0.9.13 Release (2014/06/18)
19 Fix mdb_page_alloc unlimited overflow page search
20 Documentation
21 Re-fix MDB_CURRENT doc (ITS#7793)
22 Fix MDB_GET_MULTIPLE/MDB_NEXT_MULTIPLE doc
23
24 LMDB 0.9.12 Release (2014/06/13)
25 Fix MDB_GET_BOTH regression (ITS#7875,#7681)
26 Fix MDB_MULTIPLE writing multiple keys (ITS#7834)
27 Fix mdb_rebalance (ITS#7829)
28 Fix mdb_page_split (ITS#7815)
29 Fix md_entries count (ITS#7861,#7828,#7793)
30 Fix MDB_CURRENT (ITS#7793)
31 Fix possible crash on Windows DLL detach
32 Misc code cleanup
33 Documentation
34 mdb_cursor_put: cursor moves on error (ITS#7771)
35
136
237 LMDB 0.9.11 Release (2014/01/15)
338 Add mdb_env_set_assert() (ITS#7775)
0 Copyright 2011-2013 Howard Chu, Symas Corp.
0 Copyright 2011-2014 Howard Chu, Symas Corp.
11 All rights reserved.
22
33 Redistribution and use in source and binary forms, with or without
2424 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
2525 # by quotes) that should identify the project.
2626
27 PROJECT_NAME = MDB
27 PROJECT_NAME = LMDB
2828
2929 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
3030 # This could be handy for archiving the generated documentation or
14031403 # If a tag file is not located in the directory in which doxygen
14041404 # is run, you must also specify the path to the tagfile here.
14051405
1406 TAGFILES =
1406 TAGFILES = tooltag=./man1
14071407
14081408 # When a file name is specified after GENERATE_TAGFILE, doxygen will create
14091409 # a tag file that is based on the input files it reads.
1616 # read mdb.c before changing any of them.
1717 #
1818 CC = gcc
19 W = -W -Wall -Wno-unused-parameter -Wbad-function-cast
19 W = -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized
2020 THREADS = -pthread
2121 OPT = -O2 -g
2222 CFLAGS = $(THREADS) $(OPT) $(W) $(XCFLAGS)
2828
2929 IHDRS = lmdb.h
3030 ILIBS = liblmdb.a liblmdb.so
31 IPROGS = mdb_stat mdb_copy
32 IDOCS = mdb_stat.1 mdb_copy.1
31 IPROGS = mdb_stat mdb_copy mdb_dump mdb_load
32 IDOCS = mdb_stat.1 mdb_copy.1 mdb_dump.1 mdb_load.1
3333 PROGS = $(IPROGS) mtest mtest2 mtest3 mtest4 mtest5
3434 all: $(ILIBS) $(PROGS)
3535
5555
5656 mdb_stat: mdb_stat.o liblmdb.a
5757 mdb_copy: mdb_copy.o liblmdb.a
58 mdb_dump: mdb_dump.o liblmdb.a
59 mdb_load: mdb_load.o liblmdb.a
5860 mtest: mtest.o liblmdb.a
5961 mtest2: mtest2.o liblmdb.a
6062 mtest3: mtest3.o liblmdb.a
7375
7476 %.o: %.c lmdb.h
7577 $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
78
79 COV_FLAGS=-fprofile-arcs -ftest-coverage
80 COV_OBJS=xmdb.o xmidl.o
81
82 coverage: xmtest
83 for i in mtest*.c [0-9]*.c; do j=`basename \$$i .c`; $(MAKE) $$j.o; \
84 gcc -o x$$j $$j.o $(COV_OBJS) -pthread $(COV_FLAGS); \
85 rm -rf testdb; mkdir testdb; ./x$$j; done
86 gcov xmdb.c
87 gcov xmidl.c
88
89 xmtest: mtest.o xmdb.o xmidl.o
90 gcc -o xmtest mtest.o xmdb.o xmidl.o -pthread $(COV_FLAGS)
91
92 xmdb.o: mdb.c lmdb.h midl.h
93 $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c mdb.c -o $@
94
95 xmidl.o: midl.c midl.h
96 $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -O0 $(COV_FLAGS) -c midl.c -o $@
00 /** @file lmdb.h
11 * @brief Lightning memory-mapped database library
22 *
3 * @mainpage Lightning Memory-Mapped Database Manager (MDB)
3 * @mainpage Lightning Memory-Mapped Database Manager (LMDB)
44 *
55 * @section intro_sec Introduction
6 * MDB is a Btree-based database management library modeled loosely on the
6 * LMDB is a Btree-based database management library modeled loosely on the
77 * BerkeleyDB API, but much simplified. The entire database is exposed
88 * in a memory map, and all data fetches return data directly
99 * from the mapped memory, so no malloc's or memcpy's occur during
2525 * readers, and readers don't block writers.
2626 *
2727 * Unlike other well-known database mechanisms which use either write-ahead
28 * transaction logs or append-only data writes, MDB requires no maintenance
28 * transaction logs or append-only data writes, LMDB requires no maintenance
2929 * during operation. Both write-ahead loggers and append-only databases
3030 * require periodic checkpointing and/or compaction of their log or database
31 * files otherwise they grow without bound. MDB tracks free pages within
31 * files otherwise they grow without bound. LMDB tracks free pages within
3232 * the database and re-uses them for new write operations, so the database
3333 * size does not grow without bound in normal use.
3434 *
4848 * stale locks can block further operation.
4949 *
5050 * Fix: Check for stale readers periodically, using the
51 * #mdb_reader_check function or the mdb_stat tool. Or just
51 * #mdb_reader_check function or the \ref mdb_stat_1 "mdb_stat" tool. Or just
5252 * make all programs using the database close it; the lockfile
5353 * is always reset on first open of the environment.
5454 *
8585 *
8686 * - Use an MDB_env* in the process which opened it, without fork()ing.
8787 *
88 * - Do not have open an MDB database twice in the same process at
88 * - Do not have open an LMDB database twice in the same process at
8989 * the same time. Not even from a plain open() call - close()ing it
9090 * breaks flock() advisory locking.
9191 *
108108 * - If you do that anyway, do a periodic check for stale readers. Or
109109 * close the environment once in a while, so the lockfile can get reset.
110110 *
111 * - Do not use MDB databases on remote filesystems, even between
111 * - Do not use LMDB databases on remote filesystems, even between
112112 * processes on the same host. This breaks flock() on some OSes,
113113 * possibly memory map sync, and certainly sync between programs
114114 * on different hosts.
118118 *
119119 * @author Howard Chu, Symas Corporation.
120120 *
121 * @copyright Copyright 2011-2013 Howard Chu, Symas Corp. All rights reserved.
121 * @copyright Copyright 2011-2014 Howard Chu, Symas Corp. All rights reserved.
122122 *
123123 * Redistribution and use in source and binary forms, with or without
124124 * modification, are permitted only as authorized by the OpenLDAP
171171 typedef int mdb_filehandle_t;
172172 #endif
173173
174 /** @defgroup mdb MDB API
174 /** @defgroup mdb LMDB API
175175 * @{
176176 * @brief OpenLDAP Lightning Memory-Mapped Database Manager
177177 */
183183 /** Library minor version */
184184 #define MDB_VERSION_MINOR 9
185185 /** Library patch version */
186 #define MDB_VERSION_PATCH 11
186 #define MDB_VERSION_PATCH 14
187187
188188 /** Combine args a,b,c into a single integer for easy version comparisons */
189189 #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c))
193193 MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH)
194194
195195 /** The release date of this library version */
196 #define MDB_VERSION_DATE "January 15, 2014"
196 #define MDB_VERSION_DATE "September 20, 2014"
197197
198198 /** A stringifier for the version info */
199 #define MDB_VERSTR(a,b,c,d) "MDB " #a "." #b "." #c ": (" d ")"
199 #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")"
200200
201201 /** A helper for the stringifier macro */
202202 #define MDB_VERFOO(a,b,c,d) MDB_VERSTR(a,b,c,d)
332332 #define MDB_MULTIPLE 0x80000
333333 /* @} */
334334
335 /** @defgroup mdb_copy Copy Flags
336 * @{
337 */
338 /** Compacting copy: Omit free space from copy, and renumber all
339 * pages sequentially.
340 */
341 #define MDB_CP_COMPACT 0x01
342 /* @} */
343
335344 /** @brief Cursor Get operations.
336345 *
337346 * This is the set of all operations for retrieving data
344353 MDB_GET_BOTH, /**< Position at key/data pair. Only for #MDB_DUPSORT */
345354 MDB_GET_BOTH_RANGE, /**< position at key, nearest data. Only for #MDB_DUPSORT */
346355 MDB_GET_CURRENT, /**< Return key/data at current cursor position */
347 MDB_GET_MULTIPLE, /**< Return all the duplicate data items at the current
348 cursor position. Only for #MDB_DUPFIXED */
356 MDB_GET_MULTIPLE, /**< Return key and up to a page of duplicate data items
357 from current cursor position. Move cursor to prepare
358 for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
349359 MDB_LAST, /**< Position at last key/data item */
350360 MDB_LAST_DUP, /**< Position at last data item of current key.
351361 Only for #MDB_DUPSORT */
352362 MDB_NEXT, /**< Position at next data item */
353363 MDB_NEXT_DUP, /**< Position at next data item of current key.
354364 Only for #MDB_DUPSORT */
355 MDB_NEXT_MULTIPLE, /**< Return all duplicate data items at the next
356 cursor position. Only for #MDB_DUPFIXED */
365 MDB_NEXT_MULTIPLE, /**< Return key and up to a page of duplicate data items
366 from next cursor position. Move cursor to prepare
367 for #MDB_NEXT_MULTIPLE. Only for #MDB_DUPFIXED */
357368 MDB_NEXT_NODUP, /**< Position at first data item of next key */
358369 MDB_PREV, /**< Position at previous data item */
359370 MDB_PREV_DUP, /**< Position at previous data item of current key.
383394 #define MDB_PANIC (-30795)
384395 /** Environment version mismatch */
385396 #define MDB_VERSION_MISMATCH (-30794)
386 /** File is not a valid MDB file */
397 /** File is not a valid LMDB file */
387398 #define MDB_INVALID (-30793)
388399 /** Environment mapsize reached */
389400 #define MDB_MAP_FULL (-30792)
407418 #define MDB_BAD_RSLOT (-30783)
408419 /** Transaction cannot recover - it must be aborted */
409420 #define MDB_BAD_TXN (-30782)
410 /** Too big key/data, key is empty, or wrong DUPFIXED size */
421 /** Unsupported size of key/DB name/data, or wrong DUPFIXED size */
411422 #define MDB_BAD_VALSIZE (-30781)
412 #define MDB_LAST_ERRCODE MDB_BAD_VALSIZE
423 /** The specified DBI was changed unexpectedly */
424 #define MDB_BAD_DBI (-30780)
425 /** The last defined error code */
426 #define MDB_LAST_ERRCODE MDB_BAD_DBI
413427 /** @} */
414428
415429 /** @brief Statistics for a database in the environment */
433447 unsigned int me_numreaders; /**< max reader slots used in the environment */
434448 } MDB_envinfo;
435449
436 /** @brief Return the mdb library version information.
450 /** @brief Return the LMDB library version information.
437451 *
438452 * @param[out] major if non-NULL, the library major version number is copied here
439453 * @param[out] minor if non-NULL, the library minor version number is copied here
447461 * This function is a superset of the ANSI C X3.159-1989 (ANSI C) strerror(3)
448462 * function. If the error code is greater than or equal to 0, then the string
449463 * returned by the system function strerror(3) is returned. If the error code
450 * is less than 0, an error string corresponding to the MDB library error is
451 * returned. See @ref errors for a list of MDB-specific error codes.
464 * is less than 0, an error string corresponding to the LMDB library error is
465 * returned. See @ref errors for a list of LMDB-specific error codes.
452466 * @param[in] err The error code
453467 * @retval "error message" The description of the error
454468 */
455469 char *mdb_strerror(int err);
456470
457 /** @brief Create an MDB environment handle.
471 /** @brief Create an LMDB environment handle.
458472 *
459473 * This function allocates memory for a #MDB_env structure. To release
460474 * the allocated memory and discard the handle, call #mdb_env_close().
487501 * how the operating system has allocated memory to shared libraries and other uses.
488502 * The feature is highly experimental.
489503 * <li>#MDB_NOSUBDIR
490 * By default, MDB creates its environment in a directory whose
504 * By default, LMDB creates its environment in a directory whose
491505 * pathname is given in \b path, and creates its data and lock files
492506 * under that directory. With this option, \b path is used as-is for
493507 * the database main data file. The database lock file is the \b path
494508 * with "-lock" appended.
495509 * <li>#MDB_RDONLY
496510 * Open the environment in read-only mode. No write operations will be
497 * allowed. MDB will still modify the lock file - except on read-only
498 * filesystems, where MDB does not use locks.
511 * allowed. LMDB will still modify the lock file - except on read-only
512 * filesystems, where LMDB does not use locks.
499513 * <li>#MDB_WRITEMAP
500514 * Use a writeable memory map unless MDB_RDONLY is set. This is faster
501515 * and uses fewer mallocs, but loses protection from application bugs
539553 * the user synchronizes its use. Applications that multiplex many
540554 * user threads over individual OS threads need this option. Such an
541555 * application must also serialize the write transactions in an OS
542 * thread, since MDB's write locking is unaware of the user threads.
556 * thread, since LMDB's write locking is unaware of the user threads.
543557 * <li>#MDB_NOLOCK
544558 * Don't do any locking. If concurrent access is anticipated, the
545559 * caller must manage all concurrency itself. For proper operation
578592 * @return A non-zero error value on failure and 0 on success. Some possible
579593 * errors are:
580594 * <ul>
581 * <li>#MDB_VERSION_MISMATCH - the version of the MDB library doesn't match the
595 * <li>#MDB_VERSION_MISMATCH - the version of the LMDB library doesn't match the
582596 * version that created the database environment.
583597 * <li>#MDB_INVALID - the environment file headers are corrupted.
584598 * <li>ENOENT - the directory specified by the path parameter doesn't exist.
588602 */
589603 int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode);
590604
591 /** @brief Copy an MDB environment to the specified path.
605 /** @brief Copy an LMDB environment to the specified path.
592606 *
593607 * This function may be used to make a backup of an existing environment.
594608 * No lockfile is created, since it gets recreated at need.
604618 */
605619 int mdb_env_copy(MDB_env *env, const char *path);
606620
607 /** @brief Copy an MDB environment to the specified file descriptor.
621 /** @brief Copy an LMDB environment to the specified file descriptor.
608622 *
609623 * This function may be used to make a backup of an existing environment.
610624 * No lockfile is created, since it gets recreated at need.
619633 */
620634 int mdb_env_copyfd(MDB_env *env, mdb_filehandle_t fd);
621635
622 /** @brief Return statistics about the MDB environment.
636 /** @brief Copy an LMDB environment to the specified path, with options.
637 *
638 * This function may be used to make a backup of an existing environment.
639 * No lockfile is created, since it gets recreated at need.
640 * @note This call can trigger significant file size growth if run in
641 * parallel with write transactions, because it employs a read-only
642 * transaction. See long-lived transactions under @ref caveats_sec.
643 * @param[in] env An environment handle returned by #mdb_env_create(). It
644 * must have already been opened successfully.
645 * @param[in] path The directory in which the copy will reside. This
646 * directory must already exist and be writable but must otherwise be
647 * empty.
648 * @param[in] flags Special options for this operation. This parameter
649 * must be set to 0 or by bitwise OR'ing together one or more of the
650 * values described here.
651 * <ul>
652 * <li>#MDB_CP_COMPACT - Perform compaction while copying: omit free
653 * pages and sequentially renumber all pages in output. This option
654 * consumes more CPU and runs more slowly than the default.
655 * </ul>
656 * @return A non-zero error value on failure and 0 on success.
657 */
658 int mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags);
659
660 /** @brief Copy an LMDB environment to the specified file descriptor,
661 * with options.
662 *
663 * This function may be used to make a backup of an existing environment.
664 * No lockfile is created, since it gets recreated at need. See
665 * #mdb_env_copy2() for further details.
666 * @note This call can trigger significant file size growth if run in
667 * parallel with write transactions, because it employs a read-only
668 * transaction. See long-lived transactions under @ref caveats_sec.
669 * @param[in] env An environment handle returned by #mdb_env_create(). It
670 * must have already been opened successfully.
671 * @param[in] fd The filedescriptor to write the copy to. It must
672 * have already been opened for Write access.
673 * @param[in] flags Special options for this operation.
674 * See #mdb_env_copy2() for options.
675 * @return A non-zero error value on failure and 0 on success.
676 */
677 int mdb_env_copyfd2(MDB_env *env, mdb_filehandle_t fd, unsigned int flags);
678
679 /** @brief Return statistics about the LMDB environment.
623680 *
624681 * @param[in] env An environment handle returned by #mdb_env_create()
625682 * @param[out] stat The address of an #MDB_stat structure
627684 */
628685 int mdb_env_stat(MDB_env *env, MDB_stat *stat);
629686
630 /** @brief Return information about the MDB environment.
687 /** @brief Return information about the LMDB environment.
631688 *
632689 * @param[in] env An environment handle returned by #mdb_env_create()
633690 * @param[out] stat The address of an #MDB_envinfo structure
638695 /** @brief Flush the data buffers to disk.
639696 *
640697 * Data is always written to disk when #mdb_txn_commit() is called,
641 * but the operating system may keep it buffered. MDB always flushes
698 * but the operating system may keep it buffered. LMDB always flushes
642699 * the OS buffers upon commit as well, unless the environment was
643700 * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC.
644701 * @param[in] env An environment handle returned by #mdb_env_create()
667724 /** @brief Set environment flags.
668725 *
669726 * This may be used to set some flags in addition to those from
670 * #mdb_env_open(), or to unset these flags.
727 * #mdb_env_open(), or to unset these flags. If several threads
728 * change the flags at the same time, the result is undefined.
671729 * @param[in] env An environment handle returned by #mdb_env_create()
672730 * @param[in] flags The flags to change, bitwise OR'ed together
673731 * @param[in] onoff A non-zero value sets the flags, zero clears them.
728786 * this process. Note that the library does not check for this condition,
729787 * the caller must ensure it explicitly.
730788 *
731 * If the mapsize is changed by another process, #mdb_txn_begin() will
789 * The new size takes effect immediately for the current process but
790 * will not be persisted to any others until a write transaction has been
791 * committed by the current process. Also, only mapsize increases are
792 * persisted into the environment.
793 *
794 * If the mapsize is increased by another process, and data has grown
795 * beyond the range of the current mapsize, #mdb_txn_begin() will
732796 * return #MDB_MAP_RESIZED. This function may be called with a size
733797 * of zero to adopt the new size.
734798 *
782846 * environment. Simpler applications that use the environment as a single
783847 * unnamed database can ignore this option.
784848 * This function may only be called after #mdb_env_create() and before #mdb_env_open().
849 *
850 * Currently a moderate number of slots are cheap but a huge number gets
851 * expensive: 7-120 words per transaction, and every #mdb_dbi_open()
852 * does a linear search of the opened slots.
785853 * @param[in] env An environment handle returned by #mdb_env_create()
786854 * @param[in] dbs The maximum number of databases
787855 * @return A non-zero error value on failure and 0 on success. Some possible
816884 */
817885 void *mdb_env_get_userctx(MDB_env *env);
818886
819 /** @brief A callback function for most MDB assert() failures,
887 /** @brief A callback function for most LMDB assert() failures,
820888 * called before printing the message and aborting.
821889 *
822890 * @param[in] env An environment handle returned by #mdb_env_create().
828896 * Disabled if liblmdb is buillt with NDEBUG.
829897 * @note This hack should become obsolete as lmdb's error handling matures.
830898 * @param[in] env An environment handle returned by #mdb_env_create().
831 * @parem[in] func An #MDB_assert_func function, or 0.
899 * @param[in] func An #MDB_assert_func function, or 0.
832900 * @return A non-zero error value on failure and 0 on success.
833901 */
834902 int mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
9491017 * independently of whether such a database exists.
9501018 * The database handle may be discarded by calling #mdb_dbi_close().
9511019 * The old database handle is returned if the database was already open.
952 * The handle must only be closed once.
1020 * The handle may only be closed once.
9531021 * The database handle will be private to the current transaction until
9541022 * the transaction is successfully committed. If the transaction is
9551023 * aborted the handle will be closed automatically.
9611029 * use this function.
9621030 *
9631031 * To use named databases (with name != NULL), #mdb_env_set_maxdbs()
964 * must be called before opening the environment.
1032 * must be called before opening the environment. Database names
1033 * are kept as keys in the unnamed database.
9651034 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
9661035 * @param[in] name The name of the database to open. If only a single
9671036 * database is needed in the environment, this value may be NULL.
10311100 */
10321101 int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags);
10331102
1034 /** @brief Close a database handle.
1103 /** @brief Close a database handle. Normally unnecessary. Use with care:
10351104 *
10361105 * This call is not mutex protected. Handles should only be closed by
10371106 * a single thread, and only if no other threads are going to reference
10381107 * the database handle or one of its cursors any further. Do not close
10391108 * a handle if an existing transaction has modified its database.
1109 * Doing so can cause misbehavior from database corruption to errors
1110 * like MDB_BAD_VALSIZE (since the DB name is gone).
1111 *
1112 * Closing a database handle is not necessary, but lets #mdb_dbi_open()
1113 * reuse the handle value. Usually it's better to set a bigger
1114 * #mdb_env_set_maxdbs(), unless that value would be large.
1115 *
10401116 * @param[in] env An environment handle returned by #mdb_env_create()
10411117 * @param[in] dbi A database handle returned by #mdb_dbi_open()
10421118 */
10441120
10451121 /** @brief Empty or delete+close a database.
10461122 *
1123 * See #mdb_dbi_close() for restrictions about closing the DB handle.
10471124 * @param[in] txn A transaction handle returned by #mdb_txn_begin()
10481125 * @param[in] dbi A database handle returned by #mdb_dbi_open()
10491126 * @param[in] del 0 to empty the DB, 1 to delete it from the
11891266 * reserved space, which the caller can fill in later - before
11901267 * the next update operation or the transaction ends. This saves
11911268 * an extra memcpy if the data is being generated later.
1192 * MDB does nothing else with this memory, the caller is expected
1269 * LMDB does nothing else with this memory, the caller is expected
11931270 * to modify all of the space requested.
11941271 * <li>#MDB_APPEND - append the given key/data pair to the end of the
11951272 * database. No key comparisons are performed. This option allows
13211398 /** @brief Store by cursor.
13221399 *
13231400 * This function stores key/data pairs into the database.
1324 * If the function fails for any reason, the state of the cursor will be
1325 * unchanged. If the function succeeds and an item is inserted into the
1326 * database, the cursor is always positioned to refer to the newly inserted item.
1401 * The cursor is positioned at the new item, or on failure usually near it.
1402 * @note Earlier documentation incorrectly said errors would leave the
1403 * state of the cursor unchanged.
13271404 * @param[in] cursor A cursor handle returned by #mdb_cursor_open()
13281405 * @param[in] key The key operated on.
13291406 * @param[in] data The data operated on.
13301407 * @param[in] flags Options for this operation. This parameter
13311408 * must be set to 0 or one of the values described here.
13321409 * <ul>
1333 * <li>#MDB_CURRENT - overwrite the data of the key/data pair to which
1334 * the cursor refers with the specified data item. The \b key
1335 * parameter is ignored.
1410 * <li>#MDB_CURRENT - replace the item at the current cursor position.
1411 * The \b key parameter must still be provided, and must match it.
1412 * If using sorted duplicates (#MDB_DUPSORT) the data item must still
1413 * sort into the same place. This is intended to be used when the
1414 * new data is the same size as the old. Otherwise it will simply
1415 * perform a delete of the old record followed by an insert.
13361416 * <li>#MDB_NODUPDATA - enter the new key/data pair only if it does not
13371417 * already appear in the database. This flag may only be specified
13381418 * if the database was opened with #MDB_DUPSORT. The function will
14611541 #ifdef __cplusplus
14621542 }
14631543 #endif
1544 /** @page tools LMDB Command Line Tools
1545 The following describes the command line tools that are available for LMDB.
1546 \li \ref mdb_copy_1
1547 \li \ref mdb_dump_1
1548 \li \ref mdb_load_1
1549 \li \ref mdb_stat_1
1550 */
1551
14641552 #endif /* _LMDB_H_ */
00 /** @file mdb.c
1 * @brief memory-mapped database library
1 * @brief Lightning memory-mapped database library
22 *
33 * A Btree-based database management library modeled loosely on the
44 * BerkeleyDB API, but much simplified.
55 */
66 /*
7 * Copyright 2011-2013 Howard Chu, Symas Corp.
7 * Copyright 2011-2014 Howard Chu, Symas Corp.
88 * All rights reserved.
99 *
1010 * Redistribution and use in source and binary forms, with or without
3434 #ifndef _GNU_SOURCE
3535 #define _GNU_SOURCE 1
3636 #endif
37 #include <sys/types.h>
38 #include <sys/stat.h>
3937 #ifdef _WIN32
38 #include <malloc.h>
4039 #include <windows.h>
4140 /** getpid() returns int; MinGW defines pid_t but MinGW64 typedefs it
4241 * as int64 which is wrong. MSVC doesn't define it at all, so just
4342 * don't use it.
4443 */
4544 #define MDB_PID_T int
45 #define MDB_THR_T DWORD
46 #include <sys/types.h>
47 #include <sys/stat.h>
4648 #ifdef __GNUC__
4749 # include <sys/param.h>
4850 #else
5456 # endif
5557 #endif
5658 #else
59 #include <sys/types.h>
60 #include <sys/stat.h>
5761 #define MDB_PID_T pid_t
62 #define MDB_THR_T pthread_t
5863 #include <sys/param.h>
5964 #include <sys/uio.h>
6065 #include <sys/mman.h>
6368 #endif
6469 #include <fcntl.h>
6570 #endif
71
72 #if defined(__mips) && defined(__linux)
73 /* MIPS has cache coherency issues, requires explicit cache control */
74 #include <asm/cachectl.h>
75 extern int cacheflush(char *addr, int nbytes, int cache);
76 #define CACHEFLUSH(addr, bytes, cache) cacheflush(addr, bytes, cache)
77 #else
78 #define CACHEFLUSH(addr, bytes, cache)
79 #endif
80
6681
6782 #include <errno.h>
6883 #include <limits.h>
7388 #include <string.h>
7489 #include <time.h>
7590 #include <unistd.h>
91
92 #if defined(__sun)
93 /* Most platforms have posix_memalign, older may only have memalign */
94 #define HAVE_MEMALIGN 1
95 #include <malloc.h>
96 #endif
7697
7798 #if !(defined(BYTE_ORDER) || defined(__BYTE_ORDER))
7899 #include <netinet/in.h>
144165 # error "Two's complement, reasonably sized integer types, please"
145166 #endif
146167
147 /** @defgroup internal MDB Internals
168 #ifdef __GNUC__
169 /** Put infrequently used env functions in separate section */
170 # ifdef __APPLE__
171 # define ESECT __attribute__ ((section("__TEXT,text_env")))
172 # else
173 # define ESECT __attribute__ ((section("text_env")))
174 # endif
175 #else
176 #define ESECT
177 #endif
178
179 /** @defgroup internal LMDB Internals
148180 * @{
149181 */
150182 /** @defgroup compat Compatibility Macros
155187 * @{
156188 */
157189
190 /** Features under development */
191 #ifndef MDB_DEVEL
192 #define MDB_DEVEL 0
193 #endif
194
158195 /** Wrapper around __func__, which is a C99 feature */
159196 #if __STDC_VERSION__ >= 199901L
160197 # define mdb_func_ __func__
168205 #ifdef _WIN32
169206 #define MDB_USE_HASH 1
170207 #define MDB_PIDLOCK 0
171 #define pthread_t DWORD
208 #define THREAD_RET DWORD
209 #define pthread_t HANDLE
172210 #define pthread_mutex_t HANDLE
211 #define pthread_cond_t HANDLE
173212 #define pthread_key_t DWORD
174213 #define pthread_self() GetCurrentThreadId()
175214 #define pthread_key_create(x,y) \
177216 #define pthread_key_delete(x) TlsFree(x)
178217 #define pthread_getspecific(x) TlsGetValue(x)
179218 #define pthread_setspecific(x,y) (TlsSetValue(x,y) ? 0 : ErrCode())
180 #define pthread_mutex_unlock(x) ReleaseMutex(x)
181 #define pthread_mutex_lock(x) WaitForSingleObject(x, INFINITE)
182 #define LOCK_MUTEX_R(env) pthread_mutex_lock((env)->me_rmutex)
183 #define UNLOCK_MUTEX_R(env) pthread_mutex_unlock((env)->me_rmutex)
184 #define LOCK_MUTEX_W(env) pthread_mutex_lock((env)->me_wmutex)
185 #define UNLOCK_MUTEX_W(env) pthread_mutex_unlock((env)->me_wmutex)
219 #define pthread_mutex_unlock(x) ReleaseMutex(*x)
220 #define pthread_mutex_lock(x) WaitForSingleObject(*x, INFINITE)
221 #define pthread_cond_signal(x) SetEvent(*x)
222 #define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0)
223 #define THREAD_CREATE(thr,start,arg) thr=CreateThread(NULL,0,start,arg,0,NULL)
224 #define THREAD_FINISH(thr) WaitForSingleObject(thr, INFINITE)
225 #define LOCK_MUTEX_R(env) pthread_mutex_lock(&(env)->me_rmutex)
226 #define UNLOCK_MUTEX_R(env) pthread_mutex_unlock(&(env)->me_rmutex)
227 #define LOCK_MUTEX_W(env) pthread_mutex_lock(&(env)->me_wmutex)
228 #define UNLOCK_MUTEX_W(env) pthread_mutex_unlock(&(env)->me_wmutex)
186229 #define getpid() GetCurrentProcessId()
187230 #define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd))
188231 #define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len))
197240 #endif
198241 #define Z "I"
199242 #else
200
243 #define THREAD_RET void *
244 #define THREAD_CREATE(thr,start,arg) pthread_create(&thr,NULL,start,arg)
245 #define THREAD_FINISH(thr) pthread_join(thr,NULL)
201246 #define Z "z" /**< printf format modifier for size_t */
202247
203248 /** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */
351396
352397 /** @brief The maximum size of a database page.
353398 *
354 * This is 32k, since it must fit in #MDB_page.#mp_upper.
399 * It is 32k or 64k, since value-PAGEBASE must fit in
400 * #MDB_page.%mp_upper.
355401 *
356402 * LMDB will use database pages < OS pages if needed.
357403 * That causes more I/O in write transactions: The OS must
364410 * pressure from other processes is high. So until OSs have
365411 * actual paging support for Huge pages, they're not viable.
366412 */
367 #define MAX_PAGESIZE 0x8000
413 #define MAX_PAGESIZE (PAGEBASE ? 0x10000 : 0x8000)
368414
369415 /** The minimum number of keys required in a database page.
370416 * Setting this to a larger value will place a smaller bound on the
380426 */
381427 #define MDB_MINKEYS 2
382428
383 /** A stamp that identifies a file as an MDB file.
429 /** A stamp that identifies a file as an LMDB file.
384430 * There's nothing special about this value other than that it is easily
385431 * recognizable, and it will reflect any byte order mismatches.
386432 */
387433 #define MDB_MAGIC 0xBEEFC0DE
388434
389435 /** The version number for a database's datafile format. */
390 #define MDB_DATA_VERSION 1
436 #define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1)
391437 /** The version number for a database's lockfile format. */
392438 #define MDB_LOCK_VERSION 1
393439
396442 * Define this as 0 to compute the max from the page size. 511
397443 * is default for backwards compat: liblmdb <= 0.9.10 can break
398444 * when modifying a DB with keys/dupsort data bigger than its max.
445 * #MDB_DEVEL sets the default to 0.
399446 *
400447 * Data items in an #MDB_DUPSORT database are also limited to
401448 * this size, since they're actually keys of a sub-DB. Keys and
402449 * #MDB_DUPSORT data items must fit on a node in a regular page.
403450 */
404451 #ifndef MDB_MAXKEYSIZE
405 #define MDB_MAXKEYSIZE 511
452 #define MDB_MAXKEYSIZE ((MDB_DEVEL) ? 0 : 511)
406453 #endif
407454
408455 /** The maximum size of a key we can write to the environment. */
536583 /** The process ID of the process owning this reader txn. */
537584 MDB_PID_T mrb_pid;
538585 /** The thread ID of the thread owning this txn. */
539 pthread_t mrb_tid;
586 MDB_THR_T mrb_tid;
540587 } MDB_rxbody;
541588
542589 /** The actual reader record, with cacheline padding. */
567614 * unlikely. If a collision occurs, the results are unpredictable.
568615 */
569616 typedef struct MDB_txbody {
570 /** Stamp identifying this as an MDB file. It must be set
617 /** Stamp identifying this as an LMDB file. It must be set
571618 * to #MDB_MAGIC. */
572619 uint32_t mtb_magic;
573620 /** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */
634681 #define mp_next mp_p.p_next
635682 union {
636683 pgno_t p_pgno; /**< page number */
637 void * p_next; /**< for in-memory list of freed structs */
684 struct MDB_page *p_next; /**< for in-memory list of freed pages */
638685 } mp_p;
639686 uint16_t mp_pad;
640687 /** @defgroup mdb_page Page Flags
649696 #define P_DIRTY 0x10 /**< dirty page, also set for #P_SUBP pages */
650697 #define P_LEAF2 0x20 /**< for #MDB_DUPFIXED records */
651698 #define P_SUBP 0x40 /**< for #MDB_DUPSORT sub-pages */
699 #define P_LOOSE 0x4000 /**< page was dirtied then freed, can be reused */
652700 #define P_KEEP 0x8000 /**< leave this page alone during spill */
653701 /** @} */
654702 uint16_t mp_flags; /**< @ref mdb_page */
671719 /** Address of first usable data byte in a page, after the header */
672720 #define METADATA(p) ((void *)((char *)(p) + PAGEHDRSZ))
673721
722 /** ITS#7713, change PAGEBASE to handle 65536 byte pages */
723 #define PAGEBASE ((MDB_DEVEL) ? PAGEHDRSZ : 0)
724
674725 /** Number of nodes on a page */
675 #define NUMKEYS(p) (((p)->mp_lower - PAGEHDRSZ) >> 1)
726 #define NUMKEYS(p) (((p)->mp_lower - (PAGEHDRSZ-PAGEBASE)) >> 1)
676727
677728 /** The amount of space remaining in the page */
678729 #define SIZELEFT(p) (indx_t)((p)->mp_upper - (p)->mp_lower)
698749
699750 /** The number of overflow pages needed to store the given size. */
700751 #define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
752
753 /** Link in #MDB_txn.%mt_loose_pgs list */
754 #define NEXT_LOOSE_PAGE(p) (*(MDB_page **)((p) + 2))
701755
702756 /** Header for a single key/data pair within a page.
703757 * Used in pages of type #P_BRANCH and #P_LEAF without #P_LEAF2.
750804 #define LEAFSIZE(k, d) (NODESIZE + (k)->mv_size + (d)->mv_size)
751805
752806 /** Address of node \b i in page \b p */
753 #define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i]))
807 #define NODEPTR(p, i) ((MDB_node *)((char *)(p) + (p)->mp_ptrs[i] + PAGEBASE))
754808
755809 /** Address of the key for the node */
756810 #define NODEKEY(node) (void *)((node)->mn_data)
840894 * Pages 0-1 are meta pages. Transaction N writes meta page #(N % 2).
841895 */
842896 typedef struct MDB_meta {
843 /** Stamp identifying this as an MDB file. It must be set
897 /** Stamp identifying this as an LMDB file. It must be set
844898 * to #MDB_MAGIC. */
845899 uint32_t mm_magic;
846900 /** Version number of this lock file. Must be set to #MDB_DATA_VERSION. */
897951 /** The list of pages that became unused during this transaction.
898952 */
899953 MDB_IDL mt_free_pgs;
954 /** The list of loose pages that became unused and may be reused
955 * in this transaction, linked through #NEXT_LOOSE_PAGE(page).
956 */
957 MDB_page *mt_loose_pgs;
958 /* #Number of loose pages (#mt_loose_pgs) */
959 int mt_loose_count;
900960 /** The sorted list of dirty pages we temporarily wrote to disk
901961 * because the dirty list was full. page numbers in here are
902962 * shifted left by 1, deleted slots have the LSB set.
912972 MDB_dbx *mt_dbxs;
913973 /** Array of MDB_db records for each known DB */
914974 MDB_db *mt_dbs;
975 /** Array of sequence numbers for each DB handle */
976 unsigned int *mt_dbiseqs;
915977 /** @defgroup mt_dbflag Transaction DB Flags
916978 * @ingroup internal
917979 * @{
935997 * @{
936998 */
937999 #define MDB_TXN_RDONLY 0x01 /**< read-only transaction */
938 #define MDB_TXN_ERROR 0x02 /**< an error has occurred */
1000 #define MDB_TXN_ERROR 0x02 /**< txn is unusable after an error */
9391001 #define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */
9401002 #define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */
9411003 /** @} */
9421004 unsigned int mt_flags; /**< @ref mdb_txn */
943 /** dirty_list room: Array size - #dirty pages visible to this txn.
1005 /** #dirty_list room: Array size - \#dirty pages visible to this txn.
9441006 * Includes ancestor txns' dirty pages not hidden by other txns'
9451007 * dirty/spilled pages. Thus commit(nested txn) has room to merge
9461008 * dirty_list into mt_parent after freeing hidden mt_parent pages.
10331095 #define MDB_ENV_ACTIVE 0x20000000U
10341096 /** me_txkey is set */
10351097 #define MDB_ENV_TXKEY 0x10000000U
1036 /** Have liveness lock in reader table */
1037 #define MDB_LIVE_READER 0x08000000U
10381098 uint32_t me_flags; /**< @ref mdb_env */
10391099 unsigned int me_psize; /**< DB page size, inited from me_os_psize */
10401100 unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */
10491109 MDB_meta *me_metas[2]; /**< pointers to the two meta pages */
10501110 void *me_pbuf; /**< scratch area for DUPSORT put() */
10511111 MDB_txn *me_txn; /**< current write transaction */
1112 MDB_txn *me_txn0; /**< prealloc'd write transaction */
10521113 size_t me_mapsize; /**< size of the data memory map */
10531114 off_t me_size; /**< current file size */
10541115 pgno_t me_maxpg; /**< me_mapsize / me_psize */
10551116 MDB_dbx *me_dbxs; /**< array of static DB info */
10561117 uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */
1118 unsigned int *me_dbiseqs; /**< array of dbi sequence numbers */
10571119 pthread_key_t me_txkey; /**< thread-key for readers */
1120 txnid_t me_pgoldest; /**< ID of oldest reader last time we looked */
10581121 MDB_pgstate me_pgstate; /**< state of old pages from freeDB */
10591122 # define me_pglast me_pgstate.mf_pglast
10601123 # define me_pghead me_pgstate.mf_pghead
10701133 #if !(MDB_MAXKEYSIZE)
10711134 unsigned int me_maxkey; /**< max size of a key */
10721135 #endif
1136 int me_live_reader; /**< have liveness lock in reader table */
10731137 #ifdef _WIN32
10741138 int me_pidquery; /**< Used in OpenProcess */
10751139 HANDLE me_rmutex; /* Windows mutexes don't reside in shared mem */
10951159 #define MDB_COMMIT_PAGES IOV_MAX
10961160 #endif
10971161
1098 /* max bytes to write in one call */
1162 /** max bytes to write in one call */
10991163 #define MAX_WRITE (0x80000000U >> (sizeof(ssize_t) == 4))
1164
1165 /** Check \b txn and \b dbi arguments to a function */
1166 #define TXN_DBI_EXIST(txn, dbi) \
1167 ((txn) && (dbi) < (txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & DB_VALID))
1168
1169 /** Check for misused \b dbi handles */
1170 #define TXN_DBI_CHANGED(txn, dbi) \
1171 ((txn)->mt_dbiseqs[dbi] != (txn)->mt_env->me_dbiseqs[dbi])
11001172
11011173 static int mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp);
11021174 static int mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp);
11411213 static void mdb_cursor_pop(MDB_cursor *mc);
11421214 static int mdb_cursor_push(MDB_cursor *mc, MDB_page *mp);
11431215
1144 static int mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf);
1216 static int mdb_cursor_del0(MDB_cursor *mc);
1217 static int mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags);
11451218 static int mdb_cursor_sibling(MDB_cursor *mc, int move_right);
11461219 static int mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
11471220 static int mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
11771250 return MDB_VERSION_STRING;
11781251 }
11791252
1180 /** Table of descriptions for MDB @ref errors */
1253 /** Table of descriptions for LMDB @ref errors */
11811254 static char *const mdb_errstr[] = {
11821255 "MDB_KEYEXIST: Key/data pair already exists",
11831256 "MDB_NOTFOUND: No matching key/data pair found",
11851258 "MDB_CORRUPTED: Located page was wrong type",
11861259 "MDB_PANIC: Update of meta page failed",
11871260 "MDB_VERSION_MISMATCH: Database environment version mismatch",
1188 "MDB_INVALID: File is not an MDB file",
1261 "MDB_INVALID: File is not an LMDB file",
11891262 "MDB_MAP_FULL: Environment mapsize limit reached",
11901263 "MDB_DBS_FULL: Environment maxdbs limit reached",
11911264 "MDB_READERS_FULL: Environment maxreaders limit reached",
11971270 "MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed",
11981271 "MDB_BAD_RSLOT: Invalid reuse of reader locktable slot",
11991272 "MDB_BAD_TXN: Transaction cannot recover - it must be aborted",
1200 "MDB_BAD_VALSIZE: Too big key/data, key is empty, or wrong DUPFIXED size",
1273 "MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED size",
1274 "MDB_BAD_DBI: The specified DBI handle was closed/changed unexpectedly",
12011275 };
12021276
12031277 char *
12041278 mdb_strerror(int err)
12051279 {
1280 #ifdef _WIN32
1281 /** HACK: pad 4KB on stack over the buf. Return system msgs in buf.
1282 * This works as long as no function between the call to mdb_strerror
1283 * and the actual use of the message uses more than 4K of stack.
1284 */
1285 char pad[4096];
1286 char buf[1024], *ptr = buf;
1287 #endif
12061288 int i;
12071289 if (!err)
12081290 return ("Successful return: 0");
12121294 return mdb_errstr[i];
12131295 }
12141296
1297 #ifdef _WIN32
1298 /* These are the C-runtime error codes we use. The comment indicates
1299 * their numeric value, and the Win32 error they would correspond to
1300 * if the error actually came from a Win32 API. A major mess, we should
1301 * have used LMDB-specific error codes for everything.
1302 */
1303 switch(err) {
1304 case ENOENT: /* 2, FILE_NOT_FOUND */
1305 case EIO: /* 5, ACCESS_DENIED */
1306 case ENOMEM: /* 12, INVALID_ACCESS */
1307 case EACCES: /* 13, INVALID_DATA */
1308 case EBUSY: /* 16, CURRENT_DIRECTORY */
1309 case EINVAL: /* 22, BAD_COMMAND */
1310 case ENOSPC: /* 28, OUT_OF_PAPER */
1311 return strerror(err);
1312 default:
1313 ;
1314 }
1315 buf[0] = 0;
1316 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1317 FORMAT_MESSAGE_IGNORE_INSERTS,
1318 NULL, err, 0, ptr, sizeof(buf), pad);
1319 return ptr;
1320 #else
12151321 return strerror(err);
1322 #endif
12161323 }
12171324
12181325 /** assert(3) variant in cursor context */
12821389 return buf;
12831390 }
12841391
1392 static const char *
1393 mdb_leafnode_type(MDB_node *n)
1394 {
1395 static char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}};
1396 return F_ISSET(n->mn_flags, F_BIGDATA) ? ": overflow page" :
1397 tp[F_ISSET(n->mn_flags, F_DUPDATA)][F_ISSET(n->mn_flags, F_SUBDATA)];
1398 }
1399
12851400 /** Display all the keys in the page. */
12861401 void
12871402 mdb_page_list(MDB_page *mp)
12881403 {
1404 pgno_t pgno = mdb_dbg_pgno(mp);
1405 const char *type, *state = (mp->mp_flags & P_DIRTY) ? ", dirty" : "";
12891406 MDB_node *node;
12901407 unsigned int i, nkeys, nsize, total = 0;
12911408 MDB_val key;
12921409 DKBUF;
12931410
1411 switch (mp->mp_flags & (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP)) {
1412 case P_BRANCH: type = "Branch page"; break;
1413 case P_LEAF: type = "Leaf page"; break;
1414 case P_LEAF|P_SUBP: type = "Sub-page"; break;
1415 case P_LEAF|P_LEAF2: type = "LEAF2 page"; break;
1416 case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page"; break;
1417 case P_OVERFLOW:
1418 fprintf(stderr, "Overflow page %"Z"u pages %u%s\n",
1419 pgno, mp->mp_pages, state);
1420 return;
1421 case P_META:
1422 fprintf(stderr, "Meta-page %"Z"u txnid %"Z"u\n",
1423 pgno, ((MDB_meta *)METADATA(mp))->mm_txnid);
1424 return;
1425 default:
1426 fprintf(stderr, "Bad page %"Z"u flags 0x%u\n", pgno, mp->mp_flags);
1427 return;
1428 }
1429
12941430 nkeys = NUMKEYS(mp);
1295 fprintf(stderr, "Page %"Z"u numkeys %d\n", mdb_dbg_pgno(mp), nkeys);
1431 fprintf(stderr, "%s %"Z"u numkeys %d%s\n", type, pgno, nkeys, state);
1432
12961433 for (i=0; i<nkeys; i++) {
1434 if (IS_LEAF2(mp)) { /* LEAF2 pages have no mp_ptrs[] or node headers */
1435 key.mv_size = nsize = mp->mp_pad;
1436 key.mv_data = LEAF2KEY(mp, i, nsize);
1437 total += nsize;
1438 fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key));
1439 continue;
1440 }
12971441 node = NODEPTR(mp, i);
12981442 key.mv_size = node->mn_ksize;
12991443 key.mv_data = node->mn_data;
13091453 nsize += NODEDSZ(node);
13101454 total += nsize;
13111455 nsize += sizeof(indx_t);
1312 fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key));
1456 fprintf(stderr, "key %d: nsize %d, %s%s\n",
1457 i, nsize, DKEY(&key), mdb_leafnode_type(node));
13131458 }
13141459 total = EVEN(total);
13151460 }
1316 fprintf(stderr, "Total: %d\n", total);
1461 fprintf(stderr, "Total: header %d + contents %d + unused %d\n",
1462 IS_LEAF2(mp) ? PAGEHDRSZ : PAGEBASE + mp->mp_lower, total, SIZELEFT(mp));
13171463 }
13181464
13191465 void
13391485 /** Count all the pages in each DB and in the freelist
13401486 * and make sure it matches the actual number of pages
13411487 * being used.
1488 * All named DBs must be open for a correct count.
13421489 */
13431490 static void mdb_audit(MDB_txn *txn)
13441491 {
13521499 mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
13531500 while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
13541501 freecount += *(MDB_ID *)data.mv_data;
1502 mdb_tassert(txn, rc == MDB_NOTFOUND);
13551503
13561504 count = 0;
13571505 for (i = 0; i<txn->mt_numdbs; i++) {
13581506 MDB_xcursor mx;
1507 if (!(txn->mt_dbflags[i] & DB_VALID))
1508 continue;
13591509 mdb_cursor_init(&mc, txn, i, &mx);
13601510 if (txn->mt_dbs[i].md_root == P_INVALID)
13611511 continue;
13631513 txn->mt_dbs[i].md_leaf_pages +
13641514 txn->mt_dbs[i].md_overflow_pages;
13651515 if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) {
1366 mdb_page_search(&mc, NULL, MDB_PS_FIRST);
1367 do {
1516 rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST);
1517 for (; rc == MDB_SUCCESS; rc = mdb_cursor_sibling(&mc, 1)) {
13681518 unsigned j;
13691519 MDB_page *mp;
13701520 mp = mc.mc_pg[mc.mc_top];
13781528 }
13791529 }
13801530 }
1381 while (mdb_cursor_sibling(&mc, 1) == 0);
1531 mdb_tassert(txn, rc == MDB_NOTFOUND);
13821532 }
13831533 }
13841534 if (freecount + count + 2 /* metapages */ != txn->mt_next_pgno) {
14371587 }
14381588 return ret;
14391589 }
1440
14411590 /** Free a single page.
14421591 * Saves single pages to a list, for future reuse.
14431592 * (This is not used for multi-page overflow pages.)
14751624 mdb_dpage_free(env, dl[i].mptr);
14761625 }
14771626 dl[0].mid = 0;
1627 }
1628
1629 /** Loosen or free a single page.
1630 * Saves single pages to a list for future reuse
1631 * in this same txn. It has been pulled from the freeDB
1632 * and already resides on the dirty list, but has been
1633 * deleted. Use these pages first before pulling again
1634 * from the freeDB.
1635 *
1636 * If the page wasn't dirtied in this txn, just add it
1637 * to this txn's free list.
1638 */
1639 static int
1640 mdb_page_loose(MDB_cursor *mc, MDB_page *mp)
1641 {
1642 int loose = 0;
1643 pgno_t pgno = mp->mp_pgno;
1644 MDB_txn *txn = mc->mc_txn;
1645
1646 if ((mp->mp_flags & P_DIRTY) && mc->mc_dbi != FREE_DBI) {
1647 if (txn->mt_parent) {
1648 MDB_ID2 *dl = txn->mt_u.dirty_list;
1649 /* If txn has a parent, make sure the page is in our
1650 * dirty list.
1651 */
1652 if (dl[0].mid) {
1653 unsigned x = mdb_mid2l_search(dl, pgno);
1654 if (x <= dl[0].mid && dl[x].mid == pgno) {
1655 if (mp != dl[x].mptr) { /* bad cursor? */
1656 mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
1657 txn->mt_flags |= MDB_TXN_ERROR;
1658 return MDB_CORRUPTED;
1659 }
1660 /* ok, it's ours */
1661 loose = 1;
1662 }
1663 }
1664 } else {
1665 /* no parent txn, so it's just ours */
1666 loose = 1;
1667 }
1668 }
1669 if (loose) {
1670 DPRINTF(("loosen db %d page %"Z"u", DDBI(mc),
1671 mp->mp_pgno));
1672 NEXT_LOOSE_PAGE(mp) = txn->mt_loose_pgs;
1673 txn->mt_loose_pgs = mp;
1674 txn->mt_loose_count++;
1675 mp->mp_flags |= P_LOOSE;
1676 } else {
1677 int rc = mdb_midl_append(&txn->mt_free_pgs, pgno);
1678 if (rc)
1679 return rc;
1680 }
1681
1682 return MDB_SUCCESS;
14781683 }
14791684
14801685 /** Set or clear P_KEEP in dirty, non-overflow, non-sub pages watched by txn.
14871692 static int
14881693 mdb_pages_xkeep(MDB_cursor *mc, unsigned pflags, int all)
14891694 {
1490 enum { Mask = P_SUBP|P_DIRTY|P_KEEP };
1695 enum { Mask = P_SUBP|P_DIRTY|P_LOOSE|P_KEEP };
14911696 MDB_txn *txn = mc->mc_txn;
14921697 MDB_cursor *m3;
14931698 MDB_xcursor *mx;
16381843 for (i=dl[0].mid; i && need; i--) {
16391844 MDB_ID pn = dl[i].mid << 1;
16401845 dp = dl[i].mptr;
1641 if (dp->mp_flags & P_KEEP)
1846 if (dp->mp_flags & (P_LOOSE|P_KEEP))
16421847 continue;
16431848 /* Can't spill twice, make sure it's not already in a parent's
16441849 * spill list.
17421947 #else
17431948 enum { Paranoid = 0, Max_retries = INT_MAX /*infinite*/ };
17441949 #endif
1745 int rc, retry = Max_retries;
1950 int rc, retry = num * 60;
17461951 MDB_txn *txn = mc->mc_txn;
17471952 MDB_env *env = txn->mt_env;
17481953 pgno_t pgno, *mop = env->me_pghead;
1749 unsigned i, j, k, mop_len = mop ? mop[0] : 0, n2 = num-1;
1954 unsigned i, j, mop_len = mop ? mop[0] : 0, n2 = num-1;
17501955 MDB_page *np;
17511956 txnid_t oldest = 0, last;
17521957 MDB_cursor_op op;
17531958 MDB_cursor m2;
1959 int found_old = 0;
1960
1961 /* If there are any loose pages, just use them */
1962 if (num == 1 && txn->mt_loose_pgs) {
1963 np = txn->mt_loose_pgs;
1964 txn->mt_loose_pgs = NEXT_LOOSE_PAGE(np);
1965 txn->mt_loose_count--;
1966 DPRINTF(("db %d use loose page %"Z"u", DDBI(mc),
1967 np->mp_pgno));
1968 *mp = np;
1969 return MDB_SUCCESS;
1970 }
17541971
17551972 *mp = NULL;
17561973
17631980 for (op = MDB_FIRST;; op = MDB_NEXT) {
17641981 MDB_val key, data;
17651982 MDB_node *leaf;
1766 pgno_t *idl, old_id, new_id;
1983 pgno_t *idl;
17671984
17681985 /* Seek a big enough contiguous page range. Prefer
17691986 * pages at the tail, just truncating the list.
17751992 if (mop[i-n2] == pgno+n2)
17761993 goto search_done;
17771994 } while (--i > n2);
1778 if (Max_retries < INT_MAX && --retry < 0)
1995 if (--retry < 0)
17791996 break;
17801997 }
17811998
17821999 if (op == MDB_FIRST) { /* 1st iteration */
17832000 /* Prepare to fetch more and coalesce */
1784 oldest = mdb_find_oldest(txn);
17852001 last = env->me_pglast;
2002 oldest = env->me_pgoldest;
17862003 mdb_cursor_init(&m2, txn, FREE_DBI, NULL);
17872004 if (last) {
17882005 op = MDB_SET_RANGE;
17972014
17982015 last++;
17992016 /* Do not fetch more if the record will be too recent */
1800 if (oldest <= last)
1801 break;
2017 if (oldest <= last) {
2018 if (!found_old) {
2019 oldest = mdb_find_oldest(txn);
2020 env->me_pgoldest = oldest;
2021 found_old = 1;
2022 }
2023 if (oldest <= last)
2024 break;
2025 }
18022026 rc = mdb_cursor_get(&m2, &key, NULL, op);
18032027 if (rc) {
18042028 if (rc == MDB_NOTFOUND)
18062030 goto fail;
18072031 }
18082032 last = *(txnid_t*)key.mv_data;
1809 if (oldest <= last)
1810 break;
2033 if (oldest <= last) {
2034 if (!found_old) {
2035 oldest = mdb_find_oldest(txn);
2036 env->me_pgoldest = oldest;
2037 found_old = 1;
2038 }
2039 if (oldest <= last)
2040 break;
2041 }
18112042 np = m2.mc_pg[m2.mc_top];
18122043 leaf = NODEPTR(np, m2.mc_ki[m2.mc_top]);
18132044 if ((rc = mdb_node_read(txn, leaf, &data)) != MDB_SUCCESS)
18292060 #if (MDB_DEBUG) > 1
18302061 DPRINTF(("IDL read txn %"Z"u root %"Z"u num %u",
18312062 last, txn->mt_dbs[FREE_DBI].md_root, i));
1832 for (k = i; k; k--)
1833 DPRINTF(("IDL %"Z"u", idl[k]));
2063 for (j = i; j; j--)
2064 DPRINTF(("IDL %"Z"u", idl[j]));
18342065 #endif
18352066 /* Merge in descending sorted order */
1836 j = mop_len;
1837 k = mop_len += i;
1838 mop[0] = (pgno_t)-1;
1839 old_id = mop[j];
1840 while (i) {
1841 new_id = idl[i--];
1842 for (; old_id < new_id; old_id = mop[--j])
1843 mop[k--] = old_id;
1844 mop[k--] = new_id;
1845 }
1846 mop[0] = mop_len;
2067 mdb_midl_xmerge(mop, idl);
2068 mop_len = mop[0];
18472069 }
18482070
18492071 /* Use new pages from the map when nothing suitable in the freeDB */
18982120 * alignment so memcpy may copy words instead of bytes.
18992121 */
19002122 if ((unused &= -Align) && !IS_LEAF2(src)) {
1901 upper &= -Align;
1902 memcpy(dst, src, (lower + (Align-1)) & -Align);
2123 upper = (upper + PAGEBASE) & -Align;
2124 memcpy(dst, src, (lower + PAGEBASE + (Align-1)) & -Align);
19032125 memcpy((pgno_t *)((char *)dst+upper), (pgno_t *)((char *)src+upper),
19042126 psize - upper);
19052127 } else {
20582280 if (m2->mc_pg[mc->mc_top] == mp) {
20592281 m2->mc_pg[mc->mc_top] = np;
20602282 if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
2283 IS_LEAF(np) &&
20612284 m2->mc_ki[mc->mc_top] == mc->mc_ki[mc->mc_top])
20622285 {
20632286 MDB_node *leaf = NODEPTR(np, mc->mc_ki[mc->mc_top]);
22652488 return MDB_BAD_RSLOT;
22662489 } else {
22672490 MDB_PID_T pid = env->me_pid;
2268 pthread_t tid = pthread_self();
2269
2270 if (!(env->me_flags & MDB_LIVE_READER)) {
2491 MDB_THR_T tid = pthread_self();
2492
2493 if (!env->me_live_reader) {
22712494 rc = mdb_reader_pid(env, Pidset, pid);
22722495 if (rc)
22732496 return rc;
2274 env->me_flags |= MDB_LIVE_READER;
2497 env->me_live_reader = 1;
22752498 }
22762499
22772500 LOCK_MUTEX_R(env);
23242547 txn->mt_free_pgs[0] = 0;
23252548 txn->mt_spill_pgs = NULL;
23262549 env->me_txn = txn;
2550 memcpy(txn->mt_dbiseqs, env->me_dbiseqs, env->me_maxdbs * sizeof(unsigned int));
23272551 }
23282552
23292553 /* Copy the DB info and flags */
23982622 tsize = sizeof(MDB_ntxn);
23992623 }
24002624 size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1);
2401 if (!(flags & MDB_RDONLY))
2625 if (!(flags & MDB_RDONLY)) {
2626 if (!parent) {
2627 txn = env->me_txn0;
2628 txn->mt_flags = 0;
2629 goto ok;
2630 }
24022631 size += env->me_maxdbs * sizeof(MDB_cursor *);
2632 /* child txns use parent's dbiseqs */
2633 if (!parent)
2634 size += env->me_maxdbs * sizeof(unsigned int);
2635 }
24032636
24042637 if ((txn = calloc(1, size)) == NULL) {
2405 DPRINTF(("calloc: %s", strerror(ErrCode())));
2638 DPRINTF(("calloc: %s", strerror(errno)));
24062639 return ENOMEM;
24072640 }
24082641 txn->mt_dbs = (MDB_db *) ((char *)txn + tsize);
24092642 if (flags & MDB_RDONLY) {
24102643 txn->mt_flags |= MDB_TXN_RDONLY;
24112644 txn->mt_dbflags = (unsigned char *)(txn->mt_dbs + env->me_maxdbs);
2645 txn->mt_dbiseqs = env->me_dbiseqs;
24122646 } else {
24132647 txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
2414 txn->mt_dbflags = (unsigned char *)(txn->mt_cursors + env->me_maxdbs);
2648 if (parent) {
2649 txn->mt_dbiseqs = parent->mt_dbiseqs;
2650 txn->mt_dbflags = (unsigned char *)(txn->mt_cursors + env->me_maxdbs);
2651 } else {
2652 txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs);
2653 txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs);
2654 }
24152655 }
24162656 txn->mt_env = env;
24172657
2658 ok:
24182659 if (parent) {
24192660 unsigned int i;
24202661 txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
24572698 } else {
24582699 rc = mdb_txn_renew0(txn);
24592700 }
2460 if (rc)
2461 free(txn);
2462 else {
2701 if (rc) {
2702 if (txn != env->me_txn0)
2703 free(txn);
2704 } else {
24632705 *ret = txn;
24642706 DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
24652707 txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w',
24912733 env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
24922734 } else {
24932735 char *ptr = env->me_dbxs[i].md_name.mv_data;
2494 env->me_dbxs[i].md_name.mv_data = NULL;
2495 env->me_dbxs[i].md_name.mv_size = 0;
2496 env->me_dbflags[i] = 0;
2497 free(ptr);
2736 if (ptr) {
2737 env->me_dbxs[i].md_name.mv_data = NULL;
2738 env->me_dbxs[i].md_name.mv_size = 0;
2739 env->me_dbflags[i] = 0;
2740 env->me_dbiseqs[i]++;
2741 free(ptr);
2742 }
24982743 }
24992744 }
25002745 }
25832828 if ((txn->mt_flags & MDB_TXN_RDONLY) && txn->mt_u.reader)
25842829 txn->mt_u.reader->mr_pid = 0;
25852830
2586 free(txn);
2831 if (txn != txn->mt_env->me_txn0)
2832 free(txn);
25872833 }
25882834
25892835 /** Save the freelist as of this transaction to the freeDB.
26102856 rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST|MDB_PS_MODIFY);
26112857 if (rc && rc != MDB_NOTFOUND)
26122858 return rc;
2859 }
2860
2861 if (!env->me_pghead && txn->mt_loose_pgs) {
2862 /* Put loose page numbers in mt_free_pgs, since
2863 * we may be unable to return them to me_pghead.
2864 */
2865 MDB_page *mp = txn->mt_loose_pgs;
2866 if ((rc = mdb_midl_need(&txn->mt_free_pgs, txn->mt_loose_count)) != 0)
2867 return rc;
2868 for (; mp; mp = NEXT_LOOSE_PAGE(mp))
2869 mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno);
2870 txn->mt_loose_pgs = NULL;
2871 txn->mt_loose_count = 0;
26132872 }
26142873
26152874 /* MDB_RESERVE cancels meminit in ovpage malloc (when no WRITEMAP) */
26732932 }
26742933
26752934 mop = env->me_pghead;
2676 mop_len = mop ? mop[0] : 0;
2935 mop_len = (mop ? mop[0] : 0) + txn->mt_loose_count;
26772936
26782937 /* Reserve records for me_pghead[]. Split it if multi-page,
26792938 * to avoid searching freeDB for a page range. Use keys in
27132972 total_room += head_room;
27142973 }
27152974
2975 /* Return loose page numbers to me_pghead, though usually none are
2976 * left at this point. The pages themselves remain in dirty_list.
2977 */
2978 if (txn->mt_loose_pgs) {
2979 MDB_page *mp = txn->mt_loose_pgs;
2980 unsigned count = txn->mt_loose_count;
2981 MDB_IDL loose;
2982 /* Room for loose pages + temp IDL with same */
2983 if ((rc = mdb_midl_need(&env->me_pghead, 2*count+1)) != 0)
2984 return rc;
2985 mop = env->me_pghead;
2986 loose = mop + MDB_IDL_ALLOCLEN(mop) - count;
2987 for (count = 0; mp; mp = NEXT_LOOSE_PAGE(mp))
2988 loose[ ++count ] = mp->mp_pgno;
2989 loose[0] = count;
2990 mdb_midl_sort(loose);
2991 mdb_midl_xmerge(mop, loose);
2992 txn->mt_loose_pgs = NULL;
2993 txn->mt_loose_count = 0;
2994 mop_len = mop[0];
2995 }
2996
27162997 /* Fill in the reserved me_pghead records */
27172998 rc = MDB_SUCCESS;
27182999 if (mop_len) {
27213002 mop += mop_len;
27223003 rc = mdb_cursor_first(&mc, &key, &data);
27233004 for (; !rc; rc = mdb_cursor_next(&mc, &key, &data, MDB_NEXT)) {
2724 unsigned flags = MDB_CURRENT;
27253005 txnid_t id = *(txnid_t *)key.mv_data;
27263006 ssize_t len = (ssize_t)(data.mv_size / sizeof(MDB_ID)) - 1;
27273007 MDB_ID save;
27313011 if (len > mop_len) {
27323012 len = mop_len;
27333013 data.mv_size = (len + 1) * sizeof(MDB_ID);
2734 flags = 0;
27353014 }
27363015 data.mv_data = mop -= len;
27373016 save = mop[0];
27383017 mop[0] = len;
2739 rc = mdb_cursor_put(&mc, &key, &data, flags);
3018 rc = mdb_cursor_put(&mc, &key, &data, MDB_CURRENT);
27403019 mop[0] = save;
27413020 if (rc || !(mop_len -= len))
27423021 break;
27763055 while (++i <= pagecount) {
27773056 dp = dl[i].mptr;
27783057 /* Don't flush this page yet */
2779 if (dp->mp_flags & P_KEEP) {
2780 dp->mp_flags ^= P_KEEP;
3058 if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
3059 dp->mp_flags &= ~P_KEEP;
27813060 dl[++j] = dl[i];
27823061 continue;
27833062 }
27913070 if (++i <= pagecount) {
27923071 dp = dl[i].mptr;
27933072 /* Don't flush this page yet */
2794 if (dp->mp_flags & P_KEEP) {
2795 dp->mp_flags ^= P_KEEP;
3073 if (dp->mp_flags & (P_LOOSE|P_KEEP)) {
3074 dp->mp_flags &= ~P_KEEP;
27963075 dl[i].mid = 0;
27973076 continue;
27983077 }
28673146 #endif /* _WIN32 */
28683147 }
28693148
3149 /* MIPS has cache coherency issues, this is a no-op everywhere else
3150 * Note: for any size >= on-chip cache size, entire on-chip cache is
3151 * flushed.
3152 */
3153 CACHEFLUSH(env->me_map, txn->mt_next_pgno * env->me_psize, DCACHE);
3154
28703155 for (i = keep; ++i <= pagecount; ) {
28713156 dp = dl[i].mptr;
28723157 /* This is a page we skipped above */
29213206
29223207 if (txn->mt_parent) {
29233208 MDB_txn *parent = txn->mt_parent;
3209 MDB_page **lp;
29243210 MDB_ID2L dst, src;
29253211 MDB_IDL pspill;
29263212 unsigned x, y, len, ps_len;
30183304 }
30193305 }
30203306
3307 /* Append our loose page list to parent's */
3308 for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(lp))
3309 ;
3310 *lp = txn->mt_loose_pgs;
3311 parent->mt_loose_count += txn->mt_loose_count;
3312
30213313 parent->mt_child = NULL;
30223314 mdb_midl_free(((MDB_ntxn *)txn)->mnt_pgstate.mf_pghead);
30233315 free(txn);
30493341 mdb_cursor_init(&mc, txn, MAIN_DBI, NULL);
30503342 for (i = 2; i < txn->mt_numdbs; i++) {
30513343 if (txn->mt_dbflags[i] & DB_DIRTY) {
3344 if (TXN_DBI_CHANGED(txn, i)) {
3345 rc = MDB_BAD_DBI;
3346 goto fail;
3347 }
30523348 data.mv_data = &txn->mt_dbs[i];
30533349 rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, 0);
30543350 if (rc)
30753371 (rc = mdb_env_write_meta(txn)))
30763372 goto fail;
30773373
3374 /* Free P_LOOSE pages left behind in dirty_list */
3375 if (!(env->me_flags & MDB_WRITEMAP))
3376 mdb_dlist_free(txn);
3377
30783378 done:
30793379 env->me_pglast = 0;
30803380 env->me_txn = NULL;
30823382
30833383 if (env->me_txns)
30843384 UNLOCK_MUTEX_W(env);
3085 free(txn);
3385 if (txn != env->me_txn0)
3386 free(txn);
30863387
30873388 return MDB_SUCCESS;
30883389
30973398 * @param[out] meta address of where to store the meta information
30983399 * @return 0 on success, non-zero on failure.
30993400 */
3100 static int
3401 static int ESECT
31013402 mdb_env_read_header(MDB_env *env, MDB_meta *meta)
31023403 {
31033404 MDB_metabuf pbuf;
31553456 return 0;
31563457 }
31573458
3459 static void ESECT
3460 mdb_env_init_meta0(MDB_env *env, MDB_meta *meta)
3461 {
3462 meta->mm_magic = MDB_MAGIC;
3463 meta->mm_version = MDB_DATA_VERSION;
3464 meta->mm_mapsize = env->me_mapsize;
3465 meta->mm_psize = env->me_psize;
3466 meta->mm_last_pg = 1;
3467 meta->mm_flags = env->me_flags & 0xffff;
3468 meta->mm_flags |= MDB_INTEGERKEY;
3469 meta->mm_dbs[0].md_root = P_INVALID;
3470 meta->mm_dbs[1].md_root = P_INVALID;
3471 }
3472
31583473 /** Write the environment parameters of a freshly created DB environment.
31593474 * @param[in] env the environment handle
31603475 * @param[out] meta address of where to store the meta information
31613476 * @return 0 on success, non-zero on failure.
31623477 */
3163 static int
3478 static int ESECT
31643479 mdb_env_init_meta(MDB_env *env, MDB_meta *meta)
31653480 {
31663481 MDB_page *p, *q;
31843499
31853500 psize = env->me_psize;
31863501
3187 meta->mm_magic = MDB_MAGIC;
3188 meta->mm_version = MDB_DATA_VERSION;
3189 meta->mm_mapsize = env->me_mapsize;
3190 meta->mm_psize = psize;
3191 meta->mm_last_pg = 1;
3192 meta->mm_flags = env->me_flags & 0xffff;
3193 meta->mm_flags |= MDB_INTEGERKEY;
3194 meta->mm_dbs[0].md_root = P_INVALID;
3195 meta->mm_dbs[1].md_root = P_INVALID;
3502 mdb_env_init_meta0(env, meta);
31963503
31973504 p = calloc(2, psize);
31983505 p->mp_pgno = 0;
32243531 {
32253532 MDB_env *env;
32263533 MDB_meta meta, metab, *mp;
3534 size_t mapsize;
32273535 off_t off;
32283536 int rc, len, toggle;
32293537 char *ptr;
32403548
32413549 env = txn->mt_env;
32423550 mp = env->me_metas[toggle];
3551 mapsize = env->me_metas[toggle ^ 1]->mm_mapsize;
3552 /* Persist any increases of mapsize config */
3553 if (mapsize < env->me_mapsize)
3554 mapsize = env->me_mapsize;
32433555
32443556 if (env->me_flags & MDB_WRITEMAP) {
3245 /* Persist any increases of mapsize config */
3246 if (env->me_mapsize > mp->mm_mapsize)
3247 mp->mm_mapsize = env->me_mapsize;
3557 mp->mm_mapsize = mapsize;
32483558 mp->mm_dbs[0] = txn->mt_dbs[0];
32493559 mp->mm_dbs[1] = txn->mt_dbs[1];
32503560 mp->mm_last_pg = txn->mt_next_pgno - 1;
32713581 metab.mm_txnid = env->me_metas[toggle]->mm_txnid;
32723582 metab.mm_last_pg = env->me_metas[toggle]->mm_last_pg;
32733583
3274 ptr = (char *)&meta;
3275 if (env->me_mapsize > mp->mm_mapsize) {
3276 /* Persist any increases of mapsize config */
3277 meta.mm_mapsize = env->me_mapsize;
3278 off = offsetof(MDB_meta, mm_mapsize);
3279 } else {
3280 off = offsetof(MDB_meta, mm_dbs[0].md_depth);
3281 }
3282 len = sizeof(MDB_meta) - off;
3283
3284 ptr += off;
3584 meta.mm_mapsize = mapsize;
32853585 meta.mm_dbs[0] = txn->mt_dbs[0];
32863586 meta.mm_dbs[1] = txn->mt_dbs[1];
32873587 meta.mm_last_pg = txn->mt_next_pgno - 1;
32883588 meta.mm_txnid = txn->mt_txnid;
32893589
3590 off = offsetof(MDB_meta, mm_mapsize);
3591 ptr = (char *)&meta + off;
3592 len = sizeof(MDB_meta) - off;
32903593 if (toggle)
32913594 off += env->me_psize;
32923595 off += PAGEHDRSZ;
33253628 env->me_flags |= MDB_FATAL_ERROR;
33263629 return rc;
33273630 }
3631 /* MIPS has cache coherency issues, this is a no-op everywhere else */
3632 CACHEFLUSH(env->me_map + off, len, DCACHE);
33283633 done:
33293634 /* Memory ordering issues are irrelevant; since the entire writer
33303635 * is wrapped by wmutex, all of these changes will become visible
33483653 return (env->me_metas[0]->mm_txnid < env->me_metas[1]->mm_txnid);
33493654 }
33503655
3351 int
3656 int ESECT
33523657 mdb_env_create(MDB_env **env)
33533658 {
33543659 MDB_env *e;
33733678 return MDB_SUCCESS;
33743679 }
33753680
3376 static int
3377 mdb_env_map(MDB_env *env, void *addr, int newsize)
3681 static int ESECT
3682 mdb_env_map(MDB_env *env, void *addr)
33783683 {
33793684 MDB_page *p;
33803685 unsigned int flags = env->me_flags;
33823687 int rc;
33833688 HANDLE mh;
33843689 LONG sizelo, sizehi;
3385 sizelo = env->me_mapsize & 0xffffffff;
3386 sizehi = env->me_mapsize >> 16 >> 16; /* only needed on Win64 */
3387
3388 /* Windows won't create mappings for zero length files.
3389 * Just allocate the maxsize right now.
3390 */
3391 if (newsize) {
3690 size_t msize;
3691
3692 if (flags & MDB_RDONLY) {
3693 /* Don't set explicit map size, use whatever exists */
3694 msize = 0;
3695 sizelo = 0;
3696 sizehi = 0;
3697 } else {
3698 msize = env->me_mapsize;
3699 sizelo = msize & 0xffffffff;
3700 sizehi = msize >> 16 >> 16; /* only needed on Win64 */
3701
3702 /* Windows won't create mappings for zero length files.
3703 * and won't map more than the file size.
3704 * Just set the maxsize right now.
3705 */
33923706 if (SetFilePointer(env->me_fd, sizelo, &sizehi, 0) != (DWORD)sizelo
33933707 || !SetEndOfFile(env->me_fd)
33943708 || SetFilePointer(env->me_fd, 0, NULL, 0) != 0)
33953709 return ErrCode();
33963710 }
3711
33973712 mh = CreateFileMapping(env->me_fd, NULL, flags & MDB_WRITEMAP ?
33983713 PAGE_READWRITE : PAGE_READONLY,
33993714 sizehi, sizelo, NULL);
34013716 return ErrCode();
34023717 env->me_map = MapViewOfFileEx(mh, flags & MDB_WRITEMAP ?
34033718 FILE_MAP_WRITE : FILE_MAP_READ,
3404 0, 0, env->me_mapsize, addr);
3719 0, 0, msize, addr);
34053720 rc = env->me_map ? 0 : ErrCode();
34063721 CloseHandle(mh);
34073722 if (rc)
34473762 return MDB_SUCCESS;
34483763 }
34493764
3450 int
3765 int ESECT
34513766 mdb_env_set_mapsize(MDB_env *env, size_t size)
34523767 {
34533768 /* If env is already open, caller is responsible for making
34713786 munmap(env->me_map, env->me_mapsize);
34723787 env->me_mapsize = size;
34733788 old = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : NULL;
3474 rc = mdb_env_map(env, old, 1);
3789 rc = mdb_env_map(env, old);
34753790 if (rc)
34763791 return rc;
34773792 }
34813796 return MDB_SUCCESS;
34823797 }
34833798
3484 int
3799 int ESECT
34853800 mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs)
34863801 {
34873802 if (env->me_map)
34903805 return MDB_SUCCESS;
34913806 }
34923807
3493 int
3808 int ESECT
34943809 mdb_env_set_maxreaders(MDB_env *env, unsigned int readers)
34953810 {
34963811 if (env->me_map || readers < 1)
34993814 return MDB_SUCCESS;
35003815 }
35013816
3502 int
3817 int ESECT
35033818 mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers)
35043819 {
35053820 if (!env || !readers)
35083823 return MDB_SUCCESS;
35093824 }
35103825
3511 /** Further setup required for opening an MDB environment
3826 /** Further setup required for opening an LMDB environment
35123827 */
3513 static int
3828 static int ESECT
35143829 mdb_env_open2(MDB_env *env)
35153830 {
35163831 unsigned int flags = env->me_flags;
35553870 env->me_mapsize = minsize;
35563871 }
35573872
3558 rc = mdb_env_map(env, meta.mm_address, newenv || env->me_mapsize != meta.mm_mapsize);
3873 rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL);
35593874 if (rc)
35603875 return rc;
35613876
36303945 case DLL_THREAD_DETACH:
36313946 for (i=0; i<mdb_tls_nkeys; i++) {
36323947 MDB_reader *r = pthread_getspecific(mdb_tls_keys[i]);
3633 mdb_env_reader_dest(r);
3948 if (r) {
3949 mdb_env_reader_dest(r);
3950 }
36343951 }
36353952 break;
36363953 case DLL_PROCESS_DETACH: break;
36653982 #endif
36663983
36673984 /** Downgrade the exclusive lock on the region back to shared */
3668 static int
3985 static int ESECT
36693986 mdb_env_share_locks(MDB_env *env, int *excl)
36703987 {
36713988 int rc = 0, toggle = mdb_env_pick_meta(env);
37074024 /** Try to get exlusive lock, otherwise shared.
37084025 * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive.
37094026 */
3710 static int
4027 static int ESECT
37114028 mdb_env_excl_lock(MDB_env *env, int *excl)
37124029 {
37134030 int rc = 0;
38424159 #endif
38434160
38444161 /** Open and/or initialize the lock region for the environment.
3845 * @param[in] env The MDB environment.
4162 * @param[in] env The LMDB environment.
38464163 * @param[in] lpath The pathname of the file used for the lock region.
38474164 * @param[in] mode The Unix permissions for the file, if we create it.
38484165 * @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive
38494166 * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
38504167 * @return 0 on success, non-zero on failure.
38514168 */
3852 static int
4169 static int ESECT
38534170 mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
38544171 {
38554172 #ifdef _WIN32
40794396 # error "Persistent DB flags & env flags overlap, but both go in mm_flags"
40804397 #endif
40814398
4082 int
4399 int ESECT
40834400 mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
40844401 {
40854402 int oflags, rc, len, excl = -1;
41244441 env->me_path = strdup(path);
41254442 env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx));
41264443 env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t));
4127 if (!(env->me_dbxs && env->me_path && env->me_dbflags)) {
4444 env->me_dbiseqs = calloc(env->me_maxdbs, sizeof(unsigned int));
4445 if (!(env->me_dbxs && env->me_path && env->me_dbflags && env->me_dbiseqs)) {
41284446 rc = ENOMEM;
41294447 goto leave;
41304448 }
41964514 if (!((flags & MDB_RDONLY) ||
41974515 (env->me_pbuf = calloc(1, env->me_psize))))
41984516 rc = ENOMEM;
4517 if (!(flags & MDB_RDONLY)) {
4518 MDB_txn *txn;
4519 int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs *
4520 (sizeof(MDB_db)+sizeof(MDB_cursor)+sizeof(unsigned int)+1);
4521 txn = calloc(1, size);
4522 if (txn) {
4523 txn->mt_dbs = (MDB_db *)((char *)txn + tsize);
4524 txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
4525 txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs);
4526 txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs);
4527 txn->mt_env = env;
4528 env->me_txn0 = txn;
4529 } else {
4530 rc = ENOMEM;
4531 }
4532 }
41994533 }
42004534
42014535 leave:
42074541 }
42084542
42094543 /** Destroy resources from mdb_env_open(), clear our readers & DBIs */
4210 static void
4544 static void ESECT
42114545 mdb_env_close0(MDB_env *env, int excl)
42124546 {
42134547 int i;
42204554 free(env->me_dbxs[i].md_name.mv_data);
42214555
42224556 free(env->me_pbuf);
4557 free(env->me_dbiseqs);
42234558 free(env->me_dbflags);
42244559 free(env->me_dbxs);
42254560 free(env->me_path);
42264561 free(env->me_dirty_list);
4562 free(env->me_txn0);
42274563 mdb_midl_free(env->me_free_pgs);
42284564
42294565 if (env->me_flags & MDB_ENV_TXKEY) {
42954631 env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY);
42964632 }
42974633
4298 int
4299 mdb_env_copyfd(MDB_env *env, HANDLE fd)
4300 {
4301 MDB_txn *txn = NULL;
4302 int rc;
4303 size_t wsize;
4304 char *ptr;
4305 #ifdef _WIN32
4306 DWORD len, w2;
4307 #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL)
4308 #else
4309 ssize_t len;
4310 size_t w2;
4311 #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0)
4312 #endif
4313
4314 /* Do the lock/unlock of the reader mutex before starting the
4315 * write txn. Otherwise other read txns could block writers.
4316 */
4317 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
4318 if (rc)
4319 return rc;
4320
4321 if (env->me_txns) {
4322 /* We must start the actual read txn after blocking writers */
4323 mdb_txn_reset0(txn, "reset-stage1");
4324
4325 /* Temporarily block writers until we snapshot the meta pages */
4326 LOCK_MUTEX_W(env);
4327
4328 rc = mdb_txn_renew0(txn);
4329 if (rc) {
4330 UNLOCK_MUTEX_W(env);
4331 goto leave;
4332 }
4333 }
4334
4335 wsize = env->me_psize * 2;
4336 ptr = env->me_map;
4337 w2 = wsize;
4338 while (w2 > 0) {
4339 DO_WRITE(rc, fd, ptr, w2, len);
4340 if (!rc) {
4341 rc = ErrCode();
4342 break;
4343 } else if (len > 0) {
4344 rc = MDB_SUCCESS;
4345 ptr += len;
4346 w2 -= len;
4347 continue;
4348 } else {
4349 /* Non-blocking or async handles are not supported */
4350 rc = EIO;
4351 break;
4352 }
4353 }
4354 if (env->me_txns)
4355 UNLOCK_MUTEX_W(env);
4356
4357 if (rc)
4358 goto leave;
4359
4360 wsize = txn->mt_next_pgno * env->me_psize - wsize;
4361 while (wsize > 0) {
4362 if (wsize > MAX_WRITE)
4363 w2 = MAX_WRITE;
4364 else
4365 w2 = wsize;
4366 DO_WRITE(rc, fd, ptr, w2, len);
4367 if (!rc) {
4368 rc = ErrCode();
4369 break;
4370 } else if (len > 0) {
4371 rc = MDB_SUCCESS;
4372 ptr += len;
4373 wsize -= len;
4374 continue;
4375 } else {
4376 rc = EIO;
4377 break;
4378 }
4379 }
4380
4381 leave:
4382 mdb_txn_abort(txn);
4383 return rc;
4384 }
4385
4386 int
4387 mdb_env_copy(MDB_env *env, const char *path)
4388 {
4389 int rc, len;
4390 char *lpath;
4391 HANDLE newfd = INVALID_HANDLE_VALUE;
4392
4393 if (env->me_flags & MDB_NOSUBDIR) {
4394 lpath = (char *)path;
4395 } else {
4396 len = strlen(path);
4397 len += sizeof(DATANAME);
4398 lpath = malloc(len);
4399 if (!lpath)
4400 return ENOMEM;
4401 sprintf(lpath, "%s" DATANAME, path);
4402 }
4403
4404 /* The destination path must exist, but the destination file must not.
4405 * We don't want the OS to cache the writes, since the source data is
4406 * already in the OS cache.
4407 */
4408 #ifdef _WIN32
4409 newfd = CreateFile(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
4410 FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
4411 #else
4412 newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666);
4413 #endif
4414 if (newfd == INVALID_HANDLE_VALUE) {
4415 rc = ErrCode();
4416 goto leave;
4417 }
4418
4419 #ifdef O_DIRECT
4420 /* Set O_DIRECT if the file system supports it */
4421 if ((rc = fcntl(newfd, F_GETFL)) != -1)
4422 (void) fcntl(newfd, F_SETFL, rc | O_DIRECT);
4423 #endif
4424 #ifdef F_NOCACHE /* __APPLE__ */
4425 rc = fcntl(newfd, F_NOCACHE, 1);
4426 if (rc) {
4427 rc = ErrCode();
4428 goto leave;
4429 }
4430 #endif
4431
4432 rc = mdb_env_copyfd(env, newfd);
4433
4434 leave:
4435 if (!(env->me_flags & MDB_NOSUBDIR))
4436 free(lpath);
4437 if (newfd != INVALID_HANDLE_VALUE)
4438 if (close(newfd) < 0 && rc == MDB_SUCCESS)
4439 rc = ErrCode();
4440
4441 return rc;
4442 }
4443
4444 void
4634
4635 void ESECT
44454636 mdb_env_close(MDB_env *env)
44464637 {
44474638 MDB_page *dp;
44934684 } while(!x && u > (unsigned short *)a->mv_data);
44944685 return x;
44954686 #else
4496 return memcmp(a->mv_data, b->mv_data, a->mv_size);
4497 #endif
4498 }
4687 unsigned short *u, *c, *end;
4688 int x;
4689
4690 end = (unsigned short *) ((char *) a->mv_data + a->mv_size);
4691 u = (unsigned short *)a->mv_data;
4692 c = (unsigned short *)b->mv_data;
4693 do {
4694 x = *u++ - *c++;
4695 } while(!x && u < end);
4696 return x;
4697 #endif
4698 }
4699
4700 /** Compare two items pointing at size_t's of unknown alignment. */
4701 #ifdef MISALIGNED_OK
4702 # define mdb_cmp_clong mdb_cmp_long
4703 #else
4704 # define mdb_cmp_clong mdb_cmp_cint
4705 #endif
44994706
45004707 /** Compare two items lexically */
45014708 static int
48685075 /* Make sure we're using an up-to-date root */
48695076 if (*mc->mc_dbflag & DB_STALE) {
48705077 MDB_cursor mc2;
5078 if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
5079 return MDB_BAD_DBI;
48715080 mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, NULL);
48725081 rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, 0);
48735082 if (rc)
50405249 int exact = 0;
50415250 DKBUF;
50425251
5043 if (key == NULL || data == NULL)
5044 return EINVAL;
5045
50465252 DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key)));
50475253
5048 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
5254 if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
50495255 return EINVAL;
50505256
50515257 if (txn->mt_flags & MDB_TXN_ERROR)
52115417 if (op == MDB_PREV || op == MDB_PREV_DUP) {
52125418 rc = mdb_cursor_prev(&mc->mc_xcursor->mx_cursor, data, NULL, MDB_PREV);
52135419 if (op != MDB_PREV || rc != MDB_NOTFOUND) {
5214 if (rc == MDB_SUCCESS)
5420 if (rc == MDB_SUCCESS) {
52155421 MDB_GET_KEY(leaf, key);
5422 mc->mc_flags &= ~C_EOF;
5423 }
52165424 return rc;
52175425 }
52185426 } else {
53685576 if (!mc->mc_top) {
53695577 /* There are no other pages */
53705578 mc->mc_ki[mc->mc_top] = 0;
5371 if (op == MDB_SET_RANGE) {
5579 if (op == MDB_SET_RANGE && !exactp) {
53725580 rc = 0;
53735581 goto set1;
53745582 } else
54045612 mc->mc_flags &= ~C_EOF;
54055613
54065614 if (IS_LEAF2(mp)) {
5407 key->mv_size = mc->mc_db->md_pad;
5408 key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
5615 if (op == MDB_SET_RANGE || op == MDB_SET_KEY) {
5616 key->mv_size = mc->mc_db->md_pad;
5617 key->mv_data = LEAF2KEY(mp, mc->mc_ki[mc->mc_top], key->mv_size);
5618 }
54095619 return MDB_SUCCESS;
54105620 }
54115621
56875897 rc = MDB_INCOMPATIBLE;
56885898 break;
56895899 }
5900 {
5901 MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
5902 if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
5903 MDB_GET_KEY(leaf, key);
5904 rc = mdb_node_read(mc->mc_txn, leaf, data);
5905 break;
5906 }
5907 }
56905908 if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
56915909 rc = EINVAL;
56925910 break;
57235941 if (mc->mc_dbi > MAIN_DBI && !(*mc->mc_dbflag & DB_DIRTY)) {
57245942 MDB_cursor mc2;
57255943 MDB_xcursor mcx;
5944 if (TXN_DBI_CHANGED(mc->mc_txn, mc->mc_dbi))
5945 return MDB_BAD_DBI;
57265946 mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx);
57275947 rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY);
57285948 if (rc)
57535973 uint16_t fp_flags;
57545974 MDB_val xdata, *rdata, dkey, olddata;
57555975 MDB_db dummy;
5756 int do_sub = 0, insert;
5976 int do_sub = 0, insert_key, insert_data;
57575977 unsigned int mcount = 0, dcount = 0, nospill;
57585978 size_t nsize;
57595979 int rc, rc2;
57816001 if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
57826002 return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
57836003
5784 if (flags != MDB_CURRENT && key->mv_size-1 >= ENV_MAXKEY(env))
6004 if (key->mv_size-1 >= ENV_MAXKEY(env))
57856005 return MDB_BAD_VALSIZE;
57866006
57876007 #if SIZE_MAX > MAXDATASIZE
58726092 return rc2;
58736093 }
58746094
5875 insert = rc;
5876 if (insert) {
6095 insert_key = insert_data = rc;
6096 if (insert_key) {
58776097 /* The key does not exist */
58786098 DPRINTF(("inserting key at index %i", mc->mc_ki[mc->mc_top]));
58796099 if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
58806100 LEAFSIZE(key, data) > env->me_nodemax)
58816101 {
5882 /* Too big for a node, insert in sub-DB */
6102 /* Too big for a node, insert in sub-DB. Set up an empty
6103 * "old sub-page" for prep_subDB to expand to a full page.
6104 */
58836105 fp_flags = P_LEAF|P_DIRTY;
58846106 fp = env->me_pbuf;
58856107 fp->mp_pad = data->mv_size; /* used if MDB_DUPFIXED */
5886 fp->mp_lower = fp->mp_upper = olddata.mv_size = PAGEHDRSZ;
6108 fp->mp_lower = fp->mp_upper = (PAGEHDRSZ-PAGEBASE);
6109 olddata.mv_size = PAGEHDRSZ;
58876110 goto prep_subDB;
58886111 }
58896112 } else {
58906113 /* there's only a key anyway, so this is a no-op */
58916114 if (IS_LEAF2(mc->mc_pg[mc->mc_top])) {
6115 char *ptr;
58926116 unsigned int ksize = mc->mc_db->md_pad;
58936117 if (key->mv_size != ksize)
58946118 return MDB_BAD_VALSIZE;
5895 if (flags == MDB_CURRENT) {
5896 char *ptr = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize);
5897 memcpy(ptr, key->mv_data, ksize);
6119 ptr = LEAF2KEY(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], ksize);
6120 memcpy(ptr, key->mv_data, ksize);
6121 fix_parent:
6122 /* if overwriting slot 0 of leaf, need to
6123 * update branch key if there is a parent page
6124 */
6125 if (mc->mc_top && !mc->mc_ki[mc->mc_top]) {
6126 unsigned short top = mc->mc_top;
6127 mc->mc_top--;
6128 /* slot 0 is always an empty key, find real slot */
6129 while (mc->mc_top && !mc->mc_ki[mc->mc_top])
6130 mc->mc_top--;
6131 if (mc->mc_ki[mc->mc_top])
6132 rc2 = mdb_update_key(mc, key);
6133 else
6134 rc2 = MDB_SUCCESS;
6135 mc->mc_top = top;
6136 if (rc2)
6137 return rc2;
58986138 }
58996139 return MDB_SUCCESS;
59006140 }
59236163
59246164 #if UINT_MAX < SIZE_MAX
59256165 if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t))
5926 #ifdef MISALIGNED_OK
5927 mc->mc_dbx->md_dcmp = mdb_cmp_long;
5928 #else
5929 mc->mc_dbx->md_dcmp = mdb_cmp_cint;
5930 #endif
5931 #endif
5932 /* if data matches, skip it */
6166 mc->mc_dbx->md_dcmp = mdb_cmp_clong;
6167 #endif
6168 /* does data match? */
59336169 if (!mc->mc_dbx->md_dcmp(data, &olddata)) {
59346170 if (flags & MDB_NODUPDATA)
5935 rc = MDB_KEYEXIST;
5936 else if (flags & MDB_MULTIPLE)
5937 goto next_mult;
5938 else
5939 rc = MDB_SUCCESS;
5940 return rc;
6171 return MDB_KEYEXIST;
6172 /* overwrite it */
6173 goto current;
59416174 }
59426175
59436176 /* Back up original data item */
59466179
59476180 /* Make sub-page header for the dup items, with dummy body */
59486181 fp->mp_flags = P_LEAF|P_DIRTY|P_SUBP;
5949 fp->mp_lower = PAGEHDRSZ;
6182 fp->mp_lower = (PAGEHDRSZ-PAGEBASE);
59506183 xdata.mv_size = PAGEHDRSZ + dkey.mv_size + data->mv_size;
59516184 if (mc->mc_db->md_flags & MDB_DUPFIXED) {
59526185 fp->mp_flags |= P_LEAF2;
59566189 xdata.mv_size += 2 * (sizeof(indx_t) + NODESIZE) +
59576190 (dkey.mv_size & 1) + (data->mv_size & 1);
59586191 }
5959 fp->mp_upper = xdata.mv_size;
5960 olddata.mv_size = fp->mp_upper; /* pretend olddata is fp */
6192 fp->mp_upper = xdata.mv_size - PAGEBASE;
6193 olddata.mv_size = xdata.mv_size; /* pretend olddata is fp */
59616194 } else if (leaf->mn_flags & F_SUBDATA) {
59626195 /* Data is on sub-DB, just store it */
59636196 flags |= F_DUPDATA|F_SUBDATA;
60246257 if (fp_flags & P_LEAF2) {
60256258 memcpy(METADATA(mp), METADATA(fp), NUMKEYS(fp) * fp->mp_pad);
60266259 } else {
6027 memcpy((char *)mp + mp->mp_upper, (char *)fp + fp->mp_upper,
6028 olddata.mv_size - fp->mp_upper);
6260 memcpy((char *)mp + mp->mp_upper + PAGEBASE, (char *)fp + fp->mp_upper + PAGEBASE,
6261 olddata.mv_size - fp->mp_upper - PAGEBASE);
60296262 for (i=0; i<NUMKEYS(fp); i++)
60306263 mp->mp_ptrs[i] = fp->mp_ptrs[i] + offset;
60316264 }
60346267 rdata = &xdata;
60356268 flags |= F_DUPDATA;
60366269 do_sub = 1;
6037 if (!insert)
6270 if (!insert_key)
60386271 mdb_node_del(mc, 0);
60396272 goto new_sub;
60406273 }
60756308 return ENOMEM;
60766309 id2.mid = pg;
60776310 id2.mptr = np;
6078 rc = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2);
6079 mdb_cassert(mc, rc == 0);
6311 rc2 = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2);
6312 mdb_cassert(mc, rc2 == 0);
60806313 if (!(flags & MDB_RESERVE)) {
60816314 /* Copy end of page, adjusting alignment so
60826315 * compiler may copy words instead of bytes.
60946327 data->mv_data = METADATA(omp);
60956328 else
60966329 memcpy(METADATA(omp), data->mv_data, data->mv_size);
6097 goto done;
6330 return MDB_SUCCESS;
60986331 }
60996332 }
61006333 if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS)
61066339 */
61076340 if (F_ISSET(flags, MDB_RESERVE))
61086341 data->mv_data = olddata.mv_data;
6109 else if (data->mv_size)
6342 else if (!(mc->mc_flags & C_SUB))
61106343 memcpy(olddata.mv_data, data->mv_data, data->mv_size);
6111 else
6344 else {
61126345 memcpy(NODEKEY(leaf), key->mv_data, key->mv_size);
6113 goto done;
6346 goto fix_parent;
6347 }
6348 return MDB_SUCCESS;
61146349 }
61156350 mdb_node_del(mc, 0);
6116 mc->mc_db->md_entries--;
61176351 }
61186352
61196353 rdata = data;
61236357 nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->mv_size : mdb_leaf_size(env, key, rdata);
61246358 if (SIZELEFT(mc->mc_pg[mc->mc_top]) < nsize) {
61256359 if (( flags & (F_DUPDATA|F_SUBDATA)) == F_DUPDATA )
6126 nflags &= ~MDB_APPEND;
6127 if (!insert)
6360 nflags &= ~MDB_APPEND; /* sub-page may need room to grow */
6361 if (!insert_key)
61286362 nflags |= MDB_SPLIT_REPLACE;
61296363 rc = mdb_page_split(mc, key, rdata, P_INVALID, nflags);
61306364 } else {
61316365 /* There is room already in this leaf page. */
61326366 rc = mdb_node_add(mc, mc->mc_ki[mc->mc_top], key, rdata, 0, nflags);
6133 if (rc == 0 && !do_sub && insert) {
6367 if (rc == 0 && insert_key) {
61346368 /* Adjust other cursors pointing to mp */
61356369 MDB_cursor *m2, *m3;
61366370 MDB_dbi dbi = mc->mc_dbi;
61506384 }
61516385 }
61526386
6153 if (rc != MDB_SUCCESS)
6154 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
6155 else {
6387 if (rc == MDB_SUCCESS) {
61566388 /* Now store the actual data in the child DB. Note that we're
61576389 * storing the user data in the keys field, so there are strict
61586390 * size limits on dupdata. The actual data fields of the child
61606392 */
61616393 if (do_sub) {
61626394 int xflags;
6395 size_t ecount;
61636396 put_sub:
61646397 xdata.mv_size = 0;
61656398 xdata.mv_data = "";
61756408 if (dkey.mv_size) {
61766409 rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
61776410 if (rc)
6178 return rc;
6411 goto bad_sub;
61796412 {
61806413 /* Adjust other cursors pointing to mp */
61816414 MDB_cursor *m2;
61936426 /* we've done our job */
61946427 dkey.mv_size = 0;
61956428 }
6429 ecount = mc->mc_xcursor->mx_db.md_entries;
61966430 if (flags & MDB_APPENDDUP)
61976431 xflags |= MDB_APPEND;
61986432 rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, data, &xdata, xflags);
62006434 void *db = NODEDATA(leaf);
62016435 memcpy(db, &mc->mc_xcursor->mx_db, sizeof(MDB_db));
62026436 }
6203 }
6204 /* sub-writes might have failed so check rc again.
6205 * Don't increment count if we just replaced an existing item.
6206 */
6207 if (!rc && !(flags & MDB_CURRENT))
6437 insert_data = mc->mc_xcursor->mx_db.md_entries - ecount;
6438 }
6439 /* Increment count unless we just replaced an existing item. */
6440 if (insert_data)
62086441 mc->mc_db->md_entries++;
6442 if (insert_key) {
6443 /* Invalidate txn if we created an empty sub-DB */
6444 if (rc)
6445 goto bad_sub;
6446 /* If we succeeded and the key didn't exist before,
6447 * make sure the cursor is marked valid.
6448 */
6449 mc->mc_flags |= C_INITIALIZED;
6450 }
62096451 if (flags & MDB_MULTIPLE) {
62106452 if (!rc) {
6211 next_mult:
62126453 mcount++;
62136454 /* let caller know how many succeeded, if any */
62146455 data[1].mv_size = mcount;
62156456 if (mcount < dcount) {
62166457 data[0].mv_data = (char *)data[0].mv_data + data[0].mv_size;
6458 insert_key = insert_data = 0;
62176459 goto more;
62186460 }
62196461 }
62206462 }
6221 }
6222 done:
6223 /* If we succeeded and the key didn't exist before, make sure
6224 * the cursor is marked valid.
6225 */
6226 if (!rc && insert)
6227 mc->mc_flags |= C_INITIALIZED;
6463 return rc;
6464 bad_sub:
6465 if (rc == MDB_KEYEXIST) /* should not happen, we deleted that item */
6466 rc = MDB_CORRUPTED;
6467 }
6468 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
62286469 return rc;
62296470 }
62306471
62526493 return rc;
62536494
62546495 mp = mc->mc_pg[mc->mc_top];
6496 if (IS_LEAF2(mp))
6497 goto del_key;
62556498 leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
62566499
6257 if (!IS_LEAF2(mp) && F_ISSET(leaf->mn_flags, F_DUPDATA)) {
6258 if (!(flags & MDB_NODUPDATA)) {
6500 if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
6501 if (flags & MDB_NODUPDATA) {
6502 /* mdb_cursor_del0() will subtract the final entry */
6503 mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries - 1;
6504 } else {
62596505 if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) {
62606506 mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
62616507 }
62626508 rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, MDB_NOSPILL);
6509 if (rc)
6510 return rc;
62636511 /* If sub-DB still has entries, we're done */
62646512 if (mc->mc_xcursor->mx_db.md_entries) {
62656513 if (leaf->mn_flags & F_SUBDATA) {
62906538 if (leaf->mn_flags & F_SUBDATA) {
62916539 /* add all the child DB's pages to the free list */
62926540 rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
6293 if (rc == MDB_SUCCESS) {
6294 mc->mc_db->md_entries -=
6295 mc->mc_xcursor->mx_db.md_entries;
6296 }
6297 }
6298 }
6299
6300 return mdb_cursor_del0(mc, leaf);
6541 if (rc)
6542 goto fail;
6543 }
6544 }
6545
6546 /* add overflow pages to free list */
6547 if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
6548 MDB_page *omp;
6549 pgno_t pg;
6550
6551 memcpy(&pg, NODEDATA(leaf), sizeof(pg));
6552 if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) ||
6553 (rc = mdb_ovpage_free(mc, omp)))
6554 goto fail;
6555 }
6556
6557 del_key:
6558 return mdb_cursor_del0(mc);
6559
6560 fail:
6561 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
6562 return rc;
63016563 }
63026564
63036565 /** Allocate and initialize new pages for a database.
63196581 DPRINTF(("allocated new mpage %"Z"u, page size %u",
63206582 np->mp_pgno, mc->mc_txn->mt_env->me_psize));
63216583 np->mp_flags = flags | P_DIRTY;
6322 np->mp_lower = PAGEHDRSZ;
6323 np->mp_upper = mc->mc_txn->mt_env->me_psize;
6584 np->mp_lower = (PAGEHDRSZ-PAGEBASE);
6585 np->mp_upper = mc->mc_txn->mt_env->me_psize - PAGEBASE;
63246586
63256587 if (IS_BRANCH(np))
63266588 mc->mc_db->md_branch_pages++;
65246786 }
65256787
65266788 /** Delete the specified node from a page.
6527 * @param[in] mp The page to operate on.
6528 * @param[in] indx The index of the node to delete.
6789 * @param[in] mc Cursor pointing to the node to delete.
65296790 * @param[in] ksize The size of a node. Only used if the page is
65306791 * part of a #MDB_DUPFIXED database.
65316792 */
65746835 }
65756836 }
65766837
6577 base = (char *)mp + mp->mp_upper;
6838 base = (char *)mp + mp->mp_upper + PAGEBASE;
65786839 memmove(base + sz, base, ptr - mp->mp_upper);
65796840
65806841 mp->mp_lower -= sizeof(indx_t);
66286889 mp->mp_ptrs[i] += delta;
66296890 }
66306891
6631 base = (char *)mp + mp->mp_upper;
6892 base = (char *)mp + mp->mp_upper + PAGEBASE;
66326893 memmove(base + delta, base, ptr - mp->mp_upper + NODESIZE + NODEKSZ(node));
66336894 mp->mp_upper += delta;
66346895 }
67076968 mx->mx_dbflag = DB_VALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */
67086969 #if UINT_MAX < SIZE_MAX
67096970 if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t))
6710 #ifdef MISALIGNED_OK
6711 mx->mx_dbx.md_cmp = mdb_cmp_long;
6712 #else
6713 mx->mx_dbx.md_cmp = mdb_cmp_cint;
6714 #endif
6971 mx->mx_dbx.md_cmp = mdb_cmp_clong;
67156972 #endif
67166973 }
67176974
67487005 MDB_cursor *mc;
67497006 size_t size = sizeof(MDB_cursor);
67507007
6751 if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
7008 if (!ret || !TXN_DBI_EXIST(txn, dbi))
67527009 return EINVAL;
67537010
67547011 if (txn->mt_flags & MDB_TXN_ERROR)
67807037 int
67817038 mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
67827039 {
6783 if (txn == NULL || mc == NULL || mc->mc_dbi >= txn->mt_numdbs)
7040 if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi))
67847041 return EINVAL;
67857042
67867043 if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
67877044 return EINVAL;
7045
7046 if (txn->mt_flags & MDB_TXN_ERROR)
7047 return MDB_BAD_TXN;
67887048
67897049 mdb_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor);
67907050 return MDB_SUCCESS;
68017061
68027062 if (mc->mc_xcursor == NULL)
68037063 return MDB_INCOMPATIBLE;
7064
7065 if (mc->mc_txn->mt_flags & MDB_TXN_ERROR)
7066 return MDB_BAD_TXN;
7067
7068 if (!(mc->mc_flags & C_INITIALIZED))
7069 return EINVAL;
7070
7071 if (!mc->mc_snum || (mc->mc_flags & C_EOF))
7072 return MDB_NOTFOUND;
68047073
68057074 leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
68067075 if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
68987167 mp->mp_ptrs[i] -= delta;
68997168 }
69007169
6901 base = (char *)mp + mp->mp_upper;
7170 base = (char *)mp + mp->mp_upper + PAGEBASE;
69027171 len = ptr - mp->mp_upper + NODESIZE;
69037172 memmove(base - delta, base, len);
69047173 mp->mp_upper -= delta;
69547223 unsigned int snum = csrc->mc_snum;
69557224 MDB_node *s2;
69567225 /* must find the lowest key below src */
6957 mdb_page_search_lowest(csrc);
7226 rc = mdb_page_search_lowest(csrc);
7227 if (rc)
7228 return rc;
69587229 if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
69597230 key.mv_size = csrc->mc_db->md_pad;
69607231 key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
69777248 MDB_node *s2;
69787249 MDB_val bkey;
69797250 /* must find the lowest key below dst */
6980 mdb_page_search_lowest(cdst);
6981 if (IS_LEAF2(cdst->mc_pg[cdst->mc_top])) {
6982 bkey.mv_size = cdst->mc_db->md_pad;
6983 bkey.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, bkey.mv_size);
7251 mdb_cursor_copy(cdst, &mn);
7252 rc = mdb_page_search_lowest(&mn);
7253 if (rc)
7254 return rc;
7255 if (IS_LEAF2(mn.mc_pg[mn.mc_top])) {
7256 bkey.mv_size = mn.mc_db->md_pad;
7257 bkey.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, bkey.mv_size);
69847258 } else {
6985 s2 = NODEPTR(cdst->mc_pg[cdst->mc_top], 0);
7259 s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0);
69867260 bkey.mv_size = NODEKSZ(s2);
69877261 bkey.mv_data = NODEKEY(s2);
69887262 }
6989 cdst->mc_snum = snum--;
6990 cdst->mc_top = snum;
6991 mdb_cursor_copy(cdst, &mn);
7263 mn.mc_snum = snum--;
7264 mn.mc_top = snum;
69927265 mn.mc_ki[snum] = 0;
69937266 rc = mdb_update_key(&mn, &bkey);
69947267 if (rc)
70997372 * the \b csrc page will be freed.
71007373 * @param[in] csrc Cursor pointing to the source page.
71017374 * @param[in] cdst Cursor pointing to the destination page.
7375 * @return 0 on success, non-zero on failure.
71027376 */
71037377 static int
71047378 mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
71057379 {
7380 MDB_page *psrc, *pdst;
7381 MDB_node *srcnode;
7382 MDB_val key, data;
7383 unsigned nkeys;
71067384 int rc;
7107 indx_t i, j;
7108 MDB_node *srcnode;
7109 MDB_val key, data;
7110 unsigned nkeys;
7111
7112 DPRINTF(("merging page %"Z"u into %"Z"u", csrc->mc_pg[csrc->mc_top]->mp_pgno,
7113 cdst->mc_pg[cdst->mc_top]->mp_pgno));
7385 indx_t i, j;
7386
7387 psrc = csrc->mc_pg[csrc->mc_top];
7388 pdst = cdst->mc_pg[cdst->mc_top];
7389
7390 DPRINTF(("merging page %"Z"u into %"Z"u", psrc->mp_pgno, pdst->mp_pgno));
71147391
71157392 mdb_cassert(csrc, csrc->mc_snum > 1); /* can't merge root page */
71167393 mdb_cassert(csrc, cdst->mc_snum > 1);
71217398
71227399 /* Move all nodes from src to dst.
71237400 */
7124 j = nkeys = NUMKEYS(cdst->mc_pg[cdst->mc_top]);
7125 if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
7401 j = nkeys = NUMKEYS(pdst);
7402 if (IS_LEAF2(psrc)) {
71267403 key.mv_size = csrc->mc_db->md_pad;
7127 key.mv_data = METADATA(csrc->mc_pg[csrc->mc_top]);
7128 for (i = 0; i < NUMKEYS(csrc->mc_pg[csrc->mc_top]); i++, j++) {
7404 key.mv_data = METADATA(psrc);
7405 for (i = 0; i < NUMKEYS(psrc); i++, j++) {
71297406 rc = mdb_node_add(cdst, j, &key, NULL, 0, 0);
71307407 if (rc != MDB_SUCCESS)
71317408 return rc;
71327409 key.mv_data = (char *)key.mv_data + key.mv_size;
71337410 }
71347411 } else {
7135 for (i = 0; i < NUMKEYS(csrc->mc_pg[csrc->mc_top]); i++, j++) {
7136 srcnode = NODEPTR(csrc->mc_pg[csrc->mc_top], i);
7137 if (i == 0 && IS_BRANCH(csrc->mc_pg[csrc->mc_top])) {
7138 unsigned int snum = csrc->mc_snum;
7412 for (i = 0; i < NUMKEYS(psrc); i++, j++) {
7413 srcnode = NODEPTR(psrc, i);
7414 if (i == 0 && IS_BRANCH(psrc)) {
7415 MDB_cursor mn;
71397416 MDB_node *s2;
7417 mdb_cursor_copy(csrc, &mn);
71407418 /* must find the lowest key below src */
7141 mdb_page_search_lowest(csrc);
7142 if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
7143 key.mv_size = csrc->mc_db->md_pad;
7144 key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
7419 rc = mdb_page_search_lowest(&mn);
7420 if (rc)
7421 return rc;
7422 if (IS_LEAF2(mn.mc_pg[mn.mc_top])) {
7423 key.mv_size = mn.mc_db->md_pad;
7424 key.mv_data = LEAF2KEY(mn.mc_pg[mn.mc_top], 0, key.mv_size);
71457425 } else {
7146 s2 = NODEPTR(csrc->mc_pg[csrc->mc_top], 0);
7426 s2 = NODEPTR(mn.mc_pg[mn.mc_top], 0);
71477427 key.mv_size = NODEKSZ(s2);
71487428 key.mv_data = NODEKEY(s2);
71497429 }
7150 csrc->mc_snum = snum--;
7151 csrc->mc_top = snum;
71527430 } else {
71537431 key.mv_size = srcnode->mn_ksize;
71547432 key.mv_data = NODEKEY(srcnode);
71637441 }
71647442
71657443 DPRINTF(("dst page %"Z"u now has %u keys (%.1f%% filled)",
7166 cdst->mc_pg[cdst->mc_top]->mp_pgno, NUMKEYS(cdst->mc_pg[cdst->mc_top]),
7167 (float)PAGEFILL(cdst->mc_txn->mt_env, cdst->mc_pg[cdst->mc_top]) / 10));
7444 pdst->mp_pgno, NUMKEYS(pdst),
7445 (float)PAGEFILL(cdst->mc_txn->mt_env, pdst) / 10));
71687446
71697447 /* Unlink the src page from parent and add to free list.
71707448 */
71807458 }
71817459 csrc->mc_top++;
71827460
7183 rc = mdb_midl_append(&csrc->mc_txn->mt_free_pgs,
7184 csrc->mc_pg[csrc->mc_top]->mp_pgno);
7461 psrc = csrc->mc_pg[csrc->mc_top];
7462 /* If not operating on FreeDB, allow this page to be reused
7463 * in this txn. Otherwise just add to free list.
7464 */
7465 rc = mdb_page_loose(csrc, psrc);
71857466 if (rc)
71867467 return rc;
7187 if (IS_LEAF(csrc->mc_pg[csrc->mc_top]))
7468 if (IS_LEAF(psrc))
71887469 csrc->mc_db->md_leaf_pages--;
71897470 else
71907471 csrc->mc_db->md_branch_pages--;
71927473 /* Adjust other cursors pointing to mp */
71937474 MDB_cursor *m2, *m3;
71947475 MDB_dbi dbi = csrc->mc_dbi;
7195 MDB_page *mp = cdst->mc_pg[cdst->mc_top];
71967476
71977477 for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
71987478 if (csrc->mc_flags & C_SUB)
72017481 m3 = m2;
72027482 if (m3 == csrc) continue;
72037483 if (m3->mc_snum < csrc->mc_snum) continue;
7204 if (m3->mc_pg[csrc->mc_top] == csrc->mc_pg[csrc->mc_top]) {
7205 m3->mc_pg[csrc->mc_top] = mp;
7484 if (m3->mc_pg[csrc->mc_top] == psrc) {
7485 m3->mc_pg[csrc->mc_top] = pdst;
72067486 m3->mc_ki[csrc->mc_top] += nkeys;
72077487 }
72087488 }
72097489 }
7210 mdb_cursor_pop(csrc);
7211
7212 return mdb_rebalance(csrc);
7490 {
7491 unsigned int snum = cdst->mc_snum;
7492 uint16_t depth = cdst->mc_db->md_depth;
7493 mdb_cursor_pop(cdst);
7494 rc = mdb_rebalance(cdst);
7495 /* Did the tree shrink? */
7496 if (depth > cdst->mc_db->md_depth)
7497 snum--;
7498 cdst->mc_snum = snum;
7499 cdst->mc_top = snum-1;
7500 }
7501 return rc;
72137502 }
72147503
72157504 /** Copy the contents of a cursor.
72477536 int rc;
72487537 unsigned int ptop, minkeys;
72497538 MDB_cursor mn;
7539 indx_t oldki;
72507540
72517541 minkeys = 1 + (IS_BRANCH(mc->mc_pg[mc->mc_top]));
72527542 DPRINTF(("rebalancing %s page %"Z"u (has %u keys, %.1f%% full)",
72977587 }
72987588 }
72997589 } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) {
7590 int i;
73007591 DPUTS("collapsing root page!");
73017592 rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno);
73027593 if (rc)
73087599 mc->mc_db->md_depth--;
73097600 mc->mc_db->md_branch_pages--;
73107601 mc->mc_ki[0] = mc->mc_ki[1];
7602 for (i = 1; i<mc->mc_db->md_depth; i++) {
7603 mc->mc_pg[i] = mc->mc_pg[i+1];
7604 mc->mc_ki[i] = mc->mc_ki[i+1];
7605 }
73117606 {
73127607 /* Adjust other cursors pointing to mp */
73137608 MDB_cursor *m2, *m3;
73207615 m3 = m2;
73217616 if (m3 == mc || m3->mc_snum < mc->mc_snum) continue;
73227617 if (m3->mc_pg[0] == mp) {
7323 int i;
73247618 m3->mc_snum--;
73257619 m3->mc_top--;
73267620 for (i=0; i<m3->mc_snum; i++) {
73517645 mdb_cursor_copy(mc, &mn);
73527646 mn.mc_xcursor = NULL;
73537647
7648 oldki = mc->mc_ki[mc->mc_top];
73547649 if (mc->mc_ki[ptop] == 0) {
73557650 /* We're the leftmost leaf in our parent.
73567651 */
73847679 * (A branch page must never have less than 2 keys.)
73857680 */
73867681 minkeys = 1 + (IS_BRANCH(mn.mc_pg[mn.mc_top]));
7387 if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= FILL_THRESHOLD && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys)
7388 return mdb_node_move(&mn, mc);
7389 else {
7390 if (mc->mc_ki[ptop] == 0)
7682 if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= FILL_THRESHOLD && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys) {
7683 rc = mdb_node_move(&mn, mc);
7684 if (mc->mc_ki[ptop]) {
7685 oldki++;
7686 }
7687 } else {
7688 if (mc->mc_ki[ptop] == 0) {
73917689 rc = mdb_page_merge(&mn, mc);
7392 else {
7690 } else {
7691 oldki += NUMKEYS(mn.mc_pg[mn.mc_top]);
73937692 mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1;
73947693 rc = mdb_page_merge(mc, &mn);
73957694 mdb_cursor_copy(&mn, mc);
73967695 }
7397 mc->mc_flags &= ~(C_INITIALIZED|C_EOF);
7398 }
7696 mc->mc_flags &= ~C_EOF;
7697 }
7698 mc->mc_ki[mc->mc_top] = oldki;
73997699 return rc;
74007700 }
74017701
74027702 /** Complete a delete operation started by #mdb_cursor_del(). */
74037703 static int
7404 mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf)
7704 mdb_cursor_del0(MDB_cursor *mc)
74057705 {
74067706 int rc;
74077707 MDB_page *mp;
74087708 indx_t ki;
74097709 unsigned int nkeys;
74107710
7411 mp = mc->mc_pg[mc->mc_top];
74127711 ki = mc->mc_ki[mc->mc_top];
7413
7414 /* add overflow pages to free list */
7415 if (!IS_LEAF2(mp) && F_ISSET(leaf->mn_flags, F_BIGDATA)) {
7416 MDB_page *omp;
7417 pgno_t pg;
7418
7419 memcpy(&pg, NODEDATA(leaf), sizeof(pg));
7420 if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) ||
7421 (rc = mdb_ovpage_free(mc, omp)))
7422 return rc;
7423 }
74247712 mdb_node_del(mc, mc->mc_db->md_pad);
74257713 mc->mc_db->md_entries--;
74267714 rc = mdb_rebalance(mc);
7427 if (rc != MDB_SUCCESS)
7428 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
7429 else {
7715
7716 if (rc == MDB_SUCCESS) {
74307717 MDB_cursor *m2, *m3;
74317718 MDB_dbi dbi = mc->mc_dbi;
74327719
74347721 nkeys = NUMKEYS(mp);
74357722
74367723 /* if mc points past last node in page, find next sibling */
7437 if (mc->mc_ki[mc->mc_top] >= nkeys)
7438 mdb_cursor_sibling(mc, 1);
7724 if (mc->mc_ki[mc->mc_top] >= nkeys) {
7725 rc = mdb_cursor_sibling(mc, 1);
7726 if (rc == MDB_NOTFOUND) {
7727 mc->mc_flags |= C_EOF;
7728 rc = MDB_SUCCESS;
7729 }
7730 }
74397731
74407732 /* Adjust other cursors pointing to mp */
7441 for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
7733 for (m2 = mc->mc_txn->mt_cursors[dbi]; !rc && m2; m2=m2->mc_next) {
74427734 m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
74437735 if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED))
74447736 continue;
74497741 m3->mc_flags |= C_DEL;
74507742 if (m3->mc_ki[mc->mc_top] > ki)
74517743 m3->mc_ki[mc->mc_top]--;
7744 else if (mc->mc_db->md_flags & MDB_DUPSORT)
7745 m3->mc_xcursor->mx_cursor.mc_flags |= C_EOF;
74527746 }
7453 if (m3->mc_ki[mc->mc_top] >= nkeys)
7454 mdb_cursor_sibling(m3, 1);
7747 if (m3->mc_ki[mc->mc_top] >= nkeys) {
7748 rc = mdb_cursor_sibling(m3, 1);
7749 if (rc == MDB_NOTFOUND) {
7750 m3->mc_flags |= C_EOF;
7751 rc = MDB_SUCCESS;
7752 }
7753 }
74557754 }
74567755 }
74577756 mc->mc_flags |= C_DEL;
74587757 }
74597758
7759 if (rc)
7760 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
74607761 return rc;
74617762 }
74627763
74637764 int
74647765 mdb_del(MDB_txn *txn, MDB_dbi dbi,
74657766 MDB_val *key, MDB_val *data)
7767 {
7768 if (!key || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
7769 return EINVAL;
7770
7771 if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
7772 return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
7773
7774 if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) {
7775 /* must ignore any data */
7776 data = NULL;
7777 }
7778
7779 return mdb_del0(txn, dbi, key, data, 0);
7780 }
7781
7782 static int
7783 mdb_del0(MDB_txn *txn, MDB_dbi dbi,
7784 MDB_val *key, MDB_val *data, unsigned flags)
74667785 {
74677786 MDB_cursor mc;
74687787 MDB_xcursor mx;
74697788 MDB_cursor_op op;
74707789 MDB_val rdata, *xdata;
7471 int rc, exact;
7790 int rc, exact = 0;
74727791 DKBUF;
74737792
7474 if (key == NULL)
7475 return EINVAL;
7476
74777793 DPRINTF(("====> delete db %u key [%s]", dbi, DKEY(key)));
74787794
7479 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
7480 return EINVAL;
7481
7482 if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
7483 return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
7484
74857795 mdb_cursor_init(&mc, txn, dbi, &mx);
74867796
7487 exact = 0;
7488 if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) {
7489 /* must ignore any data */
7490 data = NULL;
7491 }
74927797 if (data) {
74937798 op = MDB_GET_BOTH;
74947799 rdata = *data;
74967801 } else {
74977802 op = MDB_SET;
74987803 xdata = NULL;
7804 flags |= MDB_NODUPDATA;
74997805 }
75007806 rc = mdb_cursor_set(&mc, key, xdata, op, &exact);
75017807 if (rc == 0) {
75107816 mc.mc_flags |= C_UNTRACK;
75117817 mc.mc_next = txn->mt_cursors[dbi];
75127818 txn->mt_cursors[dbi] = &mc;
7513 rc = mdb_cursor_del(&mc, data ? 0 : MDB_NODUPDATA);
7819 rc = mdb_cursor_del(&mc, flags);
75147820 txn->mt_cursors[dbi] = mc.mc_next;
75157821 }
75167822 return rc;
75597865
75607866 if (mc->mc_snum < 2) {
75617867 if ((rc = mdb_page_new(mc, P_BRANCH, 1, &pp)))
7562 return rc;
7868 goto done;
75637869 /* shift current top to make room for new parent */
75647870 mc->mc_pg[1] = mc->mc_pg[0];
75657871 mc->mc_ki[1] = mc->mc_ki[0];
75777883 mc->mc_ki[0] = mc->mc_ki[1];
75787884 mc->mc_db->md_root = mp->mp_pgno;
75797885 mc->mc_db->md_depth--;
7580 return rc;
7886 goto done;
75817887 }
75827888 mc->mc_snum = 2;
75837889 mc->mc_top = 1;
76067912 int x;
76077913 unsigned int lsize, rsize, ksize;
76087914 /* Move half of the keys to the right sibling */
7609 copy = NULL;
76107915 x = mc->mc_ki[mc->mc_top] - split_indx;
76117916 ksize = mc->mc_db->md_pad;
76127917 split = LEAF2KEY(mp, split_indx, ksize);
76537958
76547959 /* grab a page to hold a temporary copy */
76557960 copy = mdb_page_malloc(mc->mc_txn, 1);
7656 if (copy == NULL)
7657 return ENOMEM;
7961 if (copy == NULL) {
7962 rc = ENOMEM;
7963 goto done;
7964 }
76587965 copy->mp_pgno = mp->mp_pgno;
76597966 copy->mp_flags = mp->mp_flags;
7660 copy->mp_lower = PAGEHDRSZ;
7661 copy->mp_upper = env->me_psize;
7967 copy->mp_lower = (PAGEHDRSZ-PAGEBASE);
7968 copy->mp_upper = env->me_psize - PAGEBASE;
76627969
76637970 /* prepare to insert */
76647971 for (i=0, j=0; i<nkeys; i++) {
76988005 psize += nsize;
76998006 node = NULL;
77008007 } else {
7701 node = (MDB_node *)((char *)mp + copy->mp_ptrs[i]);
8008 node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE);
77028009 psize += NODESIZE + NODEKSZ(node) + sizeof(indx_t);
77038010 if (IS_LEAF(mp)) {
77048011 if (F_ISSET(node->mn_flags, F_BIGDATA))
77188025 sepkey.mv_size = newkey->mv_size;
77198026 sepkey.mv_data = newkey->mv_data;
77208027 } else {
7721 node = (MDB_node *)((char *)mp + copy->mp_ptrs[split_indx]);
8028 node = (MDB_node *)((char *)mp + copy->mp_ptrs[split_indx] + PAGEBASE);
77228029 sepkey.mv_size = node->mn_ksize;
77238030 sepkey.mv_data = NODEKEY(node);
77248031 }
77348041 mn.mc_top--;
77358042 did_split = 1;
77368043 rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0);
8044 if (rc)
8045 goto done;
77378046
77388047 /* root split? */
77398048 if (mn.mc_snum == mc->mc_snum) {
77558064 mc->mc_ki[i] = mn.mc_ki[i];
77568065 }
77578066 mc->mc_pg[ptop] = mn.mc_pg[ptop];
7758 mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
8067 if (mn.mc_ki[ptop]) {
8068 mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
8069 } else {
8070 /* find right page's left sibling */
8071 mc->mc_ki[ptop] = mn.mc_ki[ptop];
8072 mdb_cursor_sibling(mc, 0);
8073 }
77598074 }
77608075 } else {
77618076 mn.mc_top--;
77648079 }
77658080 mc->mc_flags ^= C_SPLITTING;
77668081 if (rc != MDB_SUCCESS) {
7767 return rc;
8082 goto done;
77688083 }
77698084 if (nflags & MDB_APPEND) {
77708085 mc->mc_pg[mc->mc_top] = rp;
77718086 mc->mc_ki[mc->mc_top] = 0;
77728087 rc = mdb_node_add(mc, 0, newkey, newdata, newpgno, nflags);
77738088 if (rc)
7774 return rc;
8089 goto done;
77758090 for (i=0; i<mc->mc_top; i++)
77768091 mc->mc_ki[i] = mn.mc_ki[i];
77778092 } else if (!IS_LEAF2(mp)) {
77918106 /* Update index for the new key. */
77928107 mc->mc_ki[mc->mc_top] = j;
77938108 } else {
7794 node = (MDB_node *)((char *)mp + copy->mp_ptrs[i]);
8109 node = (MDB_node *)((char *)mp + copy->mp_ptrs[i] + PAGEBASE);
77958110 rkey.mv_data = NODEKEY(node);
77968111 rkey.mv_size = node->mn_ksize;
77978112 if (IS_LEAF(mp)) {
78098124 }
78108125
78118126 rc = mdb_node_add(mc, j, &rkey, rdata, pgno, flags);
7812 if (rc) {
7813 /* return tmp page to freelist */
7814 mdb_page_free(env, copy);
7815 return rc;
7816 }
8127 if (rc)
8128 goto done;
78178129 if (i == nkeys) {
78188130 i = 0;
78198131 j = 0;
78308142 mp->mp_lower = copy->mp_lower;
78318143 mp->mp_upper = copy->mp_upper;
78328144 memcpy(NODEPTR(mp, nkeys-1), NODEPTR(copy, nkeys-1),
7833 env->me_psize - copy->mp_upper);
8145 env->me_psize - copy->mp_upper - PAGEBASE);
78348146
78358147 /* reset back to original page */
78368148 if (newindx < split_indx) {
78478159 */
78488160 if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
78498161 mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) {
7850 for (i=0; i<ptop; i++) {
8162 for (i=0; i<=ptop; i++) {
78518163 mc->mc_pg[i] = mn.mc_pg[i];
78528164 mc->mc_ki[i] = mn.mc_ki[i];
78538165 }
7854 mc->mc_pg[ptop] = mn.mc_pg[ptop];
7855 mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
7856 }
7857 }
7858 /* return tmp page to freelist */
7859 mdb_page_free(env, copy);
8166 }
8167 }
78608168 }
78618169
78628170 {
79078215 }
79088216 }
79098217 DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp)));
8218
8219 done:
8220 if (copy) /* tmp page */
8221 mdb_page_free(env, copy);
8222 if (rc)
8223 mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
79108224 return rc;
79118225 }
79128226
79178231 MDB_cursor mc;
79188232 MDB_xcursor mx;
79198233
7920 if (key == NULL || data == NULL)
7921 return EINVAL;
7922
7923 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
8234 if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
79248235 return EINVAL;
79258236
79268237 if ((flags & (MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) != flags)
79308241 return mdb_cursor_put(&mc, key, data, flags);
79318242 }
79328243
7933 int
8244 #ifndef MDB_WBUF
8245 #define MDB_WBUF (1024*1024)
8246 #endif
8247
8248 /** State needed for a compacting copy. */
8249 typedef struct mdb_copy {
8250 pthread_mutex_t mc_mutex;
8251 pthread_cond_t mc_cond;
8252 char *mc_wbuf[2];
8253 char *mc_over[2];
8254 MDB_env *mc_env;
8255 MDB_txn *mc_txn;
8256 int mc_wlen[2];
8257 int mc_olen[2];
8258 pgno_t mc_next_pgno;
8259 HANDLE mc_fd;
8260 int mc_status;
8261 volatile int mc_new;
8262 int mc_toggle;
8263
8264 } mdb_copy;
8265
8266 /** Dedicated writer thread for compacting copy. */
8267 static THREAD_RET ESECT
8268 mdb_env_copythr(void *arg)
8269 {
8270 mdb_copy *my = arg;
8271 char *ptr;
8272 int toggle = 0, wsize, rc;
8273 #ifdef _WIN32
8274 DWORD len;
8275 #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL)
8276 #else
8277 int len;
8278 #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0)
8279 #endif
8280
8281 pthread_mutex_lock(&my->mc_mutex);
8282 my->mc_new = 0;
8283 pthread_cond_signal(&my->mc_cond);
8284 for(;;) {
8285 while (!my->mc_new)
8286 pthread_cond_wait(&my->mc_cond, &my->mc_mutex);
8287 if (my->mc_new < 0) {
8288 my->mc_new = 0;
8289 break;
8290 }
8291 my->mc_new = 0;
8292 wsize = my->mc_wlen[toggle];
8293 ptr = my->mc_wbuf[toggle];
8294 again:
8295 while (wsize > 0) {
8296 DO_WRITE(rc, my->mc_fd, ptr, wsize, len);
8297 if (!rc) {
8298 rc = ErrCode();
8299 break;
8300 } else if (len > 0) {
8301 rc = MDB_SUCCESS;
8302 ptr += len;
8303 wsize -= len;
8304 continue;
8305 } else {
8306 rc = EIO;
8307 break;
8308 }
8309 }
8310 if (rc) {
8311 my->mc_status = rc;
8312 break;
8313 }
8314 /* If there's an overflow page tail, write it too */
8315 if (my->mc_olen[toggle]) {
8316 wsize = my->mc_olen[toggle];
8317 ptr = my->mc_over[toggle];
8318 my->mc_olen[toggle] = 0;
8319 goto again;
8320 }
8321 my->mc_wlen[toggle] = 0;
8322 toggle ^= 1;
8323 pthread_cond_signal(&my->mc_cond);
8324 }
8325 pthread_cond_signal(&my->mc_cond);
8326 pthread_mutex_unlock(&my->mc_mutex);
8327 return (THREAD_RET)0;
8328 #undef DO_WRITE
8329 }
8330
8331 /** Tell the writer thread there's a buffer ready to write */
8332 static int ESECT
8333 mdb_env_cthr_toggle(mdb_copy *my, int st)
8334 {
8335 int toggle = my->mc_toggle ^ 1;
8336 pthread_mutex_lock(&my->mc_mutex);
8337 if (my->mc_status) {
8338 pthread_mutex_unlock(&my->mc_mutex);
8339 return my->mc_status;
8340 }
8341 while (my->mc_new == 1)
8342 pthread_cond_wait(&my->mc_cond, &my->mc_mutex);
8343 my->mc_new = st;
8344 my->mc_toggle = toggle;
8345 pthread_cond_signal(&my->mc_cond);
8346 pthread_mutex_unlock(&my->mc_mutex);
8347 return 0;
8348 }
8349
8350 /** Depth-first tree traversal for compacting copy. */
8351 static int ESECT
8352 mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags)
8353 {
8354 MDB_cursor mc;
8355 MDB_txn *txn = my->mc_txn;
8356 MDB_node *ni;
8357 MDB_page *mo, *mp, *leaf;
8358 char *buf, *ptr;
8359 int rc, toggle;
8360 unsigned int i;
8361
8362 /* Empty DB, nothing to do */
8363 if (*pg == P_INVALID)
8364 return MDB_SUCCESS;
8365
8366 mc.mc_snum = 1;
8367 mc.mc_top = 0;
8368 mc.mc_txn = txn;
8369
8370 rc = mdb_page_get(my->mc_txn, *pg, &mc.mc_pg[0], NULL);
8371 if (rc)
8372 return rc;
8373 rc = mdb_page_search_root(&mc, NULL, MDB_PS_FIRST);
8374 if (rc)
8375 return rc;
8376
8377 /* Make cursor pages writable */
8378 buf = ptr = malloc(my->mc_env->me_psize * mc.mc_snum);
8379 if (buf == NULL)
8380 return ENOMEM;
8381
8382 for (i=0; i<mc.mc_top; i++) {
8383 mdb_page_copy((MDB_page *)ptr, mc.mc_pg[i], my->mc_env->me_psize);
8384 mc.mc_pg[i] = (MDB_page *)ptr;
8385 ptr += my->mc_env->me_psize;
8386 }
8387
8388 /* This is writable space for a leaf page. Usually not needed. */
8389 leaf = (MDB_page *)ptr;
8390
8391 toggle = my->mc_toggle;
8392 while (mc.mc_snum > 0) {
8393 unsigned n;
8394 mp = mc.mc_pg[mc.mc_top];
8395 n = NUMKEYS(mp);
8396
8397 if (IS_LEAF(mp)) {
8398 if (!IS_LEAF2(mp) && !(flags & F_DUPDATA)) {
8399 for (i=0; i<n; i++) {
8400 ni = NODEPTR(mp, i);
8401 if (ni->mn_flags & F_BIGDATA) {
8402 MDB_page *omp;
8403 pgno_t pg;
8404
8405 /* Need writable leaf */
8406 if (mp != leaf) {
8407 mc.mc_pg[mc.mc_top] = leaf;
8408 mdb_page_copy(leaf, mp, my->mc_env->me_psize);
8409 mp = leaf;
8410 ni = NODEPTR(mp, i);
8411 }
8412
8413 memcpy(&pg, NODEDATA(ni), sizeof(pg));
8414 rc = mdb_page_get(txn, pg, &omp, NULL);
8415 if (rc)
8416 goto done;
8417 if (my->mc_wlen[toggle] >= MDB_WBUF) {
8418 rc = mdb_env_cthr_toggle(my, 1);
8419 if (rc)
8420 goto done;
8421 toggle = my->mc_toggle;
8422 }
8423 mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
8424 memcpy(mo, omp, my->mc_env->me_psize);
8425 mo->mp_pgno = my->mc_next_pgno;
8426 my->mc_next_pgno += omp->mp_pages;
8427 my->mc_wlen[toggle] += my->mc_env->me_psize;
8428 if (omp->mp_pages > 1) {
8429 my->mc_olen[toggle] = my->mc_env->me_psize * (omp->mp_pages - 1);
8430 my->mc_over[toggle] = (char *)omp + my->mc_env->me_psize;
8431 rc = mdb_env_cthr_toggle(my, 1);
8432 if (rc)
8433 goto done;
8434 toggle = my->mc_toggle;
8435 }
8436 memcpy(NODEDATA(ni), &mo->mp_pgno, sizeof(pgno_t));
8437 } else if (ni->mn_flags & F_SUBDATA) {
8438 MDB_db db;
8439
8440 /* Need writable leaf */
8441 if (mp != leaf) {
8442 mc.mc_pg[mc.mc_top] = leaf;
8443 mdb_page_copy(leaf, mp, my->mc_env->me_psize);
8444 mp = leaf;
8445 ni = NODEPTR(mp, i);
8446 }
8447
8448 memcpy(&db, NODEDATA(ni), sizeof(db));
8449 my->mc_toggle = toggle;
8450 rc = mdb_env_cwalk(my, &db.md_root, ni->mn_flags & F_DUPDATA);
8451 if (rc)
8452 goto done;
8453 toggle = my->mc_toggle;
8454 memcpy(NODEDATA(ni), &db, sizeof(db));
8455 }
8456 }
8457 }
8458 } else {
8459 mc.mc_ki[mc.mc_top]++;
8460 if (mc.mc_ki[mc.mc_top] < n) {
8461 pgno_t pg;
8462 again:
8463 ni = NODEPTR(mp, mc.mc_ki[mc.mc_top]);
8464 pg = NODEPGNO(ni);
8465 rc = mdb_page_get(txn, pg, &mp, NULL);
8466 if (rc)
8467 goto done;
8468 mc.mc_top++;
8469 mc.mc_snum++;
8470 mc.mc_ki[mc.mc_top] = 0;
8471 if (IS_BRANCH(mp)) {
8472 /* Whenever we advance to a sibling branch page,
8473 * we must proceed all the way down to its first leaf.
8474 */
8475 mdb_page_copy(mc.mc_pg[mc.mc_top], mp, my->mc_env->me_psize);
8476 goto again;
8477 } else
8478 mc.mc_pg[mc.mc_top] = mp;
8479 continue;
8480 }
8481 }
8482 if (my->mc_wlen[toggle] >= MDB_WBUF) {
8483 rc = mdb_env_cthr_toggle(my, 1);
8484 if (rc)
8485 goto done;
8486 toggle = my->mc_toggle;
8487 }
8488 mo = (MDB_page *)(my->mc_wbuf[toggle] + my->mc_wlen[toggle]);
8489 mdb_page_copy(mo, mp, my->mc_env->me_psize);
8490 mo->mp_pgno = my->mc_next_pgno++;
8491 my->mc_wlen[toggle] += my->mc_env->me_psize;
8492 if (mc.mc_top) {
8493 /* Update parent if there is one */
8494 ni = NODEPTR(mc.mc_pg[mc.mc_top-1], mc.mc_ki[mc.mc_top-1]);
8495 SETPGNO(ni, mo->mp_pgno);
8496 mdb_cursor_pop(&mc);
8497 } else {
8498 /* Otherwise we're done */
8499 *pg = mo->mp_pgno;
8500 break;
8501 }
8502 }
8503 done:
8504 free(buf);
8505 return rc;
8506 }
8507
8508 /** Copy environment with compaction. */
8509 static int ESECT
8510 mdb_env_copyfd1(MDB_env *env, HANDLE fd)
8511 {
8512 MDB_meta *mm;
8513 MDB_page *mp;
8514 mdb_copy my;
8515 MDB_txn *txn = NULL;
8516 pthread_t thr;
8517 int rc;
8518
8519 #ifdef _WIN32
8520 my.mc_mutex = CreateMutex(NULL, FALSE, NULL);
8521 my.mc_cond = CreateEvent(NULL, FALSE, FALSE, NULL);
8522 my.mc_wbuf[0] = _aligned_malloc(MDB_WBUF*2, env->me_os_psize);
8523 if (my.mc_wbuf[0] == NULL)
8524 return errno;
8525 #else
8526 pthread_mutex_init(&my.mc_mutex, NULL);
8527 pthread_cond_init(&my.mc_cond, NULL);
8528 #ifdef HAVE_MEMALIGN
8529 my.mc_wbuf[0] = memalign(env->me_os_psize, MDB_WBUF*2);
8530 if (my.mc_wbuf[0] == NULL)
8531 return errno;
8532 #else
8533 rc = posix_memalign((void **)&my.mc_wbuf[0], env->me_os_psize, MDB_WBUF*2);
8534 if (rc)
8535 return rc;
8536 #endif
8537 #endif
8538 memset(my.mc_wbuf[0], 0, MDB_WBUF*2);
8539 my.mc_wbuf[1] = my.mc_wbuf[0] + MDB_WBUF;
8540 my.mc_wlen[0] = 0;
8541 my.mc_wlen[1] = 0;
8542 my.mc_olen[0] = 0;
8543 my.mc_olen[1] = 0;
8544 my.mc_next_pgno = 2;
8545 my.mc_status = 0;
8546 my.mc_new = 1;
8547 my.mc_toggle = 0;
8548 my.mc_env = env;
8549 my.mc_fd = fd;
8550 THREAD_CREATE(thr, mdb_env_copythr, &my);
8551
8552 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
8553 if (rc)
8554 return rc;
8555
8556 mp = (MDB_page *)my.mc_wbuf[0];
8557 memset(mp, 0, 2*env->me_psize);
8558 mp->mp_pgno = 0;
8559 mp->mp_flags = P_META;
8560 mm = (MDB_meta *)METADATA(mp);
8561 mdb_env_init_meta0(env, mm);
8562 mm->mm_address = env->me_metas[0]->mm_address;
8563
8564 mp = (MDB_page *)(my.mc_wbuf[0] + env->me_psize);
8565 mp->mp_pgno = 1;
8566 mp->mp_flags = P_META;
8567 *(MDB_meta *)METADATA(mp) = *mm;
8568 mm = (MDB_meta *)METADATA(mp);
8569
8570 /* Count the number of free pages, subtract from lastpg to find
8571 * number of active pages
8572 */
8573 {
8574 MDB_ID freecount = 0;
8575 MDB_cursor mc;
8576 MDB_val key, data;
8577 mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
8578 while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
8579 freecount += *(MDB_ID *)data.mv_data;
8580 freecount += txn->mt_dbs[0].md_branch_pages +
8581 txn->mt_dbs[0].md_leaf_pages +
8582 txn->mt_dbs[0].md_overflow_pages;
8583
8584 /* Set metapage 1 */
8585 mm->mm_last_pg = txn->mt_next_pgno - freecount - 1;
8586 mm->mm_dbs[1] = txn->mt_dbs[1];
8587 mm->mm_dbs[1].md_root = mm->mm_last_pg;
8588 mm->mm_txnid = 1;
8589 }
8590 my.mc_wlen[0] = env->me_psize * 2;
8591 my.mc_txn = txn;
8592 pthread_mutex_lock(&my.mc_mutex);
8593 while(my.mc_new)
8594 pthread_cond_wait(&my.mc_cond, &my.mc_mutex);
8595 pthread_mutex_unlock(&my.mc_mutex);
8596 rc = mdb_env_cwalk(&my, &txn->mt_dbs[1].md_root, 0);
8597 if (rc == MDB_SUCCESS && my.mc_wlen[my.mc_toggle])
8598 rc = mdb_env_cthr_toggle(&my, 1);
8599 mdb_env_cthr_toggle(&my, -1);
8600 pthread_mutex_lock(&my.mc_mutex);
8601 while(my.mc_new)
8602 pthread_cond_wait(&my.mc_cond, &my.mc_mutex);
8603 pthread_mutex_unlock(&my.mc_mutex);
8604 THREAD_FINISH(thr);
8605
8606 mdb_txn_abort(txn);
8607 #ifdef _WIN32
8608 CloseHandle(my.mc_cond);
8609 CloseHandle(my.mc_mutex);
8610 _aligned_free(my.mc_wbuf[0]);
8611 #else
8612 pthread_cond_destroy(&my.mc_cond);
8613 pthread_mutex_destroy(&my.mc_mutex);
8614 free(my.mc_wbuf[0]);
8615 #endif
8616 return rc;
8617 }
8618
8619 /** Copy environment as-is. */
8620 static int ESECT
8621 mdb_env_copyfd0(MDB_env *env, HANDLE fd)
8622 {
8623 MDB_txn *txn = NULL;
8624 int rc;
8625 size_t wsize;
8626 char *ptr;
8627 #ifdef _WIN32
8628 DWORD len, w2;
8629 #define DO_WRITE(rc, fd, ptr, w2, len) rc = WriteFile(fd, ptr, w2, &len, NULL)
8630 #else
8631 ssize_t len;
8632 size_t w2;
8633 #define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0)
8634 #endif
8635
8636 /* Do the lock/unlock of the reader mutex before starting the
8637 * write txn. Otherwise other read txns could block writers.
8638 */
8639 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
8640 if (rc)
8641 return rc;
8642
8643 if (env->me_txns) {
8644 /* We must start the actual read txn after blocking writers */
8645 mdb_txn_reset0(txn, "reset-stage1");
8646
8647 /* Temporarily block writers until we snapshot the meta pages */
8648 LOCK_MUTEX_W(env);
8649
8650 rc = mdb_txn_renew0(txn);
8651 if (rc) {
8652 UNLOCK_MUTEX_W(env);
8653 goto leave;
8654 }
8655 }
8656
8657 wsize = env->me_psize * 2;
8658 ptr = env->me_map;
8659 w2 = wsize;
8660 while (w2 > 0) {
8661 DO_WRITE(rc, fd, ptr, w2, len);
8662 if (!rc) {
8663 rc = ErrCode();
8664 break;
8665 } else if (len > 0) {
8666 rc = MDB_SUCCESS;
8667 ptr += len;
8668 w2 -= len;
8669 continue;
8670 } else {
8671 /* Non-blocking or async handles are not supported */
8672 rc = EIO;
8673 break;
8674 }
8675 }
8676 if (env->me_txns)
8677 UNLOCK_MUTEX_W(env);
8678
8679 if (rc)
8680 goto leave;
8681
8682 w2 = txn->mt_next_pgno * env->me_psize;
8683 #ifdef WIN32
8684 {
8685 LARGE_INTEGER fsize;
8686 GetFileSizeEx(env->me_fd, &fsize);
8687 if (w2 > fsize.QuadPart)
8688 w2 = fsize.QuadPart;
8689 }
8690 #else
8691 {
8692 struct stat st;
8693 fstat(env->me_fd, &st);
8694 if (w2 > (size_t)st.st_size)
8695 w2 = st.st_size;
8696 }
8697 #endif
8698 wsize = w2 - wsize;
8699 while (wsize > 0) {
8700 if (wsize > MAX_WRITE)
8701 w2 = MAX_WRITE;
8702 else
8703 w2 = wsize;
8704 DO_WRITE(rc, fd, ptr, w2, len);
8705 if (!rc) {
8706 rc = ErrCode();
8707 break;
8708 } else if (len > 0) {
8709 rc = MDB_SUCCESS;
8710 ptr += len;
8711 wsize -= len;
8712 continue;
8713 } else {
8714 rc = EIO;
8715 break;
8716 }
8717 }
8718
8719 leave:
8720 mdb_txn_abort(txn);
8721 return rc;
8722 }
8723
8724 int ESECT
8725 mdb_env_copyfd2(MDB_env *env, HANDLE fd, unsigned int flags)
8726 {
8727 if (flags & MDB_CP_COMPACT)
8728 return mdb_env_copyfd1(env, fd);
8729 else
8730 return mdb_env_copyfd0(env, fd);
8731 }
8732
8733 int ESECT
8734 mdb_env_copyfd(MDB_env *env, HANDLE fd)
8735 {
8736 return mdb_env_copyfd2(env, fd, 0);
8737 }
8738
8739 int ESECT
8740 mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
8741 {
8742 int rc, len;
8743 char *lpath;
8744 HANDLE newfd = INVALID_HANDLE_VALUE;
8745
8746 if (env->me_flags & MDB_NOSUBDIR) {
8747 lpath = (char *)path;
8748 } else {
8749 len = strlen(path);
8750 len += sizeof(DATANAME);
8751 lpath = malloc(len);
8752 if (!lpath)
8753 return ENOMEM;
8754 sprintf(lpath, "%s" DATANAME, path);
8755 }
8756
8757 /* The destination path must exist, but the destination file must not.
8758 * We don't want the OS to cache the writes, since the source data is
8759 * already in the OS cache.
8760 */
8761 #ifdef _WIN32
8762 newfd = CreateFile(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
8763 FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
8764 #else
8765 newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666);
8766 #endif
8767 if (newfd == INVALID_HANDLE_VALUE) {
8768 rc = ErrCode();
8769 goto leave;
8770 }
8771
8772 if (env->me_psize >= env->me_os_psize) {
8773 #ifdef O_DIRECT
8774 /* Set O_DIRECT if the file system supports it */
8775 if ((rc = fcntl(newfd, F_GETFL)) != -1)
8776 (void) fcntl(newfd, F_SETFL, rc | O_DIRECT);
8777 #endif
8778 #ifdef F_NOCACHE /* __APPLE__ */
8779 rc = fcntl(newfd, F_NOCACHE, 1);
8780 if (rc) {
8781 rc = ErrCode();
8782 goto leave;
8783 }
8784 #endif
8785 }
8786
8787 rc = mdb_env_copyfd2(env, newfd, flags);
8788
8789 leave:
8790 if (!(env->me_flags & MDB_NOSUBDIR))
8791 free(lpath);
8792 if (newfd != INVALID_HANDLE_VALUE)
8793 if (close(newfd) < 0 && rc == MDB_SUCCESS)
8794 rc = ErrCode();
8795
8796 return rc;
8797 }
8798
8799 int ESECT
8800 mdb_env_copy(MDB_env *env, const char *path)
8801 {
8802 return mdb_env_copy2(env, path, 0);
8803 }
8804
8805 int ESECT
79348806 mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff)
79358807 {
79368808 if ((flag & CHANGEABLE) != flag)
79428814 return MDB_SUCCESS;
79438815 }
79448816
7945 int
8817 int ESECT
79468818 mdb_env_get_flags(MDB_env *env, unsigned int *arg)
79478819 {
79488820 if (!env || !arg)
79528824 return MDB_SUCCESS;
79538825 }
79548826
7955 int
8827 int ESECT
79568828 mdb_env_set_userctx(MDB_env *env, void *ctx)
79578829 {
79588830 if (!env)
79618833 return MDB_SUCCESS;
79628834 }
79638835
7964 void *
8836 void * ESECT
79658837 mdb_env_get_userctx(MDB_env *env)
79668838 {
79678839 return env ? env->me_userctx : NULL;
79688840 }
79698841
7970 int
8842 int ESECT
79718843 mdb_env_set_assert(MDB_env *env, MDB_assert_func *func)
79728844 {
79738845 if (!env)
79788850 return MDB_SUCCESS;
79798851 }
79808852
7981 int
8853 int ESECT
79828854 mdb_env_get_path(MDB_env *env, const char **arg)
79838855 {
79848856 if (!env || !arg)
79888860 return MDB_SUCCESS;
79898861 }
79908862
7991 int
8863 int ESECT
79928864 mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *arg)
79938865 {
79948866 if (!env || !arg)
80048876 * @param[out] arg the address of an #MDB_stat structure to receive the stats.
80058877 * @return 0, this function always succeeds.
80068878 */
8007 static int
8879 static int ESECT
80088880 mdb_stat0(MDB_env *env, MDB_db *db, MDB_stat *arg)
80098881 {
80108882 arg->ms_psize = env->me_psize;
80168888
80178889 return MDB_SUCCESS;
80188890 }
8019 int
8891
8892 int ESECT
80208893 mdb_env_stat(MDB_env *env, MDB_stat *arg)
80218894 {
80228895 int toggle;
80298902 return mdb_stat0(env, &env->me_metas[toggle]->mm_dbs[MAIN_DBI], arg);
80308903 }
80318904
8032 int
8905 int ESECT
80338906 mdb_env_info(MDB_env *env, MDB_envinfo *arg)
80348907 {
80358908 int toggle;
80388911 return EINVAL;
80398912
80408913 toggle = mdb_env_pick_meta(env);
8041 arg->me_mapaddr = (env->me_flags & MDB_FIXEDMAP) ? env->me_map : 0;
8914 arg->me_mapaddr = env->me_metas[toggle]->mm_address;
80428915 arg->me_mapsize = env->me_mapsize;
80438916 arg->me_maxreaders = env->me_maxreaders;
80448917
80808953 MDB_val key, data;
80818954 MDB_dbi i;
80828955 MDB_cursor mc;
8956 MDB_db dummy;
80838957 int rc, dbflag, exact;
8084 unsigned int unused = 0;
8958 unsigned int unused = 0, seq;
80858959 size_t len;
80868960
80878961 if (txn->mt_dbxs[FREE_DBI].md_cmp == NULL) {
81499023 return MDB_INCOMPATIBLE;
81509024 } else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
81519025 /* Create if requested */
8152 MDB_db dummy;
81539026 data.mv_size = sizeof(MDB_db);
81549027 data.mv_data = &dummy;
81559028 memset(&dummy, 0, sizeof(dummy));
81669039 txn->mt_dbxs[slot].md_name.mv_size = len;
81679040 txn->mt_dbxs[slot].md_rel = NULL;
81689041 txn->mt_dbflags[slot] = dbflag;
9042 /* txn-> and env-> are the same in read txns, use
9043 * tmp variable to avoid undefined assignment
9044 */
9045 seq = ++txn->mt_env->me_dbiseqs[slot];
9046 txn->mt_dbiseqs[slot] = seq;
9047
81699048 memcpy(&txn->mt_dbs[slot], data.mv_data, sizeof(MDB_db));
81709049 *dbi = slot;
81719050 mdb_default_cmp(txn, slot);
81799058
81809059 int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
81819060 {
8182 if (txn == NULL || arg == NULL || dbi >= txn->mt_numdbs)
9061 if (!arg || !TXN_DBI_EXIST(txn, dbi))
81839062 return EINVAL;
9063
9064 if (txn->mt_flags & MDB_TXN_ERROR)
9065 return MDB_BAD_TXN;
81849066
81859067 if (txn->mt_dbflags[dbi] & DB_STALE) {
81869068 MDB_cursor mc;
81979079 if (dbi <= MAIN_DBI || dbi >= env->me_maxdbs)
81989080 return;
81999081 ptr = env->me_dbxs[dbi].md_name.mv_data;
8200 env->me_dbxs[dbi].md_name.mv_data = NULL;
8201 env->me_dbxs[dbi].md_name.mv_size = 0;
8202 env->me_dbflags[dbi] = 0;
8203 free(ptr);
9082 /* If there was no name, this was already closed */
9083 if (ptr) {
9084 env->me_dbxs[dbi].md_name.mv_data = NULL;
9085 env->me_dbxs[dbi].md_name.mv_size = 0;
9086 env->me_dbflags[dbi] = 0;
9087 env->me_dbiseqs[dbi]++;
9088 free(ptr);
9089 }
82049090 }
82059091
82069092 int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags)
82079093 {
82089094 /* We could return the flags for the FREE_DBI too but what's the point? */
8209 if (txn == NULL || dbi < MAIN_DBI || dbi >= txn->mt_numdbs)
9095 if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
82109096 return EINVAL;
82119097 *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
82129098 return MDB_SUCCESS;
82469132 memcpy(&pg, NODEDATA(ni), sizeof(pg));
82479133 rc = mdb_page_get(txn, pg, &omp, NULL);
82489134 if (rc != 0)
8249 return rc;
9135 goto done;
82509136 mdb_cassert(mc, IS_OVERFLOW(omp));
82519137 rc = mdb_midl_append_range(&txn->mt_free_pgs,
82529138 pg, omp->mp_pages);
82539139 if (rc)
8254 return rc;
9140 goto done;
82559141 } else if (subs && (ni->mn_flags & F_SUBDATA)) {
82569142 mdb_xcursor_init1(mc, ni);
82579143 rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
82589144 if (rc)
8259 return rc;
9145 goto done;
82609146 }
82619147 }
82629148 } else {
82639149 if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0)
8264 return rc;
9150 goto done;
82659151 for (i=0; i<n; i++) {
82669152 pgno_t pg;
82679153 ni = NODEPTR(mp, i);
82759161 mc->mc_ki[mc->mc_top] = i;
82769162 rc = mdb_cursor_sibling(mc, 1);
82779163 if (rc) {
9164 if (rc != MDB_NOTFOUND)
9165 goto done;
82789166 /* no more siblings, go back to beginning
82799167 * of previous level.
82809168 */
82889176 }
82899177 /* free it */
82909178 rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root);
9179 done:
9180 if (rc)
9181 txn->mt_flags |= MDB_TXN_ERROR;
82919182 } else if (rc == MDB_NOTFOUND) {
82929183 rc = MDB_SUCCESS;
82939184 }
82999190 MDB_cursor *mc, *m2;
83009191 int rc;
83019192
8302 if (!txn || !dbi || dbi >= txn->mt_numdbs || (unsigned)del > 1 || !(txn->mt_dbflags[dbi] & DB_VALID))
9193 if ((unsigned)del > 1 || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
83039194 return EINVAL;
83049195
83059196 if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
83069197 return EACCES;
9198
9199 if (dbi > MAIN_DBI && TXN_DBI_CHANGED(txn, dbi))
9200 return MDB_BAD_DBI;
83079201
83089202 rc = mdb_cursor_open(txn, dbi, &mc);
83099203 if (rc)
83189212
83199213 /* Can't delete the main DB */
83209214 if (del && dbi > MAIN_DBI) {
8321 rc = mdb_del(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL);
9215 rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, 0);
83229216 if (!rc) {
83239217 txn->mt_dbflags[dbi] = DB_STALE;
83249218 mdb_dbi_close(txn->mt_env, dbi);
9219 } else {
9220 txn->mt_flags |= MDB_TXN_ERROR;
83259221 }
83269222 } else {
83279223 /* reset the DB record, mark it dirty */
83429238
83439239 int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
83449240 {
8345 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
9241 if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
83469242 return EINVAL;
83479243
83489244 txn->mt_dbxs[dbi].md_cmp = cmp;
83519247
83529248 int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
83539249 {
8354 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
9250 if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
83559251 return EINVAL;
83569252
83579253 txn->mt_dbxs[dbi].md_dcmp = cmp;
83609256
83619257 int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
83629258 {
8363 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
9259 if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
83649260 return EINVAL;
83659261
83669262 txn->mt_dbxs[dbi].md_rel = rel;
83699265
83709266 int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
83719267 {
8372 if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
9268 if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
83739269 return EINVAL;
83749270
83759271 txn->mt_dbxs[dbi].md_relctx = ctx;
83769272 return MDB_SUCCESS;
83779273 }
83789274
8379 int mdb_env_get_maxkeysize(MDB_env *env)
9275 int ESECT
9276 mdb_env_get_maxkeysize(MDB_env *env)
83809277 {
83819278 return ENV_MAXKEY(env);
83829279 }
83839280
8384 int mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
9281 int ESECT
9282 mdb_reader_list(MDB_env *env, MDB_msg_func *func, void *ctx)
83859283 {
83869284 unsigned int i, rdrs;
83879285 MDB_reader *mr;
84219319 /** Insert pid into list if not already present.
84229320 * return -1 if already present.
84239321 */
8424 static int mdb_pid_insert(MDB_PID_T *ids, MDB_PID_T pid)
9322 static int ESECT
9323 mdb_pid_insert(MDB_PID_T *ids, MDB_PID_T pid)
84259324 {
84269325 /* binary search of pid in list */
84279326 unsigned base = 0;
84579356 return 0;
84589357 }
84599358
8460 int mdb_reader_check(MDB_env *env, int *dead)
9359 int ESECT
9360 mdb_reader_check(MDB_env *env, int *dead)
84619361 {
84629362 unsigned int i, j, rdrs;
84639363 MDB_reader *mr;
0 .TH MDB_COPY 1 "2012/12/12" "LMDB 0.9.5"
1 .\" Copyright 2012 Howard Chu, Symas Corp. All Rights Reserved.
0 .TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14"
1 .\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved.
22 .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
33 .SH NAME
44 mdb_copy \- LMDB environment copy tool
55 .SH SYNOPSIS
66 .B mdb_copy
7 [\c
8 .BR \-V ]
9 [\c
10 .BR \-c ]
711 [\c
812 .BR \-n ]
913 .B srcpath
2327 written to stdout.
2428
2529 .SH OPTIONS
30 .TP
31 .BR \-V
32 Write the library version number to the standard output, and exit.
33 .TP
34 .BR \-c
35 Compact while copying. Only current data pages will be copied; freed
36 or unused pages will be omitted from the copy. This option will
37 slow down the backup process as it is more CPU-intensive.
38 .TP
2639 .BR \-n
2740 Open LDMB environment(s) which do not use subdirectories.
2841
3232 MDB_env *env;
3333 const char *progname = argv[0], *act;
3434 unsigned flags = MDB_RDONLY;
35 unsigned cpflags = 0;
3536
3637 for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
3738 if (argv[1][1] == 'n' && argv[1][2] == '\0')
3839 flags |= MDB_NOSUBDIR;
39 else
40 else if (argv[1][1] == 'c' && argv[1][2] == '\0')
41 cpflags |= MDB_CP_COMPACT;
42 else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
43 printf("%s\n", MDB_VERSION_STRING);
44 exit(0);
45 } else
4046 argc = 0;
4147 }
4248
4349 if (argc<2 || argc>3) {
44 fprintf(stderr, "usage: %s [-n] srcpath [dstpath]\n", progname);
50 fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname);
4551 exit(EXIT_FAILURE);
4652 }
4753
5763 act = "opening environment";
5864 rc = mdb_env_create(&env);
5965 if (rc == MDB_SUCCESS) {
60 rc = mdb_env_open(env, argv[1], flags, 0);
66 rc = mdb_env_open(env, argv[1], flags, 0664);
6167 }
6268 if (rc == MDB_SUCCESS) {
6369 act = "copying";
6470 if (argc == 2)
65 rc = mdb_env_copyfd(env, MDB_STDOUT);
71 rc = mdb_env_copyfd2(env, MDB_STDOUT, cpflags);
6672 else
67 rc = mdb_env_copy(env, argv[2]);
73 rc = mdb_env_copy2(env, argv[2], cpflags);
6874 }
6975 if (rc)
7076 fprintf(stderr, "%s: %s failed, error %d (%s)\n",
0 .TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14"
1 .\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved.
2 .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
3 .SH NAME
4 mdb_dump \- LMDB environment export tool
5 .SH SYNOPSIS
6 .B mdb_dump
7 .BR \ envpath
8 [\c
9 .BR \-V ]
10 [\c
11 .BI \-f \ file\fR]
12 [\c
13 .BR \-l ]
14 [\c
15 .BR \-n ]
16 [\c
17 .BR \-p ]
18 [\c
19 .BR \-a \ |
20 .BI \-s \ subdb\fR]
21 .SH DESCRIPTION
22 The
23 .B mdb_dump
24 utility reads a database and writes its contents to the
25 standard output using a portable flat-text format
26 understood by the
27 .BR mdb_load (1)
28 utility.
29 .SH OPTIONS
30 .TP
31 .BR \-V
32 Write the library version number to the standard output, and exit.
33 .TP
34 .BR \-f \ file
35 Write to the specified file instead of to the standard output.
36 .TP
37 .BR \-l
38 List the databases stored in the environment. Just the
39 names will be listed, no data will be output.
40 .TP
41 .BR \-n
42 Dump an LMDB database which does not use subdirectories.
43 .TP
44 .BR \-p
45 If characters in either the key or data items are printing characters (as
46 defined by isprint(3)), output them directly. This option permits users to
47 use standard text editors and tools to modify the contents of databases.
48
49 Note: different systems may have different notions about what characters
50 are considered printing characters, and databases dumped in this manner may
51 be less portable to external systems.
52 .TP
53 .BR \-a
54 Dump all of the subdatabases in the environment.
55 .TP
56 .BR \-s \ subdb
57 Dump a specific subdatabase. If no database is specified, only the main database is dumped.
58 .SH DIAGNOSTICS
59 Exit status is zero if no errors occur.
60 Errors result in a non-zero exit status and
61 a diagnostic message being written to standard error.
62
63 Dumping and reloading databases that use user-defined comparison functions
64 will result in new databases that use the default comparison functions.
65 \fBIn this case it is quite likely that the reloaded database will be
66 damaged beyond repair permitting neither record storage nor retrieval.\fP
67
68 The only available workaround is to modify the source for the
69 .BR mdb_load (1)
70 utility to load the database using the correct comparison functions.
71 .SH "SEE ALSO"
72 .BR mdb_load (1)
73 .SH AUTHOR
74 Howard Chu of Symas Corporation <http://www.symas.com>
0 /* mdb_dump.c - memory-mapped database dump tool */
1 /*
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted only as authorized by the OpenLDAP
7 * Public License.
8 *
9 * A copy of this license is available in the file LICENSE in the
10 * top-level directory of the distribution or, alternatively, at
11 * <http://www.OpenLDAP.org/license.html>.
12 */
13 #include <stdio.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include "lmdb.h"
21
22 #ifdef _WIN32
23 #define Z "I"
24 #else
25 #define Z "z"
26 #endif
27
28 #define PRINT 1
29 static int mode;
30
31 typedef struct flagbit {
32 int bit;
33 char *name;
34 } flagbit;
35
36 flagbit dbflags[] = {
37 { MDB_REVERSEKEY, "reversekey" },
38 { MDB_DUPSORT, "dupsort" },
39 { MDB_INTEGERKEY, "integerkey" },
40 { MDB_DUPFIXED, "dupfixed" },
41 { MDB_INTEGERDUP, "integerdup" },
42 { MDB_REVERSEDUP, "reversedup" },
43 { 0, NULL }
44 };
45
46 static volatile sig_atomic_t gotsig;
47
48 static void dumpsig( int sig )
49 {
50 gotsig=1;
51 }
52
53 static const char hexc[] = "0123456789abcdef";
54
55 static void hex(unsigned char c)
56 {
57 putchar(hexc[c >> 4]);
58 putchar(hexc[c & 0xf]);
59 }
60
61 static void text(MDB_val *v)
62 {
63 unsigned char *c, *end;
64
65 putchar(' ');
66 c = v->mv_data;
67 end = c + v->mv_size;
68 while (c < end) {
69 if (isprint(*c)) {
70 putchar(*c);
71 } else {
72 putchar('\\');
73 hex(*c);
74 }
75 c++;
76 }
77 putchar('\n');
78 }
79
80 static void byte(MDB_val *v)
81 {
82 unsigned char *c, *end;
83
84 putchar(' ');
85 c = v->mv_data;
86 end = c + v->mv_size;
87 while (c < end) {
88 hex(*c++);
89 }
90 putchar('\n');
91 }
92
93 /* Dump in BDB-compatible format */
94 static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
95 {
96 MDB_cursor *mc;
97 MDB_stat ms;
98 MDB_val key, data;
99 MDB_envinfo info;
100 unsigned int flags;
101 int rc, i;
102
103 rc = mdb_dbi_flags(txn, dbi, &flags);
104 if (rc) return rc;
105
106 rc = mdb_stat(txn, dbi, &ms);
107 if (rc) return rc;
108
109 rc = mdb_env_info(mdb_txn_env(txn), &info);
110 if (rc) return rc;
111
112 printf("VERSION=3\n");
113 printf("format=%s\n", mode & PRINT ? "print" : "bytevalue");
114 if (name)
115 printf("database=%s\n", name);
116 printf("type=btree\n");
117 printf("mapsize=%" Z "u\n", info.me_mapsize);
118 if (info.me_mapaddr)
119 printf("mapaddr=%p\n", info.me_mapaddr);
120 printf("maxreaders=%u\n", info.me_maxreaders);
121
122 if (flags & MDB_DUPSORT)
123 printf("duplicates=1\n");
124
125 for (i=0; dbflags[i].bit; i++)
126 if (flags & dbflags[i].bit)
127 printf("%s=1\n", dbflags[i].name);
128
129 printf("db_pagesize=%d\n", ms.ms_psize);
130 printf("HEADER=END\n");
131
132 rc = mdb_cursor_open(txn, dbi, &mc);
133 if (rc) return rc;
134
135 while ((rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT) == MDB_SUCCESS)) {
136 if (gotsig) {
137 rc = EINTR;
138 break;
139 }
140 if (mode & PRINT) {
141 text(&key);
142 text(&data);
143 } else {
144 byte(&key);
145 byte(&data);
146 }
147 }
148 printf("DATA=END\n");
149 if (rc == MDB_NOTFOUND)
150 rc = MDB_SUCCESS;
151
152 return rc;
153 }
154
155 static void usage(char *prog)
156 {
157 fprintf(stderr, "usage: %s dbpath [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb]\n", prog);
158 exit(EXIT_FAILURE);
159 }
160
161 int main(int argc, char *argv[])
162 {
163 int i, rc;
164 MDB_env *env;
165 MDB_txn *txn;
166 MDB_dbi dbi;
167 char *prog = argv[0];
168 char *envname;
169 char *subname = NULL;
170 int alldbs = 0, envflags = 0, list = 0;
171
172 if (argc < 2) {
173 usage(prog);
174 }
175
176 /* -a: dump main DB and all subDBs
177 * -s: dump only the named subDB
178 * -n: use NOSUBDIR flag on env_open
179 * -p: use printable characters
180 * -f: write to file instead of stdout
181 * -V: print version and exit
182 * (default) dump only the main DB
183 */
184 while ((i = getopt(argc, argv, "af:lnps:V")) != EOF) {
185 switch(i) {
186 case 'V':
187 printf("%s\n", MDB_VERSION_STRING);
188 exit(0);
189 break;
190 case 'l':
191 list = 1;
192 /*FALLTHROUGH*/;
193 case 'a':
194 if (subname)
195 usage(prog);
196 alldbs++;
197 break;
198 case 'f':
199 if (freopen(optarg, "w", stdout) == NULL) {
200 fprintf(stderr, "%s: %s: reopen: %s\n",
201 prog, optarg, strerror(errno));
202 exit(EXIT_FAILURE);
203 }
204 break;
205 case 'n':
206 envflags |= MDB_NOSUBDIR;
207 break;
208 case 'p':
209 mode |= PRINT;
210 break;
211 case 's':
212 if (alldbs)
213 usage(prog);
214 subname = optarg;
215 break;
216 default:
217 usage(prog);
218 }
219 }
220
221 if (optind != argc - 1)
222 usage(prog);
223
224 #ifdef SIGPIPE
225 signal(SIGPIPE, dumpsig);
226 #endif
227 #ifdef SIGHUP
228 signal(SIGHUP, dumpsig);
229 #endif
230 signal(SIGINT, dumpsig);
231 signal(SIGTERM, dumpsig);
232
233 envname = argv[optind];
234 rc = mdb_env_create(&env);
235 if (rc) {
236 fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
237 return EXIT_FAILURE;
238 }
239
240 if (alldbs || subname) {
241 mdb_env_set_maxdbs(env, 2);
242 }
243
244 rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
245 if (rc) {
246 fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
247 goto env_close;
248 }
249
250 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
251 if (rc) {
252 fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
253 goto env_close;
254 }
255
256 rc = mdb_open(txn, subname, 0, &dbi);
257 if (rc) {
258 fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
259 goto txn_abort;
260 }
261
262 if (alldbs) {
263 MDB_cursor *cursor;
264 MDB_val key;
265 int count = 0;
266
267 rc = mdb_cursor_open(txn, dbi, &cursor);
268 if (rc) {
269 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
270 goto txn_abort;
271 }
272 while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
273 char *str;
274 MDB_dbi db2;
275 if (memchr(key.mv_data, '\0', key.mv_size))
276 continue;
277 count++;
278 str = malloc(key.mv_size+1);
279 memcpy(str, key.mv_data, key.mv_size);
280 str[key.mv_size] = '\0';
281 rc = mdb_open(txn, str, 0, &db2);
282 if (rc == MDB_SUCCESS) {
283 if (list) {
284 printf("%s\n", str);
285 list++;
286 } else {
287 rc = dumpit(txn, db2, str);
288 if (rc)
289 break;
290 }
291 mdb_close(env, db2);
292 }
293 free(str);
294 if (rc) continue;
295 }
296 mdb_cursor_close(cursor);
297 if (!count) {
298 fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname);
299 rc = MDB_NOTFOUND;
300 } else if (rc == MDB_NOTFOUND) {
301 rc = MDB_SUCCESS;
302 }
303 } else {
304 rc = dumpit(txn, dbi, subname);
305 }
306 if (rc && rc != MDB_NOTFOUND)
307 fprintf(stderr, "%s: %s: %s\n", prog, envname, mdb_strerror(rc));
308
309 mdb_close(env, dbi);
310 txn_abort:
311 mdb_txn_abort(txn);
312 env_close:
313 mdb_env_close(env);
314
315 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
316 }
0 .TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14"
1 .\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved.
2 .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
3 .SH NAME
4 mdb_load \- LMDB environment import tool
5 .SH SYNOPSIS
6 .B mdb_load
7 .BR \ envpath
8 [\c
9 .BR \-V ]
10 [\c
11 .BI \-f \ file\fR]
12 [\c
13 .BR \-n ]
14 [\c
15 .BI \-s \ subdb\fR]
16 [\c
17 .BR \-N ]
18 [\c
19 .BR \-T ]
20 .SH DESCRIPTION
21 The
22 .B mdb_load
23 utility reads from the standard input and loads it into the
24 LMDB environment
25 .BR envpath .
26
27 The input to
28 .B mdb_load
29 must be in the output format specified by the
30 .BR mdb_dump (1)
31 utility or as specified by the
32 .B -T
33 option below.
34 .SH OPTIONS
35 .TP
36 .BR \-V
37 Write the library version number to the standard output, and exit.
38 .TP
39 .BR \-f \ file
40 Read from the specified file instead of from the standard input.
41 .TP
42 .BR \-n
43 Load an LMDB database which does not use subdirectories.
44 .TP
45 .BR \-s \ subdb
46 Load a specific subdatabase. If no database is specified, data is loaded into the main database.
47 .TP
48 .BR \-N
49 Don't overwrite existing records when loading into an already existing database; just skip them.
50 .TP
51 .BR \-T
52 Load data from simple text files. The input must be paired lines of text, where the first
53 line of the pair is the key item, and the second line of the pair is its corresponding
54 data item.
55
56 A simple escape mechanism, where newline and backslash (\\) characters are special, is
57 applied to the text input. Newline characters are interpreted as record separators.
58 Backslash characters in the text will be interpreted in one of two ways: If the backslash
59 character precedes another backslash character, the pair will be interpreted as a literal
60 backslash. If the backslash character precedes any other character, the two characters
61 following the backslash will be interpreted as a hexadecimal specification of a single
62 character; for example, \\0a is a newline character in the ASCII character set.
63
64 For this reason, any backslash or newline characters that naturally occur in the text
65 input must be escaped to avoid misinterpretation by
66 .BR mdb_load .
67
68 .SH DIAGNOSTICS
69 Exit status is zero if no errors occur.
70 Errors result in a non-zero exit status and
71 a diagnostic message being written to standard error.
72
73 .SH "SEE ALSO"
74 .BR mdb_dump (1)
75 .SH AUTHOR
76 Howard Chu of Symas Corporation <http://www.symas.com>
0 /* mdb_load.c - memory-mapped database load tool */
1 /*
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted only as authorized by the OpenLDAP
7 * Public License.
8 *
9 * A copy of this license is available in the file LICENSE in the
10 * top-level directory of the distribution or, alternatively, at
11 * <http://www.OpenLDAP.org/license.html>.
12 */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include "lmdb.h"
20
21 #define PRINT 1
22 #define NOHDR 2
23 static int mode;
24
25 static char *subname = NULL;
26
27 static size_t lineno;
28 static int version;
29
30 static int flags;
31
32 static char *prog;
33
34 static int Eof;
35
36 static MDB_envinfo info;
37
38 static MDB_val kbuf, dbuf;
39
40 #ifdef _WIN32
41 #define Z "I"
42 #else
43 #define Z "z"
44 #endif
45
46 #define STRLENOF(s) (sizeof(s)-1)
47
48 typedef struct flagbit {
49 int bit;
50 char *name;
51 int len;
52 } flagbit;
53
54 #define S(s) s, STRLENOF(s)
55
56 flagbit dbflags[] = {
57 { MDB_REVERSEKEY, S("reversekey") },
58 { MDB_DUPSORT, S("dupsort") },
59 { MDB_INTEGERKEY, S("integerkey") },
60 { MDB_DUPFIXED, S("dupfixed") },
61 { MDB_INTEGERDUP, S("integerdup") },
62 { MDB_REVERSEDUP, S("reversedup") },
63 { 0, NULL, 0 }
64 };
65
66 static void readhdr(void)
67 {
68 char *ptr;
69
70 while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) {
71 lineno++;
72 if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) {
73 version=atoi((char *)dbuf.mv_data+STRLENOF("VERSION="));
74 if (version > 3) {
75 fprintf(stderr, "%s: line %" Z "d: unsupported VERSION %d\n",
76 prog, lineno, version);
77 exit(EXIT_FAILURE);
78 }
79 } else if (!strncmp(dbuf.mv_data, "HEADER=END", STRLENOF("HEADER=END"))) {
80 break;
81 } else if (!strncmp(dbuf.mv_data, "format=", STRLENOF("format="))) {
82 if (!strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "print", STRLENOF("print")))
83 mode |= PRINT;
84 else if (strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "bytevalue", STRLENOF("bytevalue"))) {
85 fprintf(stderr, "%s: line %" Z "d: unsupported FORMAT %s\n",
86 prog, lineno, (char *)dbuf.mv_data+STRLENOF("FORMAT="));
87 exit(EXIT_FAILURE);
88 }
89 } else if (!strncmp(dbuf.mv_data, "database=", STRLENOF("database="))) {
90 ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
91 if (ptr) *ptr = '\0';
92 if (subname) free(subname);
93 subname = strdup((char *)dbuf.mv_data+STRLENOF("database="));
94 } else if (!strncmp(dbuf.mv_data, "type=", STRLENOF("type="))) {
95 if (strncmp((char *)dbuf.mv_data+STRLENOF("type="), "btree", STRLENOF("btree"))) {
96 fprintf(stderr, "%s: line %" Z "d: unsupported type %s\n",
97 prog, lineno, (char *)dbuf.mv_data+STRLENOF("type="));
98 exit(EXIT_FAILURE);
99 }
100 } else if (!strncmp(dbuf.mv_data, "mapaddr=", STRLENOF("mapaddr="))) {
101 int i;
102 ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
103 if (ptr) *ptr = '\0';
104 i = sscanf((char *)dbuf.mv_data+STRLENOF("mapaddr="), "%p", &info.me_mapaddr);
105 if (i != 1) {
106 fprintf(stderr, "%s: line %" Z "d: invalid mapaddr %s\n",
107 prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapaddr="));
108 exit(EXIT_FAILURE);
109 }
110 } else if (!strncmp(dbuf.mv_data, "mapsize=", STRLENOF("mapsize="))) {
111 int i;
112 ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
113 if (ptr) *ptr = '\0';
114 i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Z "u", &info.me_mapsize);
115 if (i != 1) {
116 fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n",
117 prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize="));
118 exit(EXIT_FAILURE);
119 }
120 } else if (!strncmp(dbuf.mv_data, "maxreaders=", STRLENOF("maxreaders="))) {
121 int i;
122 ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
123 if (ptr) *ptr = '\0';
124 i = sscanf((char *)dbuf.mv_data+STRLENOF("maxreaders="), "%u", &info.me_maxreaders);
125 if (i != 1) {
126 fprintf(stderr, "%s: line %" Z "d: invalid maxreaders %s\n",
127 prog, lineno, (char *)dbuf.mv_data+STRLENOF("maxreaders="));
128 exit(EXIT_FAILURE);
129 }
130 } else {
131 int i;
132 for (i=0; dbflags[i].bit; i++) {
133 if (!strncmp(dbuf.mv_data, dbflags[i].name, dbflags[i].len) &&
134 ((char *)dbuf.mv_data)[dbflags[i].len] == '=') {
135 flags |= dbflags[i].bit;
136 break;
137 }
138 }
139 if (!dbflags[i].bit) {
140 ptr = memchr(dbuf.mv_data, '=', dbuf.mv_size);
141 if (!ptr) {
142 fprintf(stderr, "%s: line %" Z "d: unexpected format\n",
143 prog, lineno);
144 exit(EXIT_FAILURE);
145 } else {
146 *ptr = '\0';
147 fprintf(stderr, "%s: line %" Z "d: unrecognized keyword ignored: %s\n",
148 prog, lineno, (char *)dbuf.mv_data);
149 }
150 }
151 }
152 }
153 }
154
155 static void badend(void)
156 {
157 fprintf(stderr, "%s: line %" Z "d: unexpected end of input\n",
158 prog, lineno);
159 }
160
161 static int unhex(unsigned char *c2)
162 {
163 int x, c;
164 x = *c2++ & 0x4f;
165 if (x & 0x40)
166 x -= 55;
167 c = x << 4;
168 x = *c2 & 0x4f;
169 if (x & 0x40)
170 x -= 55;
171 c |= x;
172 return c;
173 }
174
175 static int readline(MDB_val *out, MDB_val *buf)
176 {
177 unsigned char *c1, *c2, *end;
178 size_t len;
179 int c;
180
181 if (!(mode & NOHDR)) {
182 c = fgetc(stdin);
183 if (c == EOF) {
184 Eof = 1;
185 return EOF;
186 }
187 if (c != ' ') {
188 lineno++;
189 if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
190 badend:
191 Eof = 1;
192 badend();
193 return EOF;
194 }
195 if (c == 'D' && !strncmp(buf->mv_data, "ATA=END", STRLENOF("ATA=END")))
196 return EOF;
197 goto badend;
198 }
199 }
200 if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
201 Eof = 1;
202 return EOF;
203 }
204 lineno++;
205
206 c1 = buf->mv_data;
207 len = strlen((char *)c1);
208
209 /* Is buffer too short? */
210 while (c1[len-1] != '\n') {
211 buf->mv_data = realloc(buf->mv_data, buf->mv_size*2);
212 if (!buf->mv_data) {
213 Eof = 1;
214 fprintf(stderr, "%s: line %" Z "d: out of memory, line too long\n",
215 prog, lineno);
216 return EOF;
217 }
218 c1 = buf->mv_data;
219 c1 += buf->mv_size;
220 if (fgets((char *)c1, buf->mv_size, stdin) == NULL) {
221 Eof = 1;
222 badend();
223 return EOF;
224 }
225 buf->mv_size *= 2;
226 len = strlen((char *)c1);
227 }
228 c1 = c2 = buf->mv_data;
229 len = strlen((char *)c1);
230 c1[--len] = '\0';
231 end = c1 + len;
232
233 if (mode & PRINT) {
234 while (c2 < end) {
235 if (*c2 == '\\') {
236 if (c2[1] == '\\') {
237 c1++; c2 += 2;
238 } else {
239 if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) {
240 Eof = 1;
241 badend();
242 return EOF;
243 }
244 *c1++ = unhex(++c2);
245 c2 += 2;
246 }
247 } else {
248 c1++; c2++;
249 }
250 }
251 } else {
252 /* odd length not allowed */
253 if (len & 1) {
254 Eof = 1;
255 badend();
256 return EOF;
257 }
258 while (c2 < end) {
259 if (!isxdigit(*c2) || !isxdigit(c2[1])) {
260 Eof = 1;
261 badend();
262 return EOF;
263 }
264 *c1++ = unhex(c2);
265 c2 += 2;
266 }
267 }
268 c2 = out->mv_data = buf->mv_data;
269 out->mv_size = c1 - c2;
270
271 return 0;
272 }
273
274 static void usage(void)
275 {
276 fprintf(stderr, "usage: %s dbpath [-V] [-f input] [-n] [-s name] [-N] [-T]\n", prog);
277 exit(EXIT_FAILURE);
278 }
279
280 int main(int argc, char *argv[])
281 {
282 int i, rc;
283 MDB_env *env;
284 MDB_txn *txn;
285 MDB_cursor *mc;
286 MDB_dbi dbi;
287 char *envname;
288 int envflags = 0, putflags = 0;
289 int dohdr = 0;
290
291 prog = argv[0];
292
293 if (argc < 2) {
294 usage();
295 }
296
297 /* -f: load file instead of stdin
298 * -n: use NOSUBDIR flag on env_open
299 * -s: load into named subDB
300 * -N: use NOOVERWRITE on puts
301 * -T: read plaintext
302 * -V: print version and exit
303 */
304 while ((i = getopt(argc, argv, "f:ns:NTV")) != EOF) {
305 switch(i) {
306 case 'V':
307 printf("%s\n", MDB_VERSION_STRING);
308 exit(0);
309 break;
310 case 'f':
311 if (freopen(optarg, "r", stdin) == NULL) {
312 fprintf(stderr, "%s: %s: reopen: %s\n",
313 prog, optarg, strerror(errno));
314 exit(EXIT_FAILURE);
315 }
316 break;
317 case 'n':
318 envflags |= MDB_NOSUBDIR;
319 break;
320 case 's':
321 subname = strdup(optarg);
322 break;
323 case 'N':
324 putflags = MDB_NOOVERWRITE|MDB_NODUPDATA;
325 break;
326 case 'T':
327 mode |= NOHDR;
328 break;
329 default:
330 usage();
331 }
332 }
333
334 if (optind != argc - 1)
335 usage();
336
337 dbuf.mv_size = 4096;
338 dbuf.mv_data = malloc(dbuf.mv_size);
339
340 if (!(mode & NOHDR))
341 readhdr();
342
343 envname = argv[optind];
344 rc = mdb_env_create(&env);
345 if (rc) {
346 fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
347 return EXIT_FAILURE;
348 }
349
350 mdb_env_set_maxdbs(env, 2);
351
352 if (info.me_maxreaders)
353 mdb_env_set_maxreaders(env, info.me_maxreaders);
354
355 if (info.me_mapsize)
356 mdb_env_set_mapsize(env, info.me_mapsize);
357
358 if (info.me_mapaddr)
359 envflags |= MDB_FIXEDMAP;
360
361 rc = mdb_env_open(env, envname, envflags, 0664);
362 if (rc) {
363 fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
364 goto env_close;
365 }
366
367 kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2;
368 kbuf.mv_data = malloc(kbuf.mv_size);
369
370 while(!Eof) {
371 MDB_val key, data;
372 int batch = 0;
373 flags = 0;
374
375 if (!dohdr) {
376 dohdr = 1;
377 } else if (!(mode & NOHDR))
378 readhdr();
379
380 rc = mdb_txn_begin(env, NULL, 0, &txn);
381 if (rc) {
382 fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
383 goto env_close;
384 }
385
386 rc = mdb_open(txn, subname, flags|MDB_CREATE, &dbi);
387 if (rc) {
388 fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
389 goto txn_abort;
390 }
391
392 rc = mdb_cursor_open(txn, dbi, &mc);
393 if (rc) {
394 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
395 goto txn_abort;
396 }
397
398 while(1) {
399 rc = readline(&key, &kbuf);
400 if (rc == EOF)
401 break;
402 if (rc)
403 goto txn_abort;
404
405 rc = readline(&data, &dbuf);
406 if (rc)
407 goto txn_abort;
408
409 rc = mdb_cursor_put(mc, &key, &data, putflags);
410 if (rc == MDB_KEYEXIST && putflags)
411 continue;
412 if (rc)
413 goto txn_abort;
414 batch++;
415 if (batch == 100) {
416 rc = mdb_txn_commit(txn);
417 if (rc) {
418 fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
419 prog, lineno, mdb_strerror(rc));
420 goto env_close;
421 }
422 rc = mdb_txn_begin(env, NULL, 0, &txn);
423 if (rc) {
424 fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
425 goto env_close;
426 }
427 rc = mdb_cursor_open(txn, dbi, &mc);
428 if (rc) {
429 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
430 goto txn_abort;
431 }
432 batch = 0;
433 }
434 }
435 rc = mdb_txn_commit(txn);
436 txn = NULL;
437 if (rc) {
438 fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
439 prog, lineno, mdb_strerror(rc));
440 goto env_close;
441 }
442 mdb_dbi_close(env, dbi);
443 }
444
445 txn_abort:
446 mdb_txn_abort(txn);
447 env_close:
448 mdb_env_close(env);
449
450 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
451 }
0 .TH MDB_STAT 1 "2012/12/12" "LMDB 0.9.5"
1 .\" Copyright 2012 Howard Chu, Symas Corp. All Rights Reserved.
0 .TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14"
1 .\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved.
22 .\" Copying restrictions apply. See COPYRIGHT/LICENSE.
33 .SH NAME
44 mdb_stat \- LMDB environment status tool
55 .SH SYNOPSIS
66 .B mdb_stat
77 .BR \ envpath
8 [\c
9 .BR \-V ]
810 [\c
911 .BR \-e ]
1012 [\c
2123 .B mdb_stat
2224 utility displays the status of an LMDB environment.
2325 .SH OPTIONS
26 .TP
27 .BR \-V
28 Write the library version number to the standard output, and exit.
2429 .TP
2530 .BR \-e
2631 Display information about the database environment.
3636
3737 static void usage(char *prog)
3838 {
39 fprintf(stderr, "usage: %s dbpath [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb]\n", prog);
39 fprintf(stderr, "usage: %s dbpath [-V] [-n] [-e] [-r[r]] [-f[f[f]]] [-a|-s subdb]\n", prog);
4040 exit(EXIT_FAILURE);
4141 }
4242
6363 * -f: print freelist info
6464 * -r: print reader info
6565 * -n: use NOSUBDIR flag on env_open
66 * -V: print version and exit
6667 * (default) print stat of only the main DB
6768 */
68 while ((i = getopt(argc, argv, "aefnrs:")) != EOF) {
69 while ((i = getopt(argc, argv, "Vaefnrs:")) != EOF) {
6970 switch(i) {
71 case 'V':
72 printf("%s\n", MDB_VERSION_STRING);
73 exit(0);
74 break;
7075 case 'a':
7176 if (subname)
7277 usage(prog);
99104
100105 envname = argv[optind];
101106 rc = mdb_env_create(&env);
107 if (rc) {
108 fprintf(stderr, "mdb_env_create failed, error %d %s\n", rc, mdb_strerror(rc));
109 return EXIT_FAILURE;
110 }
102111
103112 if (alldbs || subname) {
104113 mdb_env_set_maxdbs(env, 4);
106115
107116 rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
108117 if (rc) {
109 printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
118 fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
110119 goto env_close;
111120 }
112121
113122 if (envinfo) {
114 rc = mdb_env_stat(env, &mst);
115 rc = mdb_env_info(env, &mei);
123 (void)mdb_env_stat(env, &mst);
124 (void)mdb_env_info(env, &mei);
116125 printf("Environment Info\n");
117126 printf(" Map address: %p\n", mei.me_mapaddr);
118127 printf(" Map size: %"Z"u\n", mei.me_mapsize);
139148
140149 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
141150 if (rc) {
142 printf("mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
151 fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
143152 goto env_close;
144153 }
145154
152161 dbi = 0;
153162 rc = mdb_cursor_open(txn, dbi, &cursor);
154163 if (rc) {
155 printf("mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
164 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
156165 goto txn_abort;
157166 }
158167 rc = mdb_stat(txn, dbi, &mst);
159168 if (rc) {
160 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
169 fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
161170 goto txn_abort;
162171 }
163172 prstat(&mst);
195204
196205 rc = mdb_open(txn, subname, 0, &dbi);
197206 if (rc) {
198 printf("mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
207 fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
199208 goto txn_abort;
200209 }
201210
202211 rc = mdb_stat(txn, dbi, &mst);
203212 if (rc) {
204 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
213 fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
205214 goto txn_abort;
206215 }
207216 printf("Status of %s\n", subname ? subname : "Main DB");
213222
214223 rc = mdb_cursor_open(txn, dbi, &cursor);
215224 if (rc) {
216 printf("mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
225 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
217226 goto txn_abort;
218227 }
219228 while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
231240 if (rc) continue;
232241 rc = mdb_stat(txn, db2, &mst);
233242 if (rc) {
234 printf("mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
243 fprintf(stderr, "mdb_stat failed, error %d %s\n", rc, mdb_strerror(rc));
235244 goto txn_abort;
236245 }
237246 prstat(&mst);
22 /* $OpenLDAP$ */
33 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
44 *
5 * Copyright 2000-2013 The OpenLDAP Foundation.
5 * Copyright 2000-2014 The OpenLDAP Foundation.
66 * All rights reserved.
77 *
88 * Redistribution and use in source and binary forms, with or without
2121 #include <sys/types.h>
2222 #include "midl.h"
2323
24 /** @defgroup internal MDB Internals
24 /** @defgroup internal LMDB Internals
2525 * @{
2626 */
2727 /** @defgroup idls ID List Management
196196 while (n)
197197 ids[n--] = id++;
198198 return 0;
199 }
200
201 void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge )
202 {
203 MDB_ID old_id, merge_id, i = merge[0], j = idl[0], k = i+j, total = k;
204 idl[0] = (MDB_ID)-1; /* delimiter for idl scan below */
205 old_id = idl[j];
206 while (i) {
207 merge_id = merge[i--];
208 for (; old_id < merge_id; old_id = idl[--j])
209 idl[k--] = old_id;
210 idl[k--] = merge_id;
211 }
212 idl[0] = total;
199213 }
200214
201215 /* Quicksort + Insertion sort for small arrays */
00 /** @file midl.h
1 * @brief mdb ID List header file.
1 * @brief LMDB ID List header file.
22 *
33 * This file was originally part of back-bdb but has been
44 * modified for use in libmdb. Most of the macros defined
1010 /* $OpenLDAP$ */
1111 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
1212 *
13 * Copyright 2000-2013 The OpenLDAP Foundation.
13 * Copyright 2000-2014 The OpenLDAP Foundation.
1414 * All rights reserved.
1515 *
1616 * Redistribution and use in source and binary forms, with or without
3131 extern "C" {
3232 #endif
3333
34 /** @defgroup internal MDB Internals
34 /** @defgroup internal LMDB Internals
3535 * @{
3636 */
3737
6666 #define MDB_IDL_CPY( dst, src ) (memcpy( dst, src, MDB_IDL_SIZEOF( src ) ))
6767 #define MDB_IDL_FIRST( ids ) ( (ids)[1] )
6868 #define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] )
69
70 /** Current max length of an #mdb_midl_alloc()ed IDL */
71 #define MDB_IDL_ALLOCLEN( ids ) ( (ids)[-1] )
6972
7073 /** Append ID to IDL. The IDL must be big enough. */
7174 #define mdb_midl_xappend(idl, id) do { \
127130 */
128131 int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
129132
133 /** Merge an IDL onto an IDL. The destination IDL must be big enough.
134 * @param[in] idl The IDL to merge into.
135 * @param[in] merge The IDL to merge.
136 */
137 void mdb_midl_xmerge( MDB_IDL idl, MDB_IDL merge );
138
130139 /** Sort an IDL.
131140 * @param[in,out] ids The IDL to sort.
132141 */
00 /* mtest.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1010 * top-level directory of the distribution or, alternatively, at
1111 * <http://www.OpenLDAP.org/license.html>.
1212 */
13 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1413 #include <stdio.h>
1514 #include <stdlib.h>
1615 #include <time.h>
1716 #include "lmdb.h"
17
18 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
19 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
20 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
21 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
1822
1923 int main(int argc,char * argv[])
2024 {
2529 MDB_txn *txn;
2630 MDB_stat mst;
2731 MDB_cursor *cursor, *cur2;
32 MDB_cursor_op op;
2833 int count;
2934 int *values;
3035 char sval[32] = "";
3136
32 srandom(time(NULL));
37 srand(time(NULL));
3338
34 count = (random()%384) + 64;
39 count = (rand()%384) + 64;
3540 values = (int *)malloc(count*sizeof(int));
3641
3742 for(i = 0;i<count;i++) {
38 values[i] = random()%1024;
43 values[i] = rand()%1024;
3944 }
4045
41 rc = mdb_env_create(&env);
42 rc = mdb_env_set_mapsize(env, 10485760);
43 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664);
44 rc = mdb_txn_begin(env, NULL, 0, &txn);
45 rc = mdb_open(txn, NULL, 0, &dbi);
46 E(mdb_env_create(&env));
47 E(mdb_env_set_mapsize(env, 10485760));
48 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
49 E(mdb_txn_begin(env, NULL, 0, &txn));
50 E(mdb_open(txn, NULL, 0, &dbi));
4651
4752 key.mv_size = sizeof(int);
4853 key.mv_data = sval;
5257 printf("Adding %d values\n", count);
5358 for (i=0;i<count;i++) {
5459 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
55 rc = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
56 if (rc) {
60 if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
5761 j++;
5862 data.mv_size = sizeof(sval);
5963 data.mv_data = sval;
6064 }
6165 }
6266 if (j) printf("%d duplicates skipped\n", j);
63 rc = mdb_txn_commit(txn);
64 rc = mdb_env_stat(env, &mst);
67 E(mdb_txn_commit(txn));
68 E(mdb_env_stat(env, &mst));
6569
66 rc = mdb_txn_begin(env, NULL, 1, &txn);
67 rc = mdb_cursor_open(txn, dbi, &cursor);
70 E(mdb_txn_begin(env, NULL, 1, &txn));
71 E(mdb_cursor_open(txn, dbi, &cursor));
6872 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
6973 printf("key: %p %.*s, data: %p %.*s\n",
7074 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
7175 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7276 }
77 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
7378 mdb_cursor_close(cursor);
7479 mdb_txn_abort(txn);
7580
7681 j=0;
7782 key.mv_data = sval;
78 for (i= count - 1; i > -1; i-= (random()%5)) {
83 for (i= count - 1; i > -1; i-= (rand()%5)) {
7984 j++;
8085 txn=NULL;
81 rc = mdb_txn_begin(env, NULL, 0, &txn);
86 E(mdb_txn_begin(env, NULL, 0, &txn));
8287 sprintf(sval, "%03x ", values[i]);
83 rc = mdb_del(txn, dbi, &key, NULL);
84 if (rc) {
88 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
8589 j--;
8690 mdb_txn_abort(txn);
8791 } else {
88 rc = mdb_txn_commit(txn);
92 E(mdb_txn_commit(txn));
8993 }
9094 }
9195 free(values);
9296 printf("Deleted %d values\n", j);
9397
94 rc = mdb_env_stat(env, &mst);
95 rc = mdb_txn_begin(env, NULL, 1, &txn);
96 rc = mdb_cursor_open(txn, dbi, &cursor);
98 E(mdb_env_stat(env, &mst));
99 E(mdb_txn_begin(env, NULL, 1, &txn));
100 E(mdb_cursor_open(txn, dbi, &cursor));
97101 printf("Cursor next\n");
98102 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
99103 printf("key: %.*s, data: %.*s\n",
100104 (int) key.mv_size, (char *) key.mv_data,
101105 (int) data.mv_size, (char *) data.mv_data);
102106 }
107 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
103108 printf("Cursor last\n");
104 rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST);
109 E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
105110 printf("key: %.*s, data: %.*s\n",
106111 (int) key.mv_size, (char *) key.mv_data,
107112 (int) data.mv_size, (char *) data.mv_data);
111116 (int) key.mv_size, (char *) key.mv_data,
112117 (int) data.mv_size, (char *) data.mv_data);
113118 }
119 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
114120 printf("Cursor last/prev\n");
115 rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST);
121 E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
116122 printf("key: %.*s, data: %.*s\n",
117123 (int) key.mv_size, (char *) key.mv_data,
118124 (int) data.mv_size, (char *) data.mv_data);
119 rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV);
125 E(mdb_cursor_get(cursor, &key, &data, MDB_PREV));
120126 printf("key: %.*s, data: %.*s\n",
121127 (int) key.mv_size, (char *) key.mv_data,
122128 (int) data.mv_size, (char *) data.mv_data);
124130 mdb_txn_abort(txn);
125131
126132 printf("Deleting with cursor\n");
127 rc = mdb_txn_begin(env, NULL, 0, &txn);
128 rc = mdb_cursor_open(txn, dbi, &cur2);
133 E(mdb_txn_begin(env, NULL, 0, &txn));
134 E(mdb_cursor_open(txn, dbi, &cur2));
129135 for (i=0; i<50; i++) {
130 rc = mdb_cursor_get(cur2, &key, &data, MDB_NEXT);
131 if (rc)
136 if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT)))
132137 break;
133138 printf("key: %p %.*s, data: %p %.*s\n",
134139 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
135140 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
136 rc = mdb_del(txn, dbi, &key, NULL);
141 E(mdb_del(txn, dbi, &key, NULL));
137142 }
138143
139144 printf("Restarting cursor in txn\n");
140 rc = mdb_cursor_get(cur2, &key, &data, MDB_FIRST);
141 printf("key: %p %.*s, data: %p %.*s\n",
142 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
143 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
144 for (i=0; i<32; i++) {
145 rc = mdb_cursor_get(cur2, &key, &data, MDB_NEXT);
146 if (rc) break;
145 for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
146 if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op)))
147 break;
147148 printf("key: %p %.*s, data: %p %.*s\n",
148149 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
149150 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
150151 }
151152 mdb_cursor_close(cur2);
152 rc = mdb_txn_commit(txn);
153 E(mdb_txn_commit(txn));
153154
154155 printf("Restarting cursor outside txn\n");
155 rc = mdb_txn_begin(env, NULL, 0, &txn);
156 rc = mdb_cursor_open(txn, dbi, &cursor);
157 rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
158 printf("key: %p %.*s, data: %p %.*s\n",
159 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
160 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
161 for (i=0; i<32; i++) {
162 rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT);
163 if (rc) break;
156 E(mdb_txn_begin(env, NULL, 0, &txn));
157 E(mdb_cursor_open(txn, dbi, &cursor));
158 for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
159 if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op)))
160 break;
164161 printf("key: %p %.*s, data: %p %.*s\n",
165162 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
166163 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
00 /* mtest2.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1313
1414 /* Just like mtest.c, but using a subDB instead of the main DB */
1515
16 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1716 #include <stdio.h>
1817 #include <stdlib.h>
1918 #include <time.h>
2019 #include "lmdb.h"
20
21 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
2125
2226 int main(int argc,char * argv[])
2327 {
3236 int *values;
3337 char sval[32] = "";
3438
35 srandom(time(NULL));
39 srand(time(NULL));
3640
37 count = (random()%384) + 64;
41 count = (rand()%384) + 64;
3842 values = (int *)malloc(count*sizeof(int));
3943
4044 for(i = 0;i<count;i++) {
41 values[i] = random()%1024;
45 values[i] = rand()%1024;
4246 }
4347
44 rc = mdb_env_create(&env);
45 rc = mdb_env_set_mapsize(env, 10485760);
46 rc = mdb_env_set_maxdbs(env, 4);
47 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
48 rc = mdb_txn_begin(env, NULL, 0, &txn);
49 rc = mdb_open(txn, "id1", MDB_CREATE, &dbi);
48 E(mdb_env_create(&env));
49 E(mdb_env_set_mapsize(env, 10485760));
50 E(mdb_env_set_maxdbs(env, 4));
51 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
52 E(mdb_txn_begin(env, NULL, 0, &txn));
53 E(mdb_open(txn, "id1", MDB_CREATE, &dbi));
5054
5155 key.mv_size = sizeof(int);
5256 key.mv_data = sval;
5660 printf("Adding %d values\n", count);
5761 for (i=0;i<count;i++) {
5862 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
59 rc = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
60 if (rc) j++;
63 if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE)))
64 j++;
6165 }
6266 if (j) printf("%d duplicates skipped\n", j);
63 rc = mdb_txn_commit(txn);
64 rc = mdb_env_stat(env, &mst);
67 E(mdb_txn_commit(txn));
68 E(mdb_env_stat(env, &mst));
6569
66 rc = mdb_txn_begin(env, NULL, 1, &txn);
67 rc = mdb_cursor_open(txn, dbi, &cursor);
70 E(mdb_txn_begin(env, NULL, 1, &txn));
71 E(mdb_cursor_open(txn, dbi, &cursor));
6872 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
6973 printf("key: %p %.*s, data: %p %.*s\n",
7074 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
7175 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7276 }
77 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
7378 mdb_cursor_close(cursor);
7479 mdb_txn_abort(txn);
7580
7681 j=0;
7782 key.mv_data = sval;
78 for (i= count - 1; i > -1; i-= (random()%5)) {
83 for (i= count - 1; i > -1; i-= (rand()%5)) {
7984 j++;
8085 txn=NULL;
81 rc = mdb_txn_begin(env, NULL, 0, &txn);
86 E(mdb_txn_begin(env, NULL, 0, &txn));
8287 sprintf(sval, "%03x ", values[i]);
83 rc = mdb_del(txn, dbi, &key, NULL);
84 if (rc) {
88 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
8589 j--;
8690 mdb_txn_abort(txn);
8791 } else {
88 rc = mdb_txn_commit(txn);
92 E(mdb_txn_commit(txn));
8993 }
9094 }
9195 free(values);
9296 printf("Deleted %d values\n", j);
9397
94 rc = mdb_env_stat(env, &mst);
95 rc = mdb_txn_begin(env, NULL, 1, &txn);
96 rc = mdb_cursor_open(txn, dbi, &cursor);
98 E(mdb_env_stat(env, &mst));
99 E(mdb_txn_begin(env, NULL, 1, &txn));
100 E(mdb_cursor_open(txn, dbi, &cursor));
97101 printf("Cursor next\n");
98102 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
99103 printf("key: %.*s, data: %.*s\n",
100104 (int) key.mv_size, (char *) key.mv_data,
101105 (int) data.mv_size, (char *) data.mv_data);
102106 }
107 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
103108 printf("Cursor prev\n");
104109 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
105110 printf("key: %.*s, data: %.*s\n",
106111 (int) key.mv_size, (char *) key.mv_data,
107112 (int) data.mv_size, (char *) data.mv_data);
108113 }
114 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
109115 mdb_cursor_close(cursor);
110116 mdb_close(env, dbi);
111117
00 /* mtest3.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1212 */
1313
1414 /* Tests for sorted duplicate DBs */
15 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1615 #include <stdio.h>
1716 #include <stdlib.h>
1817 #include <string.h>
1918 #include <time.h>
2019 #include "lmdb.h"
20
21 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
2125
2226 int main(int argc,char * argv[])
2327 {
3337 char sval[32];
3438 char kval[sizeof(int)];
3539
36 srandom(time(NULL));
40 srand(time(NULL));
3741
3842 memset(sval, 0, sizeof(sval));
3943
40 count = (random()%384) + 64;
44 count = (rand()%384) + 64;
4145 values = (int *)malloc(count*sizeof(int));
4246
4347 for(i = 0;i<count;i++) {
44 values[i] = random()%1024;
48 values[i] = rand()%1024;
4549 }
4650
47 rc = mdb_env_create(&env);
48 rc = mdb_env_set_mapsize(env, 10485760);
49 rc = mdb_env_set_maxdbs(env, 4);
50 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
51 rc = mdb_txn_begin(env, NULL, 0, &txn);
52 rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi);
51 E(mdb_env_create(&env));
52 E(mdb_env_set_mapsize(env, 10485760));
53 E(mdb_env_set_maxdbs(env, 4));
54 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
55 E(mdb_txn_begin(env, NULL, 0, &txn));
56 E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
5357
5458 key.mv_size = sizeof(int);
5559 key.mv_data = kval;
6165 if (!(i & 0x0f))
6266 sprintf(kval, "%03x", values[i]);
6367 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
64 rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
65 if (rc) j++;
68 if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
69 j++;
6670 }
6771 if (j) printf("%d duplicates skipped\n", j);
68 rc = mdb_txn_commit(txn);
69 rc = mdb_env_stat(env, &mst);
72 E(mdb_txn_commit(txn));
73 E(mdb_env_stat(env, &mst));
7074
71 rc = mdb_txn_begin(env, NULL, 1, &txn);
72 rc = mdb_cursor_open(txn, dbi, &cursor);
75 E(mdb_txn_begin(env, NULL, 1, &txn));
76 E(mdb_cursor_open(txn, dbi, &cursor));
7377 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
7478 printf("key: %p %.*s, data: %p %.*s\n",
7579 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
7680 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7781 }
82 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
7883 mdb_cursor_close(cursor);
7984 mdb_txn_abort(txn);
8085
8186 j=0;
8287
83 for (i= count - 1; i > -1; i-= (random()%5)) {
88 for (i= count - 1; i > -1; i-= (rand()%5)) {
8489 j++;
8590 txn=NULL;
86 rc = mdb_txn_begin(env, NULL, 0, &txn);
91 E(mdb_txn_begin(env, NULL, 0, &txn));
8792 sprintf(kval, "%03x", values[i & ~0x0f]);
8893 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
8994 key.mv_size = sizeof(int);
9095 key.mv_data = kval;
9196 data.mv_size = sizeof(sval);
9297 data.mv_data = sval;
93 rc = mdb_del(txn, dbi, &key, &data);
94 if (rc) {
98 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
9599 j--;
96100 mdb_txn_abort(txn);
97101 } else {
98 rc = mdb_txn_commit(txn);
102 E(mdb_txn_commit(txn));
99103 }
100104 }
101105 free(values);
102106 printf("Deleted %d values\n", j);
103107
104 rc = mdb_env_stat(env, &mst);
105 rc = mdb_txn_begin(env, NULL, 1, &txn);
106 rc = mdb_cursor_open(txn, dbi, &cursor);
108 E(mdb_env_stat(env, &mst));
109 E(mdb_txn_begin(env, NULL, 1, &txn));
110 E(mdb_cursor_open(txn, dbi, &cursor));
107111 printf("Cursor next\n");
108112 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
109113 printf("key: %.*s, data: %.*s\n",
110114 (int) key.mv_size, (char *) key.mv_data,
111115 (int) data.mv_size, (char *) data.mv_data);
112116 }
117 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
113118 printf("Cursor prev\n");
114119 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
115120 printf("key: %.*s, data: %.*s\n",
116121 (int) key.mv_size, (char *) key.mv_data,
117122 (int) data.mv_size, (char *) data.mv_data);
118123 }
124 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
119125 mdb_cursor_close(cursor);
120126 mdb_close(env, dbi);
121127
00 /* mtest4.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1212 */
1313
1414 /* Tests for sorted duplicate DBs with fixed-size keys */
15 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1615 #include <stdio.h>
1716 #include <stdlib.h>
1817 #include <string.h>
1918 #include <time.h>
2019 #include "lmdb.h"
20
21 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
2125
2226 int main(int argc,char * argv[])
2327 {
4246 values[i] = i*5;
4347 }
4448
45 rc = mdb_env_create(&env);
46 rc = mdb_env_set_mapsize(env, 10485760);
47 rc = mdb_env_set_maxdbs(env, 4);
48 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
49 rc = mdb_txn_begin(env, NULL, 0, &txn);
50 rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi);
49 E(mdb_env_create(&env));
50 E(mdb_env_set_mapsize(env, 10485760));
51 E(mdb_env_set_maxdbs(env, 4));
52 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
53 E(mdb_txn_begin(env, NULL, 0, &txn));
54 E(mdb_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi));
5155
5256 key.mv_size = sizeof(int);
5357 key.mv_data = kval;
5862 strcpy(kval, "001");
5963 for (i=0;i<count;i++) {
6064 sprintf(sval, "%07x", values[i]);
61 rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
62 if (rc) j++;
65 if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
66 j++;
6367 }
6468 if (j) printf("%d duplicates skipped\n", j);
65 rc = mdb_txn_commit(txn);
66 rc = mdb_env_stat(env, &mst);
69 E(mdb_txn_commit(txn));
70 E(mdb_env_stat(env, &mst));
6771
6872 /* there should be one full page of dups now.
6973 */
70 rc = mdb_txn_begin(env, NULL, 1, &txn);
71 rc = mdb_cursor_open(txn, dbi, &cursor);
74 E(mdb_txn_begin(env, NULL, 1, &txn));
75 E(mdb_cursor_open(txn, dbi, &cursor));
7276 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
7377 printf("key: %p %.*s, data: %p %.*s\n",
7478 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
7579 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7680 }
81 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
7782 mdb_cursor_close(cursor);
7883 mdb_txn_abort(txn);
7984
8994 data.mv_data = sval;
9095
9196 sprintf(sval, "%07x", values[3]+1);
92 rc = mdb_txn_begin(env, NULL, 0, &txn);
93 rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
97 E(mdb_txn_begin(env, NULL, 0, &txn));
98 (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
9499 mdb_txn_abort(txn);
95100
96101 sprintf(sval, "%07x", values[255]+1);
97 rc = mdb_txn_begin(env, NULL, 0, &txn);
98 rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
102 E(mdb_txn_begin(env, NULL, 0, &txn));
103 (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
99104 mdb_txn_abort(txn);
100105
101106 sprintf(sval, "%07x", values[500]+1);
102 rc = mdb_txn_begin(env, NULL, 0, &txn);
103 rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
104 rc = mdb_txn_commit(txn);
107 E(mdb_txn_begin(env, NULL, 0, &txn));
108 (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
109 E(mdb_txn_commit(txn));
105110
106111 /* Try MDB_NEXT_MULTIPLE */
107 rc = mdb_txn_begin(env, NULL, 0, &txn);
108 rc = mdb_cursor_open(txn, dbi, &cursor);
112 E(mdb_txn_begin(env, NULL, 0, &txn));
113 E(mdb_cursor_open(txn, dbi, &cursor));
109114 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT_MULTIPLE)) == 0) {
110115 printf("key: %.*s, data: %.*s\n",
111116 (int) key.mv_size, (char *) key.mv_data,
112117 (int) data.mv_size, (char *) data.mv_data);
113118 }
119 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
114120 mdb_cursor_close(cursor);
115121 mdb_txn_abort(txn);
116122 j=0;
117123
118 for (i= count - 1; i > -1; i-= (random()%3)) {
124 for (i= count - 1; i > -1; i-= (rand()%3)) {
119125 j++;
120126 txn=NULL;
121 rc = mdb_txn_begin(env, NULL, 0, &txn);
127 E(mdb_txn_begin(env, NULL, 0, &txn));
122128 sprintf(sval, "%07x", values[i]);
123129 key.mv_size = sizeof(int);
124130 key.mv_data = kval;
125131 data.mv_size = sizeof(sval);
126132 data.mv_data = sval;
127 rc = mdb_del(txn, dbi, &key, &data);
128 if (rc) {
133 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
129134 j--;
130135 mdb_txn_abort(txn);
131136 } else {
132 rc = mdb_txn_commit(txn);
137 E(mdb_txn_commit(txn));
133138 }
134139 }
135140 free(values);
136141 printf("Deleted %d values\n", j);
137142
138 rc = mdb_env_stat(env, &mst);
139 rc = mdb_txn_begin(env, NULL, 1, &txn);
140 rc = mdb_cursor_open(txn, dbi, &cursor);
143 E(mdb_env_stat(env, &mst));
144 E(mdb_txn_begin(env, NULL, 1, &txn));
145 E(mdb_cursor_open(txn, dbi, &cursor));
141146 printf("Cursor next\n");
142147 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
143148 printf("key: %.*s, data: %.*s\n",
144149 (int) key.mv_size, (char *) key.mv_data,
145150 (int) data.mv_size, (char *) data.mv_data);
146151 }
152 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
147153 printf("Cursor prev\n");
148154 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
149155 printf("key: %.*s, data: %.*s\n",
150156 (int) key.mv_size, (char *) key.mv_data,
151157 (int) data.mv_size, (char *) data.mv_data);
152158 }
159 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
153160 mdb_cursor_close(cursor);
154161 mdb_close(env, dbi);
155162
00 /* mtest5.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1212 */
1313
1414 /* Tests for sorted duplicate DBs using cursor_put */
15 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1615 #include <stdio.h>
1716 #include <stdlib.h>
1817 #include <string.h>
1918 #include <time.h>
2019 #include "lmdb.h"
20
21 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
2125
2226 int main(int argc,char * argv[])
2327 {
3337 char sval[32];
3438 char kval[sizeof(int)];
3539
36 srandom(time(NULL));
40 srand(time(NULL));
3741
3842 memset(sval, 0, sizeof(sval));
3943
40 count = (random()%384) + 64;
44 count = (rand()%384) + 64;
4145 values = (int *)malloc(count*sizeof(int));
4246
4347 for(i = 0;i<count;i++) {
44 values[i] = random()%1024;
48 values[i] = rand()%1024;
4549 }
4650
47 rc = mdb_env_create(&env);
48 rc = mdb_env_set_mapsize(env, 10485760);
49 rc = mdb_env_set_maxdbs(env, 4);
50 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
51 rc = mdb_txn_begin(env, NULL, 0, &txn);
52 rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi);
53 rc = mdb_cursor_open(txn, dbi, &cursor);
51 E(mdb_env_create(&env));
52 E(mdb_env_set_mapsize(env, 10485760));
53 E(mdb_env_set_maxdbs(env, 4));
54 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
55 E(mdb_txn_begin(env, NULL, 0, &txn));
56 E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
57 E(mdb_cursor_open(txn, dbi, &cursor));
5458
5559 key.mv_size = sizeof(int);
5660 key.mv_data = kval;
6266 if (!(i & 0x0f))
6367 sprintf(kval, "%03x", values[i]);
6468 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
65 rc = mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA);
66 if (rc) j++;
69 if (RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA)))
70 j++;
6771 }
6872 if (j) printf("%d duplicates skipped\n", j);
6973 mdb_cursor_close(cursor);
70 rc = mdb_txn_commit(txn);
71 rc = mdb_env_stat(env, &mst);
74 E(mdb_txn_commit(txn));
75 E(mdb_env_stat(env, &mst));
7276
73 rc = mdb_txn_begin(env, NULL, 1, &txn);
74 rc = mdb_cursor_open(txn, dbi, &cursor);
77 E(mdb_txn_begin(env, NULL, 1, &txn));
78 E(mdb_cursor_open(txn, dbi, &cursor));
7579 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
7680 printf("key: %p %.*s, data: %p %.*s\n",
7781 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
7882 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7983 }
84 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
8085 mdb_cursor_close(cursor);
8186 mdb_txn_abort(txn);
8287
8388 j=0;
8489
85 for (i= count - 1; i > -1; i-= (random()%5)) {
90 for (i= count - 1; i > -1; i-= (rand()%5)) {
8691 j++;
8792 txn=NULL;
88 rc = mdb_txn_begin(env, NULL, 0, &txn);
93 E(mdb_txn_begin(env, NULL, 0, &txn));
8994 sprintf(kval, "%03x", values[i & ~0x0f]);
9095 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
9196 key.mv_size = sizeof(int);
9297 key.mv_data = kval;
9398 data.mv_size = sizeof(sval);
9499 data.mv_data = sval;
95 rc = mdb_del(txn, dbi, &key, &data);
96 if (rc) {
100 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
97101 j--;
98102 mdb_txn_abort(txn);
99103 } else {
100 rc = mdb_txn_commit(txn);
104 E(mdb_txn_commit(txn));
101105 }
102106 }
103107 free(values);
104108 printf("Deleted %d values\n", j);
105109
106 rc = mdb_env_stat(env, &mst);
107 rc = mdb_txn_begin(env, NULL, 1, &txn);
108 rc = mdb_cursor_open(txn, dbi, &cursor);
110 E(mdb_env_stat(env, &mst));
111 E(mdb_txn_begin(env, NULL, 1, &txn));
112 E(mdb_cursor_open(txn, dbi, &cursor));
109113 printf("Cursor next\n");
110114 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
111115 printf("key: %.*s, data: %.*s\n",
112116 (int) key.mv_size, (char *) key.mv_data,
113117 (int) data.mv_size, (char *) data.mv_data);
114118 }
119 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
115120 printf("Cursor prev\n");
116121 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
117122 printf("key: %.*s, data: %.*s\n",
118123 (int) key.mv_size, (char *) key.mv_data,
119124 (int) data.mv_size, (char *) data.mv_data);
120125 }
126 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
121127 mdb_cursor_close(cursor);
122128 mdb_close(env, dbi);
123129
00 /* mtest6.c - memory-mapped database tester/toy */
11 /*
2 * Copyright 2011 Howard Chu, Symas Corp.
2 * Copyright 2011-2014 Howard Chu, Symas Corp.
33 * All rights reserved.
44 *
55 * Redistribution and use in source and binary forms, with or without
1212 */
1313
1414 /* Tests for DB splits and merges */
15 #define _XOPEN_SOURCE 500 /* srandom(), random() */
1615 #include <stdio.h>
1716 #include <stdlib.h>
1817 #include <string.h>
1918 #include <time.h>
2019 #include "lmdb.h"
20
21 #define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22 #define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23 #define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24 "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
2125
2226 char dkbuf[1024];
2327
3539 long kval;
3640 char *sval;
3741
38 srandom(time(NULL));
42 srand(time(NULL));
3943
40 rc = mdb_env_create(&env);
41 rc = mdb_env_set_mapsize(env, 10485760);
42 rc = mdb_env_set_maxdbs(env, 4);
43 rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
44 rc = mdb_txn_begin(env, NULL, 0, &txn);
45 rc = mdb_open(txn, "id2", MDB_CREATE|MDB_INTEGERKEY, &dbi);
46 rc = mdb_cursor_open(txn, dbi, &cursor);
47 rc = mdb_stat(txn, dbi, &mst);
44 E(mdb_env_create(&env));
45 E(mdb_env_set_mapsize(env, 10485760));
46 E(mdb_env_set_maxdbs(env, 4));
47 E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
48 E(mdb_txn_begin(env, NULL, 0, &txn));
49 E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi));
50 E(mdb_cursor_open(txn, dbi, &cursor));
51 E(mdb_stat(txn, dbi, &mst));
4852
4953 sval = calloc(1, mst.ms_psize / 4);
5054 key.mv_size = sizeof(long);
5660 for (i=0;i<12;i++) {
5761 kval = i*5;
5862 sprintf(sval, "%08x", kval);
59 rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
63 (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
6064 }
6165 printf("Adding 12 more values, should yield 3 splits\n");
6266 for (i=0;i<12;i++) {
6367 kval = i*5+4;
6468 sprintf(sval, "%08x", kval);
65 rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
69 (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
6670 }
6771 printf("Adding 12 more values, should yield 3 splits\n");
6872 for (i=0;i<12;i++) {
6973 kval = i*5+1;
7074 sprintf(sval, "%08x", kval);
71 rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
75 (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
7276 }
73 rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
77 E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST));
7478
7579 do {
7680 printf("key: %p %s, data: %p %.*s\n",
7781 key.mv_data, mdb_dkey(&key, dkbuf),
7882 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
7983 } while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0);
84 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
8085 mdb_cursor_close(cursor);
8186 mdb_txn_commit(txn);
8287
8388 #if 0
8489 j=0;
8590
86 for (i= count - 1; i > -1; i-= (random()%5)) {
91 for (i= count - 1; i > -1; i-= (rand()%5)) {
8792 j++;
8893 txn=NULL;
89 rc = mdb_txn_begin(env, NULL, 0, &txn);
94 E(mdb_txn_begin(env, NULL, 0, &txn));
9095 sprintf(kval, "%03x", values[i & ~0x0f]);
9196 sprintf(sval, "%03x %d foo bar", values[i], values[i]);
9297 key.mv_size = sizeof(int);
9398 key.mv_data = kval;
9499 data.mv_size = sizeof(sval);
95100 data.mv_data = sval;
96 rc = mdb_del(txn, dbi, &key, &data);
97 if (rc) {
101 if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
98102 j--;
99103 mdb_txn_abort(txn);
100104 } else {
101 rc = mdb_txn_commit(txn);
105 E(mdb_txn_commit(txn));
102106 }
103107 }
104108 free(values);
105109 printf("Deleted %d values\n", j);
106110
107 rc = mdb_env_stat(env, &mst);
108 rc = mdb_txn_begin(env, NULL, 1, &txn);
109 rc = mdb_cursor_open(txn, dbi, &cursor);
111 E(mdb_env_stat(env, &mst));
112 E(mdb_txn_begin(env, NULL, 1, &txn));
113 E(mdb_cursor_open(txn, dbi, &cursor));
110114 printf("Cursor next\n");
111115 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
112116 printf("key: %.*s, data: %.*s\n",
113117 (int) key.mv_size, (char *) key.mv_data,
114118 (int) data.mv_size, (char *) data.mv_data);
115119 }
120 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
116121 printf("Cursor prev\n");
117122 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
118123 printf("key: %.*s, data: %.*s\n",
119124 (int) key.mv_size, (char *) key.mv_data,
120125 (int) data.mv_size, (char *) data.mv_data);
121126 }
127 CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
122128 mdb_cursor_close(cursor);
123 mdb_close(txn, dbi);
129 mdb_close(env, dbi);
124130
125131 mdb_txn_abort(txn);
126132 #endif
+0
-71
libraries/liblmdb/sample-bdb.c less more
0 /* sample-bdb.c - BerkeleyDB toy/sample
1 *
2 * Do a line-by-line comparison of this and sample-mdb.c
3 */
4 /*
5 * Copyright 2012 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <db.h>
19
20 int main(int argc,char * argv[])
21 {
22 int rc;
23 DB_ENV *env;
24 DB *dbi;
25 DBT key, data;
26 DB_TXN *txn;
27 DBC *cursor;
28 char sval[32], kval[32];
29
30 #define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
31 rc = db_env_create(&env, 0);
32 rc = env->open(env, "./testdb", FLAGS, 0664);
33 rc = db_create(&dbi, env, 0);
34 rc = env->txn_begin(env, NULL, &txn, 0);
35 rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
36
37 memset(&key, 0, sizeof(DBT));
38 memset(&data, 0, sizeof(DBT));
39 key.size = sizeof(int);
40 key.data = sval;
41 data.size = sizeof(sval);
42 data.data = sval;
43
44 sprintf(sval, "%03x %d foo bar", 32, 3141592);
45 rc = dbi->put(dbi, txn, &key, &data, 0);
46 rc = txn->commit(txn, 0);
47 if (rc) {
48 fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
49 goto leave;
50 }
51 rc = env->txn_begin(env, NULL, &txn, 0);
52 rc = dbi->cursor(dbi, txn, &cursor, 0);
53 key.flags = DB_DBT_USERMEM;
54 key.data = kval;
55 key.ulen = sizeof(kval);
56 data.flags = DB_DBT_USERMEM;
57 data.data = sval;
58 data.ulen = sizeof(sval);
59 while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
60 printf("key: %p %.*s, data: %p %.*s\n",
61 key.data, (int) key.size, (char *) key.data,
62 data.data, (int) data.size, (char *) data.data);
63 }
64 rc = cursor->c_close(cursor);
65 rc = txn->abort(txn);
66 leave:
67 rc = dbi->close(dbi, 0);
68 rc = env->close(env, 0);
69 return rc;
70 }
0 /* sample-bdb.txt - BerkeleyDB toy/sample
1 *
2 * Do a line-by-line comparison of this and sample-mdb.txt
3 */
4 /*
5 * Copyright 2012 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <db.h>
19
20 int main(int argc,char * argv[])
21 {
22 int rc;
23 DB_ENV *env;
24 DB *dbi;
25 DBT key, data;
26 DB_TXN *txn;
27 DBC *cursor;
28 char sval[32], kval[32];
29
30 /* Note: Most error checking omitted for simplicity */
31
32 #define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
33 rc = db_env_create(&env, 0);
34 rc = env->open(env, "./testdb", FLAGS, 0664);
35 rc = db_create(&dbi, env, 0);
36 rc = env->txn_begin(env, NULL, &txn, 0);
37 rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
38
39 memset(&key, 0, sizeof(DBT));
40 memset(&data, 0, sizeof(DBT));
41 key.size = sizeof(int);
42 key.data = sval;
43 data.size = sizeof(sval);
44 data.data = sval;
45
46 sprintf(sval, "%03x %d foo bar", 32, 3141592);
47 rc = dbi->put(dbi, txn, &key, &data, 0);
48 rc = txn->commit(txn, 0);
49 if (rc) {
50 fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
51 goto leave;
52 }
53 rc = env->txn_begin(env, NULL, &txn, 0);
54 rc = dbi->cursor(dbi, txn, &cursor, 0);
55 key.flags = DB_DBT_USERMEM;
56 key.data = kval;
57 key.ulen = sizeof(kval);
58 data.flags = DB_DBT_USERMEM;
59 data.data = sval;
60 data.ulen = sizeof(sval);
61 while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
62 printf("key: %p %.*s, data: %p %.*s\n",
63 key.data, (int) key.size, (char *) key.data,
64 data.data, (int) data.size, (char *) data.data);
65 }
66 rc = cursor->c_close(cursor);
67 rc = txn->abort(txn);
68 leave:
69 rc = dbi->close(dbi, 0);
70 rc = env->close(env, 0);
71 return rc;
72 }
+0
-60
libraries/liblmdb/sample-mdb.c less more
0 /* sample-mdb.c - MDB toy/sample
1 *
2 * Do a line-by-line comparison of this and sample-bdb.c
3 */
4 /*
5 * Copyright 2012 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16 #include <stdio.h>
17 #include "lmdb.h"
18
19 int main(int argc,char * argv[])
20 {
21 int rc;
22 MDB_env *env;
23 MDB_dbi dbi;
24 MDB_val key, data;
25 MDB_txn *txn;
26 MDB_cursor *cursor;
27 char sval[32];
28
29 rc = mdb_env_create(&env);
30 rc = mdb_env_open(env, "./testdb", 0, 0664);
31 rc = mdb_txn_begin(env, NULL, 0, &txn);
32 rc = mdb_open(txn, NULL, 0, &dbi);
33
34 key.mv_size = sizeof(int);
35 key.mv_data = sval;
36 data.mv_size = sizeof(sval);
37 data.mv_data = sval;
38
39 sprintf(sval, "%03x %d foo bar", 32, 3141592);
40 rc = mdb_put(txn, dbi, &key, &data, 0);
41 rc = mdb_txn_commit(txn);
42 if (rc) {
43 fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc));
44 goto leave;
45 }
46 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
47 rc = mdb_cursor_open(txn, dbi, &cursor);
48 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
49 printf("key: %p %.*s, data: %p %.*s\n",
50 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
51 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
52 }
53 mdb_cursor_close(cursor);
54 mdb_txn_abort(txn);
55 leave:
56 mdb_close(env, dbi);
57 mdb_env_close(env);
58 return 0;
59 }
0 /* sample-mdb.txt - MDB toy/sample
1 *
2 * Do a line-by-line comparison of this and sample-bdb.txt
3 */
4 /*
5 * Copyright 2012 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16 #include <stdio.h>
17 #include "lmdb.h"
18
19 int main(int argc,char * argv[])
20 {
21 int rc;
22 MDB_env *env;
23 MDB_dbi dbi;
24 MDB_val key, data;
25 MDB_txn *txn;
26 MDB_cursor *cursor;
27 char sval[32];
28
29 /* Note: Most error checking omitted for simplicity */
30
31 rc = mdb_env_create(&env);
32 rc = mdb_env_open(env, "./testdb", 0, 0664);
33 rc = mdb_txn_begin(env, NULL, 0, &txn);
34 rc = mdb_open(txn, NULL, 0, &dbi);
35
36 key.mv_size = sizeof(int);
37 key.mv_data = sval;
38 data.mv_size = sizeof(sval);
39 data.mv_data = sval;
40
41 sprintf(sval, "%03x %d foo bar", 32, 3141592);
42 rc = mdb_put(txn, dbi, &key, &data, 0);
43 rc = mdb_txn_commit(txn);
44 if (rc) {
45 fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc));
46 goto leave;
47 }
48 rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
49 rc = mdb_cursor_open(txn, dbi, &cursor);
50 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
51 printf("key: %p %.*s, data: %p %.*s\n",
52 key.mv_data, (int) key.mv_size, (char *) key.mv_data,
53 data.mv_data, (int) data.mv_size, (char *) data.mv_data);
54 }
55 mdb_cursor_close(cursor);
56 mdb_txn_abort(txn);
57 leave:
58 mdb_close(env, dbi);
59 mdb_env_close(env);
60 return 0;
61 }
0 <tagfile>
1 <compound kind="page">
2 <name>mdb_copy_1</name>
3 <title>mdb_copy - environment copy tool</title>
4 <filename>mdb_copy.1</filename>
5 </compound>
6 <compound kind="page">
7 <name>mdb_dump_1</name>
8 <title>mdb_dump - environment export tool</title>
9 <filename>mdb_dump.1</filename>
10 </compound>
11 <compound kind="page">
12 <name>mdb_load_1</name>
13 <title>mdb_load - environment import tool</title>
14 <filename>mdb_load.1</filename>
15 </compound>
16 <compound kind="page">
17 <name>mdb_stat_1</name>
18 <title>mdb_stat - environment status tool</title>
19 <filename>mdb_stat.1</filename>
20 </compound>
21 </tagfile>