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(not(feature = "http3"), allow(dead_code))]
50 Quic,
51}
52
53#[derive(Debug, Clone, Hash, PartialEq, Eq)]
54pub(crate) struct PoolKey {
55 pub(crate) host: String,
56 pub(crate) port: u16,
57 pub(crate) scheme: String,
58 pub(crate) proxy: Option<String>,
59 pub(crate) transport: Transport,
60 pub(crate) partition: u64,
61}
62
63pub struct H1Slot {
64 pub(crate) io: Box<dyn H1Io>,
65}
66
67pub(crate) enum PooledConn {
68 H2 {
69 handle: H2Client,
70 last_use: Instant,
71 tls: TlsInfo,
72 },
73 H1 {
74 idle: VecDeque<(H1Slot, Instant)>,
75 last_use: Instant,
76 tls: TlsInfo,
77 },
78 #[cfg(feature = "http3")]
79 H3 {
80 handle: H3Client,
81 last_use: Instant,
82 tls: TlsInfo,
83 },
84}
85
86impl PooledConn {
87 pub(crate) fn last_use(&self) -> Instant {
88 match self {
89 PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use,
90 #[cfg(feature = "http3")]
91 PooledConn::H3 { last_use, .. } => *last_use,
92 }
93 }
94
95 pub(crate) fn set_last_use(&mut self, now: Instant) {
96 match self {
97 PooledConn::H2 { last_use, .. } | PooledConn::H1 { last_use, .. } => *last_use = now,
98 #[cfg(feature = "http3")]
99 PooledConn::H3 { last_use, .. } => *last_use = now,
100 }
101 }
102
103 pub(crate) fn is_dead(&self) -> bool {
104 match self {
105 PooledConn::H2 { handle, .. } => handle.is_closed(),
106 PooledConn::H1 { idle, .. } => idle.is_empty(),
107 #[cfg(feature = "http3")]
108 PooledConn::H3 { handle, .. } => handle.is_closed(),
109 }
110 }
111}
112
113#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
114#[non_exhaustive]
115pub struct PoolStats {
116 pub entries: usize,
117 pub max_connections: usize,
118 pub h2_hits: u64,
119 pub h2_misses: u64,
120 pub h1_hits: u64,
121 pub h1_misses: u64,
122 pub h3_hits: u64,
123 pub h3_misses: u64,
124 pub evictions_idle: u64,
125 pub evictions_lru: u64,
126 pub evictions_dead: u64,
127 pub stale_probed: u64,
128 pub h2_ping_failures: u64,
129 pub installs: u64,
130 pub busy: usize,
131 pub idle: usize,
132}
133
134#[derive(Default)]
135pub(crate) struct PoolCounters {
136 pub(crate) h2_hits: AtomicU64,
137 pub(crate) h2_misses: AtomicU64,
138 pub(crate) h1_hits: AtomicU64,
139 pub(crate) h1_misses: AtomicU64,
140 pub(crate) h3_hits: AtomicU64,
141 pub(crate) h3_misses: AtomicU64,
142 pub(crate) evictions_idle: AtomicU64,
143 pub(crate) evictions_lru: AtomicU64,
144 pub(crate) evictions_dead: AtomicU64,
145 pub(crate) stale_probed: AtomicU64,
146 pub(crate) h2_ping_failures: AtomicU64,
147 pub(crate) installs: AtomicU64,
148}