mdbx: fix/avoid meta-update from setup_dxb() in read-only mode.

Change-Id: I60359f92aba31bb5a22e9a39ea4658d2393e957d
This commit is contained in:
Leo Yuriev 2017-07-21 12:16:07 +03:00
parent 109be210b4
commit 599711a007

View File

@ -4529,25 +4529,27 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
mdbx_ensure(env, meta.mm_geo.now >= meta.mm_geo.next); mdbx_ensure(env, meta.mm_geo.now >= meta.mm_geo.next);
} }
uint64_t filesize; uint64_t filesize_before_mmap;
err = mdbx_filesize(env->me_fd, &filesize); err = mdbx_filesize(env->me_fd, &filesize_before_mmap);
if (unlikely(err != MDBX_SUCCESS)) if (unlikely(err != MDBX_SUCCESS))
return err; return err;
const size_t expected_bytes = pgno2bytes(env, meta.mm_geo.now); const size_t expected_bytes = pgno2bytes(env, meta.mm_geo.now);
const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next);
if (filesize != expected_bytes) { mdbx_ensure(env, expected_bytes >= used_bytes);
if (filesize_before_mmap != expected_bytes) {
if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) {
mdbx_info("filesize mismatch (expect %" PRIuPTR ", have %" PRIu64 "), " mdbx_info("filesize mismatch (expect %" PRIuPTR ", have %" PRIu64 "), "
"assume collision in non-exclusive mode", "assume collision in non-exclusive mode",
expected_bytes, filesize); expected_bytes, filesize_before_mmap);
} else { } else {
mdbx_notice("filesize mismatch (expect %" PRIuPTR ", have %" PRIu64 ")", mdbx_notice("filesize mismatch (expect %" PRIuPTR ", have %" PRIu64 ")",
expected_bytes, filesize); expected_bytes, filesize_before_mmap);
if (filesize < used_bytes) { if (filesize_before_mmap < used_bytes) {
mdbx_error("last-page beyond end-of-file (last %" PRIaPGNO mdbx_error("last-page beyond end-of-file (last %" PRIaPGNO
", have %" PRIaPGNO ")", ", have %" PRIaPGNO ")",
meta.mm_geo.next, bytes2pgno(env, (size_t)filesize)); meta.mm_geo.next,
bytes2pgno(env, (size_t)filesize_before_mmap));
return MDBX_CORRUPTED; return MDBX_CORRUPTED;
} }
@ -4561,6 +4563,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
expected_bytes); expected_bytes);
return err; return err;
} }
filesize_before_mmap = expected_bytes;
} }
} }
} }
@ -4638,20 +4641,28 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
const MDBX_meta *head = mdbx_meta_head(env); const MDBX_meta *head = mdbx_meta_head(env);
if (lck_rc == /* lck exclusive */ MDBX_RESULT_TRUE) { if (lck_rc == /* lck exclusive */ MDBX_RESULT_TRUE) {
/* re-check file size after mmap */ /* re-check file size after mmap */
err = mdbx_filesize(env->me_fd, &filesize); uint64_t filesize_after_mmap;
err = mdbx_filesize(env->me_fd, &filesize_after_mmap);
if (unlikely(err != MDBX_SUCCESS)) if (unlikely(err != MDBX_SUCCESS))
return err; return err;
if (filesize != expected_bytes) { if (filesize_after_mmap != expected_bytes) {
mdbx_info("datafile resized by system to %" PRIu64 " bytes", filesize); if (filesize_after_mmap != filesize_before_mmap)
if (filesize % env->me_os_psize || filesize > env->me_dbgeo.upper || mdbx_info("datafile resized by system to %" PRIu64 " bytes",
filesize < used_bytes) { filesize_after_mmap);
mdbx_info("unacceptable/unexpected datafile size %" PRIu64, filesize); if (filesize_after_mmap % env->me_os_psize ||
filesize_after_mmap > env->me_dbgeo.upper ||
filesize_after_mmap < used_bytes) {
mdbx_info("unacceptable/unexpected datafile size %" PRIu64,
filesize_after_mmap);
return MDBX_PROBLEM; return MDBX_PROBLEM;
} }
meta.mm_geo.now = bytes2pgno(env, env->me_dbgeo.now = (size_t)filesize); if ((env->me_flags & MDBX_RDONLY) == 0) {
mdbx_info("update meta-geo to filesize %" PRIuPTR " bytes, %" PRIaPGNO meta.mm_geo.now =
" pages", bytes2pgno(env, env->me_dbgeo.now = (size_t)filesize_after_mmap);
env->me_dbgeo.now, meta.mm_geo.now); mdbx_info("update meta-geo to filesize %" PRIuPTR " bytes, %" PRIaPGNO
" pages",
env->me_dbgeo.now, meta.mm_geo.now);
}
} }
if (memcmp(&meta.mm_geo, &head->mm_geo, sizeof(meta.mm_geo))) { if (memcmp(&meta.mm_geo, &head->mm_geo, sizeof(meta.mm_geo))) {