From db510359c9c8398cd95ffc750e4739f4a165e6a7 Mon Sep 17 00:00:00 2001 From: Hallvard Furuseth Date: Wed, 18 Nov 2015 16:30:24 +0100 Subject: [PATCH 01/18] ITS#8312 Fix loose pages in commit(nested txn) --- libraries/liblmdb/mdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index fc0340c51e..0c9ab93c5e 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -3474,7 +3474,7 @@ mdb_txn_commit(MDB_txn *txn) } /* Append our loose page list to parent's */ - for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(lp)) + for (lp = &parent->mt_loose_pgs; *lp; lp = &NEXT_LOOSE_PAGE(*lp)) ; *lp = txn->mt_loose_pgs; parent->mt_loose_count += txn->mt_loose_count; From 2fb8219aa3af03ab1ad132fb8db985b742e1eb1a Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 18 Nov 2015 21:33:51 +0000 Subject: [PATCH 02/18] ITS#8313 more for ITS#8062 dummy flags must be init'd due to 3d46d550 --- libraries/liblmdb/mdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 0c9ab93c5e..deeaf9cc37 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -8055,6 +8055,7 @@ mdb_rebalance(MDB_cursor *mc) mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; /* We want mdb_rebalance to find mn when doing fixups */ if (mc->mc_flags & C_SUB) { + dummy.mc_flags = C_INITIALIZED; dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy; dummy.mc_xcursor = (MDB_xcursor *)&mn; From 1edb0e3a42826b488cda0677e96d9bc16eba95cc Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 18 Nov 2015 23:38:34 +0000 Subject: [PATCH 03/18] ITS#8315 fix ovpage_free Keep dirty_room sync'd with dirty_list --- libraries/liblmdb/mdb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index deeaf9cc37..5cd4536efb 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -5449,6 +5449,7 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) return MDB_CORRUPTED; } } + txn->mt_dirty_room++; if (!(env->me_flags & MDB_WRITEMAP)) mdb_dpage_free(env, mp); release: @@ -6583,6 +6584,7 @@ current: return ENOMEM; id2.mid = pg; id2.mptr = np; + /* Note - this page is already counted in parent's dirty_room */ rc2 = mdb_mid2l_insert(mc->mc_txn->mt_u.dirty_list, &id2); mdb_cassert(mc, rc2 == 0); if (!(flags & MDB_RESERVE)) { From 657dbcc811e3c02aa48f27cb9e7ac9b9be06002f Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 19 Nov 2015 17:29:42 +0000 Subject: [PATCH 04/18] ITS#8312, 8313, 8315 --- libraries/liblmdb/CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/liblmdb/CHANGES b/libraries/liblmdb/CHANGES index c9f9f38de2..d35d487c45 100644 --- a/libraries/liblmdb/CHANGES +++ b/libraries/liblmdb/CHANGES @@ -17,6 +17,9 @@ LMDB 0.9.17 Release Engineering Fix ITS#7971 mdb_txn_renew0() new reader slots Fix ITS#7969 use __sync_synchronize on non-x86 Fix ITS#8311 page_split from update_key + Fix ITS#8312 loose pages in nested txn + Fix ITS#8313 mdb_rebalance dummy cursor + Fix ITS#8315 dirty_room in nested txn Added mdb_txn_id() (ITS#7994) Added robust mutex support Miscellaneous cleanup/simplification From 28b57ba8b9ab29b0d89865911675815eec02f939 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 19 Nov 2015 20:04:16 +0000 Subject: [PATCH 05/18] ITS#8316 cursor fixup in page_merge Deleting the merged page requires bumping down other ki's of the page's parent. --- libraries/liblmdb/mdb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 5cd4536efb..819a631910 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -7842,6 +7842,9 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) m3->mc_pg[top] = pdst; m3->mc_ki[top] += nkeys; m3->mc_ki[top-1] = cdst->mc_ki[top-1]; + } else if (m3->mc_pg[top-1] == csrc->mc_pg[top-1] && + m3->mc_ki[top-1] > csrc->mc_ki[top-1]) { + m3->mc_ki[top-1]--; } } } From f13b971960a50915c1eb45fcf74209f5b6059d57 Mon Sep 17 00:00:00 2001 From: Oskari Timperi Date: Fri, 5 Dec 2014 12:56:22 +0200 Subject: [PATCH 06/18] ITS#7992 assume Windows paths are UTF-8 --- libraries/liblmdb/mdb.c | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 819a631910..1bd9cb718d 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1372,6 +1372,8 @@ static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_ static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_ATTRIBUTES mdb_all_sa; static int mdb_sec_inited; + +static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize); #endif /** Return the library version info. */ @@ -4440,9 +4442,12 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) off_t size, rsize; #ifdef _WIN32 - env->me_lfd = CreateFileA(lpath, GENERIC_READ|GENERIC_WRITE, + wchar_t *wlpath; + utf8_to_utf16(lpath, -1, &wlpath, NULL); + env->me_lfd = CreateFileW(wlpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + free(wlpath); #else env->me_lfd = open(lpath, O_RDWR|O_CREAT|MDB_CLOEXEC, mode); #endif @@ -4660,6 +4665,9 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode { int oflags, rc, len, excl = -1; char *lpath, *dpath; +#ifdef _WIN32 + wchar_t *wpath; +#endif if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) return EINVAL; @@ -4723,8 +4731,10 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode len = OPEN_ALWAYS; } mode = FILE_ATTRIBUTE_NORMAL; - env->me_fd = CreateFileA(dpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE, + utf8_to_utf16(dpath, -1, &wpath, NULL); + env->me_fd = CreateFileW(wpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len, mode, NULL); + free(wpath); #else if (F_ISSET(flags, MDB_RDONLY)) oflags = O_RDONLY; @@ -4753,9 +4763,11 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode */ #ifdef _WIN32 len = OPEN_EXISTING; - env->me_mfd = CreateFileA(dpath, oflags, + utf8_to_utf16(dpath, -1, &wpath, NULL); + env->me_mfd = CreateFileW(wpath, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len, mode | FILE_FLAG_WRITE_THROUGH, NULL); + free(wpath); #else oflags &= ~O_CREAT; env->me_mfd = open(dpath, oflags | MDB_DSYNC, mode); @@ -9145,6 +9157,9 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags) int rc, len; char *lpath; HANDLE newfd = INVALID_HANDLE_VALUE; +#ifdef _WIN32 + wchar_t *wpath; +#endif if (env->me_flags & MDB_NOSUBDIR) { lpath = (char *)path; @@ -9162,8 +9177,10 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags) * already in the OS cache. */ #ifdef _WIN32 - newfd = CreateFileA(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW, + utf8_to_utf16(lpath, -1, &wpath, NULL); + newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL); + free(wpath); #else newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL, 0666); #endif @@ -9868,3 +9885,22 @@ mdb_mutex_failed(MDB_env *env, mdb_mutexref_t mutex, int rc) } #endif /* MDB_ROBUST_SUPPORTED */ /** @} */ + +#if defined(_WIN32) +static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize) +{ + int need; + wchar_t *result; + need = MultiByteToWideChar(CP_UTF8, 0, src, srcsize, NULL, 0); + if (need == 0xFFFD) + return EILSEQ; + if (need == 0) + return EINVAL; + result = malloc(sizeof(wchar_t) * need); + MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need); + if (dstsize) + *dstsize = need; + *dst = result; + return 0; +} +#endif /* defined(_WIN32) */ From bfe20889464c8a5bbbab1fd2bd08e0c1835509ad Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 20 Nov 2015 09:20:16 +0000 Subject: [PATCH 07/18] Refix root split check from 5da67968afb599697d7557c13b65fb961ec408dd --- libraries/liblmdb/mdb.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 1bd9cb718d..5e2b690694 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -8450,6 +8450,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno /* Copy separator key to the parent. */ if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) { + int snum = mc->mc_snum; mn.mc_snum--; mn.mc_top--; did_split = 1; @@ -8458,13 +8459,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno goto done; /* root split? */ - if (mn.mc_snum == mc->mc_snum) { - mc->mc_pg[mc->mc_snum] = mc->mc_pg[mc->mc_top]; - mc->mc_ki[mc->mc_snum] = mc->mc_ki[mc->mc_top]; - mc->mc_pg[mc->mc_top] = mc->mc_pg[ptop]; - mc->mc_ki[mc->mc_top] = mc->mc_ki[ptop]; - mc->mc_snum++; - mc->mc_top++; + if (mc->mc_snum > snum) { ptop++; } /* Right page might now have changed parent. @@ -8595,8 +8590,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno continue; if (!(m2->mc_flags & m3->mc_flags & C_INITIALIZED)) continue; - if (m3->mc_flags & C_SPLITTING) - continue; if (new_root) { int k; /* root split */ @@ -8613,6 +8606,8 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno m3->mc_snum++; m3->mc_top++; } + if (m3->mc_flags & C_SPLITTING) + continue; if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE)) m3->mc_ki[mc->mc_top]++; From ba85adb52db9c1700d02dc4ed9880cd8a5e07137 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 20 Nov 2015 09:47:56 +0000 Subject: [PATCH 08/18] Silence some valgrind uninit warnings --- libraries/liblmdb/mdb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 5e2b690694..28f3be3f87 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -7635,6 +7635,8 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; + if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) + continue; if (m3 != cdst && m3->mc_pg[csrc->mc_top] == mpd && m3->mc_ki[csrc->mc_top] >= cdst->mc_ki[csrc->mc_top]) { @@ -7657,6 +7659,8 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst) else m3 = m2; if (m3 == csrc) continue; + if (!(m3->mc_flags & C_INITIALIZED) || m3->mc_top < csrc->mc_top) + continue; if (m3->mc_pg[csrc->mc_top] == mps) { if (!m3->mc_ki[csrc->mc_top]) { m3->mc_pg[csrc->mc_top] = cdst->mc_pg[cdst->mc_top]; @@ -7957,7 +7961,8 @@ mdb_rebalance(MDB_cursor *mc) m3 = &m2->mc_xcursor->mx_cursor; else m3 = m2; - if (m3->mc_snum < mc->mc_snum) continue; + if (!(m3->mc_flags & C_INITIALIZED) || (m3->mc_snum < mc->mc_snum)) + continue; if (m3->mc_pg[0] == mp) { m3->mc_snum = 0; m3->mc_top = 0; @@ -7993,6 +7998,8 @@ mdb_rebalance(MDB_cursor *mc) else m3 = m2; if (m3 == mc) continue; + if (!(m3->mc_flags & C_INITIALIZED)) + continue; if (m3->mc_pg[0] == mp) { for (i=0; imc_db->md_depth; i++) { m3->mc_pg[i] = m3->mc_pg[i+1]; From 94e8009ca4d740c03e485149a2b7f6962ab69fe5 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Fri, 20 Nov 2015 13:34:11 +0000 Subject: [PATCH 09/18] ITS#8300 more for prev commit Just tell explicitly which direction we moved/merged from --- libraries/liblmdb/mdb.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 28f3be3f87..77287b7728 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1327,7 +1327,7 @@ static int mdb_node_add(MDB_cursor *mc, indx_t indx, MDB_val *key, MDB_val *data, pgno_t pgno, unsigned int flags); static void mdb_node_del(MDB_cursor *mc, int ksize); static void mdb_node_shrink(MDB_page *mp, indx_t indx); -static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst); +static int mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft); static int mdb_node_read(MDB_txn *txn, MDB_node *leaf, MDB_val *data); static size_t mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data); static size_t mdb_branch_size(MDB_env *env, MDB_val *key); @@ -7526,7 +7526,7 @@ mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst); /** Move a node from csrc to cdst. */ static int -mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst) +mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) { MDB_node *srcnode; MDB_val key, data; @@ -7628,7 +7628,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst) mps = csrc->mc_pg[csrc->mc_top]; /* If we're adding on the left, bump others up */ - if (!cdst->mc_ki[csrc->mc_top]) { + if (fromleft) { mpd = cdst->mc_pg[csrc->mc_top]; for (m2 = csrc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (csrc->mc_flags & C_SUB) @@ -7910,7 +7910,7 @@ static int mdb_rebalance(MDB_cursor *mc) { MDB_node *node; - int rc; + int rc, fromleft; unsigned int ptop, minkeys, thresh; MDB_cursor mn; indx_t oldki; @@ -8043,6 +8043,7 @@ mdb_rebalance(MDB_cursor *mc) return rc; mn.mc_ki[mn.mc_top] = 0; mc->mc_ki[mc->mc_top] = NUMKEYS(mc->mc_pg[mc->mc_top]); + fromleft = 0; } else { /* There is at least one neighbor to the left. */ @@ -8054,6 +8055,7 @@ mdb_rebalance(MDB_cursor *mc) return rc; mn.mc_ki[mn.mc_top] = NUMKEYS(mn.mc_pg[mn.mc_top]) - 1; mc->mc_ki[mc->mc_top] = 0; + fromleft = 1; } DPRINTF(("found neighbor page %"Z"u (%u keys, %.1f%% full)", @@ -8065,13 +8067,13 @@ mdb_rebalance(MDB_cursor *mc) * (A branch page must never have less than 2 keys.) */ if (PAGEFILL(mc->mc_txn->mt_env, mn.mc_pg[mn.mc_top]) >= thresh && NUMKEYS(mn.mc_pg[mn.mc_top]) > minkeys) { - rc = mdb_node_move(&mn, mc); - if (!mc->mc_ki[mc->mc_top]) { + rc = mdb_node_move(&mn, mc, fromleft); + if (fromleft) { /* if we inserted on left, bump position up */ oldki++; } } else { - if (mc->mc_ki[ptop] == 0) { + if (!fromleft) { rc = mdb_page_merge(&mn, mc); } else { MDB_cursor dummy; From 91dc62506b7427a121c4d5af7e1b05f42acab425 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 22 Nov 2015 22:11:30 +0000 Subject: [PATCH 10/18] ITS#8321 Fix del/dupsort When deleting a dupsort key, if other cursors pointed at that key, set them to uninit'd, not EOF. They no longer have anything to point at. --- libraries/liblmdb/mdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 77287b7728..a4a9e1f318 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -8131,7 +8131,7 @@ mdb_cursor_del0(MDB_cursor *mc) if (m3->mc_ki[mc->mc_top] > ki) m3->mc_ki[mc->mc_top]--; else if (mc->mc_db->md_flags & MDB_DUPSORT) - m3->mc_xcursor->mx_cursor.mc_flags |= C_EOF; + m3->mc_xcursor->mx_cursor.mc_flags &= ~C_INITIALIZED; } } } From 8773a08c438f33c0c8c8dbb329e7d8fd6376b115 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:07:57 +0000 Subject: [PATCH 11/18] ITS#8321 don't skip fixups on splitting cursors Adjustments can't be skipped, in recursive calls each level must fixup their own level. --- libraries/liblmdb/mdb.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index a4a9e1f318..12e8eff87f 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1161,7 +1161,6 @@ struct MDB_cursor { #define C_EOF 0x02 /**< No more data */ #define C_SUB 0x04 /**< Cursor is a sub-cursor */ #define C_DEL 0x08 /**< last op was a cursor_del */ -#define C_SPLITTING 0x20 /**< Cursor is in page_split */ #define C_UNTRACK 0x40 /**< Un-track cursor when closing */ /** @} */ unsigned int mc_flags; /**< @ref mdb_cursor */ @@ -8314,7 +8313,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno DPRINTF(("parent branch page is %"Z"u", mc->mc_pg[ptop]->mp_pgno)); } - mc->mc_flags |= C_SPLITTING; mdb_cursor_copy(mc, &mn); mn.mc_pg[mn.mc_top] = rp; mn.mc_ki[ptop] = mc->mc_ki[ptop]+1; @@ -8494,7 +8492,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno rc = mdb_node_add(&mn, mn.mc_ki[ptop], &sepkey, NULL, rp->mp_pgno, 0); mn.mc_top++; } - mc->mc_flags ^= C_SPLITTING; if (rc != MDB_SUCCESS) { goto done; } @@ -8615,8 +8612,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno m3->mc_snum++; m3->mc_top++; } - if (m3->mc_flags & C_SPLITTING) - continue; if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE)) m3->mc_ki[mc->mc_top]++; From 0ec3967e1d655d8a9601768a6a9372da5ee875b5 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:10:05 +0000 Subject: [PATCH 12/18] ITS#8321 fix mdb_cursor_chk() It was reporting spurious errors due to uninit'd cursors --- libraries/liblmdb/mdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 12e8eff87f..a4d2aad57a 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1604,7 +1604,7 @@ mdb_cursor_chk(MDB_cursor *mc) MDB_node *node; MDB_page *mp; - if (!mc->mc_snum && !(mc->mc_flags & C_INITIALIZED)) return; + if (!mc->mc_snum || !(mc->mc_flags & C_INITIALIZED)) return; for (i=0; imc_top; i++) { mp = mc->mc_pg[i]; node = NODEPTR(mp, mc->mc_ki[i]); From 94831f7c3f0f49b6795c34ef71901b5cd5cf6e28 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:13:16 +0000 Subject: [PATCH 13/18] ITS#8321 fix mdb_cursor_shadow() Set a valid txn so that cursor fixup code works on the shadows --- libraries/liblmdb/mdb.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index a4d2aad57a..bf3b4ba0ab 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -2489,14 +2489,15 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst) *bk = *mc; mc->mc_backup = bk; mc->mc_db = &dst->mt_dbs[i]; - /* Kill pointers into src - and dst to reduce abuse: The - * user may not use mc until dst ends. Otherwise we'd... + /* Kill pointers into src to reduce abuse: The + * user may not use mc until dst ends. But we need a valid + * txn pointer here for cursor fixups to keep working. */ - mc->mc_txn = NULL; /* ...set this to dst */ - mc->mc_dbflag = NULL; /* ...and &dst->mt_dbflags[i] */ + mc->mc_txn = dst; + mc->mc_dbflag = &dst->mt_dbflags[i]; if ((mx = mc->mc_xcursor) != NULL) { *(MDB_xcursor *)(bk+1) = *mx; - mx->mx_cursor.mc_txn = NULL; /* ...and dst. */ + mx->mx_cursor.mc_txn = dst; } mc->mc_next = dst->mt_cursors[i]; dst->mt_cursors[i] = mc; From 5c7b84b465da1614ec8f6547a7ac5a39b2278178 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:16:36 +0000 Subject: [PATCH 14/18] ITS#8321 fix mdb_cursor_put Ignore sub-cursors that shouldn't be fixed up --- libraries/liblmdb/mdb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index bf3b4ba0ab..638f5a94a2 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -6710,6 +6710,7 @@ put_sub: MDB_xcursor *mx = mc->mc_xcursor; unsigned i = mc->mc_top; MDB_page *mp = mc->mc_pg[i]; + int nkeys = NUMKEYS(mp); for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) { if (m2 == mc || m2->mc_snum < mc->mc_snum) continue; @@ -6717,9 +6718,9 @@ put_sub: if (m2->mc_pg[i] == mp) { if (m2->mc_ki[i] == mc->mc_ki[i]) { mdb_xcursor_init2(m2, mx, new_dupdata); - } else if (!insert_key) { + } else if (!insert_key && m2->mc_ki[i] < nkeys) { MDB_node *n2 = NODEPTR(mp, m2->mc_ki[i]); - if (!(n2->mn_flags & F_SUBDATA)) + if ((n2->mn_flags & (F_SUBDATA|F_DUPDATA)) == F_DUPDATA) m2->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(n2); } } From 7a76ded03062ca4ff1499cc6ddc48b5e6a83ee2e Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:30:02 +0000 Subject: [PATCH 15/18] ITS#8321 track temporary cursors In rebalance/split operations, temporary cursors need to be visible to propagate fixups --- libraries/liblmdb/mdb.c | 51 ++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 638f5a94a2..752fdfaafc 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -7524,6 +7524,22 @@ mdb_update_key(MDB_cursor *mc, MDB_val *key) static void mdb_cursor_copy(const MDB_cursor *csrc, MDB_cursor *cdst); +/** Track a temporary cursor */ +#define CURSOR_TMP_TRACK(mc, mn, dummy, tracked) \ + if (mc->mc_flags & C_SUB) { \ + dummy.mc_flags = C_INITIALIZED; \ + dummy.mc_xcursor = (MDB_xcursor *)&mn; \ + tracked = &dummy; \ + } else { \ + tracked = &mn; \ + } \ + tracked->mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; \ + mc->mc_txn->mt_cursors[mc->mc_dbi] = tracked + +/** Stop tracking a temporary cursor */ +#define CURSOR_TMP_UNTRACK(mc, tracked) \ + mc->mc_txn->mt_cursors[mc->mc_dbi] = tracked->mc_next + /** Move a node from csrc to cdst. */ static int @@ -7679,6 +7695,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) */ if (csrc->mc_ki[csrc->mc_top] == 0) { if (csrc->mc_ki[csrc->mc_top-1] != 0) { + MDB_cursor dummy, *tracked; if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size); } else { @@ -7691,7 +7708,11 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) mdb_cursor_copy(csrc, &mn); mn.mc_snum--; mn.mc_top--; - if ((rc = mdb_update_key(&mn, &key)) != MDB_SUCCESS) + /* We want mdb_rebalance to find mn when doing fixups */ + CURSOR_TMP_TRACK(csrc, mn, dummy, tracked); + rc = mdb_update_key(&mn, &key); + CURSOR_TMP_UNTRACK(csrc, tracked); + if (rc) return rc; } if (IS_BRANCH(csrc->mc_pg[csrc->mc_top])) { @@ -7707,6 +7728,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) if (cdst->mc_ki[cdst->mc_top] == 0) { if (cdst->mc_ki[cdst->mc_top-1] != 0) { + MDB_cursor dummy, *tracked; if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) { key.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, key.mv_size); } else { @@ -7719,7 +7741,11 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst, int fromleft) mdb_cursor_copy(cdst, &mn); mn.mc_snum--; mn.mc_top--; - if ((rc = mdb_update_key(&mn, &key)) != MDB_SUCCESS) + /* We want mdb_rebalance to find mn when doing fixups */ + CURSOR_TMP_TRACK(cdst, mn, dummy, tracked); + rc = mdb_update_key(&mn, &key); + CURSOR_TMP_UNTRACK(cdst, tracked); + if (rc) return rc; } if (IS_BRANCH(cdst->mc_pg[cdst->mc_top])) { @@ -8077,24 +8103,13 @@ mdb_rebalance(MDB_cursor *mc) if (!fromleft) { rc = mdb_page_merge(&mn, mc); } else { - MDB_cursor dummy; + MDB_cursor dummy, *tracked; oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; /* We want mdb_rebalance to find mn when doing fixups */ - if (mc->mc_flags & C_SUB) { - dummy.mc_flags = C_INITIALIZED; - dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; - mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy; - dummy.mc_xcursor = (MDB_xcursor *)&mn; - } else { - mn.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; - mc->mc_txn->mt_cursors[mc->mc_dbi] = &mn; - } + CURSOR_TMP_TRACK(mc, mn, dummy, tracked); rc = mdb_page_merge(mc, &mn); - if (mc->mc_flags & C_SUB) - mc->mc_txn->mt_cursors[mc->mc_dbi] = dummy.mc_next; - else - mc->mc_txn->mt_cursors[mc->mc_dbi] = mn.mc_next; + CURSOR_TMP_UNTRACK(mc, tracked); mdb_cursor_copy(&mn, mc); } mc->mc_flags &= ~C_EOF; @@ -8460,10 +8475,14 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno */ if (SIZELEFT(mn.mc_pg[ptop]) < mdb_branch_size(env, &sepkey)) { int snum = mc->mc_snum; + MDB_cursor dummy, *tracked; mn.mc_snum--; mn.mc_top--; did_split = 1; + /* We want other splits to find mn when doing fixups */ + CURSOR_TMP_TRACK(mc, mn, dummy, tracked); rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0); + CURSOR_TMP_UNTRACK(mc, tracked); if (rc) goto done; From 8fdf79600a2d1b1d50cc7d052e45d2d27fd447ad Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:33:00 +0000 Subject: [PATCH 16/18] ITS#8321 simplify page_split fixups --- libraries/liblmdb/mdb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 752fdfaafc..236f58d90a 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -8606,7 +8606,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno /* Adjust other cursors pointing to mp */ MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; - int fixup = NUMKEYS(mp); + nkeys = NUMKEYS(mp); for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) { if (mc->mc_flags & C_SUB) @@ -8619,12 +8619,15 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno continue; if (new_root) { int k; + /* sub cursors may be on different DB */ + if (m3->mc_pg[0] != mp) + continue; /* root split */ for (k=new_root; k>=0; k--) { m3->mc_ki[k+1] = m3->mc_ki[k]; m3->mc_pg[k+1] = m3->mc_pg[k]; } - if (m3->mc_ki[0] >= split_indx) { + if (m3->mc_ki[0] > nkeys) { m3->mc_ki[0] = 1; } else { m3->mc_ki[0] = 0; @@ -8636,10 +8639,13 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno if (m3->mc_top >= mc->mc_top && m3->mc_pg[mc->mc_top] == mp) { if (m3->mc_ki[mc->mc_top] >= newindx && !(nflags & MDB_SPLIT_REPLACE)) m3->mc_ki[mc->mc_top]++; - if (m3->mc_ki[mc->mc_top] >= fixup) { + if (m3->mc_ki[mc->mc_top] >= nkeys) { m3->mc_pg[mc->mc_top] = rp; - m3->mc_ki[mc->mc_top] -= fixup; - m3->mc_ki[ptop] = mn.mc_ki[ptop]; + m3->mc_ki[mc->mc_top] -= nkeys; + for (i=0; imc_top; i++) { + m3->mc_ki[i] = mn.mc_ki[i]; + m3->mc_pg[i] = mn.mc_pg[i]; + } } } else if (!did_split && m3->mc_top >= ptop && m3->mc_pg[ptop] == mc->mc_pg[ptop] && m3->mc_ki[ptop] >= mc->mc_ki[ptop]) { From d78ffc951706afab5dbb11feac143f76f1674951 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:34:26 +0000 Subject: [PATCH 17/18] ITS#8321 reorganize page_split fixups DUPFIXED fixups needed to occur after separator update. MDB_RESERVE handling moved after split fixup. --- libraries/liblmdb/mdb.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 236f58d90a..c5174e983a 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -8380,8 +8380,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno rp->mp_lower += sizeof(indx_t); rp->mp_upper -= ksize - sizeof(indx_t); mc->mc_ki[mc->mc_top] = x; - mc->mc_pg[mc->mc_top] = rp; - mc->mc_ki[ptop]++; } } else { int psize, nsize, k; @@ -8582,11 +8580,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno /* reset back to original page */ if (newindx < split_indx) { mc->mc_pg[mc->mc_top] = mp; - if (nflags & MDB_RESERVE) { - node = NODEPTR(mp, mc->mc_ki[mc->mc_top]); - if (!(node->mn_flags & F_BIGDATA)) - newdata->mv_data = NODEDATA(node); - } } else { mc->mc_pg[mc->mc_top] = rp; mc->mc_ki[ptop]++; @@ -8600,6 +8593,25 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno } } } + if (nflags & MDB_RESERVE) { + node = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]); + if (!(node->mn_flags & F_BIGDATA)) + newdata->mv_data = NODEDATA(node); + } + } else { + if (newindx >= split_indx) { + mc->mc_pg[mc->mc_top] = rp; + mc->mc_ki[ptop]++; + /* Make sure mc_ki is still valid. + */ + if (mn.mc_pg[ptop] != mc->mc_pg[ptop] && + mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) { + for (i=0; i<=ptop; i++) { + mc->mc_pg[i] = mn.mc_pg[i]; + mc->mc_ki[i] = mn.mc_ki[i]; + } + } + } } { From b0851a13af677067f93cea408768b679cdc372d0 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Mon, 23 Nov 2015 01:51:45 +0000 Subject: [PATCH 18/18] ITS#8316, 8321 --- libraries/liblmdb/CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/liblmdb/CHANGES b/libraries/liblmdb/CHANGES index d35d487c45..b0aad290ae 100644 --- a/libraries/liblmdb/CHANGES +++ b/libraries/liblmdb/CHANGES @@ -20,6 +20,8 @@ LMDB 0.9.17 Release Engineering Fix ITS#8312 loose pages in nested txn Fix ITS#8313 mdb_rebalance dummy cursor Fix ITS#8315 dirty_room in nested txn + Fix ITS#8316 page_merge cursor tracking + Fix ITS#8321 cursor tracking Added mdb_txn_id() (ITS#7994) Added robust mutex support Miscellaneous cleanup/simplification