Move deferred-work orchestration from arena into pa/pac.

Move most arena-owned PAC deferral & background thread relevant codes
out to pa/pac for decoupling purposes.
This commit is contained in:
guangli-dai 2026-06-30 16:28:27 -07:00 committed by Guangli Dai
parent e16ebfe27e
commit 01df5c96e0
5 changed files with 274 additions and 202 deletions

View file

@ -152,8 +152,12 @@ void pa_shard_reset(tsdn_t *tsdn, pa_shard_t *shard);
*/
void pa_shard_destroy(tsdn_t *tsdn, pa_shard_t *shard);
/* Flush any caches used by shard */
void pa_shard_flush(tsdn_t *tsdn, pa_shard_t *shard);
/*
* Flush the shard's front caches (SEC + HPA) back to the ecaches. If all is
* true, also fully decay-purge the PAC dirty (and muzzy, unless skipped) extents
* to the OS -- the "save as much memory as possible" path.
*/
void pa_shard_flush(tsdn_t *tsdn, pa_shard_t *shard, bool all);
/* Gets an edata for the given allocation. */
edata_t *pa_alloc(tsdn_t *tsdn, pa_shard_t *shard, size_t size,
@ -178,21 +182,35 @@ bool pa_shrink(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
void pa_dalloc(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata,
bool *deferred_work_generated);
bool pa_decay_ms_set(tsdn_t *tsdn, pa_shard_t *shard, extent_state_t state,
ssize_t decay_ms, pac_purge_eagerness_t eagerness);
ssize_t decay_ms);
ssize_t pa_decay_ms_get(pa_shard_t *shard, extent_state_t state);
/*
* Do deferred work on this PA shard: both PAC decay and the HPA deferred work
* symetrically. The only exception in the symetry is PAC decay-purge policy
* requires the eagerness, which is passed in from the arena.
*/
void pa_shard_set_deferral_allowed(
tsdn_t *tsdn, pa_shard_t *shard, bool deferral_allowed);
/*
* Do deferred work on this PA shard: dispatch to PAC (decay-purge) then HPA.
* Each allocator owns its own policy -- PAC decides eagerness from
* is_background_thread and, on the application path, notifies the background
* thread; the bg-thread driver passes is_background_thread=true and is never
* self-notified.
*/
void pa_shard_do_deferred_work(
tsdn_t *tsdn, pa_shard_t *shard, pac_purge_eagerness_t eagerness);
tsdn_t *tsdn, pa_shard_t *shard, bool is_background_thread);
void pa_shard_try_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
uint64_t pa_shard_time_until_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
/*
* Called on the application path after a pa operation (alloc/expand/shrink/
* dalloc) reports deferred_work_generated -- i.e. it left PAC decay due or
* HPA work (hugify/dehugify/purge) pending. If PAC dirty decay is immediate
* (dirty_decay_ms == 0), purge dirty synchronously; then, if a background
* thread is enabled but idle (sleeping indefinitely), wake it early so the
* pending work runs promptly rather than at the next scheduled wakeup.
*
* Application thread only; must never be called on the background thread.
*/
void pa_shard_handle_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
/******************************************************************************/
/*
* Various bits of "boring" functionality that are still part of this module,

View file

@ -240,10 +240,10 @@ bool pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
pac_purge_eagerness_t eagerness);
/*
* Result of a pac_do_deferred_work() pass. Reported per decay state so the
* caller (on the user-inline path) can decide, per state, whether to notify the
* background thread. npages_new is the per-state epoch backlog delta, only
* meaningful when the corresponding *_epoch_advanced is true.
* Result of a pac_decay_deferred() pass. Reported per decay state so
* pac_do_deferred_work can decide, per state, whether to notify the background
* thread. npages_new is the per-state epoch backlog delta, only meaningful when
* the corresponding *_epoch_advanced is true.
*/
typedef struct pac_deferred_work_result_s pac_deferred_work_result_t;
struct pac_deferred_work_result_s {
@ -254,11 +254,20 @@ struct pac_deferred_work_result_s {
};
/*
* Non-forced deferred decay work for both the dirty and muzzy states.
* Corresponding decay->mtx are acquired internally.
* All deferred decay-purge work for a PAC shard: decide the eagerness from the
* caller context, run pac_decay_deferred, and (application path only) notify the
* background thread for any decay epoch that advanced. The bg-thread driver
* passes is_background_thread=true and is never self-notified.
*/
void pac_do_deferred_work(tsdn_t *tsdn, pac_t *pac,
pac_purge_eagerness_t eagerness, pac_deferred_work_result_t *result);
void pac_do_deferred_work(
tsdn_t *tsdn, pac_t *pac, bool is_background_thread);
/*
* Application-path hook (after deferred_work_generated): wake the background
* thread if it is sleeping idle. Runs the same early-wake logic as the notify
* path (pac_maybe_wake_bg), gated on the thread being idle.
*/
void pac_wake_bg_on_deferred(tsdn_t *tsdn, pac_t *pac);
/*
* Fully decay the extents of the given state, acquiring decay->mtx internally.
@ -278,7 +287,7 @@ bool pac_retain_grow_limit_get_set(
tsdn_t *tsdn, pac_t *pac, size_t *old_limit, size_t *new_limit);
bool pac_decay_ms_set(tsdn_t *tsdn, pac_t *pac, extent_state_t state,
ssize_t decay_ms, pac_purge_eagerness_t eagerness);
ssize_t decay_ms);
ssize_t pac_decay_ms_get(pac_t *pac, extent_state_t state);
/* Whether the muzzy decay path is relevant (muzzy pages exist, or decay is on). */
@ -288,6 +297,12 @@ pac_should_decay_muzzy(pac_t *pac) {
|| pac_decay_ms_get(pac, extent_state_muzzy) > 0;
}
/* Whether dirty decay is immediate (dirty_decay_ms == 0). */
static inline bool
pac_decay_immediately(pac_t *pac) {
return decay_immediately(&pac->decay_dirty);
}
void pac_destroy(tsdn_t *tsdn, pac_t *pac);
void pac_sec_flush(tsdn_t *tsdn, pac_t *pac);