This commit is contained in:
Alexey
2026-08-27 00:06:37 +03:00
parent 1b3477a333
commit 14e8d10ad3
34 changed files with 221 additions and 299 deletions
+14 -16
View File
@@ -4,8 +4,8 @@ use std::time::{Duration, Instant};
use sha2::{Digest, Sha256};
use super::negotiation::{CarrierClientClass, CarrierLearningContext};
use super::ProfileKey;
use super::negotiation::{CarrierClientClass, CarrierLearningContext};
use crate::config::{WebCarrier, WebCarrierNegotiationAggressiveness};
const PROFILE_WEIGHT: i16 = 32;
@@ -85,9 +85,7 @@ impl Evidence {
}
aggregate.outcomes = aggregate.outcomes.saturating_add(bucket.outcomes);
for (score, value) in aggregate.scores.iter_mut().zip(bucket.scores) {
*score = score
.saturating_add(value)
.clamp(SCORE_MIN, SCORE_MAX);
*score = score.saturating_add(value).clamp(SCORE_MIN, SCORE_MAX);
}
for cohort in bucket.cohorts.iter().flatten() {
if !aggregate.cohorts.contains(&Some(*cohort))
@@ -262,10 +260,9 @@ impl CarrierLearning {
let user_agent_ready = user_agent
.as_ref()
.is_some_and(|entry| entry.outcomes >= thresholds.user_agent);
let ip_ready = thresholds.ip.is_some_and(|minimum| {
ip.as_ref()
.is_some_and(|entry| entry.outcomes >= minimum)
});
let ip_ready = thresholds
.ip
.is_some_and(|minimum| ip.as_ref().is_some_and(|entry| entry.outcomes >= minimum));
let mut scores = [0i16; 4];
for carrier in WebCarrier::ALL {
let index = carrier.index();
@@ -274,11 +271,9 @@ impl CarrierLearning {
* PROFILE_WEIGHT;
}
if user_agent_ready {
scores[index] += i16::from(
user_agent
.as_ref()
.map_or(0, |value| value.scores[index]),
) * USER_AGENT_WEIGHT;
scores[index] +=
i16::from(user_agent.as_ref().map_or(0, |value| value.scores[index]))
* USER_AGENT_WEIGHT;
}
if ip_ready {
scores[index] +=
@@ -362,7 +357,11 @@ impl CarrierLearning {
if !current {
continue;
}
if self.entries.get(&key).is_some_and(|entry| entry.is_live(slot)) {
if self
.entries
.get(&key)
.is_some_and(|entry| entry.is_live(slot))
{
self.insertion_order.push_back((key, sequence));
} else {
self.entries.remove(&key);
@@ -411,8 +410,7 @@ impl CarrierLearning {
let Some(insertion_sequence) = self.next_insertion_sequence() else {
return;
};
self.entries
.insert(key, Evidence::new(insertion_sequence));
self.entries.insert(key, Evidence::new(insertion_sequence));
self.insertion_order.push_back((key, insertion_sequence));
if let Some(entry) = self.entries.get_mut(&key) {
entry.update(slot, deltas, cohort);
+5 -4
View File
@@ -189,9 +189,7 @@ impl CarrierRequest {
/// Checks the complete idempotent identity of one exact attempt request.
pub(crate) fn matches_attempt(self, other: Self) -> bool {
self.matches_client(other)
&& self.attempt == other.attempt
&& self.failure == other.failure
self.matches_client(other) && self.attempt == other.attempt && self.failure == other.failure
}
fn capabilities_bits(self) -> Option<u8> {
@@ -252,7 +250,10 @@ mod tests {
#[test]
fn invalid_candidate_or_attempt_counts_have_no_deadline_slot() {
for (candidate_count, attempt) in [(0, 1), (5, 1), (1, 0), (1, 2), (3, 4)] {
assert_eq!(carrier_attempt_deadline_index(candidate_count, attempt), None);
assert_eq!(
carrier_attempt_deadline_index(candidate_count, attempt),
None
);
}
}
}
+44 -38
View File
@@ -7,14 +7,15 @@ use sha2::{Digest, Sha256};
use subtle::ConstantTimeEq;
use zeroize::Zeroizing;
use super::negotiation::carrier_attempt_deadline_index;
use super::session_admission::admit_initial;
use super::state::{
CarrierChainPhase, decrement_map, matching_profile, new_unique_token, profile_key,
remember_closed_token_locked, remove_expired_locked,
};
use super::negotiation::carrier_attempt_deadline_index;
use super::session_admission::admit_initial;
use super::{
CarrierLearningContext, CarrierRequest, CreateResult, ManagerError, TokenHash, WebProcessRuntime,
CarrierLearningContext, CarrierRequest, CreateResult, ManagerError, TokenHash,
WebProcessRuntime,
};
use crate::config::{WebCarrier, WebRuntimeProfile};
use crate::web::frame;
@@ -62,7 +63,9 @@ impl WebProcessRuntime {
return Err(ManagerError::Authentication);
}
if entry.used {
if entry.carrier_deadline_at.is_some_and(|deadline| now >= deadline)
if entry
.carrier_deadline_at
.is_some_and(|deadline| now >= deadline)
&& entry
.session
.as_ref()
@@ -112,9 +115,8 @@ impl WebProcessRuntime {
token: entry.session_token.as_str().to_owned(),
carrier: session.carrier(),
attempt: carrier_request.attempt(),
candidate_count: automatic.then(|| {
u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)
}),
candidate_count: automatic
.then(|| u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)),
deadline_secs: automatic
.then_some(entry.profile.carrier_negotiation_deadlines_secs[3]),
carrier_state: automatic.then_some(carrier_state),
@@ -139,14 +141,16 @@ impl WebProcessRuntime {
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
)
{
return Err(if matches!(
entry.carrier_phase,
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
) {
ManagerError::Committed
} else {
ManagerError::Protocol
});
return Err(
if matches!(
entry.carrier_phase,
CarrierChainPhase::CommittedPendingHealth | CarrierChainPhase::Healthy
) {
ManagerError::Committed
} else {
ManagerError::Protocol
},
);
}
let Some(carrier) = entry
.carrier_candidates
@@ -155,8 +159,8 @@ impl WebProcessRuntime {
else {
return Err(ManagerError::Protocol);
};
let candidate_count = u8::try_from(entry.carrier_candidates.len())
.map_err(|_| ManagerError::Protocol)?;
let candidate_count =
u8::try_from(entry.carrier_candidates.len()).map_err(|_| ManagerError::Protocol)?;
let deadline_index = carrier_attempt_deadline_index(candidate_count, next_attempt)
.ok_or(ManagerError::Protocol)?;
if entry.carrier_started_at.is_some_and(|started| {
@@ -211,8 +215,8 @@ impl WebProcessRuntime {
if carrier_request.is_automatic() && !profile.carrier_negotiation_enabled {
return Err(ManagerError::Protocol);
}
let capability_selection = carrier_request.uses_capabilities()
&& profile.carrier_negotiation_enabled;
let capability_selection =
carrier_request.uses_capabilities() && profile.carrier_negotiation_enabled;
let learning_policy = (
config.web.carrier_negotiation_enabled() && config.web.carrier_learning,
config.web.carrier_negotiation_aggressiveness,
@@ -222,11 +226,9 @@ impl WebProcessRuntime {
&& profile.carrier_learning
{
let learning = self.learning.lock();
if let Some(epoch) = learning.epoch_for_policy(
learning_policy.0,
learning_policy.1,
learning_policy.2,
) {
if let Some(epoch) =
learning.epoch_for_policy(learning_policy.0, learning_policy.1, learning_policy.2)
{
let (candidates, scores) = learning.rank(
now,
&profile.carriers,
@@ -259,8 +261,7 @@ impl WebProcessRuntime {
[0; 4],
None,
)
} else if carrier_request.uses_capabilities()
&& !carrier_request.supports(profile.carrier)
} else if carrier_request.uses_capabilities() && !carrier_request.supports(profile.carrier)
{
return Err(ManagerError::Protocol);
} else {
@@ -276,9 +277,9 @@ impl WebProcessRuntime {
self.limit_hits.fetch_add(1, Ordering::Relaxed);
return Err(ManagerError::Limit);
};
let carrier_deadline_at = carrier_request.is_automatic().then_some(
now + Duration::from_secs(profile.carrier_negotiation_deadlines_secs[3]),
);
let carrier_deadline_at = carrier_request
.is_automatic()
.then_some(now + Duration::from_secs(profile.carrier_negotiation_deadlines_secs[3]));
let learning_context = learning_epoch.map(|epoch| CarrierLearningContext {
profile_key,
client_ip,
@@ -336,9 +337,7 @@ impl WebProcessRuntime {
token: session_token,
carrier,
attempt: carrier_request.attempt(),
candidate_count: carrier_request
.is_automatic()
.then_some(candidate_count),
candidate_count: carrier_request.is_automatic().then_some(candidate_count),
deadline_secs: carrier_request
.is_automatic()
.then_some(profile.carrier_negotiation_deadlines_secs[3]),
@@ -494,9 +493,7 @@ impl WebProcessRuntime {
token: session_token,
carrier: replacement.carrier,
attempt: Some(replacement.attempt),
candidate_count: Some(
u8::try_from(entry.carrier_candidates.len()).unwrap_or(4),
),
candidate_count: Some(u8::try_from(entry.carrier_candidates.len()).unwrap_or(4)),
deadline_secs: Some(entry.profile.carrier_negotiation_deadlines_secs[3]),
carrier_state: Some(CarrierChainPhase::Provisional.as_str()),
};
@@ -512,7 +509,10 @@ impl WebProcessRuntime {
replacement.old_session.carrier(),
replacement.attempt - 1,
replacement.scores,
replacement.request.failure().map(|failure| failure.as_str()),
replacement
.request
.failure()
.map(|failure| failure.as_str()),
);
self.trace.record_carrier_lifecycle(
client_ip,
@@ -522,7 +522,10 @@ impl WebProcessRuntime {
replacement.old_session.carrier(),
replacement.attempt - 1,
replacement.scores,
replacement.request.failure().map(|failure| failure.as_str()),
replacement
.request
.failure()
.map(|failure| failure.as_str()),
);
self.trace.record_carrier_lifecycle(
client_ip,
@@ -540,7 +543,10 @@ impl WebProcessRuntime {
identity,
TraceLifecycleEvent::SessionCreated,
None,
replacement.request.failure().map(|failure| failure.as_str()),
replacement
.request
.failure()
.map(|failure| failure.as_str()),
);
Ok(result)
}
+3 -8
View File
@@ -357,9 +357,7 @@ fn select_victim(
let requester_usage = runtime.data_budget.owner_usage(owner);
let now = runtime.websocket_tick();
let mut registry = runtime.websockets.lock();
if claim
&& registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight
{
if claim && registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight {
return None;
}
let selected = registry
@@ -408,9 +406,7 @@ fn select_pressure_victim(
claim: bool,
) -> Option<Arc<WebSocketEntry>> {
let mut registry = runtime.websockets.lock();
if claim
&& registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight
{
if claim && registry.evictions_in_flight >= runtime.limits.max_websocket_evictions_in_flight {
return None;
}
let selected = registry
@@ -447,8 +443,7 @@ fn claim_stale_victims(runtime: &WebProcessRuntime, now: u64) -> Vec<Arc<WebSock
.values()
.filter(|entry| !entry.closing.load(Ordering::Acquire))
.filter(|entry| {
now.saturating_sub(entry.last_peer_tick.load(Ordering::Acquire))
>= dead_after(entry)
now.saturating_sub(entry.last_peer_tick.load(Ordering::Acquire)) >= dead_after(entry)
})
.take(available)
.cloned()