1use std::collections::VecDeque;
2use std::sync::atomic::AtomicU64;
3use std::time::Instant;
4
5use crate::h2::client::H2Client;
6#[cfg(feature = "http3")]
7use crate::quic::H3Client;
8
9use crate::pool::h1::H1Io;
10
11#[derive(Debug, Clone, Default)]
12#[non_exhaustive]
13pub struct TlsInfo {
14 pub peer_cert_der: Option<Vec<u8>>,
15 pub version: Option<String>,
16 pub cipher: Option<String>,
17}
18
19pub(crate) struct Opened<C> {
20 pub(crate) conn: C,
21 pub(crate) tls: TlsInfo,
22 pub(crate) started: Instant,
23 pub(crate) connect_ms: Option<u32>,
24}
25
26impl<C> Opened<C> {
27 pub(crate) fn pooled((conn, tls): (C, TlsInfo)) -> Self {
28 Self {
29 conn,
30 tls,
31 started: Instant::now(),
32 connect_ms: None,
33 }
34 }
35
36 pub(crate) fn fresh((conn, tls): (C, TlsInfo), started: Instant) -> Self {
37 Self {
38 conn,
39 tls,
40 started,
41 connect_ms: Some(crate::ResponseTiming::millis(started)),
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
47pub(crate) enum Transport {
48 Tcp,
49 #[cfg_attr(
50 not(feature = "http3"),
51 allow(dead_code, reason = "QUIC transport exists only with http3")
52 )]
53 Quic,
54}
55
56#[derive(Debug, Clone, Hash, PartialEq, Eq)]
57pub(crate) struct PoolKey {
58 pub(crate) host: String,
59 pub(crate) port: u16,
60 pub(crate) scheme: String,
61 pub(crate) proxy: Option<String>,
62 pub(crate) transport: Transport,
63 pub(crate) partition: u64,
64}
65
66pub struct H1Slot {
67 pub(crate) io: Box<dyn H1Io>,
68}
69
70pub(crate) enum PooledConn {
71 H2 {
72 handle: H2Client,
73 last_use: Instant,
74 tls: TlsInfo,
75 },
76 H1 {
77 idle: VecDeque<(H1Slot, Instant)>,
78 last_use: Instant,
79 tls: TlsInfo,
80 },
81 #[cfg(feature = "http3")]
82 H3 {
83 handle: H3Client,
84 last_use: Instant,
85 tls: TlsInfo,
86 },
87}
88
89impl PooledConn {
90 pub(crate) fn last_use(&self) -> Instant {
91 match self {
92 PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use,
93 #[cfg(feature = "http3")]
94 PooledConn::H3 { last_use, .. } => *last_use,
95 }
96 }
97
98 pub(crate) fn set_last_use(&mut self, now: Instant) {
99 match self {
100 PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use = now,
101 #[cfg(feature = "http3")]
102 PooledConn::H3 { last_use, .. } => *last_use = now,
103 }
104 }
105
106 pub(crate) fn is_dead(&self) -> bool {
107 match self {
108 PooledConn::H2 { handle, .. } => handle.is_closed(),
109 PooledConn::H1 { idle, .. } => idle.is_empty(),
110 #[cfg(feature = "http3")]
111 PooledConn::H3 { handle, .. } => handle.is_closed(),
112 }
113 }
114}
115
116#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
117#[non_exhaustive]
118pub struct PoolStats {
119 pub entries: usize,
120 pub max_connections: usize,
121 pub h2_hits: u64,
122 pub h2_misses: u64,
123 pub h1_hits: u64,
124 pub h1_misses: u64,
125 pub h3_hits: u64,
126 pub h3_misses: u64,
127 pub evictions_idle: u64,
128 pub evictions_lru: u64,
129 pub evictions_dead: u64,
130 pub stale_probed: u64,
131 pub h2_ping_failures: u64,
132 pub installs: u64,
133 pub busy: usize,
134 pub idle: usize,
135}
136
137#[derive(Default)]
138pub(crate) struct PoolCounters {
139 pub(crate) h2_hits: AtomicU64,
140 pub(crate) h2_misses: AtomicU64,
141 pub(crate) h1_hits: AtomicU64,
142 pub(crate) h1_misses: AtomicU64,
143 pub(crate) h3_hits: AtomicU64,
144 pub(crate) h3_misses: AtomicU64,
145 pub(crate) evictions_idle: AtomicU64,
146 pub(crate) evictions_lru: AtomicU64,
147 pub(crate) evictions_dead: AtomicU64,
148 pub(crate) stale_probed: AtomicU64,
149 pub(crate) h2_ping_failures: AtomicU64,
150 pub(crate) installs: AtomicU64,
151}