mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx: refine read_header(), add MDBX_TOO_LARGE.
Change-Id: I25b9bb2e3817993d627b2b784dfa496d9ba7e7b0
This commit is contained in:
parent
61d7ea283f
commit
7e85ad82f1
4
mdbx.h
4
mdbx.h
@ -414,6 +414,10 @@ typedef enum MDBX_cursor_op {
|
|||||||
* when mdbx_cursor_put() called with MDBX_CURRENT option. */
|
* when mdbx_cursor_put() called with MDBX_CURRENT option. */
|
||||||
#define MDBX_EKEYMISMATCH (-30418)
|
#define MDBX_EKEYMISMATCH (-30418)
|
||||||
|
|
||||||
|
/* Database is too large for current system, i.e. could NOT be mapped into RAM.
|
||||||
|
*/
|
||||||
|
#define MDBX_TOO_LARGE (-30417)
|
||||||
|
|
||||||
/* Statistics for a database in the environment */
|
/* Statistics for a database in the environment */
|
||||||
typedef struct MDBX_stat {
|
typedef struct MDBX_stat {
|
||||||
uint32_t ms_psize; /* Size of a database page.
|
uint32_t ms_psize; /* Size of a database page.
|
||||||
|
82
src/mdbx.c
82
src/mdbx.c
@ -689,6 +689,9 @@ static const char *__mdbx_strerr(int errnum) {
|
|||||||
case MDBX_EKEYMISMATCH:
|
case MDBX_EKEYMISMATCH:
|
||||||
return "MDBX_EKEYMISMATCH: The given key value is mismatched to the "
|
return "MDBX_EKEYMISMATCH: The given key value is mismatched to the "
|
||||||
"current cursor position";
|
"current cursor position";
|
||||||
|
case MDBX_TOO_LARGE:
|
||||||
|
return "Database is too large for current system, i.e.could NOT be mapped "
|
||||||
|
"into RAM.";
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -3384,6 +3387,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
assert(offsetof(MDBX_page, mp_meta) == PAGEHDRSZ);
|
assert(offsetof(MDBX_page, mp_meta) == PAGEHDRSZ);
|
||||||
memset(meta, 0, sizeof(MDBX_meta));
|
memset(meta, 0, sizeof(MDBX_meta));
|
||||||
meta->mm_datasync_sign = MDBX_DATASIGN_WEAK;
|
meta->mm_datasync_sign = MDBX_DATASIGN_WEAK;
|
||||||
|
int rc = MDBX_CORRUPTED;
|
||||||
|
|
||||||
/* Read twice all meta pages so we can find the latest one. */
|
/* Read twice all meta pages so we can find the latest one. */
|
||||||
unsigned loop_limit = NUM_METAS * 2;
|
unsigned loop_limit = NUM_METAS * 2;
|
||||||
@ -3402,19 +3406,19 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
|
|
||||||
unsigned retryleft = 42;
|
unsigned retryleft = 42;
|
||||||
while (1) {
|
while (1) {
|
||||||
int rc = mdbx_pread(env->me_fd, &page, sizeof(page), offset);
|
int err = mdbx_pread(env->me_fd, &page, sizeof(page), offset);
|
||||||
if (rc != MDBX_SUCCESS) {
|
if (err != MDBX_SUCCESS) {
|
||||||
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(page),
|
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(page),
|
||||||
rc, mdbx_strerror(rc));
|
err, mdbx_strerror(err));
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDBX_page again;
|
MDBX_page again;
|
||||||
rc = mdbx_pread(env->me_fd, &again, sizeof(again), offset);
|
err = mdbx_pread(env->me_fd, &again, sizeof(again), offset);
|
||||||
if (rc != MDBX_SUCCESS) {
|
if (err != MDBX_SUCCESS) {
|
||||||
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(again),
|
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(again),
|
||||||
rc, mdbx_strerror(rc));
|
err, mdbx_strerror(err));
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(&page, &again, sizeof(page)) == 0 || --retryleft == 0)
|
if (memcmp(&page, &again, sizeof(page)) == 0 || --retryleft == 0)
|
||||||
@ -3451,26 +3455,6 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* LY: check pagesize */
|
|
||||||
STATIC_ASSERT(MIN_PAGESIZE < MAX_PAGESIZE);
|
|
||||||
if (!is_power2(page.mp_meta.mm_psize) ||
|
|
||||||
page.mp_meta.mm_psize < MIN_PAGESIZE ||
|
|
||||||
page.mp_meta.mm_psize > MAX_PAGESIZE) {
|
|
||||||
mdbx_notice("meta[%u] has invalid pagesize %u, skip it", meta_number,
|
|
||||||
page.mp_meta.mm_psize);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LY: check mapsize limits */
|
|
||||||
STATIC_ASSERT(MAX_MAPSIZE < SSIZE_MAX - MAX_PAGESIZE);
|
|
||||||
STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
|
|
||||||
if (page.mp_meta.mm_mapsize < MIN_MAPSIZE ||
|
|
||||||
page.mp_meta.mm_mapsize > MAX_MAPSIZE) {
|
|
||||||
mdbx_notice("meta[%u] has invalid mapsize %" PRIu64 ", skip it",
|
|
||||||
meta_number, page.mp_meta.mm_mapsize);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LY: check signature as a checksum */
|
/* LY: check signature as a checksum */
|
||||||
if (META_IS_STEADY(&page.mp_meta) &&
|
if (META_IS_STEADY(&page.mp_meta) &&
|
||||||
page.mp_meta.mm_datasync_sign != mdbx_meta_sign(&page.mp_meta)) {
|
page.mp_meta.mm_datasync_sign != mdbx_meta_sign(&page.mp_meta)) {
|
||||||
@ -3481,6 +3465,33 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* LY: check pagesize */
|
||||||
|
if (!is_power2(page.mp_meta.mm_psize) ||
|
||||||
|
page.mp_meta.mm_psize < MIN_PAGESIZE ||
|
||||||
|
page.mp_meta.mm_psize > MAX_PAGESIZE) {
|
||||||
|
mdbx_notice("meta[%u] has invalid pagesize %u, skip it", meta_number,
|
||||||
|
page.mp_meta.mm_psize);
|
||||||
|
rc = MDBX_VERSION_MISMATCH;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LY: check mapsize limits */
|
||||||
|
STATIC_ASSERT(MAX_MAPSIZE < SSIZE_MAX - MAX_PAGESIZE);
|
||||||
|
if (page.mp_meta.mm_mapsize < MIN_MAPSIZE) {
|
||||||
|
mdbx_notice("meta[%u] has invalid mapsize %" PRIu64 ", skip it",
|
||||||
|
meta_number, page.mp_meta.mm_mapsize);
|
||||||
|
rc = MDBX_VERSION_MISMATCH;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_ASSERT(MIN_MAPSIZE < MAX_MAPSIZE);
|
||||||
|
if (page.mp_meta.mm_mapsize > MAX_MAPSIZE) {
|
||||||
|
mdbx_notice("meta[%u] has too large mapsize %" PRIu64 ", skip it",
|
||||||
|
meta_number, page.mp_meta.mm_mapsize);
|
||||||
|
rc = MDBX_TOO_LARGE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* LY: check mapsize with given given pagesize */
|
/* LY: check mapsize with given given pagesize */
|
||||||
if (page.mp_meta.mm_mapsize <
|
if (page.mp_meta.mm_mapsize <
|
||||||
MIN_PAGENO * (uint64_t)page.mp_meta.mm_psize ||
|
MIN_PAGENO * (uint64_t)page.mp_meta.mm_psize ||
|
||||||
@ -3489,6 +3500,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
mdbx_notice("meta[%u] has invalid mapsize %" PRIu64
|
mdbx_notice("meta[%u] has invalid mapsize %" PRIu64
|
||||||
", with given pagesize %u, skip it",
|
", with given pagesize %u, skip it",
|
||||||
meta_number, page.mp_meta.mm_mapsize, page.mp_meta.mm_psize);
|
meta_number, page.mp_meta.mm_mapsize, page.mp_meta.mm_psize);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3499,6 +3511,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
page.mp_meta.mm_mapsize / page.mp_meta.mm_psize) {
|
page.mp_meta.mm_mapsize / page.mp_meta.mm_psize) {
|
||||||
mdbx_notice("meta[%u] has invalid last-pageno %" PRIaPGNO ", skip it",
|
mdbx_notice("meta[%u] has invalid last-pageno %" PRIaPGNO ", skip it",
|
||||||
meta_number, page.mp_meta.mm_last_pg);
|
meta_number, page.mp_meta.mm_last_pg);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3510,12 +3523,14 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
page.mp_meta.mm_dbs[FREE_DBI].md_leaf_pages ||
|
page.mp_meta.mm_dbs[FREE_DBI].md_leaf_pages ||
|
||||||
page.mp_meta.mm_dbs[FREE_DBI].md_overflow_pages) {
|
page.mp_meta.mm_dbs[FREE_DBI].md_overflow_pages) {
|
||||||
mdbx_notice("meta[%u] has false-empty freedb, skip it", meta_number);
|
mdbx_notice("meta[%u] has false-empty freedb, skip it", meta_number);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (page.mp_meta.mm_dbs[FREE_DBI].md_root >
|
} else if (page.mp_meta.mm_dbs[FREE_DBI].md_root >
|
||||||
page.mp_meta.mm_last_pg) {
|
page.mp_meta.mm_last_pg) {
|
||||||
mdbx_notice("meta[%u] has invalid freedb-root %" PRIaPGNO ", skip it",
|
mdbx_notice("meta[%u] has invalid freedb-root %" PRIaPGNO ", skip it",
|
||||||
meta_number, page.mp_meta.mm_dbs[FREE_DBI].md_root);
|
meta_number, page.mp_meta.mm_dbs[FREE_DBI].md_root);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3527,12 +3542,14 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
page.mp_meta.mm_dbs[MAIN_DBI].md_leaf_pages ||
|
page.mp_meta.mm_dbs[MAIN_DBI].md_leaf_pages ||
|
||||||
page.mp_meta.mm_dbs[MAIN_DBI].md_overflow_pages) {
|
page.mp_meta.mm_dbs[MAIN_DBI].md_overflow_pages) {
|
||||||
mdbx_notice("meta[%u] has false-empty maindb", meta_number);
|
mdbx_notice("meta[%u] has false-empty maindb", meta_number);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (page.mp_meta.mm_dbs[MAIN_DBI].md_root >
|
} else if (page.mp_meta.mm_dbs[MAIN_DBI].md_root >
|
||||||
page.mp_meta.mm_last_pg) {
|
page.mp_meta.mm_last_pg) {
|
||||||
mdbx_notice("meta[%u] has invalid maindb-root %" PRIaPGNO ", skip it",
|
mdbx_notice("meta[%u] has invalid maindb-root %" PRIaPGNO ", skip it",
|
||||||
meta_number, page.mp_meta.mm_dbs[MAIN_DBI].md_root);
|
meta_number, page.mp_meta.mm_dbs[MAIN_DBI].md_root);
|
||||||
|
rc = MDBX_CORRUPTED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3545,7 +3562,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
|||||||
|
|
||||||
if (META_IS_WEAK(meta)) {
|
if (META_IS_WEAK(meta)) {
|
||||||
mdbx_error("no usable meta-pages, database is corrupted");
|
mdbx_error("no usable meta-pages, database is corrupted");
|
||||||
return MDBX_CORRUPTED;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MDBX_SUCCESS;
|
return MDBX_SUCCESS;
|
||||||
@ -3963,6 +3980,9 @@ int __cold mdbx_env_set_mapsize(MDBX_env *env, size_t size) {
|
|||||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||||
return MDBX_EBADSIGN;
|
return MDBX_EBADSIGN;
|
||||||
|
|
||||||
|
if (unlikely(size < MIN_MAPSIZE || size > MAX_MAPSIZE))
|
||||||
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
if (unlikely(size < pgno2bytes(env, MIN_PAGENO)))
|
if (unlikely(size < pgno2bytes(env, MIN_PAGENO)))
|
||||||
return MDBX_EINVAL;
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
@ -3976,8 +3996,6 @@ int __cold mdbx_env_set_mapsize(MDBX_env *env, size_t size) {
|
|||||||
|
|
||||||
/* FIXME: lock/unlock */
|
/* FIXME: lock/unlock */
|
||||||
meta = mdbx_meta_head(env);
|
meta = mdbx_meta_head(env);
|
||||||
if (!size)
|
|
||||||
size = meta->mm_mapsize;
|
|
||||||
/* Silently round up to minimum if the size is too small */
|
/* Silently round up to minimum if the size is too small */
|
||||||
const size_t usedsize = pgno2bytes(env, meta->mm_last_pg + 1);
|
const size_t usedsize = pgno2bytes(env, meta->mm_last_pg + 1);
|
||||||
if (size < usedsize)
|
if (size < usedsize)
|
||||||
@ -4104,7 +4122,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
|||||||
/* Was a mapsize configured? */
|
/* Was a mapsize configured? */
|
||||||
if (!env->me_mapsize || (env->me_flags & MDBX_RDONLY) ||
|
if (!env->me_mapsize || (env->me_flags & MDBX_RDONLY) ||
|
||||||
lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE)
|
lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE)
|
||||||
env->me_mapsize = meta.mm_mapsize;
|
env->me_mapsize = (size_t)meta.mm_mapsize;
|
||||||
else if (env->me_mapsize < usedsize)
|
else if (env->me_mapsize < usedsize)
|
||||||
env->me_mapsize = usedsize;
|
env->me_mapsize = usedsize;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user