New upstream version 0.9.15
Ondřej Surý
8 years ago
0 | 0 | LMDB 0.9 Change Log |
1 | ||
2 | LMDB 0.9.15 Release (2015/06/19) | |
3 | Fix txn init (ITS#7961,#7987) | |
4 | Fix MDB_PREV_DUP (ITS#7955,#7671) | |
5 | Fix compact of empty env (ITS#7956) | |
6 | Fix mdb_copy file mode | |
7 | Fix mdb_env_close() after failed mdb_env_open() | |
8 | Fix mdb_rebalance collapsing root (ITS#8062) | |
9 | Fix mdb_load with large values (ITS#8066) | |
10 | Fix to retry writes on EINTR (ITS#8106) | |
11 | Fix mdb_cursor_del on empty DB (ITS#8109) | |
12 | Fix MDB_INTEGERDUP key compare (ITS#8117) | |
13 | Fix error handling (ITS#7959,#8157,etc.) | |
14 | Fix race conditions (ITS#7969,7970) | |
15 | Added workaround for fdatasync bug in ext3fs | |
16 | Build | |
17 | Don't use -fPIC for static lib | |
18 | Update .gitignore (ITS#7952,#7953) | |
19 | Cleanup for "make test" (ITS#7841), "make clean", mtest*.c | |
20 | Misc. Android/Windows cleanup | |
21 | Documentation | |
22 | Fix MDB_APPEND doc | |
23 | Fix MDB_MAXKEYSIZE doc (ITS#8156) | |
24 | Fix mdb_cursor_put,mdb_cursor_del EACCES description | |
25 | Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021) | |
26 | Clarify MDB_WRITEMAP doc (ITS#8021) | |
27 | Clarify mdb_env_open doc | |
28 | Clarify mdb_dbi_open doc | |
1 | 29 | |
2 | 30 | LMDB 0.9.14 Release (2014/09/20) |
3 | 31 | Fix to support 64K page size (ITS#7713) |
0 | Copyright 2011-2014 Howard Chu, Symas Corp. | |
0 | Copyright 2011-2015 Howard Chu, Symas Corp. | |
1 | 1 | All rights reserved. |
2 | 2 | |
3 | 3 | Redistribution and use in source and binary forms, with or without |
10 | 10 | # - MDB_USE_POSIX_SEM |
11 | 11 | # - MDB_DSYNC |
12 | 12 | # - MDB_FDATASYNC |
13 | # - MDB_FDATASYNC_WORKS | |
13 | 14 | # - MDB_USE_PWRITEV |
14 | 15 | # |
15 | 16 | # There may be other macros in mdb.c of interest. You should |
40 | 41 | for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done |
41 | 42 | |
42 | 43 | clean: |
43 | rm -rf $(PROGS) *.[ao] *.so *~ testdb | |
44 | rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb | |
44 | 45 | |
45 | 46 | test: all |
46 | mkdir testdb | |
47 | rm -rf testdb && mkdir testdb | |
47 | 48 | ./mtest && ./mdb_stat testdb |
48 | 49 | |
49 | 50 | liblmdb.a: mdb.o midl.o |
50 | 51 | ar rs $@ mdb.o midl.o |
51 | 52 | |
52 | liblmdb.so: mdb.o midl.o | |
53 | liblmdb.so: mdb.lo midl.lo | |
53 | 54 | # $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) |
54 | $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.o midl.o $(SOLIBS) | |
55 | $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS) | |
55 | 56 | |
56 | 57 | mdb_stat: mdb_stat.o liblmdb.a |
57 | 58 | mdb_copy: mdb_copy.o liblmdb.a |
65 | 66 | mtest6: mtest6.o liblmdb.a |
66 | 67 | |
67 | 68 | mdb.o: mdb.c lmdb.h midl.h |
68 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c | |
69 | $(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c | |
69 | 70 | |
70 | 71 | midl.o: midl.c midl.h |
71 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c | |
72 | $(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c | |
73 | ||
74 | mdb.lo: mdb.c lmdb.h midl.h | |
75 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@ | |
76 | ||
77 | midl.lo: midl.c midl.h | |
78 | $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@ | |
72 | 79 | |
73 | 80 | %: %.o |
74 | 81 | $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ |
118 | 118 | * |
119 | 119 | * @author Howard Chu, Symas Corporation. |
120 | 120 | * |
121 | * @copyright Copyright 2011-2014 Howard Chu, Symas Corp. All rights reserved. | |
121 | * @copyright Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved. | |
122 | 122 | * |
123 | 123 | * Redistribution and use in source and binary forms, with or without |
124 | 124 | * modification, are permitted only as authorized by the OpenLDAP |
183 | 183 | /** Library minor version */ |
184 | 184 | #define MDB_VERSION_MINOR 9 |
185 | 185 | /** Library patch version */ |
186 | #define MDB_VERSION_PATCH 14 | |
186 | #define MDB_VERSION_PATCH 15 | |
187 | 187 | |
188 | 188 | /** Combine args a,b,c into a single integer for easy version comparisons */ |
189 | 189 | #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) |
193 | 193 | MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) |
194 | 194 | |
195 | 195 | /** The release date of this library version */ |
196 | #define MDB_VERSION_DATE "September 20, 2014" | |
196 | #define MDB_VERSION_DATE "June 19, 2015" | |
197 | 197 | |
198 | 198 | /** A stringifier for the version info */ |
199 | 199 | #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" |
295 | 295 | #define MDB_REVERSEKEY 0x02 |
296 | 296 | /** use sorted duplicates */ |
297 | 297 | #define MDB_DUPSORT 0x04 |
298 | /** numeric keys in native byte order. | |
298 | /** numeric keys in native byte order: either unsigned int or size_t. | |
299 | 299 | * The keys must all be of the same size. */ |
300 | 300 | #define MDB_INTEGERKEY 0x08 |
301 | 301 | /** with #MDB_DUPSORT, sorted dup items have fixed size */ |
302 | 302 | #define MDB_DUPFIXED 0x10 |
303 | /** with #MDB_DUPSORT, dups are numeric in native byte order */ | |
303 | /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */ | |
304 | 304 | #define MDB_INTEGERDUP 0x20 |
305 | 305 | /** with #MDB_DUPSORT, use reverse string dups */ |
306 | 306 | #define MDB_REVERSEDUP 0x40 |
515 | 515 | * and uses fewer mallocs, but loses protection from application bugs |
516 | 516 | * like wild pointer writes and other bad updates into the database. |
517 | 517 | * Incompatible with nested transactions. |
518 | * Processes with and without MDB_WRITEMAP on the same environment do | |
519 | * not cooperate well. | |
518 | * Do not mix processes with and without MDB_WRITEMAP on the same | |
519 | * environment. This can defeat durability (#mdb_env_sync etc). | |
520 | 520 | * <li>#MDB_NOMETASYNC |
521 | 521 | * Flush system buffers to disk only once per transaction, omit the |
522 | 522 | * metadata flush. Defer that until the system flushes files to disk, |
587 | 587 | * reserved in that case. |
588 | 588 | * This flag may be changed at any time using #mdb_env_set_flags(). |
589 | 589 | * </ul> |
590 | * @param[in] mode The UNIX permissions to set on created files. This parameter | |
591 | * is ignored on Windows. | |
590 | * @param[in] mode The UNIX permissions to set on created files and semaphores. | |
591 | * This parameter is ignored on Windows. | |
592 | 592 | * @return A non-zero error value on failure and 0 on success. Some possible |
593 | 593 | * errors are: |
594 | 594 | * <ul> |
697 | 697 | * Data is always written to disk when #mdb_txn_commit() is called, |
698 | 698 | * but the operating system may keep it buffered. LMDB always flushes |
699 | 699 | * the OS buffers upon commit as well, unless the environment was |
700 | * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. | |
700 | * opened with #MDB_NOSYNC or in part #MDB_NOMETASYNC. This call is | |
701 | * not valid if the environment was opened with #MDB_RDONLY. | |
701 | 702 | * @param[in] env An environment handle returned by #mdb_env_create() |
702 | 703 | * @param[in] force If non-zero, force a synchronous flush. Otherwise |
703 | 704 | * if the environment has the #MDB_NOSYNC flag set the flushes |
705 | 706 | * @return A non-zero error value on failure and 0 on success. Some possible |
706 | 707 | * errors are: |
707 | 708 | * <ul> |
709 | * <li>EACCES - the environment is read-only. | |
708 | 710 | * <li>EINVAL - an invalid parameter was specified. |
709 | 711 | * <li>EIO - an error occurred during synchronization. |
710 | 712 | * </ul> |
1018 | 1020 | * The database handle may be discarded by calling #mdb_dbi_close(). |
1019 | 1021 | * The old database handle is returned if the database was already open. |
1020 | 1022 | * The handle may only be closed once. |
1023 | * | |
1021 | 1024 | * The database handle will be private to the current transaction until |
1022 | 1025 | * the transaction is successfully committed. If the transaction is |
1023 | 1026 | * aborted the handle will be closed automatically. |
1024 | * After a successful commit the | |
1025 | * handle will reside in the shared environment, and may be used | |
1026 | * by other transactions. This function must not be called from | |
1027 | * multiple concurrent transactions. A transaction that uses this function | |
1028 | * must finish (either commit or abort) before any other transaction may | |
1029 | * use this function. | |
1027 | * After a successful commit the handle will reside in the shared | |
1028 | * environment, and may be used by other transactions. | |
1029 | * | |
1030 | * This function must not be called from multiple concurrent | |
1031 | * transactions in the same process. A transaction that uses | |
1032 | * this function must finish (either commit or abort) before | |
1033 | * any other transaction in the process may use this function. | |
1030 | 1034 | * |
1031 | 1035 | * To use named databases (with name != NULL), #mdb_env_set_maxdbs() |
1032 | 1036 | * must be called before opening the environment. Database names |
1047 | 1051 | * keys may have multiple data items, stored in sorted order.) By default |
1048 | 1052 | * keys must be unique and may have only a single data item. |
1049 | 1053 | * <li>#MDB_INTEGERKEY |
1050 | * Keys are binary integers in native byte order. Setting this option | |
1051 | * requires all keys to be the same size, typically sizeof(int) | |
1052 | * or sizeof(size_t). | |
1054 | * Keys are binary integers in native byte order, either unsigned int | |
1055 | * or size_t, and will be sorted as such. | |
1056 | * The keys must all be of the same size. | |
1053 | 1057 | * <li>#MDB_DUPFIXED |
1054 | 1058 | * This flag may only be used in combination with #MDB_DUPSORT. This option |
1055 | 1059 | * tells the library that the data items for this database are all the same |
1057 | 1061 | * all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE |
1058 | 1062 | * cursor operations may be used to retrieve multiple items at once. |
1059 | 1063 | * <li>#MDB_INTEGERDUP |
1060 | * This option specifies that duplicate data items are also integers, and | |
1061 | * should be sorted as such. | |
1064 | * This option specifies that duplicate data items are binary integers, | |
1065 | * similar to #MDB_INTEGERKEY keys. | |
1062 | 1066 | * <li>#MDB_REVERSEDUP |
1063 | 1067 | * This option specifies that duplicate data items should be compared as |
1064 | 1068 | * strings in reverse order. |
1269 | 1273 | * LMDB does nothing else with this memory, the caller is expected |
1270 | 1274 | * to modify all of the space requested. |
1271 | 1275 | * <li>#MDB_APPEND - append the given key/data pair to the end of the |
1272 | * database. No key comparisons are performed. This option allows | |
1273 | * fast bulk loading when keys are already known to be in the | |
1274 | * correct order. Loading unsorted keys with this flag will cause | |
1275 | * data corruption. | |
1276 | * database. This option allows fast bulk loading when keys are | |
1277 | * already known to be in the correct order. Loading unsorted keys | |
1278 | * with this flag will cause a #MDB_KEYEXIST error. | |
1276 | 1279 | * <li>#MDB_APPENDDUP - as above, but for sorted dup data. |
1277 | 1280 | * </ul> |
1278 | 1281 | * @return A non-zero error value on failure and 0 on success. Some possible |
1448 | 1451 | * <ul> |
1449 | 1452 | * <li>#MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). |
1450 | 1453 | * <li>#MDB_TXN_FULL - the transaction has too many dirty pages. |
1451 | * <li>EACCES - an attempt was made to modify a read-only database. | |
1454 | * <li>EACCES - an attempt was made to write in a read-only transaction. | |
1452 | 1455 | * <li>EINVAL - an invalid parameter was specified. |
1453 | 1456 | * </ul> |
1454 | 1457 | */ |
1468 | 1471 | * @return A non-zero error value on failure and 0 on success. Some possible |
1469 | 1472 | * errors are: |
1470 | 1473 | * <ul> |
1471 | * <li>EACCES - an attempt was made to modify a read-only database. | |
1474 | * <li>EACCES - an attempt was made to write in a read-only transaction. | |
1472 | 1475 | * <li>EINVAL - an invalid parameter was specified. |
1473 | 1476 | * </ul> |
1474 | 1477 | */ |
4 | 4 | * BerkeleyDB API, but much simplified. |
5 | 5 | */ |
6 | 6 | /* |
7 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
7 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
8 | 8 | * All rights reserved. |
9 | 9 | * |
10 | 10 | * Redistribution and use in source and binary forms, with or without |
78 | 78 | #define CACHEFLUSH(addr, bytes, cache) |
79 | 79 | #endif |
80 | 80 | |
81 | #if defined(__linux) && !defined(MDB_FDATASYNC_WORKS) | |
82 | /** fdatasync is broken on ext3/ext4fs on older kernels, see | |
83 | * description in #mdb_env_open2 comments. You can safely | |
84 | * define MDB_FDATASYNC_WORKS if this code will only be run | |
85 | * on kernels 3.6 and newer. | |
86 | */ | |
87 | #define BROKEN_FDATASYNC | |
88 | #endif | |
81 | 89 | |
82 | 90 | #include <errno.h> |
83 | 91 | #include <limits.h> |
89 | 97 | #include <time.h> |
90 | 98 | #include <unistd.h> |
91 | 99 | |
92 | #if defined(__sun) | |
100 | #if defined(__sun) || defined(ANDROID) | |
93 | 101 | /* Most platforms have posix_memalign, older may only have memalign */ |
94 | 102 | #define HAVE_MEMALIGN 1 |
95 | 103 | #include <malloc.h> |
437 | 445 | /** The version number for a database's lockfile format. */ |
438 | 446 | #define MDB_LOCK_VERSION 1 |
439 | 447 | |
440 | /** @brief The max size of a key we can write, or 0 for dynamic max. | |
448 | /** @brief The max size of a key we can write, or 0 for computed max. | |
441 | 449 | * |
442 | * Define this as 0 to compute the max from the page size. 511 | |
443 | * is default for backwards compat: liblmdb <= 0.9.10 can break | |
444 | * when modifying a DB with keys/dupsort data bigger than its max. | |
445 | * #MDB_DEVEL sets the default to 0. | |
450 | * This macro should normally be left alone or set to 0. | |
451 | * Note that a database with big keys or dupsort data cannot be | |
452 | * reliably modified by a liblmdb which uses a smaller max. | |
453 | * The default is 511 for backwards compat, or 0 when #MDB_DEVEL. | |
454 | * | |
455 | * Other values are allowed, for backwards compat. However: | |
456 | * A value bigger than the computed max can break if you do not | |
457 | * know what you are doing, and liblmdb <= 0.9.10 can break when | |
458 | * modifying a DB with keys/dupsort data bigger than its max. | |
446 | 459 | * |
447 | 460 | * Data items in an #MDB_DUPSORT database are also limited to |
448 | 461 | * this size, since they're actually keys of a sub-DB. Keys and |
579 | 592 | * started from so we can avoid overwriting any data used in that |
580 | 593 | * particular version. |
581 | 594 | */ |
582 | txnid_t mrb_txnid; | |
595 | volatile txnid_t mrb_txnid; | |
583 | 596 | /** The process ID of the process owning this reader txn. */ |
584 | MDB_PID_T mrb_pid; | |
597 | volatile MDB_PID_T mrb_pid; | |
585 | 598 | /** The thread ID of the thread owning this txn. */ |
586 | MDB_THR_T mrb_tid; | |
599 | volatile MDB_THR_T mrb_tid; | |
587 | 600 | } MDB_rxbody; |
588 | 601 | |
589 | 602 | /** The actual reader record, with cacheline padding. */ |
631 | 644 | * This is recorded here only for convenience; the value can always |
632 | 645 | * be determined by reading the main database meta pages. |
633 | 646 | */ |
634 | txnid_t mtb_txnid; | |
647 | volatile txnid_t mtb_txnid; | |
635 | 648 | /** The number of slots that have been used in the reader table. |
636 | 649 | * This always records the maximum count, it is not decremented |
637 | 650 | * when readers release their slots. |
638 | 651 | */ |
639 | unsigned mtb_numreaders; | |
652 | volatile unsigned mtb_numreaders; | |
640 | 653 | } MDB_txbody; |
641 | 654 | |
642 | 655 | /** The actual reader table definition. */ |
897 | 910 | /** Stamp identifying this as an LMDB file. It must be set |
898 | 911 | * to #MDB_MAGIC. */ |
899 | 912 | uint32_t mm_magic; |
900 | /** Version number of this lock file. Must be set to #MDB_DATA_VERSION. */ | |
913 | /** Version number of this file. Must be set to #MDB_DATA_VERSION. */ | |
901 | 914 | uint32_t mm_version; |
902 | 915 | void *mm_address; /**< address for fixed mapping */ |
903 | 916 | size_t mm_mapsize; /**< size of mmap region */ |
907 | 920 | /** Any persistent environment flags. @ref mdb_env */ |
908 | 921 | #define mm_flags mm_dbs[0].md_flags |
909 | 922 | pgno_t mm_last_pg; /**< last used page in file */ |
910 | txnid_t mm_txnid; /**< txnid that committed this page */ | |
923 | volatile txnid_t mm_txnid; /**< txnid that committed this page */ | |
911 | 924 | } MDB_meta; |
912 | 925 | |
913 | 926 | /** Buffer for a stack-allocated meta page. |
1095 | 1108 | #define MDB_ENV_ACTIVE 0x20000000U |
1096 | 1109 | /** me_txkey is set */ |
1097 | 1110 | #define MDB_ENV_TXKEY 0x10000000U |
1111 | /** fdatasync is unreliable */ | |
1112 | #define MDB_FSYNCONLY 0x08000000U | |
1098 | 1113 | uint32_t me_flags; /**< @ref mdb_env */ |
1099 | 1114 | unsigned int me_psize; /**< DB page size, inited from me_os_psize */ |
1100 | 1115 | unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ |
1234 | 1249 | static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; |
1235 | 1250 | /** @endcond */ |
1236 | 1251 | |
1252 | /** Compare two items pointing at size_t's of unknown alignment. */ | |
1253 | #ifdef MISALIGNED_OK | |
1254 | # define mdb_cmp_clong mdb_cmp_long | |
1255 | #else | |
1256 | # define mdb_cmp_clong mdb_cmp_cint | |
1257 | #endif | |
1258 | ||
1237 | 1259 | #ifdef _WIN32 |
1238 | 1260 | static SECURITY_DESCRIPTOR mdb_null_sd; |
1239 | 1261 | static SECURITY_ATTRIBUTES mdb_all_sa; |
1315 | 1337 | buf[0] = 0; |
1316 | 1338 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
1317 | 1339 | FORMAT_MESSAGE_IGNORE_INSERTS, |
1318 | NULL, err, 0, ptr, sizeof(buf), pad); | |
1340 | NULL, err, 0, ptr, sizeof(buf), (va_list *)pad); | |
1319 | 1341 | return ptr; |
1320 | 1342 | #else |
1321 | 1343 | return strerror(err); |
1547 | 1569 | int |
1548 | 1570 | mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) |
1549 | 1571 | { |
1550 | return txn->mt_dbxs[dbi].md_dcmp(a, b); | |
1572 | MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp; | |
1573 | #if UINT_MAX < SIZE_MAX | |
1574 | if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t)) | |
1575 | dcmp = mdb_cmp_clong; | |
1576 | #endif | |
1577 | return dcmp(a, b); | |
1551 | 1578 | } |
1552 | 1579 | |
1553 | 1580 | /** Allocate memory for a page. |
2301 | 2328 | mdb_env_sync(MDB_env *env, int force) |
2302 | 2329 | { |
2303 | 2330 | int rc = 0; |
2331 | if (env->me_flags & MDB_RDONLY) | |
2332 | return EACCES; | |
2304 | 2333 | if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { |
2305 | 2334 | if (env->me_flags & MDB_WRITEMAP) { |
2306 | 2335 | int flags = ((env->me_flags & MDB_MAPASYNC) && !force) |
2312 | 2341 | rc = ErrCode(); |
2313 | 2342 | #endif |
2314 | 2343 | } else { |
2344 | #ifdef BROKEN_FDATASYNC | |
2345 | if (env->me_flags & MDB_FSYNCONLY) { | |
2346 | if (fsync(env->me_fd)) | |
2347 | rc = ErrCode(); | |
2348 | } else | |
2349 | #endif | |
2315 | 2350 | if (MDB_FDATASYNC(env->me_fd)) |
2316 | 2351 | rc = ErrCode(); |
2317 | 2352 | } |
2467 | 2502 | MDB_env *env = txn->mt_env; |
2468 | 2503 | MDB_txninfo *ti = env->me_txns; |
2469 | 2504 | MDB_meta *meta; |
2470 | unsigned int i, nr; | |
2505 | unsigned int i, nr, flags = txn->mt_flags; | |
2471 | 2506 | uint16_t x; |
2472 | 2507 | int rc, new_notls = 0; |
2473 | 2508 | |
2474 | /* Setup db info */ | |
2475 | txn->mt_numdbs = env->me_numdbs; | |
2476 | txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ | |
2477 | ||
2478 | if (txn->mt_flags & MDB_TXN_RDONLY) { | |
2509 | if ((flags &= MDB_TXN_RDONLY) != 0) { | |
2479 | 2510 | if (!ti) { |
2480 | 2511 | meta = env->me_metas[ mdb_env_pick_meta(env) ]; |
2481 | 2512 | txn->mt_txnid = meta->mm_txnid; |
2521 | 2552 | return rc; |
2522 | 2553 | } |
2523 | 2554 | } |
2524 | txn->mt_txnid = r->mr_txnid = ti->mti_txnid; | |
2555 | do /* LY: Retry on a race, ITS#7970. */ | |
2556 | r->mr_txnid = ti->mti_txnid; | |
2557 | while(r->mr_txnid != ti->mti_txnid); | |
2558 | txn->mt_txnid = r->mr_txnid; | |
2525 | 2559 | txn->mt_u.reader = r; |
2526 | 2560 | meta = env->me_metas[txn->mt_txnid & 1]; |
2527 | 2561 | } |
2562 | txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ | |
2528 | 2563 | } else { |
2529 | 2564 | if (ti) { |
2530 | 2565 | LOCK_MUTEX_W(env); |
2540 | 2575 | if (txn->mt_txnid == mdb_debug_start) |
2541 | 2576 | mdb_debug = 1; |
2542 | 2577 | #endif |
2578 | txn->mt_child = NULL; | |
2579 | txn->mt_loose_pgs = NULL; | |
2580 | txn->mt_loose_count = 0; | |
2543 | 2581 | txn->mt_dirty_room = MDB_IDL_UM_MAX; |
2544 | 2582 | txn->mt_u.dirty_list = env->me_dirty_list; |
2545 | 2583 | txn->mt_u.dirty_list[0].mid = 0; |
2556 | 2594 | /* Moved to here to avoid a data race in read TXNs */ |
2557 | 2595 | txn->mt_next_pgno = meta->mm_last_pg+1; |
2558 | 2596 | |
2597 | txn->mt_flags = flags; | |
2598 | ||
2599 | /* Setup db info */ | |
2600 | txn->mt_numdbs = env->me_numdbs; | |
2559 | 2601 | for (i=2; i<txn->mt_numdbs; i++) { |
2560 | 2602 | x = env->me_dbflags[i]; |
2561 | 2603 | txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; |
2621 | 2663 | } |
2622 | 2664 | tsize = sizeof(MDB_ntxn); |
2623 | 2665 | } |
2624 | size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1); | |
2666 | size = tsize; | |
2625 | 2667 | if (!(flags & MDB_RDONLY)) { |
2626 | 2668 | if (!parent) { |
2627 | txn = env->me_txn0; | |
2628 | txn->mt_flags = 0; | |
2669 | txn = env->me_txn0; /* just reuse preallocated write txn */ | |
2629 | 2670 | goto ok; |
2630 | 2671 | } |
2672 | /* child txns use own copy of cursors */ | |
2631 | 2673 | 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 | } | |
2674 | } | |
2675 | size += env->me_maxdbs * (sizeof(MDB_db)+1); | |
2636 | 2676 | |
2637 | 2677 | if ((txn = calloc(1, size)) == NULL) { |
2638 | 2678 | DPRINTF(("calloc: %s", strerror(errno))); |
2773 | 2813 | txn->mt_numdbs = 0; /* close nothing if called again */ |
2774 | 2814 | txn->mt_dbxs = NULL; /* mark txn as reset */ |
2775 | 2815 | } else { |
2816 | pgno_t *pghead = env->me_pghead; | |
2817 | ||
2776 | 2818 | mdb_cursors_close(txn, 0); |
2777 | ||
2778 | 2819 | if (!(env->me_flags & MDB_WRITEMAP)) { |
2779 | 2820 | mdb_dlist_free(txn); |
2780 | 2821 | } |
2781 | mdb_midl_free(env->me_pghead); | |
2782 | ||
2783 | if (txn->mt_parent) { | |
2822 | ||
2823 | if (!txn->mt_parent) { | |
2824 | if (mdb_midl_shrink(&txn->mt_free_pgs)) | |
2825 | env->me_free_pgs = txn->mt_free_pgs; | |
2826 | /* me_pgstate: */ | |
2827 | env->me_pghead = NULL; | |
2828 | env->me_pglast = 0; | |
2829 | ||
2830 | env->me_txn = NULL; | |
2831 | /* The writer mutex was locked in mdb_txn_begin. */ | |
2832 | if (env->me_txns) | |
2833 | UNLOCK_MUTEX_W(env); | |
2834 | } else { | |
2784 | 2835 | txn->mt_parent->mt_child = NULL; |
2785 | 2836 | env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; |
2786 | 2837 | mdb_midl_free(txn->mt_free_pgs); |
2787 | 2838 | mdb_midl_free(txn->mt_spill_pgs); |
2788 | 2839 | free(txn->mt_u.dirty_list); |
2789 | return; | |
2790 | } | |
2791 | ||
2792 | if (mdb_midl_shrink(&txn->mt_free_pgs)) | |
2793 | env->me_free_pgs = txn->mt_free_pgs; | |
2794 | env->me_pghead = NULL; | |
2795 | env->me_pglast = 0; | |
2796 | ||
2797 | env->me_txn = NULL; | |
2798 | /* The writer mutex was locked in mdb_txn_begin. */ | |
2799 | if (env->me_txns) | |
2800 | UNLOCK_MUTEX_W(env); | |
2840 | } | |
2841 | ||
2842 | mdb_midl_free(pghead); | |
2801 | 2843 | } |
2802 | 2844 | } |
2803 | 2845 | |
3105 | 3147 | /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ |
3106 | 3148 | if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { |
3107 | 3149 | if (n) { |
3150 | retry_write: | |
3108 | 3151 | /* Write previous page(s) */ |
3109 | 3152 | #ifdef MDB_USE_PWRITEV |
3110 | 3153 | wres = pwritev(env->me_fd, iov, n, wpos); |
3112 | 3155 | if (n == 1) { |
3113 | 3156 | wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); |
3114 | 3157 | } else { |
3158 | retry_seek: | |
3115 | 3159 | if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { |
3116 | 3160 | rc = ErrCode(); |
3161 | if (rc == EINTR) | |
3162 | goto retry_seek; | |
3117 | 3163 | DPRINTF(("lseek: %s", strerror(rc))); |
3118 | 3164 | return rc; |
3119 | 3165 | } |
3123 | 3169 | if (wres != wsize) { |
3124 | 3170 | if (wres < 0) { |
3125 | 3171 | rc = ErrCode(); |
3172 | if (rc == EINTR) | |
3173 | goto retry_write; | |
3126 | 3174 | DPRINTF(("Write error: %s", strerror(rc))); |
3127 | 3175 | } else { |
3128 | 3176 | rc = EIO; /* TODO: Use which error code? */ |
3492 | 3540 | int len; |
3493 | 3541 | #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ |
3494 | 3542 | len = pwrite(fd, ptr, size, pos); \ |
3495 | rc = (len >= 0); } while(0) | |
3543 | if (len == -1 && ErrCode() == EINTR) continue; \ | |
3544 | rc = (len >= 0); break; } while(1) | |
3496 | 3545 | #endif |
3497 | 3546 | |
3498 | 3547 | DPUTS("writing new meta page"); |
3597 | 3646 | /* Write to the SYNC fd */ |
3598 | 3647 | mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ? |
3599 | 3648 | env->me_fd : env->me_mfd; |
3649 | retry_write: | |
3600 | 3650 | #ifdef _WIN32 |
3601 | 3651 | { |
3602 | 3652 | memset(&ov, 0, sizeof(ov)); |
3609 | 3659 | #endif |
3610 | 3660 | if (rc != len) { |
3611 | 3661 | rc = rc < 0 ? ErrCode() : EIO; |
3662 | if (rc == EINTR) | |
3663 | goto retry_write; | |
3612 | 3664 | DPUTS("write failed, disk error?"); |
3613 | 3665 | /* On a failure, the pagecache still contains the new data. |
3614 | 3666 | * Write some old data back, to prevent it from being used. |
3823 | 3875 | return MDB_SUCCESS; |
3824 | 3876 | } |
3825 | 3877 | |
3878 | static int ESECT | |
3879 | mdb_fsize(HANDLE fd, size_t *size) | |
3880 | { | |
3881 | #ifdef _WIN32 | |
3882 | LARGE_INTEGER fsize; | |
3883 | ||
3884 | if (!GetFileSizeEx(fd, &fsize)) | |
3885 | return ErrCode(); | |
3886 | ||
3887 | *size = fsize.QuadPart; | |
3888 | #else | |
3889 | struct stat st; | |
3890 | ||
3891 | if (fstat(fd, &st)) | |
3892 | return ErrCode(); | |
3893 | ||
3894 | *size = st.st_size; | |
3895 | #endif | |
3896 | return MDB_SUCCESS; | |
3897 | } | |
3898 | ||
3899 | #ifdef BROKEN_FDATASYNC | |
3900 | #include <sys/utsname.h> | |
3901 | #include <sys/vfs.h> | |
3902 | #endif | |
3903 | ||
3826 | 3904 | /** Further setup required for opening an LMDB environment |
3827 | 3905 | */ |
3828 | 3906 | static int ESECT |
3840 | 3918 | else |
3841 | 3919 | env->me_pidquery = PROCESS_QUERY_INFORMATION; |
3842 | 3920 | #endif /* _WIN32 */ |
3921 | #ifdef BROKEN_FDATASYNC | |
3922 | /* ext3/ext4 fdatasync is broken on some older Linux kernels. | |
3923 | * https://lkml.org/lkml/2012/9/3/83 | |
3924 | * Kernels after 3.6-rc6 are known good. | |
3925 | * https://lkml.org/lkml/2012/9/10/556 | |
3926 | * See if the DB is on ext3/ext4, then check for new enough kernel | |
3927 | * Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known | |
3928 | * to be patched. | |
3929 | */ | |
3930 | { | |
3931 | struct statfs st; | |
3932 | fstatfs(env->me_fd, &st); | |
3933 | while (st.f_type == 0xEF53) { | |
3934 | struct utsname uts; | |
3935 | int i; | |
3936 | uname(&uts); | |
3937 | if (uts.release[0] < '3') { | |
3938 | if (!strncmp(uts.release, "2.6.32.", 7)) { | |
3939 | i = atoi(uts.release+7); | |
3940 | if (i >= 60) | |
3941 | break; /* 2.6.32.60 and newer is OK */ | |
3942 | } else if (!strncmp(uts.release, "2.6.34.", 7)) { | |
3943 | i = atoi(uts.release+7); | |
3944 | if (i >= 15) | |
3945 | break; /* 2.6.34.15 and newer is OK */ | |
3946 | } | |
3947 | } else if (uts.release[0] == '3') { | |
3948 | i = atoi(uts.release+2); | |
3949 | if (i > 5) | |
3950 | break; /* 3.6 and newer is OK */ | |
3951 | if (i == 5) { | |
3952 | i = atoi(uts.release+4); | |
3953 | if (i >= 4) | |
3954 | break; /* 3.5.4 and newer is OK */ | |
3955 | } else if (i == 2) { | |
3956 | i = atoi(uts.release+4); | |
3957 | if (i >= 30) | |
3958 | break; /* 3.2.30 and newer is OK */ | |
3959 | } | |
3960 | } else { /* 4.x and newer is OK */ | |
3961 | break; | |
3962 | } | |
3963 | env->me_flags |= MDB_FSYNCONLY; | |
3964 | break; | |
3965 | } | |
3966 | } | |
3967 | #endif | |
3843 | 3968 | |
3844 | 3969 | memset(&meta, 0, sizeof(meta)); |
3845 | 3970 | |
3971 | 4096 | extern const PIMAGE_TLS_CALLBACK mdb_tls_cbp; |
3972 | 4097 | const PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback; |
3973 | 4098 | #pragma const_seg() |
3974 | #else /* WIN32 */ | |
4099 | #else /* _WIN32 */ | |
3975 | 4100 | #pragma comment(linker, "/INCLUDE:__tls_used") |
3976 | 4101 | #pragma comment(linker, "/INCLUDE:_mdb_tls_cbp") |
3977 | 4102 | #pragma data_seg(".CRT$XLB") |
4021 | 4146 | return rc; |
4022 | 4147 | } |
4023 | 4148 | |
4024 | /** Try to get exlusive lock, otherwise shared. | |
4149 | /** Try to get exclusive lock, otherwise shared. | |
4025 | 4150 | * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive. |
4026 | 4151 | */ |
4027 | 4152 | static int ESECT |
4162 | 4287 | * @param[in] env The LMDB environment. |
4163 | 4288 | * @param[in] lpath The pathname of the file used for the lock region. |
4164 | 4289 | * @param[in] mode The Unix permissions for the file, if we create it. |
4165 | * @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive | |
4166 | 4290 | * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive |
4167 | 4291 | * @return 0 on success, non-zero on failure. |
4168 | 4292 | */ |
4517 | 4641 | if (!(flags & MDB_RDONLY)) { |
4518 | 4642 | MDB_txn *txn; |
4519 | 4643 | int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs * |
4520 | (sizeof(MDB_db)+sizeof(MDB_cursor)+sizeof(unsigned int)+1); | |
4644 | (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1); | |
4521 | 4645 | txn = calloc(1, size); |
4522 | 4646 | if (txn) { |
4523 | 4647 | txn->mt_dbs = (MDB_db *)((char *)txn + tsize); |
4525 | 4649 | txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs); |
4526 | 4650 | txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs); |
4527 | 4651 | txn->mt_env = env; |
4652 | txn->mt_dbxs = env->me_dbxs; | |
4528 | 4653 | env->me_txn0 = txn; |
4529 | 4654 | } else { |
4530 | 4655 | rc = ENOMEM; |
4550 | 4675 | return; |
4551 | 4676 | |
4552 | 4677 | /* Doing this here since me_dbxs may not exist during mdb_env_close */ |
4553 | for (i = env->me_maxdbs; --i > MAIN_DBI; ) | |
4554 | free(env->me_dbxs[i].md_name.mv_data); | |
4678 | if (env->me_dbxs) { | |
4679 | for (i = env->me_maxdbs; --i > MAIN_DBI; ) | |
4680 | free(env->me_dbxs[i].md_name.mv_data); | |
4681 | free(env->me_dbxs); | |
4682 | } | |
4555 | 4683 | |
4556 | 4684 | free(env->me_pbuf); |
4557 | 4685 | free(env->me_dbiseqs); |
4558 | 4686 | free(env->me_dbflags); |
4559 | free(env->me_dbxs); | |
4560 | 4687 | free(env->me_path); |
4561 | 4688 | free(env->me_dirty_list); |
4562 | 4689 | free(env->me_txn0); |
4659 | 4786 | *(size_t *)a->mv_data > *(size_t *)b->mv_data; |
4660 | 4787 | } |
4661 | 4788 | |
4662 | /** Compare two items pointing at aligned unsigned int's */ | |
4789 | /** Compare two items pointing at aligned unsigned int's. | |
4790 | * | |
4791 | * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp, | |
4792 | * but #mdb_cmp_clong() is called instead if the data type is size_t. | |
4793 | */ | |
4663 | 4794 | static int |
4664 | 4795 | mdb_cmp_int(const MDB_val *a, const MDB_val *b) |
4665 | 4796 | { |
4696 | 4827 | return x; |
4697 | 4828 | #endif |
4698 | 4829 | } |
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 | |
4706 | 4830 | |
4707 | 4831 | /** Compare two items lexically */ |
4708 | 4832 | static int |
5423 | 5547 | } |
5424 | 5548 | return rc; |
5425 | 5549 | } |
5426 | } else { | |
5427 | mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); | |
5428 | if (op == MDB_PREV_DUP) | |
5429 | return MDB_NOTFOUND; | |
5430 | } | |
5550 | } | |
5551 | } else { | |
5552 | mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); | |
5553 | if (op == MDB_PREV_DUP) | |
5554 | return MDB_NOTFOUND; | |
5431 | 5555 | } |
5432 | 5556 | } |
5433 | 5557 | |
5639 | 5763 | return rc; |
5640 | 5764 | } |
5641 | 5765 | } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { |
5642 | MDB_val d2; | |
5643 | if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS) | |
5766 | MDB_val olddata; | |
5767 | MDB_cmp_func *dcmp; | |
5768 | if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS) | |
5644 | 5769 | return rc; |
5645 | rc = mc->mc_dbx->md_dcmp(data, &d2); | |
5770 | dcmp = mc->mc_dbx->md_dcmp; | |
5771 | #if UINT_MAX < SIZE_MAX | |
5772 | if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) | |
5773 | dcmp = mdb_cmp_clong; | |
5774 | #endif | |
5775 | rc = dcmp(data, &olddata); | |
5646 | 5776 | if (rc) { |
5647 | 5777 | if (op == MDB_GET_BOTH || rc > 0) |
5648 | 5778 | return MDB_NOTFOUND; |
5649 | 5779 | rc = 0; |
5650 | *data = d2; | |
5780 | *data = olddata; | |
5651 | 5781 | } |
5652 | 5782 | |
5653 | 5783 | } else { |
6157 | 6287 | |
6158 | 6288 | /* Was a single item before, must convert now */ |
6159 | 6289 | if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { |
6290 | MDB_cmp_func *dcmp; | |
6160 | 6291 | /* Just overwrite the current item */ |
6161 | 6292 | if (flags == MDB_CURRENT) |
6162 | 6293 | goto current; |
6163 | ||
6294 | dcmp = mc->mc_dbx->md_dcmp; | |
6164 | 6295 | #if UINT_MAX < SIZE_MAX |
6165 | if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) | |
6166 | mc->mc_dbx->md_dcmp = mdb_cmp_clong; | |
6296 | if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) | |
6297 | dcmp = mdb_cmp_clong; | |
6167 | 6298 | #endif |
6168 | 6299 | /* does data match? */ |
6169 | if (!mc->mc_dbx->md_dcmp(data, &olddata)) { | |
6300 | if (!dcmp(data, &olddata)) { | |
6170 | 6301 | if (flags & MDB_NODUPDATA) |
6171 | 6302 | return MDB_KEYEXIST; |
6172 | 6303 | /* overwrite it */ |
6986 | 7117 | mc->mc_snum = 0; |
6987 | 7118 | mc->mc_top = 0; |
6988 | 7119 | mc->mc_pg[0] = 0; |
7120 | mc->mc_ki[0] = 0; | |
6989 | 7121 | mc->mc_flags = 0; |
6990 | 7122 | if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { |
6991 | 7123 | mdb_tassert(txn, mx != NULL); |
7359 | 7491 | cdst->mc_ki[cdst->mc_top] = 0; |
7360 | 7492 | rc = mdb_update_key(cdst, &nullkey); |
7361 | 7493 | cdst->mc_ki[cdst->mc_top] = ix; |
7362 | mdb_cassert(csrc, rc == MDB_SUCCESS); | |
7494 | mdb_cassert(cdst, rc == MDB_SUCCESS); | |
7363 | 7495 | } |
7364 | 7496 | } |
7365 | 7497 | |
7615 | 7747 | m3 = m2; |
7616 | 7748 | if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; |
7617 | 7749 | if (m3->mc_pg[0] == mp) { |
7618 | m3->mc_snum--; | |
7619 | m3->mc_top--; | |
7620 | 7750 | for (i=0; i<m3->mc_snum; i++) { |
7621 | 7751 | m3->mc_pg[i] = m3->mc_pg[i+1]; |
7622 | 7752 | m3->mc_ki[i] = m3->mc_ki[i+1]; |
7623 | 7753 | } |
7754 | m3->mc_snum--; | |
7755 | m3->mc_top--; | |
7624 | 7756 | } |
7625 | 7757 | } |
7626 | 7758 | } |
7688 | 7820 | if (mc->mc_ki[ptop] == 0) { |
7689 | 7821 | rc = mdb_page_merge(&mn, mc); |
7690 | 7822 | } else { |
7823 | MDB_cursor dummy; | |
7691 | 7824 | oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); |
7692 | 7825 | mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; |
7826 | /* We want mdb_rebalance to find mn when doing fixups */ | |
7827 | if (mc->mc_flags & C_SUB) { | |
7828 | dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; | |
7829 | mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy; | |
7830 | dummy.mc_xcursor = (MDB_xcursor *)&mn; | |
7831 | } else { | |
7832 | mn.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; | |
7833 | mc->mc_txn->mt_cursors[mc->mc_dbi] = &mn; | |
7834 | } | |
7693 | 7835 | rc = mdb_page_merge(mc, &mn); |
7836 | if (mc->mc_flags & C_SUB) | |
7837 | mc->mc_txn->mt_cursors[mc->mc_dbi] = dummy.mc_next; | |
7838 | else | |
7839 | mc->mc_txn->mt_cursors[mc->mc_dbi] = mn.mc_next; | |
7694 | 7840 | mdb_cursor_copy(&mn, mc); |
7695 | 7841 | } |
7696 | 7842 | mc->mc_flags &= ~C_EOF; |
7716 | 7862 | if (rc == MDB_SUCCESS) { |
7717 | 7863 | MDB_cursor *m2, *m3; |
7718 | 7864 | MDB_dbi dbi = mc->mc_dbi; |
7865 | ||
7866 | /* DB is totally empty now, just bail out. | |
7867 | * Other cursors adjustments were already done | |
7868 | * by mdb_rebalance and aren't needed here. | |
7869 | */ | |
7870 | if (!mc->mc_snum) | |
7871 | return rc; | |
7719 | 7872 | |
7720 | 7873 | mp = mc->mc_pg[mc->mc_top]; |
7721 | 7874 | nkeys = NUMKEYS(mp); |
8584 | 8737 | /* Set metapage 1 */ |
8585 | 8738 | mm->mm_last_pg = txn->mt_next_pgno - freecount - 1; |
8586 | 8739 | mm->mm_dbs[1] = txn->mt_dbs[1]; |
8587 | mm->mm_dbs[1].md_root = mm->mm_last_pg; | |
8588 | mm->mm_txnid = 1; | |
8740 | if (mm->mm_last_pg > 1) { | |
8741 | mm->mm_dbs[1].md_root = mm->mm_last_pg; | |
8742 | mm->mm_txnid = 1; | |
8743 | } else { | |
8744 | mm->mm_dbs[1].md_root = P_INVALID; | |
8745 | } | |
8589 | 8746 | } |
8590 | 8747 | my.mc_wlen[0] = env->me_psize * 2; |
8591 | 8748 | my.mc_txn = txn; |
8680 | 8837 | goto leave; |
8681 | 8838 | |
8682 | 8839 | w2 = txn->mt_next_pgno * env->me_psize; |
8683 | #ifdef WIN32 | |
8684 | 8840 | { |
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 | |
8841 | size_t fsize = 0; | |
8842 | if ((rc = mdb_fsize(env->me_fd, &fsize))) | |
8843 | goto leave; | |
8844 | if (w2 > fsize) | |
8845 | w2 = fsize; | |
8846 | } | |
8698 | 8847 | wsize = w2 - wsize; |
8699 | 8848 | while (wsize > 0) { |
8700 | 8849 | if (wsize > MAX_WRITE) |
0 | 0 | .TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14" |
1 | .\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved. | |
1 | .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. | |
2 | 2 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. |
3 | 3 | .SH NAME |
4 | 4 | mdb_copy \- LMDB environment copy tool |
0 | 0 | /* mdb_copy.c - memory-mapped database backup tool */ |
1 | 1 | /* |
2 | * Copyright 2012 Howard Chu, Symas Corp. | |
2 | * Copyright 2012-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
63 | 63 | act = "opening environment"; |
64 | 64 | rc = mdb_env_create(&env); |
65 | 65 | if (rc == MDB_SUCCESS) { |
66 | rc = mdb_env_open(env, argv[1], flags, 0664); | |
66 | rc = mdb_env_open(env, argv[1], flags, 0600); | |
67 | 67 | } |
68 | 68 | if (rc == MDB_SUCCESS) { |
69 | 69 | act = "copying"; |
0 | 0 | .TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14" |
1 | .\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved. | |
1 | .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. | |
2 | 2 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. |
3 | 3 | .SH NAME |
4 | 4 | mdb_dump \- LMDB environment export tool |
0 | 0 | /* mdb_dump.c - memory-mapped database dump tool */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
0 | 0 | .TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14" |
1 | .\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved. | |
1 | .\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. | |
2 | 2 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. |
3 | 3 | .SH NAME |
4 | 4 | mdb_load \- LMDB environment import tool |
0 | 0 | /* mdb_load.c - memory-mapped database load tool */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
175 | 175 | static int readline(MDB_val *out, MDB_val *buf) |
176 | 176 | { |
177 | 177 | unsigned char *c1, *c2, *end; |
178 | size_t len; | |
178 | size_t len, l2; | |
179 | 179 | int c; |
180 | 180 | |
181 | 181 | if (!(mode & NOHDR)) { |
205 | 205 | |
206 | 206 | c1 = buf->mv_data; |
207 | 207 | len = strlen((char *)c1); |
208 | l2 = len; | |
208 | 209 | |
209 | 210 | /* Is buffer too short? */ |
210 | 211 | while (c1[len-1] != '\n') { |
216 | 217 | return EOF; |
217 | 218 | } |
218 | 219 | c1 = buf->mv_data; |
219 | c1 += buf->mv_size; | |
220 | if (fgets((char *)c1, buf->mv_size, stdin) == NULL) { | |
220 | c1 += l2; | |
221 | if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) { | |
221 | 222 | Eof = 1; |
222 | 223 | badend(); |
223 | 224 | return EOF; |
224 | 225 | } |
225 | 226 | buf->mv_size *= 2; |
226 | 227 | len = strlen((char *)c1); |
228 | l2 += len; | |
227 | 229 | } |
228 | 230 | c1 = c2 = buf->mv_data; |
229 | len = strlen((char *)c1); | |
231 | len = l2; | |
230 | 232 | c1[--len] = '\0'; |
231 | 233 | end = c1 + len; |
232 | 234 |
0 | 0 | .TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14" |
1 | .\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved. | |
1 | .\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. | |
2 | 2 | .\" Copying restrictions apply. See COPYRIGHT/LICENSE. |
3 | 3 | .SH NAME |
4 | 4 | mdb_stat \- LMDB environment status tool |
0 | 0 | /* mdb_stat.c - memory-mapped database status tool */ |
1 | 1 | /* |
2 | * Copyright 2011-2013 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
2 | 2 | /* $OpenLDAP$ */ |
3 | 3 | /* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
4 | 4 | * |
5 | * Copyright 2000-2014 The OpenLDAP Foundation. | |
5 | * Copyright 2000-2015 The OpenLDAP Foundation. | |
6 | 6 | * All rights reserved. |
7 | 7 | * |
8 | 8 | * Redistribution and use in source and binary forms, with or without |
10 | 10 | /* $OpenLDAP$ */ |
11 | 11 | /* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
12 | 12 | * |
13 | * Copyright 2000-2014 The OpenLDAP Foundation. | |
13 | * Copyright 2000-2015 The OpenLDAP Foundation. | |
14 | 14 | * All rights reserved. |
15 | 15 | * |
16 | 16 | * Redistribution and use in source and binary forms, with or without |
0 | 0 | /* mtest.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
44 | 44 | } |
45 | 45 | |
46 | 46 | E(mdb_env_create(&env)); |
47 | E(mdb_env_set_maxreaders(env, 1)); | |
47 | 48 | E(mdb_env_set_mapsize(env, 10485760)); |
48 | 49 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664)); |
50 | ||
49 | 51 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
50 | E(mdb_open(txn, NULL, 0, &dbi)); | |
52 | E(mdb_dbi_open(txn, NULL, 0, &dbi)); | |
51 | 53 | |
52 | 54 | key.mv_size = sizeof(int); |
53 | 55 | key.mv_data = sval; |
54 | data.mv_size = sizeof(sval); | |
55 | data.mv_data = sval; | |
56 | 56 | |
57 | 57 | printf("Adding %d values\n", count); |
58 | 58 | for (i=0;i<count;i++) { |
59 | 59 | sprintf(sval, "%03x %d foo bar", values[i], values[i]); |
60 | /* Set <data> in each iteration, since MDB_NOOVERWRITE may modify it */ | |
61 | data.mv_size = sizeof(sval); | |
62 | data.mv_data = sval; | |
60 | 63 | if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) { |
61 | 64 | j++; |
62 | 65 | data.mv_size = sizeof(sval); |
67 | 70 | E(mdb_txn_commit(txn)); |
68 | 71 | E(mdb_env_stat(env, &mst)); |
69 | 72 | |
70 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
73 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
71 | 74 | E(mdb_cursor_open(txn, dbi, &cursor)); |
72 | 75 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
73 | 76 | printf("key: %p %.*s, data: %p %.*s\n", |
96 | 99 | printf("Deleted %d values\n", j); |
97 | 100 | |
98 | 101 | E(mdb_env_stat(env, &mst)); |
99 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
102 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
100 | 103 | E(mdb_cursor_open(txn, dbi, &cursor)); |
101 | 104 | printf("Cursor next\n"); |
102 | 105 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
127 | 130 | (int) key.mv_size, (char *) key.mv_data, |
128 | 131 | (int) data.mv_size, (char *) data.mv_data); |
129 | 132 | |
133 | mdb_cursor_close(cursor); | |
130 | 134 | mdb_txn_abort(txn); |
131 | 135 | |
132 | 136 | printf("Deleting with cursor\n"); |
163 | 167 | data.mv_data, (int) data.mv_size, (char *) data.mv_data); |
164 | 168 | } |
165 | 169 | mdb_cursor_close(cursor); |
166 | mdb_close(env, dbi); | |
170 | mdb_txn_abort(txn); | |
167 | 171 | |
168 | mdb_txn_abort(txn); | |
172 | mdb_dbi_close(env, dbi); | |
169 | 173 | mdb_env_close(env); |
170 | 174 | |
171 | 175 | return 0; |
0 | 0 | /* mtest2.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
46 | 46 | } |
47 | 47 | |
48 | 48 | E(mdb_env_create(&env)); |
49 | E(mdb_env_set_maxreaders(env, 1)); | |
49 | 50 | E(mdb_env_set_mapsize(env, 10485760)); |
50 | 51 | E(mdb_env_set_maxdbs(env, 4)); |
51 | 52 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); |
53 | ||
52 | 54 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
53 | E(mdb_open(txn, "id1", MDB_CREATE, &dbi)); | |
55 | E(mdb_dbi_open(txn, "id1", MDB_CREATE, &dbi)); | |
54 | 56 | |
55 | 57 | key.mv_size = sizeof(int); |
56 | 58 | key.mv_data = sval; |
57 | data.mv_size = sizeof(sval); | |
58 | data.mv_data = sval; | |
59 | 59 | |
60 | 60 | printf("Adding %d values\n", count); |
61 | 61 | for (i=0;i<count;i++) { |
62 | 62 | sprintf(sval, "%03x %d foo bar", values[i], values[i]); |
63 | data.mv_size = sizeof(sval); | |
64 | data.mv_data = sval; | |
63 | 65 | if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) |
64 | 66 | j++; |
65 | 67 | } |
67 | 69 | E(mdb_txn_commit(txn)); |
68 | 70 | E(mdb_env_stat(env, &mst)); |
69 | 71 | |
70 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
72 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
71 | 73 | E(mdb_cursor_open(txn, dbi, &cursor)); |
72 | 74 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
73 | 75 | printf("key: %p %.*s, data: %p %.*s\n", |
96 | 98 | printf("Deleted %d values\n", j); |
97 | 99 | |
98 | 100 | E(mdb_env_stat(env, &mst)); |
99 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
101 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
100 | 102 | E(mdb_cursor_open(txn, dbi, &cursor)); |
101 | 103 | printf("Cursor next\n"); |
102 | 104 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
113 | 115 | } |
114 | 116 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); |
115 | 117 | mdb_cursor_close(cursor); |
116 | mdb_close(env, dbi); | |
118 | mdb_txn_abort(txn); | |
117 | 119 | |
118 | mdb_txn_abort(txn); | |
120 | mdb_dbi_close(env, dbi); | |
119 | 121 | mdb_env_close(env); |
120 | ||
121 | 122 | return 0; |
122 | 123 | } |
0 | 0 | /* mtest3.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
52 | 52 | E(mdb_env_set_mapsize(env, 10485760)); |
53 | 53 | E(mdb_env_set_maxdbs(env, 4)); |
54 | 54 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); |
55 | ||
55 | 56 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
56 | E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); | |
57 | E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); | |
57 | 58 | |
58 | 59 | key.mv_size = sizeof(int); |
59 | 60 | key.mv_data = kval; |
72 | 73 | E(mdb_txn_commit(txn)); |
73 | 74 | E(mdb_env_stat(env, &mst)); |
74 | 75 | |
75 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
76 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
76 | 77 | E(mdb_cursor_open(txn, dbi, &cursor)); |
77 | 78 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
78 | 79 | printf("key: %p %.*s, data: %p %.*s\n", |
106 | 107 | printf("Deleted %d values\n", j); |
107 | 108 | |
108 | 109 | E(mdb_env_stat(env, &mst)); |
109 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
110 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
110 | 111 | E(mdb_cursor_open(txn, dbi, &cursor)); |
111 | 112 | printf("Cursor next\n"); |
112 | 113 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
123 | 124 | } |
124 | 125 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); |
125 | 126 | mdb_cursor_close(cursor); |
126 | mdb_close(env, dbi); | |
127 | mdb_txn_abort(txn); | |
127 | 128 | |
128 | mdb_txn_abort(txn); | |
129 | mdb_dbi_close(env, dbi); | |
129 | 130 | mdb_env_close(env); |
130 | ||
131 | 131 | return 0; |
132 | 132 | } |
0 | 0 | /* mtest4.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
50 | 50 | E(mdb_env_set_mapsize(env, 10485760)); |
51 | 51 | E(mdb_env_set_maxdbs(env, 4)); |
52 | 52 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); |
53 | ||
53 | 54 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
54 | E(mdb_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi)); | |
55 | E(mdb_dbi_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi)); | |
55 | 56 | |
56 | 57 | key.mv_size = sizeof(int); |
57 | 58 | key.mv_data = kval; |
71 | 72 | |
72 | 73 | /* there should be one full page of dups now. |
73 | 74 | */ |
74 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
75 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
75 | 76 | E(mdb_cursor_open(txn, dbi, &cursor)); |
76 | 77 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
77 | 78 | printf("key: %p %.*s, data: %p %.*s\n", |
141 | 142 | printf("Deleted %d values\n", j); |
142 | 143 | |
143 | 144 | E(mdb_env_stat(env, &mst)); |
144 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
145 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
145 | 146 | E(mdb_cursor_open(txn, dbi, &cursor)); |
146 | 147 | printf("Cursor next\n"); |
147 | 148 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
158 | 159 | } |
159 | 160 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); |
160 | 161 | mdb_cursor_close(cursor); |
161 | mdb_close(env, dbi); | |
162 | mdb_txn_abort(txn); | |
162 | 163 | |
163 | mdb_txn_abort(txn); | |
164 | mdb_dbi_close(env, dbi); | |
164 | 165 | mdb_env_close(env); |
165 | ||
166 | 166 | return 0; |
167 | 167 | } |
0 | 0 | /* mtest5.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
52 | 52 | E(mdb_env_set_mapsize(env, 10485760)); |
53 | 53 | E(mdb_env_set_maxdbs(env, 4)); |
54 | 54 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); |
55 | ||
55 | 56 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
56 | E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); | |
57 | E(mdb_dbi_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi)); | |
57 | 58 | E(mdb_cursor_open(txn, dbi, &cursor)); |
58 | 59 | |
59 | 60 | key.mv_size = sizeof(int); |
74 | 75 | E(mdb_txn_commit(txn)); |
75 | 76 | E(mdb_env_stat(env, &mst)); |
76 | 77 | |
77 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
78 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
78 | 79 | E(mdb_cursor_open(txn, dbi, &cursor)); |
79 | 80 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
80 | 81 | printf("key: %p %.*s, data: %p %.*s\n", |
108 | 109 | printf("Deleted %d values\n", j); |
109 | 110 | |
110 | 111 | E(mdb_env_stat(env, &mst)); |
111 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
112 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
112 | 113 | E(mdb_cursor_open(txn, dbi, &cursor)); |
113 | 114 | printf("Cursor next\n"); |
114 | 115 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
125 | 126 | } |
126 | 127 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); |
127 | 128 | mdb_cursor_close(cursor); |
128 | mdb_close(env, dbi); | |
129 | mdb_txn_abort(txn); | |
129 | 130 | |
130 | mdb_txn_abort(txn); | |
131 | mdb_dbi_close(env, dbi); | |
131 | 132 | mdb_env_close(env); |
132 | ||
133 | 133 | return 0; |
134 | 134 | } |
0 | 0 | /* mtest6.c - memory-mapped database tester/toy */ |
1 | 1 | /* |
2 | * Copyright 2011-2014 Howard Chu, Symas Corp. | |
2 | * Copyright 2011-2015 Howard Chu, Symas Corp. | |
3 | 3 | * All rights reserved. |
4 | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without |
30 | 30 | int i = 0, j = 0, rc; |
31 | 31 | MDB_env *env; |
32 | 32 | MDB_dbi dbi; |
33 | MDB_val key, data; | |
33 | MDB_val key, data, sdata; | |
34 | 34 | MDB_txn *txn; |
35 | 35 | MDB_stat mst; |
36 | 36 | MDB_cursor *cursor; |
45 | 45 | E(mdb_env_set_mapsize(env, 10485760)); |
46 | 46 | E(mdb_env_set_maxdbs(env, 4)); |
47 | 47 | E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); |
48 | ||
48 | 49 | E(mdb_txn_begin(env, NULL, 0, &txn)); |
49 | E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); | |
50 | E(mdb_dbi_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi)); | |
50 | 51 | E(mdb_cursor_open(txn, dbi, &cursor)); |
51 | 52 | E(mdb_stat(txn, dbi, &mst)); |
52 | 53 | |
53 | 54 | sval = calloc(1, mst.ms_psize / 4); |
54 | 55 | key.mv_size = sizeof(long); |
55 | 56 | key.mv_data = &kval; |
56 | data.mv_size = mst.ms_psize / 4 - 30; | |
57 | data.mv_data = sval; | |
57 | sdata.mv_size = mst.ms_psize / 4 - 30; | |
58 | sdata.mv_data = sval; | |
58 | 59 | |
59 | 60 | printf("Adding 12 values, should yield 3 splits\n"); |
60 | 61 | for (i=0;i<12;i++) { |
61 | 62 | kval = i*5; |
62 | 63 | sprintf(sval, "%08x", kval); |
64 | data = sdata; | |
63 | 65 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); |
64 | 66 | } |
65 | 67 | printf("Adding 12 more values, should yield 3 splits\n"); |
66 | 68 | for (i=0;i<12;i++) { |
67 | 69 | kval = i*5+4; |
68 | 70 | sprintf(sval, "%08x", kval); |
71 | data = sdata; | |
69 | 72 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); |
70 | 73 | } |
71 | 74 | printf("Adding 12 more values, should yield 3 splits\n"); |
72 | 75 | for (i=0;i<12;i++) { |
73 | 76 | kval = i*5+1; |
74 | 77 | sprintf(sval, "%08x", kval); |
78 | data = sdata; | |
75 | 79 | (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE)); |
76 | 80 | } |
77 | 81 | E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST)); |
109 | 113 | printf("Deleted %d values\n", j); |
110 | 114 | |
111 | 115 | E(mdb_env_stat(env, &mst)); |
112 | E(mdb_txn_begin(env, NULL, 1, &txn)); | |
116 | E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); | |
113 | 117 | E(mdb_cursor_open(txn, dbi, &cursor)); |
114 | 118 | printf("Cursor next\n"); |
115 | 119 | while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { |
126 | 130 | } |
127 | 131 | CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get"); |
128 | 132 | mdb_cursor_close(cursor); |
129 | mdb_close(env, dbi); | |
133 | mdb_txn_abort(txn); | |
130 | 134 | |
131 | mdb_txn_abort(txn); | |
135 | mdb_dbi_close(env, dbi); | |
132 | 136 | #endif |
133 | 137 | mdb_env_close(env); |
134 | 138 |
2 | 2 | * Do a line-by-line comparison of this and sample-mdb.txt |
3 | 3 | */ |
4 | 4 | /* |
5 | * Copyright 2012 Howard Chu, Symas Corp. | |
5 | * Copyright 2012-2015 Howard Chu, Symas Corp. | |
6 | 6 | * All rights reserved. |
7 | 7 | * |
8 | 8 | * Redistribution and use in source and binary forms, with or without |
2 | 2 | * Do a line-by-line comparison of this and sample-bdb.txt |
3 | 3 | */ |
4 | 4 | /* |
5 | * Copyright 2012 Howard Chu, Symas Corp. | |
5 | * Copyright 2012-2015 Howard Chu, Symas Corp. | |
6 | 6 | * All rights reserved. |
7 | 7 | * |
8 | 8 | * Redistribution and use in source and binary forms, with or without |
31 | 31 | rc = mdb_env_create(&env); |
32 | 32 | rc = mdb_env_open(env, "./testdb", 0, 0664); |
33 | 33 | rc = mdb_txn_begin(env, NULL, 0, &txn); |
34 | rc = mdb_open(txn, NULL, 0, &dbi); | |
34 | rc = mdb_dbi_open(txn, NULL, 0, &dbi); | |
35 | 35 | |
36 | 36 | key.mv_size = sizeof(int); |
37 | 37 | key.mv_data = sval; |
55 | 55 | mdb_cursor_close(cursor); |
56 | 56 | mdb_txn_abort(txn); |
57 | 57 | leave: |
58 | mdb_close(env, dbi); | |
58 | mdb_dbi_close(env, dbi); | |
59 | 59 | mdb_env_close(env); |
60 | 60 | return 0; |
61 | 61 | } |