|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Seeded xorshift64 jitter, injectable clock, and the per-host governor. More...
#include "mdl_politeness.h"#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include "ra8_attributes.h"Go to the source code of this file.
Enumerations | |
| enum | mdl_seed_t : uint64_t { k_seed_fallback = 0x9E3779B97F4A7C15ULL } |
| Fallback seed so the xorshift64 state is never 0. More... | |
| enum | mdl_xorshift_t : uint8_t { k_xs_shift_a = 13U , k_xs_shift_b = 7U , k_xs_shift_c = 17U } |
| xorshift64 shift triple (Marsaglia's 13/7/17). More... | |
| enum | mdl_time_unit_t : uint32_t { k_ms_per_s = 1000U , k_ns_per_ms = 1000000U , k_dec_base = 10U } |
| Time-unit conversions shared by the sleep and governor clocks. More... | |
| enum | mdl_http_throttle_t : uint16_t { k_http_too_many_req = 429U , k_http_unavailable = 503U } |
| HTTP status codes the governor treats as a throttle. More... | |
| enum | mdl_gov_defaults_t : uint32_t { k_def_rate_per_min = 60U , k_def_burst = 4U , k_def_backoff_base_ms = 1000U , k_def_backoff_max_ms = 60000U } |
| Governor default tunables (conservative; see mdl_gov_cfg_default). More... | |
| enum | mdl_gov_defaults16_t : uint16_t { k_def_decay_after = 4U , k_def_max_inflight = 1U } |
| Governor default counts that fit uint16 fields. More... | |
Functions | |
| void | mdl_politeness_init (mdl_politeness_t *p, uint64_t seed) |
| Seed the jitter source, using the real host clock for sleeps. | |
| void | mdl_politeness_init_clock (mdl_politeness_t *p, uint64_t seed, mdl_sleep_fn sleep_fn, void *sleep_ctx) |
| Seed the jitter source and inject a clock for the blocking sleep. | |
| static uint64_t | internal_next_rand (uint64_t *state) |
| Advance an xorshift64 state in place and return the new value. | |
| static uint32_t | internal_draw_range (uint64_t *state, uint32_t min_ms, uint32_t max_ms) |
| Draw a jittered value in [min_ms, max(min_ms, max_ms)] from state. | |
| static void | internal_host_sleep_ms (uint32_t ms) |
| Block for ms milliseconds on the host clock. | |
| uint32_t | mdl_politeness_wait (mdl_politeness_t *p, uint32_t min_ms, uint32_t max_ms) |
| Sleep a jittered delay in [min_ms, max_ms] and return it. | |
| static uint32_t | internal_ms_from_secs (int64_t secs) |
| Saturating conversion of a signed-seconds delay into a ms delay. | |
| static bool | internal_all_digits (const char *s) |
| True when s is a non-empty run of ASCII digits. | |
| static bool | internal_parse_http_date (const char *value, int64_t now_wall_s, uint32_t *out_ms) |
| Parse an HTTP-date Retry-After (IMF-fixdate or RFC 850) into a delay. | |
| bool | mdl_retry_after_parse (const char *value, int64_t now_wall_s, uint32_t *out_ms) |
| Parse an HTTP Retry-After header value into a delay in milliseconds. | |
| static int64_t | internal_min_i64 (int64_t a, int64_t b) |
| Smaller of two signed millisecond values. | |
| static int64_t | internal_max_i64 (int64_t a, int64_t b) |
| Larger of two signed millisecond values. | |
| static int64_t | internal_gov_now (const mdl_governor_t *g) |
| Read the governor's clock: injected now_fn, else CLOCK_MONOTONIC. | |
| static void | internal_gov_sleep (mdl_governor_t *g, int64_t ms) |
| Sleep ms through the injected sleeper, else the host clock. | |
| static int64_t | internal_gov_interval_ms (const mdl_gov_cfg_t *cfg) |
| Token interval (ms per request); 0 when rate limiting is disabled. | |
| static int64_t | internal_gov_cap_ms (const mdl_gov_cfg_t *cfg) |
| Token-bucket capacity in ms (interval * burst). | |
| static mdl_host_rec_t * | internal_gov_find (mdl_governor_t *g, const char *host) |
| Find an existing per-host record, or NULL. | |
| static mdl_host_rec_t * | internal_gov_get (mdl_governor_t *g, const char *host, int64_t now) |
| Find-or-create a per-host record; NULL if the table is full or host NULL. | |
| static int64_t | internal_gov_schedule (mdl_governor_t *g, mdl_host_rec_t *rec, int64_t now) |
| Refill credit to now, gate on rate + backoff, consume one token. | |
| mdl_gov_cfg_t | mdl_gov_cfg_default (void) |
| Conservative default tunables for a site that configures none. | |
| void | mdl_governor_init (mdl_governor_t *g, const mdl_gov_cfg_t *cfg, uint64_t seed) |
| Initialise a governor on the real host clock and blocking sleep. | |
| void | mdl_governor_init_clock (mdl_governor_t *g, const mdl_gov_cfg_t *cfg, uint64_t seed, mdl_now_fn now_fn, void *now_ctx, mdl_sleep_fn sleep_fn, void *sleep_ctx) |
| Initialise a governor with injected clock and sleep seams (DI). | |
| ra8_err_t | mdl_governor_acquire (mdl_governor_t *g, const char *host, uint32_t jitter_min_ms, uint32_t jitter_max_ms) |
| Reserve an in-flight slot for a request to host, pacing as required. | |
| void | mdl_governor_release (mdl_governor_t *g, const char *host) |
| Release the in-flight slot reserved by a matching mdl_governor_acquire. | |
| static int64_t | internal_gov_backoff_window (const mdl_gov_cfg_t *cfg, uint16_t level) |
| Exponential backoff window for a level: min(base << (level-1), ceil). | |
| static void | internal_gov_on_throttle (mdl_governor_t *g, mdl_host_rec_t *rec, int64_t now, uint32_t retry_ms) |
| Apply a throttle: raise the backoff level and push the gate forward. | |
| static void | internal_gov_on_success (mdl_governor_t *g, mdl_host_rec_t *rec, int64_t now, bool has_retry, uint32_t retry_ms) |
| Apply a non-throttle outcome: count success, decay, honour Retry-After. | |
| void | mdl_governor_observe_at_wall (mdl_governor_t *g, const char *host, long status, const char *retry_after, int64_t now_wall_s) |
| Observe a response using an explicit wall-clock timestamp. | |
| void | mdl_governor_observe (mdl_governor_t *g, const char *host, long status, const char *retry_after) |
| Feed a completed request's outcome back into the host's governor state. | |
| bool | mdl_governor_peek (const mdl_governor_t *g, const char *host, uint16_t *backoff_level, int64_t *earliest_next_ms) |
| Read a host's current backoff level and earliest-next gate. | |
Seeded xorshift64 jitter, injectable clock, and the per-host governor.
Implements deterministic jitter, fixed-capacity per-host pacing, throttle backoff, and Retry-After parsing behind injectable clock seams. Production uses the host clocks; tests can advance virtual time without sleeping. All governor state remains in caller-owned storage.
Definition in file mdl_politeness.c.
| enum mdl_gov_defaults16_t : uint16_t |
Governor default counts that fit uint16 fields.
| Enumerator | |
|---|---|
| k_def_decay_after | Successes that drop one backoff level. |
| k_def_max_inflight | Strictly serial per host by default. |
Definition at line 168 of file mdl_politeness.c.
| enum mdl_gov_defaults_t : uint32_t |
Governor default tunables (conservative; see mdl_gov_cfg_default).
| Enumerator | |
|---|---|
| k_def_rate_per_min | ~1 request/second sustained. |
| k_def_burst | Small burst allowance. |
| k_def_backoff_base_ms | 1 s first backoff window. |
| k_def_backoff_max_ms | 60 s backoff ceiling. |
Definition at line 160 of file mdl_politeness.c.
| enum mdl_http_throttle_t : uint16_t |
HTTP status codes the governor treats as a throttle.
| Enumerator | |
|---|---|
| k_http_too_many_req | Too Many Requests. |
| k_http_unavailable | Service Unavailable. |
Definition at line 154 of file mdl_politeness.c.
| enum mdl_seed_t : uint64_t |
Fallback seed so the xorshift64 state is never 0.
A zero state is the one fixed point of xorshift64 – it would emit zeros forever. The constant is the golden-ratio odd multiplier used by SplitMix64, chosen for good avalanche from a small seed.
| Enumerator | |
|---|---|
| k_seed_fallback | Substituted when the seed is 0. |
Definition at line 30 of file mdl_politeness.c.
| enum mdl_time_unit_t : uint32_t |
Time-unit conversions shared by the sleep and governor clocks.
| Enumerator | |
|---|---|
| k_ms_per_s | Milliseconds per second. |
| k_ns_per_ms | Nanoseconds per millisecond. |
| k_dec_base | Base-10 radix for strtoull. |
Definition at line 42 of file mdl_politeness.c.
| enum mdl_xorshift_t : uint8_t |
xorshift64 shift triple (Marsaglia's 13/7/17).
| Enumerator | |
|---|---|
| k_xs_shift_a | First left shift. |
| k_xs_shift_b | Right shift. |
| k_xs_shift_c | Second left shift. |
Definition at line 35 of file mdl_politeness.c.
|
static |
True when s is a non-empty run of ASCII digits.
Rejects an empty string and any byte outside 0 through 9.
| [in] | s | NUL-terminated candidate string. |
| true | A non-empty digit run was found. |
| false | The string is empty or contains another byte. |
s is non-NULL and NUL-terminated. s is unchanged. Definition at line 212 of file mdl_politeness.c.
References RA8_INTERNAL.
Referenced by mdl_retry_after_parse().
|
static |
Draw a jittered value in [min_ms, max(min_ms, max_ms)] from state.
Advances the PRNG once and maps the result across the inclusive range.
| [in,out] | state | Non-zero PRNG state. |
| [in] | min_ms | Inclusive lower bound. |
| [in] | max_ms | Inclusive upper bound, clamped up to min_ms. |
| other | A value in the documented inclusive range. |
state points to writable non-zero state. min_ms. state. Definition at line 104 of file mdl_politeness.c.
References internal_next_rand(), and RA8_INTERNAL.
Referenced by internal_gov_on_throttle(), mdl_governor_acquire(), and mdl_politeness_wait().
|
static |
Exponential backoff window for a level: min(base << (level-1), ceil).
Doubles from the configured base with bounded shifts and ceiling saturation.
| [in] | cfg | Governor backoff configuration. |
| [in] | level | One-based throttle level; zero uses the base window. |
| other | A value no greater than backoff_max_ms. |
cfg is non-NULL. level is bounded by k_mdl_gov_level_max in stored state. cfg is unchanged. Definition at line 577 of file mdl_politeness.c.
References mdl_gov_cfg_t::backoff_base_ms, mdl_gov_cfg_t::backoff_max_ms, k_mdl_gov_level_max, and RA8_INTERNAL.
Referenced by internal_gov_on_throttle().
|
static |
Token-bucket capacity in ms (interval * burst).
Expresses the configured burst capacity on the rate-credit timeline.
| [in] | cfg | Governor rate and burst configuration. |
| 0 | Rate limiting is disabled or burst is zero. |
| other | Product of interval and burst. |
cfg is non-NULL. cfg is unchanged. Definition at line 412 of file mdl_politeness.c.
References mdl_gov_cfg_t::burst, internal_gov_interval_ms(), and RA8_INTERNAL.
Referenced by internal_gov_get(), and internal_gov_schedule().
|
static |
Find an existing per-host record, or NULL.
Definition at line 418 of file mdl_politeness.c.
References mdl_host_rec_t::host, mdl_governor_t::hosts, k_mdl_gov_max_hosts, RA8_INTERNAL, strcmp(), and mdl_host_rec_t::used.
Referenced by internal_gov_get(), and mdl_governor_release().
|
static |
Find-or-create a per-host record; NULL if the table is full or host NULL.
Definition at line 433 of file mdl_politeness.c.
References mdl_governor_t::cfg, mdl_host_rec_t::credit_ms, mdl_host_rec_t::earliest_next_ms, mdl_host_rec_t::host, mdl_governor_t::hosts, internal_gov_cap_ms(), internal_gov_find(), k_mdl_gov_max_hosts, mdl_host_rec_t::last_ms, and mdl_host_rec_t::used.
Referenced by mdl_governor_acquire(), and mdl_governor_observe_at_wall().
|
static |
Token interval (ms per request); 0 when rate limiting is disabled.
Converts the configured requests-per-minute ceiling by integer division.
| [in] | cfg | Governor rate configuration. |
| 0 | Rate limiting is disabled. |
| other | Positive request interval. |
cfg is non-NULL. cfg is unchanged. Definition at line 392 of file mdl_politeness.c.
References k_mdl_gov_ms_per_req, RA8_INTERNAL, and mdl_gov_cfg_t::rate_per_min.
Referenced by internal_gov_cap_ms(), and internal_gov_schedule().
|
static |
Read the governor's clock: injected now_fn, else CLOCK_MONOTONIC.
Preserves the arbitrary monotonic epoch used for rate and backoff differences.
| [in] | g | Initialised governor containing the optional clock seam. |
| other | A reading on the governor timeline. |
g is non-NULL and initialised. Definition at line 335 of file mdl_politeness.c.
References k_ms_per_s, k_ns_per_ms, mdl_governor_t::now_ctx, mdl_governor_t::now_fn, and RA8_INTERNAL.
Referenced by mdl_governor_acquire(), and mdl_governor_observe_at_wall().
|
static |
Apply a non-throttle outcome: count success, decay, honour Retry-After.
Advances the success streak, decays one level at threshold, and applies an optional gate.
| [in] | g | Governor providing the decay threshold. |
| [in,out] | rec | Matching host record. |
| [in] | now | Current monotonic time in milliseconds. |
| [in] | has_retry | Whether retry_ms came from a valid header. |
| [in] | retry_ms | Parsed Retry-After delay. |
g and rec are non-NULL and associated. now is on the governor timeline. Definition at line 634 of file mdl_politeness.c.
References mdl_host_rec_t::backoff_level, mdl_governor_t::cfg, mdl_gov_cfg_t::decay_after, mdl_host_rec_t::earliest_next_ms, internal_max_i64(), RA8_INTERNAL, and mdl_host_rec_t::success_streak.
Referenced by mdl_governor_observe_at_wall().
|
static |
Apply a throttle: raise the backoff level and push the gate forward.
Applies capped exponential full jitter while allowing a longer Retry-After to win.
| [in,out] | g | Governor whose jitter state advances. |
| [in,out] | rec | Matching host record. |
| [in] | now | Current monotonic time in milliseconds. |
| [in] | retry_ms | Parsed Retry-After delay, or zero. |
g and rec are non-NULL and associated. now is on the governor timeline. Definition at line 606 of file mdl_politeness.c.
References mdl_host_rec_t::backoff_level, mdl_governor_t::cfg, mdl_host_rec_t::earliest_next_ms, internal_draw_range(), internal_gov_backoff_window(), internal_max_i64(), k_mdl_gov_level_max, mdl_governor_t::rng, and mdl_host_rec_t::success_streak.
Referenced by mdl_governor_observe_at_wall().
|
static |
Refill credit to now, gate on rate + backoff, consume one token.
Caps accrued credit, selects the later rate/backoff gate, and charges one request.
| [in] | g | Initialised governor configuration. |
| [in,out] | rec | Host record to schedule. |
| [in] | now | Current monotonic time in milliseconds. |
| 0 | The request may start immediately. |
| other | Positive wait in milliseconds. |
g and rec are non-NULL and belong to the same governor. now is on the governor's monotonic timeline. rec records the scheduled start and consumed token. rec. Definition at line 470 of file mdl_politeness.c.
References mdl_governor_t::cfg, mdl_host_rec_t::credit_ms, mdl_host_rec_t::earliest_next_ms, internal_gov_cap_ms(), internal_gov_interval_ms(), internal_max_i64(), internal_min_i64(), and mdl_host_rec_t::last_ms.
Referenced by mdl_governor_acquire().
|
static |
Sleep ms through the injected sleeper, else the host clock.
Ignores non-positive delays and saturates positive delays to uint32_t.
| [in,out] | g | Initialised governor containing the optional sleeper seam. |
| [in] | ms | Requested signed delay in milliseconds. |
g is non-NULL and initialised. Definition at line 365 of file mdl_politeness.c.
References internal_host_sleep_ms(), RA8_INTERNAL, mdl_governor_t::sleep_ctx, and mdl_governor_t::sleep_fn.
Referenced by mdl_governor_acquire().
|
static |
Block for ms milliseconds on the host clock.
Converts milliseconds to timespec and delegates to nanosleep.
| [in] | ms | Requested duration in milliseconds. |
ms is a finite uint32_t duration. Definition at line 127 of file mdl_politeness.c.
References k_ms_per_s, k_ns_per_ms, and RA8_INTERNAL.
Referenced by internal_gov_sleep(), and mdl_politeness_wait().
|
static |
Larger of two signed millisecond values.
Performs a direct signed comparison.
| [in] | a | First value. |
| [in] | b | Second value. |
| other | Either a or b. |
Definition at line 317 of file mdl_politeness.c.
References RA8_INTERNAL.
Referenced by internal_gov_on_success(), internal_gov_on_throttle(), and internal_gov_schedule().
|
static |
Smaller of two signed millisecond values.
Performs a direct signed comparison.
| [in] | a | First value. |
| [in] | b | Second value. |
| other | Either a or b. |
Definition at line 298 of file mdl_politeness.c.
References RA8_INTERNAL.
Referenced by internal_gov_schedule().
|
static |
Saturating conversion of a signed-seconds delay into a ms delay.
Clamps past dates to zero and values above the millisecond range to UINT32_MAX.
| [in] | secs | Signed duration in seconds. |
| 0 | secs is non-positive. |
| UINT32_MAX | The converted value would overflow. |
secs uses the same second scale as the parsed date. Definition at line 187 of file mdl_politeness.c.
References k_ms_per_s, and RA8_INTERNAL.
Referenced by internal_parse_http_date(), and mdl_retry_after_parse().
|
static |
Advance an xorshift64 state in place and return the new value.
Applies the fixed three-shift recurrence used by every jitter draw.
| [in,out] | state | Non-zero PRNG state. |
| other | Updated non-zero xorshift64 state. |
state points to writable storage. state. Definition at line 79 of file mdl_politeness.c.
References k_xs_shift_a, k_xs_shift_b, k_xs_shift_c, and RA8_INTERNAL.
Referenced by internal_draw_range().
|
static |
Parse an HTTP-date Retry-After (IMF-fixdate or RFC 850) into a delay.
Tries both supported UTC formats and saturates the deadline delta to milliseconds.
| [in] | value | NUL-terminated HTTP-date text. |
| [in] | now_wall_s | Current Unix wall-clock time in seconds. |
| [out] | out_ms | Parsed non-negative delay. |
| true | out_ms was written. |
| false | Neither date format was valid. |
value and out_ms are non-NULL. now_wall_s and the parsed date share the Unix epoch. out_ms contains a saturated delay. out_ms is unchanged. Definition at line 242 of file mdl_politeness.c.
References internal_ms_from_secs().
Referenced by mdl_retry_after_parse().
| mdl_gov_cfg_t mdl_gov_cfg_default | ( | void | ) |
Conservative default tunables for a site that configures none.
A cautious ceiling that a careful human reader would not exceed: roughly one request per second sustained with a small burst, one-second base backoff doubling to a one-minute cap, and strictly serial per host. A site descriptor may raise or lower any field.
| (by | value) Never fails; always returns the conservative defaults. |
Definition at line 484 of file mdl_politeness.c.
References k_def_backoff_base_ms, k_def_backoff_max_ms, k_def_burst, k_def_decay_after, k_def_max_inflight, and k_def_rate_per_min.
Referenced by internal_config_set_defaults(), mdl_config_gov_cfg(), and mdl_governor_init_clock().
| ra8_err_t mdl_governor_acquire | ( | mdl_governor_t * | g, |
| const char * | host, | ||
| uint32_t | jitter_min_ms, | ||
| uint32_t | jitter_max_ms ) |
Reserve an in-flight slot for a request to host, pacing as required.
The gate every request passes before hitting the network. In order it (1) refuses – without sleeping – when host already has max_inflight requests in flight, so a future parallel loop is bounded per host; (2) computes the token-bucket wait so the sustained rate stays under rate_per_min with up to burst back-to-back; (3) raises that to the host's backoff / Retry-After gate if it is later; (4) adds a jittered spacing delay drawn from [jitter_min_ms, jitter_max_ms]; then sleeps the total through the injected clock and marks one request in flight. On success the caller MUST later call mdl_governor_release. A NULL governor is a no-op that succeeds (politeness disabled), matching a NULL jitter source.
| [in,out] | g | Governor, or NULL to disable pacing. |
| [in] | host | Host key (e.g. from mdl_url_host); may be NULL. |
| [in] | jitter_min_ms | Baseline spacing floor (e.g. the site img delay). |
| [in] | jitter_max_ms | Baseline spacing ceiling (clamped up to the floor). |
| k_ra8_ok | Reserved; the request may proceed (release later). |
| k_ra8_err_would_block | host is at its in-flight cap; try again later. |
Definition at line 527 of file mdl_politeness.c.
References mdl_governor_t::cfg, mdl_host_rec_t::inflight, internal_draw_range(), internal_gov_get(), internal_gov_now(), internal_gov_schedule(), internal_gov_sleep(), k_ra8_err_would_block, k_ra8_ok, mdl_gov_cfg_t::max_inflight, and mdl_governor_t::rng.
Referenced by internal_discover_fetch(), internal_mdl_fetch_governed_get_body(), and priv_mdl_fetch_cache_get_buf().
| void mdl_governor_init | ( | mdl_governor_t * | g, |
| const mdl_gov_cfg_t * | cfg, | ||
| uint64_t | seed ) |
Initialise a governor on the real host clock and blocking sleep.
Equivalent to mdl_governor_init_clock with NULL clock seams: time comes from the host monotonic clock and mdl_governor_acquire blocks on nanosleep. Clamps cfg->burst and cfg->max_inflight up to 1 and seeds the jitter PRNG.
| [out] | g | Governor to initialise (non-NULL). |
| [in] | cfg | Tunables to copy, or NULL for mdl_gov_cfg_default. |
| [in] | seed | Jitter seed; 0 is remapped to a non-zero constant. |
Definition at line 496 of file mdl_politeness.c.
References mdl_governor_init_clock().
Referenced by internal_run_prepared(), and mdl_app_run_discover().
| void mdl_governor_init_clock | ( | mdl_governor_t * | g, |
| const mdl_gov_cfg_t * | cfg, | ||
| uint64_t | seed, | ||
| mdl_now_fn | now_fn, | ||
| void * | now_ctx, | ||
| mdl_sleep_fn | sleep_fn, | ||
| void * | sleep_ctx ) |
Initialise a governor with injected clock and sleep seams (DI).
The dependency-injection entry point. Wires now_fn as the time source and sleep_fn as the sleeper, so a test drives the whole governor against a virtual clock with no real delay. NULL seams select the host clock/sleep, making this a strict superset of mdl_governor_init.
| [out] | g | Governor to initialise (non-NULL). |
| [in] | cfg | Tunables to copy, or NULL for mdl_gov_cfg_default. |
| [in] | seed | Jitter seed; 0 is remapped to a non-zero constant. |
| [in] | now_fn | Injected monotonic clock, or NULL for the host clock. |
| [in] | now_ctx | Context forwarded to now_fn (may be NULL). |
| [in] | sleep_fn | Injected sleeper, or NULL for the host clock. |
| [in] | sleep_ctx | Context forwarded to sleep_fn (may be NULL). |
now_ctx / sleep_ctx outlive every governor call on g. Definition at line 501 of file mdl_politeness.c.
References mdl_gov_cfg_t::burst, mdl_governor_t::cfg, k_seed_fallback, mdl_gov_cfg_t::max_inflight, mdl_gov_cfg_default(), memset(), mdl_governor_t::now_ctx, mdl_governor_t::now_fn, mdl_governor_t::rng, mdl_governor_t::sleep_ctx, and mdl_governor_t::sleep_fn.
Referenced by mdl_governor_init().
| void mdl_governor_observe | ( | mdl_governor_t * | g, |
| const char * | host, | ||
| long | status, | ||
| const char * | retry_after ) |
Feed a completed request's outcome back into the host's governor state.
Closes the loop. On a throttle (status 429 or 503) it raises backoff_level by one (capped), computes an exponential window min(base << (level-1), ceil), draws a full-jitter delay in [0, window], and sets the host's earliest-next gate to now + max(jittered_backoff,
Retry-After) – so Retry-After wins whenever it is longer, in both delta-seconds and HTTP-date forms. On any non-throttle outcome it counts a success and, after decay_after of them, drops one backoff level, easing back toward the base rate; a non-throttle response that still carries Retry-After is honoured as a floor. Call once per request, after the fetch, before the next acquire to the same host observes the new gate.
| [in,out] | g | Governor, or NULL (no-op). |
| [in] | host | Host key of the completed request; may be NULL. |
| [in] | status | HTTP status observed (0 if none / transport error). |
| [in] | retry_after | Raw Retry-After header, or NULL/"" if absent. |
Definition at line 678 of file mdl_politeness.c.
References mdl_governor_observe_at_wall().
Referenced by internal_discover_fetch(), internal_mdl_fetch_governed_get_body(), and priv_mdl_fetch_cache_get_buf().
| void mdl_governor_observe_at_wall | ( | mdl_governor_t * | g, |
| const char * | host, | ||
| long | status, | ||
| const char * | retry_after, | ||
| int64_t | now_wall_s ) |
Observe a response using an explicit wall-clock timestamp.
This is the deterministic-clock form of mdl_governor_observe. The governor still schedules gates against its monotonic clock, but parses an HTTP-date Retry-After relative to now_wall_s. Production callers should use mdl_governor_observe; tests and platforms with an injected wall clock may use this entry point.
| [in,out] | g | Governor, or NULL (no-op). |
| [in] | host | Host key of the completed request; may be NULL. |
| [in] | status | HTTP status observed. |
| [in] | retry_after | Raw Retry-After header, or NULL/empty. |
| [in] | now_wall_s | Current Unix wall-clock time in seconds. |
Definition at line 652 of file mdl_politeness.c.
References internal_gov_get(), internal_gov_now(), internal_gov_on_success(), internal_gov_on_throttle(), k_http_too_many_req, k_http_unavailable, and mdl_retry_after_parse().
Referenced by mdl_governor_observe().
| bool mdl_governor_peek | ( | const mdl_governor_t * | g, |
| const char * | host, | ||
| uint16_t * | backoff_level, | ||
| int64_t * | earliest_next_ms ) |
Read a host's current backoff level and earliest-next gate.
Read-only introspection into the per-host table, used by the unit tests to assert backoff growth/decay and gate scheduling deterministically, and usable by a caller that wants to log a host's throttle state. Does not create a record: an unknown host reports false and leaves the outputs untouched.
| [in] | g | Governor, or NULL. |
| [in] | host | Host key to look up; may be NULL. |
| [out] | backoff_level | Receives the consecutive-throttle level. May be NULL. |
| [out] | earliest_next_ms | Receives the earliest-next gate (mono-ms). May be NULL. |
| true | A record exists; the requested outputs were written. |
| false | No record for host (or NULL argument); outputs untouched. |
Definition at line 683 of file mdl_politeness.c.
References mdl_host_rec_t::backoff_level, mdl_host_rec_t::earliest_next_ms, mdl_host_rec_t::host, mdl_governor_t::hosts, k_mdl_gov_max_hosts, strcmp(), and mdl_host_rec_t::used.
| void mdl_governor_release | ( | mdl_governor_t * | g, |
| const char * | host ) |
Release the in-flight slot reserved by a matching mdl_governor_acquire.
Decrements the matching host record's in-flight count when it is non-zero. NULL arguments, unknown hosts, and unmatched releases are tolerated no-ops so cleanup paths can remain unconditional.
| [in,out] | g | Governor, or NULL (no-op). |
| [in] | host | Host key passed to the paired acquire; may be NULL. |
Definition at line 552 of file mdl_politeness.c.
References mdl_host_rec_t::inflight, and internal_gov_find().
Referenced by internal_discover_fetch(), internal_mdl_fetch_governed_get_body(), and priv_mdl_fetch_cache_get_buf().
| void mdl_politeness_init | ( | mdl_politeness_t * | p, |
| uint64_t | seed ) |
Seed the jitter source, using the real host clock for sleeps.
Equivalent to mdl_politeness_init_clock with a NULL sleeper: the jitter is seeded deterministically and mdl_politeness_wait blocks on nanosleep.
| [in,out] | p | State to initialise (must be non-NULL). |
| [in] | seed | Any value; 0 is remapped to a non-zero constant. |
Definition at line 48 of file mdl_politeness.c.
References mdl_politeness_init_clock().
Referenced by internal_download_page_images().
| void mdl_politeness_init_clock | ( | mdl_politeness_t * | p, |
| uint64_t | seed, | ||
| mdl_sleep_fn | sleep_fn, | ||
| void * | sleep_ctx ) |
Seed the jitter source and inject a clock for the blocking sleep.
The dependency-injection entry point. Wires sleep_fn / sleep_ctx as the sleeper mdl_politeness_wait calls, so a test drives spacing/backoff timing through a fake clock with no real delay. A NULL sleep_fn selects the host clock, making this a strict superset of mdl_politeness_init.
| [in,out] | p | State to initialise (must be non-NULL). |
| [in] | seed | Any value; 0 is remapped to a non-zero constant. |
| [in] | sleep_fn | Injected sleeper, or NULL for the host clock. |
| [in] | sleep_ctx | Context forwarded to sleep_fn (may be NULL). |
sleep_ctx outlives every mdl_politeness_wait call on p. Definition at line 53 of file mdl_politeness.c.
References k_seed_fallback, mdl_politeness_t::sleep_ctx, mdl_politeness_t::sleep_fn, and mdl_politeness_t::state.
Referenced by mdl_politeness_init().
| uint32_t mdl_politeness_wait | ( | mdl_politeness_t * | p, |
| uint32_t | min_ms, | ||
| uint32_t | max_ms ) |
Sleep a jittered delay in [min_ms, max_ms] and return it.
Draws the next xorshift64 value, maps it into [min_ms, max_ms], then blocks for that long – through the injected mdl_sleep_fn when one was wired, else on the host nanosleep. The returned delay is exactly the one requested of the sleeper, so a test with a recording fake can assert the timing without any wall-clock time elapsing.
| [in,out] | p | Jitter source (may be NULL). |
| [in] | min_ms | Lower bound, milliseconds. |
| [in] | max_ms | Upper bound, milliseconds (clamped up to min_ms). |
| 0 | p is NULL (no sleep is performed). |
| other | A value in [min_ms, max(min_ms, max_ms)]. |
Definition at line 134 of file mdl_politeness.c.
References internal_draw_range(), internal_host_sleep_ms(), mdl_politeness_t::sleep_ctx, mdl_politeness_t::sleep_fn, and mdl_politeness_t::state.
Referenced by internal_download_page_image().
| bool mdl_retry_after_parse | ( | const char * | value, |
| int64_t | now_wall_s, | ||
| uint32_t * | out_ms ) |
Parse an HTTP Retry-After header value into a delay in milliseconds.
Accepts both forms RFC 7231 defines: a non-negative delta-seconds integer ("120"), returned as 120000; and an HTTP-date, whose delay is the date minus now_wall_s (clamped at zero, so a past date yields 0). Both the preferred IMF-fixdate ("Sun, 06 Nov 1994 08:49:37 GMT") and the obsolete RFC 850 form are recognised. A pure function with no clock of its own, so a test drives both forms deterministically by supplying now_wall_s.
| [in] | value | Raw header value (leading spaces tolerated), or NULL. |
| [in] | now_wall_s | Current wall-clock time in seconds (for the date form). |
| [out] | out_ms | Receives the delay in milliseconds (non-NULL). |
value parsed as a valid Retry-After. | true | Parsed; *out_ms holds the delay (saturated at UINT32_MAX ms). |
| false | NULL/empty/unparseable input; *out_ms is left unchanged. |
Definition at line 262 of file mdl_politeness.c.
References internal_all_digits(), internal_ms_from_secs(), internal_parse_http_date(), and k_dec_base.
Referenced by mdl_governor_observe_at_wall().