mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-29 23:19:20 +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. */
|
||||
#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 */
|
||||
typedef struct MDBX_stat {
|
||||
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:
|
||||
return "MDBX_EKEYMISMATCH: The given key value is mismatched to the "
|
||||
"current cursor position";
|
||||
case MDBX_TOO_LARGE:
|
||||
return "Database is too large for current system, i.e.could NOT be mapped "
|
||||
"into RAM.";
|
||||
default:
|
||||
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);
|
||||
memset(meta, 0, sizeof(MDBX_meta));
|
||||
meta->mm_datasync_sign = MDBX_DATASIGN_WEAK;
|
||||
int rc = MDBX_CORRUPTED;
|
||||
|
||||
/* Read twice all meta pages so we can find the latest one. */
|
||||
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;
|
||||
while (1) {
|
||||
int rc = mdbx_pread(env->me_fd, &page, sizeof(page), offset);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
int err = mdbx_pread(env->me_fd, &page, sizeof(page), offset);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(page),
|
||||
rc, mdbx_strerror(rc));
|
||||
return rc;
|
||||
err, mdbx_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
MDBX_page again;
|
||||
rc = mdbx_pread(env->me_fd, &again, sizeof(again), offset);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
err = mdbx_pread(env->me_fd, &again, sizeof(again), offset);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
mdbx_error("read meta[%u,%u]: %i, %s", offset, (unsigned)sizeof(again),
|
||||
rc, mdbx_strerror(rc));
|
||||
return rc;
|
||||
err, mdbx_strerror(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (META_IS_STEADY(&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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (page.mp_meta.mm_mapsize <
|
||||
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
|
||||
", with given pagesize %u, skip it",
|
||||
meta_number, page.mp_meta.mm_mapsize, page.mp_meta.mm_psize);
|
||||
rc = MDBX_CORRUPTED;
|
||||
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) {
|
||||
mdbx_notice("meta[%u] has invalid last-pageno %" PRIaPGNO ", skip it",
|
||||
meta_number, page.mp_meta.mm_last_pg);
|
||||
rc = MDBX_CORRUPTED;
|
||||
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_overflow_pages) {
|
||||
mdbx_notice("meta[%u] has false-empty freedb, skip it", meta_number);
|
||||
rc = MDBX_CORRUPTED;
|
||||
continue;
|
||||
}
|
||||
} else if (page.mp_meta.mm_dbs[FREE_DBI].md_root >
|
||||
page.mp_meta.mm_last_pg) {
|
||||
mdbx_notice("meta[%u] has invalid freedb-root %" PRIaPGNO ", skip it",
|
||||
meta_number, page.mp_meta.mm_dbs[FREE_DBI].md_root);
|
||||
rc = MDBX_CORRUPTED;
|
||||
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_overflow_pages) {
|
||||
mdbx_notice("meta[%u] has false-empty maindb", meta_number);
|
||||
rc = MDBX_CORRUPTED;
|
||||
continue;
|
||||
}
|
||||
} else if (page.mp_meta.mm_dbs[MAIN_DBI].md_root >
|
||||
page.mp_meta.mm_last_pg) {
|
||||
mdbx_notice("meta[%u] has invalid maindb-root %" PRIaPGNO ", skip it",
|
||||
meta_number, page.mp_meta.mm_dbs[MAIN_DBI].md_root);
|
||||
rc = MDBX_CORRUPTED;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3545,7 +3562,7 @@ static int __cold mdbx_read_header(MDBX_env *env, MDBX_meta *meta) {
|
||||
|
||||
if (META_IS_WEAK(meta)) {
|
||||
mdbx_error("no usable meta-pages, database is corrupted");
|
||||
return MDBX_CORRUPTED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
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))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
if (unlikely(size < MIN_MAPSIZE || size > MAX_MAPSIZE))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(size < pgno2bytes(env, MIN_PAGENO)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
@ -3976,8 +3996,6 @@ int __cold mdbx_env_set_mapsize(MDBX_env *env, size_t size) {
|
||||
|
||||
/* FIXME: lock/unlock */
|
||||
meta = mdbx_meta_head(env);
|
||||
if (!size)
|
||||
size = meta->mm_mapsize;
|
||||
/* Silently round up to minimum if the size is too small */
|
||||
const size_t usedsize = pgno2bytes(env, meta->mm_last_pg + 1);
|
||||
if (size < usedsize)
|
||||
@ -4104,7 +4122,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, int lck_rc) {
|
||||
/* Was a mapsize configured? */
|
||||
if (!env->me_mapsize || (env->me_flags & MDBX_RDONLY) ||
|
||||
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)
|
||||
env->me_mapsize = usedsize;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user