mirror of
				https://github.com/isar/libmdbx.git
				synced 2025-10-31 03:29:01 +08:00 
			
		
		
		
	mdbx: добавление MDBX_opt_gc_time_limit.
This commit is contained in:
		
							
								
								
									
										28
									
								
								mdbx.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								mdbx.h
									
									
									
									
									
								
							| @@ -2133,6 +2133,7 @@ enum MDBX_option_t { | ||||
|   /** \brief Controls the in-process limit to grow a list of reclaimed/recycled | ||||
|    * page's numbers for finding a sequence of contiguous pages for large data | ||||
|    * items. | ||||
|    * \see MDBX_opt_gc_time_limit | ||||
|    * | ||||
|    * \details A long values requires allocation of contiguous database pages. | ||||
|    * To find such sequences, it may be necessary to accumulate very large lists, | ||||
| @@ -2293,6 +2294,33 @@ enum MDBX_option_t { | ||||
|    * in the \ref MDBX_WRITEMAP mode by clearing ones through file handle before | ||||
|    * touching. */ | ||||
|   MDBX_opt_prefault_write_enable, | ||||
|  | ||||
|   /** \brief Controls the in-process spending time limit of searching | ||||
|    *  consecutive pages inside GC. | ||||
|    * \see MDBX_opt_rp_augment_limit | ||||
|    * | ||||
|    * \details Задаёт ограничение времени в 1/65536 долях секунды, которое может | ||||
|    * быть потрачено в ходе пишущей транзакции на поиск последовательностей | ||||
|    * страниц внутри GC/freelist после достижения ограничения задаваемого опцией | ||||
|    * \ref MDBX_opt_rp_augment_limit. Контроль по времени не выполняется при | ||||
|    * поиске/выделении одиночных страниц и выделении страниц под нужды GC (при | ||||
|    * обновлении GC в ходе фиксации транзакции). | ||||
|    * | ||||
|    * Задаваемый лимит времени исчисляется по "настенным часам" и контролируется | ||||
|    * в рамках транзакции, наследуется для вложенных транзакций и с | ||||
|    * аккумулированием в родительской при их фиксации. Контроль по времени | ||||
|    * производится только при достижении ограничения задаваемого опцией \ref | ||||
|    * MDBX_opt_rp_augment_limit. Это позволяет гибко управлять поведением | ||||
|    * используя обе опции. | ||||
|    * | ||||
|    * По умолчанию ограничение устанавливается в 0, что приводит к | ||||
|    * незамедлительной остановке поиска в GC при достижении \ref | ||||
|    * MDBX_opt_rp_augment_limit во внутреннем состоянии транзакции и | ||||
|    * соответствует поведению до появления опции `MDBX_opt_gc_time_limit`. | ||||
|    * С другой стороны, при минимальном значении (включая 0) | ||||
|    * `MDBX_opt_rp_augment_limit` переработка GC будет ограничиваться | ||||
|    * преимущественно затраченным временем. */ | ||||
|   MDBX_opt_gc_time_limit | ||||
| }; | ||||
| #ifndef __cplusplus | ||||
| /** \ingroup c_settings */ | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/core.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								src/core.c
									
									
									
									
									
								
							| @@ -7674,12 +7674,24 @@ bailout: | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| struct monotime_cache { | ||||
|   uint64_t value; | ||||
|   int expire_countdown; | ||||
| }; | ||||
| 
 | ||||
| static __inline uint64_t monotime_since_cached(uint64_t begin_timestamp, | ||||
|                                                struct monotime_cache *cache) { | ||||
|   if (cache->expire_countdown) | ||||
|     cache->expire_countdown -= 1; | ||||
|   else { | ||||
|     cache->value = osal_monotime(); | ||||
|     cache->expire_countdown = 42 / 3; | ||||
|   } | ||||
|   return cache->value - begin_timestamp; | ||||
| } | ||||
| 
 | ||||
