mirror of
				https://github.com/isar/libmdbx.git
				synced 2025-10-31 15:38:57 +08:00 
			
		
		
		
	mdbx: оптимизация page_copy() для LEAF2 и добавление параноидального контроля от переполнения.
				
					
				
			This commit is contained in:
		
							
								
								
									
										45
									
								
								src/core.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								src/core.c
									
									
									
									
									
								
							| @@ -752,7 +752,7 @@ __cold static const char *pagetype_caption(const uint8_t type, | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| __cold static __must_check_result int MDBX_PRINTF_ARGS(2, 3) | __cold static int MDBX_PRINTF_ARGS(2, 3) | ||||||
|     bad_page(const MDBX_page *mp, const char *fmt, ...) { |     bad_page(const MDBX_page *mp, const char *fmt, ...) { | ||||||
|   if (LOG_ENABLED(MDBX_LOG_ERROR)) { |   if (LOG_ENABLED(MDBX_LOG_ERROR)) { | ||||||
|     static const MDBX_page *prev; |     static const MDBX_page *prev; | ||||||
| @@ -7232,26 +7232,47 @@ __hot static pgr_t page_alloc(const MDBX_cursor *mc) { | |||||||
|   return page_alloc_slowpath(mc, 1, MDBX_ALLOC_ALL); |   return page_alloc_slowpath(mc, 1, MDBX_ALLOC_ALL); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Copy the used portions of a non-large/overflow page. */ | /* Copy the used portions of a page. */ | ||||||
| __hot static void page_copy(MDBX_page *dst, const MDBX_page *src, | __hot static void page_copy(MDBX_page *const dst, const MDBX_page *const src, | ||||||
|                             size_t psize) { |                             const size_t size) { | ||||||
|   STATIC_ASSERT(UINT16_MAX > MAX_PAGESIZE - PAGEHDRSZ); |   STATIC_ASSERT(UINT16_MAX > MAX_PAGESIZE - PAGEHDRSZ); | ||||||
|   STATIC_ASSERT(MIN_PAGESIZE > PAGEHDRSZ + NODESIZE * 4); |   STATIC_ASSERT(MIN_PAGESIZE > PAGEHDRSZ + NODESIZE * 4); | ||||||
|  |   char *copy_dst = (void *)dst; | ||||||
|  |   const char *copy_src = (const void *)src; | ||||||
|  |   size_t copy_len = size; | ||||||
|  |   if (src->mp_flags & P_LEAF2) { | ||||||
|  |     copy_len = PAGEHDRSZ + src->mp_leaf2_ksize * page_numkeys(src); | ||||||
|  |     if (unlikely(copy_len > size)) | ||||||
|  |       goto bailout; | ||||||
|  |   } | ||||||
|   if ((src->mp_flags & (P_LEAF2 | P_OVERFLOW)) == 0) { |   if ((src->mp_flags & (P_LEAF2 | P_OVERFLOW)) == 0) { | ||||||
|     size_t upper = src->mp_upper, lower = src->mp_lower, unused = upper - lower; |     size_t upper = src->mp_upper, lower = src->mp_lower; | ||||||
|  |     intptr_t unused = upper - lower; | ||||||
|     /* If page isn't full, just copy the used portion. Adjust |     /* If page isn't full, just copy the used portion. Adjust | ||||||
|      * alignment so memcpy may copy words instead of bytes. */ |      * alignment so memcpy may copy words instead of bytes. */ | ||||||
|     if (unused >= MDBX_CACHELINE_SIZE * 2) { |     if (unused > MDBX_CACHELINE_SIZE * 3) { | ||||||
|       lower = ceil_powerof2(lower + PAGEHDRSZ, sizeof(void *)); |       lower = ceil_powerof2(lower + PAGEHDRSZ, sizeof(void *)); | ||||||
|       upper = floor_powerof2(upper + PAGEHDRSZ, sizeof(void *)); |       upper = floor_powerof2(upper + PAGEHDRSZ, sizeof(void *)); | ||||||
|       memcpy(dst, src, lower); |       if (unlikely(upper > copy_len)) | ||||||
|       dst = (void *)((char *)dst + upper); |         goto bailout; | ||||||
|       src = (void *)((char *)src + upper); |       memcpy(copy_dst, copy_src, lower); | ||||||
|       psize -= upper; |       copy_dst += upper; | ||||||
|  |       copy_src += upper; | ||||||
|  |       copy_len -= upper; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   memcpy(dst, src, psize); |   memcpy(copy_dst, copy_src, copy_len); | ||||||
|  |   return; | ||||||
|  |  | ||||||
|  | bailout: | ||||||
|  |   if (src->mp_flags & P_LEAF2) | ||||||
|  |     bad_page(src, "%s addr %p, n-keys %zu, ksize %u", | ||||||
|  |              "invalid/corrupted source page", __Wpedantic_format_voidptr(src), | ||||||
|  |              page_numkeys(src), src->mp_leaf2_ksize); | ||||||
|  |   else | ||||||
|  |     bad_page(src, "%s addr %p, upper %u", "invalid/corrupted source page", | ||||||
|  |              __Wpedantic_format_voidptr(src), src->mp_upper); | ||||||
|  |   memset(dst, -1, size); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Pull a page off the txn's spill list, if present. | /* Pull a page off the txn's spill list, if present. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user