From e74d70e88e838c0f1e80b00e7c3cf6ea57762d0d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 11 Dec 2012 12:03:19 -0800 Subject: [PATCH 1/3] Partially revert 65d40eb5d2c7c28df05e2c1d9b21d90e2a82e0b5 Allow both increasing and decreasing the environment size. But don't allow decreasing below the currently occupied space. --- libraries/liblmdb/lmdb.h | 3 +++ libraries/liblmdb/mdb.c | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h index 9c21cdc68b..e4d55c8b22 100644 --- a/libraries/liblmdb/lmdb.h +++ b/libraries/liblmdb/lmdb.h @@ -574,6 +574,9 @@ int mdb_env_get_path(MDB_env *env, const char **path); * of the database. The value should be chosen as large as possible, * to accommodate future growth of the database. * This function may only be called after #mdb_env_create() and before #mdb_env_open(). + * The size may be changed by closing and reopening the environment. + * Any attempt to set a size smaller than the space already consumed + * by the environment will be silently changed to the current size of the used space. * @param[in] env An environment handle returned by #mdb_env_create() * @param[in] size The size in bytes * @return A non-zero error value on failure and 0 on success. Some possible diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 4fe330b1d1..b25c372fb7 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -2722,11 +2722,22 @@ mdb_env_open2(MDB_env *env) return i; DPUTS("new mdbenv"); newenv = 1; - meta.mm_mapsize = env->me_mapsize > DEFAULT_MAPSIZE ? env->me_mapsize : DEFAULT_MAPSIZE; } - if (env->me_mapsize < meta.mm_mapsize) - env->me_mapsize = meta.mm_mapsize; + /* Was a mapsize configured? */ + if (!env->me_mapsize) { + /* If this is a new environment, take the default, + * else use the size recorded in the existing env. + */ + env->me_mapsize = newenv ? DEFAULT_MAPSIZE : meta.mm_mapsize; + } else if (env->me_mapsize < meta.mm_mapsize) { + /* If the configured size is smaller, make sure it's + * still big enough. Silently round up to minimum if not. + */ + size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize; + if (env->me_mapsize < minsize) + env->me_mapsize = minsize; + } #ifdef _WIN32 { From ed86a086f7ae92c8f8bd40032ab5dc3e02cf40b0 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 11 Dec 2012 12:46:17 -0800 Subject: [PATCH 2/3] More for prev commit Use the latest meta page --- libraries/liblmdb/mdb.c | 76 ++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index b25c372fb7..4492a76030 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -2416,47 +2416,61 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta) MDB_pagebuf pbuf; MDB_page *p; MDB_meta *m; - int rc, err; + int i, rc, err; /* We don't know the page size yet, so use a minimum value. + * Read both meta pages so we can use the latest one. */ + for (i=0; i<2; i++) { #ifdef _WIN32 - if (!ReadFile(env->me_fd, &pbuf, MDB_PAGESIZE, (DWORD *)&rc, NULL) || rc == 0) + if (!ReadFile(env->me_fd, &pbuf, MDB_PAGESIZE, (DWORD *)&rc, NULL) || rc == 0) #else - if ((rc = read(env->me_fd, &pbuf, MDB_PAGESIZE)) == 0) + if ((rc = read(env->me_fd, &pbuf, MDB_PAGESIZE)) == 0) #endif - { - return ENOENT; - } - else if (rc != MDB_PAGESIZE) { - err = ErrCode(); - if (rc > 0) - err = MDB_INVALID; - DPRINTF("read: %s", strerror(err)); - return err; - } + { + return ENOENT; + } + else if (rc != MDB_PAGESIZE) { + err = ErrCode(); + if (rc > 0) + err = MDB_INVALID; + DPRINTF("read: %s", strerror(err)); + return err; + } - p = (MDB_page *)&pbuf; + p = (MDB_page *)&pbuf; - if (!F_ISSET(p->mp_flags, P_META)) { - DPRINTF("page %zu not a meta page", p->mp_pgno); - return MDB_INVALID; + if (!F_ISSET(p->mp_flags, P_META)) { + DPRINTF("page %zu not a meta page", p->mp_pgno); + return MDB_INVALID; + } + + m = METADATA(p); + if (m->mm_magic != MDB_MAGIC) { + DPUTS("meta has invalid magic"); + return MDB_INVALID; + } + + if (m->mm_version != MDB_VERSION) { + DPRINTF("database is version %u, expected version %u", + m->mm_version, MDB_VERSION); + return MDB_VERSION_MISMATCH; + } + + if (i) { + if (m->mm_txnid > meta->mm_txnid) + memcpy(meta, m, sizeof(*m)); + } else { + memcpy(meta, m, sizeof(*m)); +#ifdef _WIN32 + if (SetFilePointer(env->me_fd, meta->mm_psize, NULL, FILE_BEGIN) != meta->mm_psize) +#else + if (lseek(env->me_fd, meta->mm_psize, SEEK_SET) != meta->mm_psize) +#endif + return ErrCode(); + } } - - m = METADATA(p); - if (m->mm_magic != MDB_MAGIC) { - DPUTS("meta has invalid magic"); - return MDB_INVALID; - } - - if (m->mm_version != MDB_VERSION) { - DPRINTF("database is version %u, expected version %u", - m->mm_version, MDB_VERSION); - return MDB_VERSION_MISMATCH; - } - - memcpy(meta, m, sizeof(*m)); return 0; } From 9acf801cc119d187e1252474cab7d228dc6d7676 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Tue, 11 Dec 2012 12:55:47 -0800 Subject: [PATCH 3/3] Make sure init_meta is at beginning of file --- libraries/liblmdb/mdb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 4492a76030..e6f75406e1 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -2518,10 +2518,12 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta) #ifdef _WIN32 { DWORD len; + SetFilePointer(env->me_fd, 0, NULL, FILE_BEGIN); rc = WriteFile(env->me_fd, p, psize * 2, &len, NULL); rc = (len == psize * 2) ? MDB_SUCCESS : ErrCode(); } #else + lseek(env->me_fd, 0, SEEK_SET); rc = write(env->me_fd, p, psize * 2); rc = (rc == (int)psize * 2) ? MDB_SUCCESS : ErrCode(); #endif