| static pgr_t page_alloc_slowpath(const MDBX_cursor *const mc, const size_t num, | ||||
|                                  uint8_t flags) { | ||||
| #if MDBX_ENABLE_PROFGC | ||||
|   const uint64_t monotime_before = osal_monotime(); | ||||
| #endif /* MDBX_ENABLE_PROFGC */ | ||||
| 
 | ||||
|   pgr_t ret; | ||||
|   MDBX_txn *const txn = mc->mc_txn; | ||||
|   MDBX_env *const env = txn->mt_env; | ||||
| @@ -7694,8 +7706,19 @@ static pgr_t page_alloc_slowpath(const MDBX_cursor *const mc, const size_t num, | ||||
|   eASSERT(env, pnl_check_allocated(txn->tw.relist, | ||||
|                                    txn->mt_next_pgno - MDBX_ENABLE_REFUND)); | ||||
| 
 | ||||
|   pgno_t pgno = 0; | ||||
|   size_t newnext; | ||||
|   const uint64_t monotime_begin = | ||||
|       (MDBX_ENABLE_PROFGC || (num > 1 && env->me_options.gc_time_limit)) | ||||
|           ? osal_monotime() | ||||
|           : 0; | ||||
|   struct monotime_cache now_cache; | ||||
|   now_cache.expire_countdown = | ||||
|       1 /* старт с 1 позволяет избавиться как от лишних системных вызовов когда
 | ||||
|            лимит времени задан нулевой или уже исчерпан, так и от подсчета | ||||
|            времени при не-достижении rp_augment_limit */ | ||||
|       ; | ||||
|   now_cache.value = monotime_begin; | ||||
|   pgno_t pgno = 0; | ||||
|   if (num > 1) { | ||||
| #if MDBX_ENABLE_PROFGC | ||||
|     prof->xpages += 1; | ||||
| @@ -7871,7 +7894,10 @@ next_gc:; | ||||
|                      txn->tw.relist) >= env->me_options.rp_augment_limit) && | ||||
|         ((/* not a slot-request from gc-update */ num && | ||||
|           /* have enough unallocated space */ txn->mt_geo.upper >= | ||||
|               txn->mt_next_pgno + num) || | ||||
|               txn->mt_next_pgno + num && | ||||
|           monotime_since_cached(monotime_begin, &now_cache) + | ||||
|                   txn->tw.gc_time_acc >= | ||||
|               env->me_options.gc_time_limit) || | ||||
|          gc_len + MDBX_PNL_GETSIZE(txn->tw.relist) >= MDBX_PGL_LIMIT)) { | ||||
|       /* Stop reclaiming to avoid large/overflow the page list. This is a rare
 | ||||
|        * case while search for a continuously multi-page region in a | ||||
| @@ -8173,6 +8199,8 @@ done: | ||||
|                   (size_t)txn->mt_dbs[FREE_DBI].md_entries); | ||||
|       ret.page = NULL; | ||||
|     } | ||||
|     if (num > 1) | ||||
|       txn->tw.gc_time_acc += monotime_since_cached(monotime_begin, &now_cache); | ||||
|   } else { | ||||
|   early_exit: | ||||
|     DEBUG("return NULL for %zu pages for ALLOC_%s, rc %d", num, | ||||
| @@ -8181,7 +8209,7 @@ done: | ||||
|   } | ||||
| 
 | ||||
| #if MDBX_ENABLE_PROFGC | ||||
|   prof->rtime_monotonic += osal_monotime() - monotime_before; | ||||
|   prof->rtime_monotonic += osal_monotime() - monotime_begin; | ||||
| #endif /* MDBX_ENABLE_PROFGC */ | ||||
|   return ret; | ||||
| } | ||||
| @@ -9352,6 +9380,7 @@ static int txn_renew(MDBX_txn *txn, const unsigned flags) { | ||||
|     MDBX_PNL_SETSIZE(txn->tw.retired_pages, 0); | ||||
|     txn->tw.spilled.list = NULL; | ||||
|     txn->tw.spilled.least_removed = 0; | ||||
|     txn->tw.gc_time_acc = 0; | ||||
|     txn->tw.last_reclaimed = 0; | ||||
|     if (txn->tw.lifo_reclaimed) | ||||
|       MDBX_PNL_SETSIZE(txn->tw.lifo_reclaimed, 0); | ||||
| @@ -9800,6 +9829,7 @@ int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, | ||||
|                       = parent->mt_next_pgno) - | ||||
|                          MDBX_ENABLE_REFUND)); | ||||
| 
 | ||||
