mirror of
				https://github.com/isar/libmdbx.git
				synced 2025-10-31 15:38:57 +08:00 
			
		
		
		
	mdbx: fix/refine mdbx_setup_dxb() for case open existing DB with new geo-params.
Change-Id: Iebb9b19c8f81d8629c4b28ed547d27f1a139dc7f
This commit is contained in:
		| @@ -7792,10 +7792,10 @@ int __cold mdbx_env_get_maxreaders(MDBX_env *env, unsigned *readers) { | |||||||
|  |  | ||||||
| /* Further setup required for opening an MDBX environment */ | /* Further setup required for opening an MDBX environment */ | ||||||
| static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | ||||||
|   uint64_t filesize_before_mmap; |   uint64_t filesize_before; | ||||||
|   MDBX_meta meta; |   MDBX_meta meta; | ||||||
|   int rc = MDBX_RESULT_FALSE; |   int rc = MDBX_RESULT_FALSE; | ||||||
|   int err = mdbx_read_header(env, &meta, &filesize_before_mmap); |   int err = mdbx_read_header(env, &meta, &filesize_before); | ||||||
|   if (unlikely(err != MDBX_SUCCESS)) { |   if (unlikely(err != MDBX_SUCCESS)) { | ||||||
|     if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE || err != MDBX_ENODATA || |     if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE || err != MDBX_ENODATA || | ||||||
|         (env->me_flags & MDBX_RDONLY) != 0) |         (env->me_flags & MDBX_RDONLY) != 0) | ||||||
| @@ -7821,12 +7821,12 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|     if (unlikely(err != MDBX_SUCCESS)) |     if (unlikely(err != MDBX_SUCCESS)) | ||||||
|       return err; |       return err; | ||||||
|  |  | ||||||
|     err = mdbx_ftruncate(env->me_fd, filesize_before_mmap = env->me_dbgeo.now); |     err = mdbx_ftruncate(env->me_fd, filesize_before = env->me_dbgeo.now); | ||||||
|     if (unlikely(err != MDBX_SUCCESS)) |     if (unlikely(err != MDBX_SUCCESS)) | ||||||
|       return err; |       return err; | ||||||
|  |  | ||||||
| #ifndef NDEBUG /* just for checking */ | #ifndef NDEBUG /* just for checking */ | ||||||
|     err = mdbx_read_header(env, &meta, &filesize_before_mmap); |     err = mdbx_read_header(env, &meta, &filesize_before); | ||||||
|     if (unlikely(err != MDBX_SUCCESS)) |     if (unlikely(err != MDBX_SUCCESS)) | ||||||
|       return err; |       return err; | ||||||
| #endif | #endif | ||||||
| @@ -7842,38 +7842,39 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|  |  | ||||||
|   mdbx_setup_pagesize(env, meta.mm_psize); |   mdbx_setup_pagesize(env, meta.mm_psize); | ||||||
|   const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); |   const size_t used_bytes = pgno2bytes(env, meta.mm_geo.next); | ||||||
|  |   const size_t used_aligned2os_bytes = | ||||||
|  |       roundup_powerof2(used_bytes, env->me_os_psize); | ||||||
|   if ((env->me_flags & MDBX_RDONLY) /* readonly */ |   if ((env->me_flags & MDBX_RDONLY) /* readonly */ | ||||||
|       || lck_rc != MDBX_RESULT_TRUE /* not exclusive */) { |       || lck_rc != MDBX_RESULT_TRUE /* not exclusive */) { | ||||||
|     /* use present params from db */ |     /* use present params from db */ | ||||||
|  |     const size_t pagesize = meta.mm_psize; | ||||||
|     err = mdbx_env_set_geometry( |     err = mdbx_env_set_geometry( | ||||||
|         env, meta.mm_geo.lower * (uint64_t)meta.mm_psize, |         env, meta.mm_geo.lower * pagesize, meta.mm_geo.now * pagesize, | ||||||
|         meta.mm_geo.now * (uint64_t)meta.mm_psize, |         meta.mm_geo.upper * pagesize, meta.mm_geo.grow * pagesize, | ||||||
|         meta.mm_geo.upper * (uint64_t)meta.mm_psize, |         meta.mm_geo.shrink * pagesize, meta.mm_psize); | ||||||
|         meta.mm_geo.grow * (uint64_t)meta.mm_psize, |  | ||||||
|         meta.mm_geo.shrink * (uint64_t)meta.mm_psize, meta.mm_psize); |  | ||||||
|     if (unlikely(err != MDBX_SUCCESS)) { |     if (unlikely(err != MDBX_SUCCESS)) { | ||||||
|       mdbx_error("%s", "could not use present dbsize-params from db"); |       mdbx_error("%s", "could not use present dbsize-params from db"); | ||||||
|       return MDBX_INCOMPATIBLE; |       return MDBX_INCOMPATIBLE; | ||||||
|     } |     } | ||||||
|   } else if (env->me_dbgeo.now) { |   } else if (env->me_dbgeo.now) { | ||||||
|     /* silently growth to last used page */ |     /* silently growth to last used page */ | ||||||
|     if (env->me_dbgeo.now < used_bytes) |     if (env->me_dbgeo.now < used_aligned2os_bytes) | ||||||
|       env->me_dbgeo.now = used_bytes; |       env->me_dbgeo.now = used_aligned2os_bytes; | ||||||
|     if (env->me_dbgeo.upper < used_bytes) |     if (env->me_dbgeo.upper < used_aligned2os_bytes) | ||||||
|       env->me_dbgeo.upper = used_bytes; |       env->me_dbgeo.upper = used_aligned2os_bytes; | ||||||
|  |  | ||||||
|     /* apply preconfigured params, but only if substantial changes: |     /* apply preconfigured params, but only if substantial changes: | ||||||
|      *  - upper or lower limit changes |      *  - upper or lower limit changes | ||||||
|      *  - shrink threshold or growth step |      *  - shrink threshold or growth step | ||||||
|      * But ignore change just a 'now/current' size. */ |      * But ignore change just a 'now/current' size. */ | ||||||
|     if (bytes_align2os_bytes(env, env->me_dbgeo.upper) != |     if (bytes_align2os_bytes(env, env->me_dbgeo.upper) != | ||||||
|             pgno_align2os_bytes(env, meta.mm_geo.upper) || |             pgno2bytes(env, meta.mm_geo.upper) || | ||||||
|         bytes_align2os_bytes(env, env->me_dbgeo.lower) != |         bytes_align2os_bytes(env, env->me_dbgeo.lower) != | ||||||
|             pgno_align2os_bytes(env, meta.mm_geo.lower) || |             pgno2bytes(env, meta.mm_geo.lower) || | ||||||
|         bytes_align2os_bytes(env, env->me_dbgeo.shrink) != |         bytes_align2os_bytes(env, env->me_dbgeo.shrink) != | ||||||
|             pgno_align2os_bytes(env, meta.mm_geo.shrink) || |             pgno2bytes(env, meta.mm_geo.shrink) || | ||||||
|         bytes_align2os_bytes(env, env->me_dbgeo.grow) != |         bytes_align2os_bytes(env, env->me_dbgeo.grow) != | ||||||
|             pgno_align2os_bytes(env, meta.mm_geo.grow)) { |             pgno2bytes(env, meta.mm_geo.grow)) { | ||||||
|  |  | ||||||
|       if (env->me_dbgeo.shrink && env->me_dbgeo.now > used_bytes) |       if (env->me_dbgeo.shrink && env->me_dbgeo.now > used_bytes) | ||||||
|         /* pre-shrink if enabled */ |         /* pre-shrink if enabled */ | ||||||
| @@ -7902,11 +7903,15 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|                    meta.mm_geo.lower, meta.mm_geo.next, meta.mm_geo.now, |                    meta.mm_geo.lower, meta.mm_geo.next, meta.mm_geo.now, | ||||||
|                    meta.mm_geo.upper, meta.mm_geo.grow, meta.mm_geo.shrink, |                    meta.mm_geo.upper, meta.mm_geo.grow, meta.mm_geo.shrink, | ||||||
|                    meta.mm_txnid_a.inconsistent, mdbx_durable_str(&meta)); |                    meta.mm_txnid_a.inconsistent, mdbx_durable_str(&meta)); | ||||||
|  |     } else { | ||||||
|  |       /* fetch back 'now/current' size, since it was ignored during comparison | ||||||
|  |        * and may differ. */ | ||||||
|  |       env->me_dbgeo.now = pgno_align2os_bytes(env, meta.mm_geo.now); | ||||||
|     } |     } | ||||||
|     mdbx_ensure(env, meta.mm_geo.now >= meta.mm_geo.next); |     mdbx_ensure(env, meta.mm_geo.now >= meta.mm_geo.next); | ||||||
|   } else { |   } else { | ||||||
|     /* geo-params not pre-configured by user, |     /* geo-params are not pre-configured by user, | ||||||
|      * get current values from a meta. */ |      * get current values from the meta. */ | ||||||
|     env->me_dbgeo.now = pgno2bytes(env, meta.mm_geo.now); |     env->me_dbgeo.now = pgno2bytes(env, meta.mm_geo.now); | ||||||
|     env->me_dbgeo.lower = pgno2bytes(env, meta.mm_geo.lower); |     env->me_dbgeo.lower = pgno2bytes(env, meta.mm_geo.lower); | ||||||
|     env->me_dbgeo.upper = pgno2bytes(env, meta.mm_geo.upper); |     env->me_dbgeo.upper = pgno2bytes(env, meta.mm_geo.upper); | ||||||
| @@ -7914,48 +7919,38 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|     env->me_dbgeo.shrink = pgno2bytes(env, meta.mm_geo.shrink); |     env->me_dbgeo.shrink = pgno2bytes(env, meta.mm_geo.shrink); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   const size_t expected_bytes = pgno_align2os_bytes(env, meta.mm_geo.now); |   mdbx_ensure(env, | ||||||
|   mdbx_ensure(env, expected_bytes >= used_bytes); |               pgno_align2os_bytes(env, meta.mm_geo.now) == env->me_dbgeo.now); | ||||||
|   if (filesize_before_mmap != expected_bytes) { |   mdbx_ensure(env, env->me_dbgeo.now >= used_bytes); | ||||||
|  |   if (unlikely(filesize_before != env->me_dbgeo.now)) { | ||||||
|     if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { |     if (lck_rc != /* lck exclusive */ MDBX_RESULT_TRUE) { | ||||||
|       mdbx_verbose("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO |       mdbx_verbose("filesize mismatch (expect %" PRIuPTR "b/%" PRIaPGNO | ||||||
|                    "p, have %" PRIu64 "b/%" PRIaPGNO "p), " |                    "p, have %" PRIu64 "b/%" PRIaPGNO "p), " | ||||||
|                    "assume other process working", |                    "assume other process working", | ||||||
|                    expected_bytes, bytes2pgno(env, expected_bytes), |                    env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now), | ||||||
|                    filesize_before_mmap, |                    filesize_before, bytes2pgno(env, (size_t)filesize_before)); | ||||||
|                    bytes2pgno(env, (size_t)filesize_before_mmap)); |  | ||||||
|     } else { |     } else { | ||||||
|       mdbx_notice("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO |       mdbx_notice("filesize mismatch (expect %" PRIuSIZE "b/%" PRIaPGNO | ||||||
|                   "p, have %" PRIu64 "b/%" PRIaPGNO "p)", |                   "p, have %" PRIu64 "b/%" PRIaPGNO "p)", | ||||||
|                   expected_bytes, bytes2pgno(env, expected_bytes), |                   env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now), | ||||||
|                   filesize_before_mmap, |                   filesize_before, bytes2pgno(env, (size_t)filesize_before)); | ||||||
|                   bytes2pgno(env, (size_t)filesize_before_mmap)); |       if (filesize_before < 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, |                    meta.mm_geo.next, bytes2pgno(env, (size_t)filesize_before)); | ||||||
|                    bytes2pgno(env, (size_t)filesize_before_mmap)); |  | ||||||
|         return MDBX_CORRUPTED; |         return MDBX_CORRUPTED; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       if (env->me_flags & MDBX_RDONLY) { |       if (env->me_flags & MDBX_RDONLY) { | ||||||
|         if (filesize_before_mmap % env->me_os_psize) { |         if (filesize_before & (env->me_os_psize - 1)) { | ||||||
|           mdbx_error("%s", "filesize should be rounded-up to system page"); |           mdbx_error("%s", "filesize should be rounded-up to system page"); | ||||||
|           return MDBX_WANNA_RECOVERY; |           return MDBX_WANNA_RECOVERY; | ||||||
|         } |         } | ||||||
|         mdbx_warning("%s", "ignore filesize mismatch in readonly-mode"); |         mdbx_warning("%s", "ignore filesize mismatch in readonly-mode"); | ||||||
|       } else { |       } else { | ||||||
|         mdbx_verbose("resize datafile to %" PRIuSIZE " bytes, %" PRIaPGNO |         mdbx_verbose("will resize datafile to %" PRIuSIZE " bytes, %" PRIaPGNO | ||||||
|                      " pages", |                      " pages", | ||||||
|                      expected_bytes, bytes2pgno(env, expected_bytes)); |                      env->me_dbgeo.now, bytes2pgno(env, env->me_dbgeo.now)); | ||||||
|         err = mdbx_ftruncate(env->me_fd, expected_bytes); |  | ||||||
|         if (unlikely(err != MDBX_SUCCESS)) { |  | ||||||
|           mdbx_error("error %d, while resize datafile to %" PRIuSIZE |  | ||||||
|                      " bytes, %" PRIaPGNO " pages", |  | ||||||
|                      rc, expected_bytes, bytes2pgno(env, expected_bytes)); |  | ||||||
|           return err; |  | ||||||
|         } |  | ||||||
|         filesize_before_mmap = expected_bytes; |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -7973,8 +7968,6 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|                                                      : MADV_DONTDUMP); |                                                      : MADV_DONTDUMP); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   const size_t used_aligned2os_bytes = |  | ||||||
|       roundup_powerof2(used_bytes, env->me_os_psize); |  | ||||||
|   *env->me_discarded_tail = bytes2pgno(env, used_aligned2os_bytes); |   *env->me_discarded_tail = bytes2pgno(env, used_aligned2os_bytes); | ||||||
|   if (used_aligned2os_bytes < env->me_dxb_mmap.current) { |   if (used_aligned2os_bytes < env->me_dxb_mmap.current) { | ||||||
| #if defined(MADV_REMOVE) | #if defined(MADV_REMOVE) | ||||||
| @@ -8124,7 +8117,7 @@ static int __cold mdbx_setup_dxb(MDBX_env *env, const int lck_rc) { | |||||||
|                  env->me_dxb_mmap.current); |                  env->me_dxb_mmap.current); | ||||||
|       return MDBX_PROBLEM; |       return MDBX_PROBLEM; | ||||||
|     } |     } | ||||||
|     if (env->me_dxb_mmap.current != expected_bytes && |     if (env->me_dxb_mmap.current != env->me_dbgeo.now && | ||||||
|         (env->me_flags & MDBX_RDONLY) == 0) { |         (env->me_flags & MDBX_RDONLY) == 0) { | ||||||
|       meta.mm_geo.now = bytes2pgno(env, env->me_dxb_mmap.current); |       meta.mm_geo.now = bytes2pgno(env, env->me_dxb_mmap.current); | ||||||
|       mdbx_verbose("update meta-geo to filesize %" PRIuPTR " bytes, %" PRIaPGNO |       mdbx_verbose("update meta-geo to filesize %" PRIuPTR " bytes, %" PRIaPGNO | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user