@@ -70,6 +70,7 @@ typedef enum { DB_NO_OP, ONE_FILE, RELOAD_DB, FLUSH_CACHE, RELOAD_RULES } db_ops
7070#define TRUST_DB_RELOAD_HIGHWATER_PERCENT 85
7171#define TRUST_DB_SHRINK_TRIGGER_PERCENT 65
7272#define TRUST_DB_SHRINK_HYSTERESIS_PERCENT 75
73+ #define TRUST_DB_RELOAD_WORK_FACTOR 2
7374/*
7475 * The decision worker configuration is added later in the worker-pool
7576 * roadmap. Size LMDB readers now for that planned cap plus maintenance users
@@ -136,6 +137,7 @@ struct trust_db_sizing_state {
136137 size_t map_pages ;
137138 size_t active_pages ;
138139 size_t allocated_pages ;
140+ size_t reload_work_pages ;
139141 size_t active_target_pages ;
140142 size_t highwater_target_pages ;
141143 size_t recommended_pages ;
@@ -339,6 +341,20 @@ static size_t pages_for_percent(size_t pages, unsigned int percent)
339341 return ((pages * 100 ) + percent - 1 ) / percent ;
340342}
341343
344+ /*
345+ * pages_times - multiply page counts without wrapping.
346+ * @pages: base page count.
347+ * @factor: integer multiplier.
348+ *
349+ * Returns the product, or the largest size_t value if it would overflow.
350+ */
351+ static size_t pages_times (size_t pages , unsigned int factor )
352+ {
353+ if (factor != 0 && pages > ((size_t )-1 ) / factor )
354+ return (size_t )-1 ;
355+ return pages * factor ;
356+ }
357+
342358/*
343359 * percent_of - calculate an integer percentage.
344360 * @used: numerator value.
@@ -397,10 +413,33 @@ static unsigned int pages_to_mb(size_t pages, size_t page_size)
397413 */
398414static void complete_lmdb_sizing_state (struct trust_db_sizing_state * state )
399415{
416+ size_t reload_cap = pages_times (state -> active_pages ,
417+ TRUST_DB_RELOAD_WORK_FACTOR );
418+
419+ /*
420+ * me_last_pgno is LMDB's file high-water mark. It is useful for
421+ * seeing that reload churn has touched most of the map, but it is not
422+ * the same as live trust data. If auto sizing chases that monotonic
423+ * high-water mark directly, every drop/rebuild can make the next
424+ * target slightly larger even when the backend entry set is unchanged.
425+ *
426+ * Bound the reload target to a working set derived from the active DB:
427+ * one copy for the currently published trust set and one copy for a
428+ * rebuild when old pages cannot be reused immediately because LMDB
429+ * readers or freelist bookkeeping still reference them. This keeps
430+ * enough headroom for copy-on-write reloads without turning file
431+ * high-water growth into permanent map growth.
432+ */
433+ state -> reload_work_pages = state -> allocated_pages ;
434+ if (state -> reload_work_pages < state -> active_pages )
435+ state -> reload_work_pages = state -> active_pages ;
436+ if (reload_cap && state -> reload_work_pages > reload_cap )
437+ state -> reload_work_pages = reload_cap ;
438+
400439 state -> active_target_pages = pages_for_percent (state -> active_pages ,
401440 TRUST_DB_ACTIVE_TARGET_PERCENT );
402441 state -> highwater_target_pages =
403- pages_for_percent (state -> allocated_pages ,
442+ pages_for_percent (state -> reload_work_pages ,
404443 TRUST_DB_RELOAD_HIGHWATER_PERCENT );
405444 state -> recommended_pages = state -> active_target_pages ;
406445 if (state -> highwater_target_pages > state -> recommended_pages )
@@ -506,10 +545,10 @@ static int autosize_shrink_allowed(const conf_t *config,
506545 *
507546 * Auto sizing has two targets. The active-page target keeps the final trust
508547 * database near 75 percent utilization so normal package changes have room.
509- * The high-water target keeps LMDB allocated pages below 85 percent so a full
510- * drop/rebuild reload has room to commit metadata before old pages are
511- * reusable. Manual configurations are not changed here; callers should log
512- * the recommended size for administrators.
548+ * The reload target keeps a bounded copy-on-write working set below 85
549+ * percent so a full drop/rebuild reload has room to commit metadata before
550+ * old pages are reusable. Manual configurations are not changed here; callers
551+ * should log the recommended size for administrators.
513552 *
514553 * Returns 1 when config->db_max_size changed, 0 otherwise.
515554 */
@@ -530,11 +569,12 @@ static int apply_autosize_plan(conf_t *config,
530569 msg (LOG_INFO ,
531570 "autosize: %s growing map %u->%u MiB "
532571 "(entries=%zu active=%zu/%zu pages %lu%%, "
533- "allocated=%zu/%zu pages %lu%%)" ,
572+ "allocated=%zu/%zu pages %lu%%, reload_work=%zu )" ,
534573 context , config -> db_max_size , target_mb , state -> entries ,
535574 state -> active_pages , state -> map_pages ,
536575 state -> active_percent , state -> allocated_pages ,
537- state -> map_pages , state -> allocated_percent );
576+ state -> map_pages , state -> allocated_percent ,
577+ state -> reload_work_pages );
538578 config -> db_max_size = target_mb ;
539579 if (autosize_reload_floor_mb < target_mb )
540580 autosize_reload_floor_mb = target_mb ;
@@ -554,11 +594,11 @@ static int apply_autosize_plan(conf_t *config,
554594 msg (LOG_INFO ,
555595 "autosize: %s shrinking map %u->%u MiB "
556596 "(entries=%zu active=%zu/%zu pages %lu%%, "
557- "allocated=%zu/%zu pages %lu%%)" ,
597+ "allocated=%zu/%zu pages %lu%%, reload_work=%zu )" ,
558598 context , config -> db_max_size , target_mb , state -> entries ,
559599 state -> active_pages , state -> map_pages , state -> active_percent ,
560600 state -> allocated_pages , state -> map_pages ,
561- state -> allocated_percent );
601+ state -> allocated_percent , state -> reload_work_pages );
562602 config -> db_max_size = target_mb ;
563603 return 1 ;
564604}
@@ -1018,30 +1058,47 @@ static void check_db_size(const conf_t *config)
10181058 max_pages = state .map_pages ;
10191059
10201060 // Active DB pages can stay steady while LMDB's high-water mark grows
1021- // if readers pin old pages across repeated rebuilds.
1061+ // across repeated rebuilds. In auto mode this is informational unless
1062+ // a write actually fails; manual mode keeps it as a warning because the
1063+ // administrator may need to adjust db_max_size.
10221064 msg (LOG_DEBUG ,
10231065 "Trust database active pages: %lu (%lu%%), allocated pages: %zu (%lu%%)" ,
10241066 pages , state .active_percent , state .allocated_pages ,
10251067 state .allocated_percent );
10261068 if (state .allocated_percent > TRUST_DB_RELOAD_HIGHWATER_PERCENT &&
10271069 state .allocated_percent > state .active_percent ) {
1028- msg (LOG_WARNING ,
1070+ int priority = config -> do_audit_db_sizing ? LOG_INFO :
1071+ LOG_WARNING ;
1072+
1073+ msg (priority ,
10291074 "Trust database LMDB map high-water at %lu%% capacity "
10301075 "while active DB pages are at %lu%%" ,
10311076 state .allocated_percent , state .active_percent );
1032- log_lmdb_state (LOG_WARNING , "trust database size check" , 0 );
1077+ if (!config -> do_audit_db_sizing )
1078+ log_lmdb_state (LOG_WARNING ,
1079+ "trust database size check" , 0 );
10331080 }
10341081
10351082 target_mb = autosize_effective_target_mb (& state );
10361083 if (config -> do_audit_db_sizing ) {
1037- if (target_mb > config -> db_max_size )
1038- msg (LOG_WARNING , "Trust database at %lu%% capacity - "
1039- "map will grow automatically before next rebuild" ,
1040- state .active_percent );
1041- else if (autosize_shrink_allowed (config , & state , target_mb ))
1042- msg (LOG_WARNING , "Trust database at %lu%% capacity - "
1084+ if (target_mb > config -> db_max_size ) {
1085+ if (state .active_target_pages > state .map_pages )
1086+ msg (LOG_INFO ,
1087+ "Trust database at %lu%% capacity - "
1088+ "map will grow automatically before next rebuild" ,
1089+ state .active_percent );
1090+ else
1091+ msg (LOG_INFO ,
1092+ "Trust database reload headroom target is %u MiB "
1093+ "(active=%lu%% high-water=%lu%%) - "
1094+ "map will grow automatically before next rebuild" ,
1095+ target_mb , state .active_percent ,
1096+ state .allocated_percent );
1097+ } else if (autosize_shrink_allowed (config , & state , target_mb )) {
1098+ msg (LOG_INFO , "Trust database at %lu%% capacity - "
10431099 "map will shrink automatically on next rebuild" ,
10441100 state .active_percent );
1101+ }
10451102 return ;
10461103 }
10471104
0 commit comments