|     txn->tw.gc_time_acc = parent->tw.gc_time_acc; | ||||
|     txn->tw.last_reclaimed = parent->tw.last_reclaimed; | ||||
|     if (parent->tw.lifo_reclaimed) { | ||||
|       txn->tw.lifo_reclaimed = parent->tw.lifo_reclaimed; | ||||
| @@ -12037,6 +12067,7 @@ int mdbx_txn_commit_ex(MDBX_txn *txn, MDBX_commit_latency *latency) { | ||||
|     pnl_free(parent->tw.relist); | ||||
|     parent->tw.relist = txn->tw.relist; | ||||
|     txn->tw.relist = NULL; | ||||
|     parent->tw.gc_time_acc = txn->tw.gc_time_acc; | ||||
|     parent->tw.last_reclaimed = txn->tw.last_reclaimed; | ||||
| 
 | ||||
|     parent->mt_geo = txn->mt_geo; | ||||
| @@ -25875,6 +25906,21 @@ __cold int mdbx_env_set_option(MDBX_env *env, const MDBX_option_t option, | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|   case MDBX_opt_gc_time_limit: | ||||
|     if (value == /* default */ UINT64_MAX) | ||||
|       value = 0; | ||||
|     if (unlikely(value > UINT32_MAX)) | ||||
|       return MDBX_EINVAL; | ||||
|     if (unlikely(env->me_flags & MDBX_RDONLY)) | ||||
|       return MDBX_EACCESS; | ||||
|     value = osal_16dot16_to_monotime((uint32_t)value); | ||||
|     if (value != env->me_options.gc_time_limit) { | ||||
|       if (env->me_txn && env->me_txn0->mt_owner != osal_thread_self()) | ||||
|         return MDBX_EPERM; | ||||
|       env->me_options.gc_time_limit = value; | ||||
|     } | ||||
|     break; | ||||
| 
 | ||||
|   case MDBX_opt_txn_dp_limit: | ||||
|   case MDBX_opt_txn_dp_initial: | ||||
|     if (value == /* default */ UINT64_MAX) | ||||
| @@ -26027,6 +26073,10 @@ __cold int mdbx_env_get_option(const MDBX_env *env, const MDBX_option_t option, | ||||
|     *pvalue = env->me_options.rp_augment_limit; | ||||
|     break; | ||||
| 
 | ||||
|   case MDBX_opt_gc_time_limit: | ||||
|     *pvalue = osal_monotime_to_16dot16(env->me_options.gc_time_limit); | ||||
|     break; | ||||
| 
 | ||||
|   case MDBX_opt_txn_dp_limit: | ||||
|     *pvalue = env->me_options.dp_limit; | ||||
|     break; | ||||
|   | ||||
| @@ -1260,6 +1260,7 @@ struct MDBX_txn { | ||||
|         size_t writemap_dirty_npages; | ||||
|         size_t writemap_spilled_npages; | ||||
|       }; | ||||
|       uint64_t gc_time_acc; | ||||
|     } tw; | ||||
|   }; | ||||
| }; | ||||
| @@ -1422,6 +1423,7 @@ struct MDBX_env { | ||||
|     unsigned rp_augment_limit; | ||||
|     unsigned dp_limit; | ||||
|     unsigned dp_initial; | ||||
|     uint64_t gc_time_limit; | ||||
|     uint8_t dp_loose_limit; | ||||
|     uint8_t spill_max_denominator; | ||||
|     uint8_t spill_min_denominator; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user